From c9bd7ebd9d84aab11c74b96730d7d40f92f57219 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 30 Mar 2023 10:45:00 +0200 Subject: [PATCH 01/85] gitignore: ignore build folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 87b3202f..2d733b59 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ src/glyphs.h *.pyc .idea .vscode +build From 97cf7683dbb23dfeec8fe7b9ffcc73d00534c31d Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 4 Apr 2023 14:48:18 +0200 Subject: [PATCH 02/85] glyphs and icons: update for stax and apply guidelines --- glyphs/bitcoin_64px.gif | Bin 0 -> 284 bytes glyphs/bitcoin_cash_64px.gif | Bin 0 -> 284 bytes glyphs/bitcoin_gold_64px.gif | Bin 0 -> 283 bytes glyphs/bitcoin_legacy_64px.gif | Bin 0 -> 284 bytes glyphs/bitcoin_private_64px.gif | Bin 0 -> 294 bytes glyphs/bitcoin_testnet_64px.gif | Bin 0 -> 284 bytes glyphs/bitcoin_testnet_legacy_64px.gif | Bin 0 -> 284 bytes glyphs/dash_64px.gif | Bin 0 -> 227 bytes glyphs/digibyte_64px.gif | Bin 0 -> 279 bytes glyphs/dogecoin_64px.gif | Bin 0 -> 266 bytes glyphs/firo_64px.gif | Bin 0 -> 225 bytes glyphs/gamecredits_64px.gif | Bin 0 -> 255 bytes glyphs/horizen_64px.gif | Bin 0 -> 331 bytes glyphs/hydra_64px.gif | Bin 0 -> 525 bytes glyphs/hydra_testnet_64px.gif | Bin 0 -> 525 bytes glyphs/icon_back.gif | Bin 74 -> 74 bytes glyphs/icon_certificate.gif | Bin 1133 -> 1127 bytes glyphs/icon_coggle.gif | Bin 1128 -> 1122 bytes glyphs/icon_crossmark.gif | Bin 1131 -> 1125 bytes glyphs/icon_dashboard.gif | Bin 1133 -> 1127 bytes glyphs/icon_dashboard_x.gif | Bin 1126 -> 1120 bytes glyphs/icon_eye.gif | Bin 1130 -> 1124 bytes glyphs/icon_validate_14.gif | Bin 1125 -> 1119 bytes glyphs/icon_warning.gif | Bin 1130 -> 1124 bytes glyphs/komodo_64px.gif | Bin 0 -> 336 bytes glyphs/lbry_64px.gif | Bin 0 -> 303 bytes glyphs/litecoin_64px.gif | Bin 0 -> 216 bytes glyphs/nanos_badge_bitcoin.gif | Bin 68 -> 76 bytes glyphs/nanos_badge_bitcoin_cash.gif | Bin 68 -> 76 bytes glyphs/nanos_badge_bitcoin_gold.gif | Bin 68 -> 76 bytes glyphs/nanos_badge_bitcoin_private.gif | Bin 1134 -> 1128 bytes glyphs/nanos_badge_bitcoin_testnet.gif | Bin 68 -> 76 bytes glyphs/nanos_badge_dash.gif | Bin 74 -> 74 bytes glyphs/nanos_badge_digibyte.gif | Bin 1130 -> 1123 bytes glyphs/nanos_badge_dogecoin.gif | Bin 75 -> 75 bytes glyphs/nanos_badge_komodo.gif | Bin 77 -> 77 bytes glyphs/nanos_badge_lbry.gif | Bin 68 -> 76 bytes glyphs/nanos_badge_litecoin.gif | Bin 75 -> 75 bytes glyphs/nanos_badge_nix.gif | Bin 1134 -> 1128 bytes glyphs/nanos_badge_peercoin.gif | Bin 75 -> 75 bytes glyphs/nanos_badge_pivx.gif | Bin 1133 -> 1125 bytes glyphs/nanos_badge_qtum.gif | Bin 1132 -> 1125 bytes glyphs/nanos_badge_ravencoin.gif | Bin 65 -> 73 bytes glyphs/nanos_badge_resistance.gif | Bin 74 -> 74 bytes glyphs/nanos_badge_stealth.gif | Bin 1135 -> 1127 bytes glyphs/nanos_badge_stratis.gif | Bin 76 -> 76 bytes glyphs/nanos_badge_vertcoin.gif | Bin 1131 -> 1123 bytes glyphs/nanos_badge_viacoin.gif | Bin 1132 -> 1124 bytes glyphs/nanos_badge_xrhodium.gif | Bin 68 -> 76 bytes glyphs/nanos_badge_xsn.gif | Bin 1132 -> 1126 bytes glyphs/nanos_badge_zcash.gif | Bin 74 -> 74 bytes glyphs/nanos_badge_zcoin.gif | Bin 4098 -> 862 bytes glyphs/nanos_badge_zencash.gif | Bin 1134 -> 1128 bytes glyphs/nanos_icon_back.gif | Bin 74 -> 74 bytes glyphs/nanos_icon_dashboard.gif | Bin 1133 -> 1127 bytes glyphs/nix_64px.gif | Bin 0 -> 354 bytes glyphs/peercoin_64px.gif | Bin 0 -> 320 bytes glyphs/pivx_64px.gif | Bin 0 -> 221 bytes glyphs/qtum_64px.gif | Bin 0 -> 419 bytes glyphs/ravencoin_64px.gif | Bin 0 -> 305 bytes glyphs/resistance_64px.gif | Bin 0 -> 161 bytes glyphs/stealth_64px.gif | Bin 0 -> 367 bytes glyphs/stratis_64px.gif | Bin 0 -> 286 bytes glyphs/vertcoin_64px.gif | Bin 0 -> 241 bytes glyphs/viacoin_64px.gif | Bin 0 -> 263 bytes glyphs/xrhodium_64px.gif | Bin 0 -> 270 bytes glyphs/xsn_64px.gif | Bin 0 -> 170 bytes glyphs/zcash.gif | Bin 0 -> 219 bytes glyphs/zcash_64px.gif | Bin 0 -> 219 bytes glyphs/zclassic_64px.gif | Bin 0 -> 311 bytes icons/nanos_app_bitcoin_cash.gif | Bin 1131 -> 1125 bytes icons/nanos_app_bitcoin_gold.gif | Bin 1131 -> 1125 bytes icons/nanos_app_bitcoin_legacy.gif | Bin 1131 -> 1125 bytes icons/nanos_app_bitcoin_private.gif | Bin 1131 -> 1125 bytes icons/nanos_app_bitcoin_testnet_legacy.gif | Bin 1131 -> 1125 bytes icons/nanos_app_dash.gif | Bin 69 -> 69 bytes icons/nanos_app_digibyte.gif | Bin 1124 -> 1117 bytes icons/nanos_app_dogecoin.gif | Bin 70 -> 70 bytes icons/nanos_app_gamecredits.gif | Bin 1128 -> 1122 bytes icons/nanos_app_horizen.gif | Bin 66 -> 74 bytes icons/nanos_app_hydra.gif | Bin 82 -> 68 bytes icons/nanos_app_hydra_testnet.gif | Bin 82 -> 68 bytes icons/nanos_app_komodo.gif | Bin 76 -> 76 bytes icons/nanos_app_lbry.gif | Bin 1129 -> 1122 bytes icons/nanos_app_litecoin.gif | Bin 67 -> 67 bytes icons/nanos_app_nix.gif | Bin 1131 -> 1125 bytes icons/nanos_app_peercoin.gif | Bin 67 -> 67 bytes icons/nanos_app_pivx.gif | Bin 1128 -> 1120 bytes icons/nanos_app_qtum.gif | Bin 1128 -> 1121 bytes icons/nanos_app_ravencoin.gif | Bin 62 -> 70 bytes icons/nanos_app_resistance.gif | Bin 1128 -> 1122 bytes icons/nanos_app_stealth.gif | Bin 1134 -> 1126 bytes icons/nanos_app_stratis.gif | Bin 71 -> 71 bytes icons/nanos_app_vertcoin.gif | Bin 1122 -> 1114 bytes icons/nanos_app_viacoin.gif | Bin 1129 -> 1121 bytes icons/nanos_app_xrhodium.gif | Bin 82 -> 82 bytes icons/nanos_app_xsn.gif | Bin 648 -> 59 bytes icons/nanos_app_zcash.gif | Bin 67 -> 67 bytes icons/nanos_app_zclassic.gif | Bin 1130 -> 1124 bytes icons/nanox_app_hydra.gif | Bin 79 -> 65 bytes icons/nanox_app_hydra_testnet.gif | Bin 79 -> 65 bytes icons/nanox_app_ravencoin.gif | Bin 73 -> 73 bytes icons/nanox_app_xsn.gif | Bin 646 -> 57 bytes icons/stax_app_bitcoin.gif | Bin 0 -> 167 bytes icons/stax_app_bitcoin_cash.gif | Bin 0 -> 167 bytes icons/stax_app_bitcoin_gold.gif | Bin 0 -> 171 bytes icons/stax_app_bitcoin_legacy.gif | Bin 0 -> 167 bytes icons/stax_app_bitcoin_private.gif | Bin 0 -> 171 bytes icons/stax_app_bitcoin_testnet.gif | Bin 0 -> 167 bytes icons/stax_app_bitcoin_testnet_legacy.gif | Bin 0 -> 167 bytes icons/stax_app_dash.gif | Bin 0 -> 163 bytes icons/stax_app_digibyte.gif | Bin 0 -> 172 bytes icons/stax_app_dogecoin.gif | Bin 0 -> 185 bytes icons/stax_app_firo.gif | Bin 0 -> 174 bytes icons/stax_app_gamecredits.gif | Bin 0 -> 173 bytes icons/stax_app_horizen.gif | Bin 0 -> 189 bytes icons/stax_app_hydra.gif | Bin 0 -> 159 bytes icons/stax_app_hydra_testnet.gif | Bin 0 -> 159 bytes icons/stax_app_komodo.gif | Bin 0 -> 186 bytes icons/stax_app_lbry.gif | Bin 0 -> 163 bytes icons/stax_app_litecoin.gif | Bin 0 -> 156 bytes icons/stax_app_nix.gif | Bin 0 -> 185 bytes icons/stax_app_peercoin.gif | Bin 0 -> 186 bytes icons/stax_app_pivx.gif | Bin 0 -> 155 bytes icons/stax_app_qtum.gif | Bin 0 -> 209 bytes icons/stax_app_ravencoin.gif | Bin 0 -> 166 bytes icons/stax_app_resistance.gif | Bin 0 -> 170 bytes icons/stax_app_stealth.gif | Bin 0 -> 192 bytes icons/stax_app_stratis.gif | Bin 0 -> 171 bytes icons/stax_app_vertcoin.gif | Bin 0 -> 152 bytes icons/stax_app_viacoin.gif | Bin 0 -> 163 bytes icons/stax_app_xrhodium.gif | Bin 0 -> 170 bytes icons/stax_app_xsn.gif | Bin 0 -> 154 bytes icons/stax_app_zcash.gif | Bin 0 -> 156 bytes icons/stax_app_zclassic.gif | Bin 0 -> 183 bytes 135 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 glyphs/bitcoin_64px.gif create mode 100644 glyphs/bitcoin_cash_64px.gif create mode 100644 glyphs/bitcoin_gold_64px.gif create mode 100644 glyphs/bitcoin_legacy_64px.gif create mode 100644 glyphs/bitcoin_private_64px.gif create mode 100644 glyphs/bitcoin_testnet_64px.gif create mode 100644 glyphs/bitcoin_testnet_legacy_64px.gif create mode 100644 glyphs/dash_64px.gif create mode 100644 glyphs/digibyte_64px.gif create mode 100644 glyphs/dogecoin_64px.gif create mode 100644 glyphs/firo_64px.gif create mode 100644 glyphs/gamecredits_64px.gif create mode 100644 glyphs/horizen_64px.gif create mode 100644 glyphs/hydra_64px.gif create mode 100644 glyphs/hydra_testnet_64px.gif create mode 100644 glyphs/komodo_64px.gif create mode 100644 glyphs/lbry_64px.gif create mode 100644 glyphs/litecoin_64px.gif create mode 100644 glyphs/nix_64px.gif create mode 100644 glyphs/peercoin_64px.gif create mode 100644 glyphs/pivx_64px.gif create mode 100644 glyphs/qtum_64px.gif create mode 100644 glyphs/ravencoin_64px.gif create mode 100644 glyphs/resistance_64px.gif create mode 100644 glyphs/stealth_64px.gif create mode 100644 glyphs/stratis_64px.gif create mode 100644 glyphs/vertcoin_64px.gif create mode 100644 glyphs/viacoin_64px.gif create mode 100644 glyphs/xrhodium_64px.gif create mode 100644 glyphs/xsn_64px.gif create mode 100644 glyphs/zcash.gif create mode 100644 glyphs/zcash_64px.gif create mode 100644 glyphs/zclassic_64px.gif create mode 100644 icons/stax_app_bitcoin.gif create mode 100644 icons/stax_app_bitcoin_cash.gif create mode 100644 icons/stax_app_bitcoin_gold.gif create mode 100644 icons/stax_app_bitcoin_legacy.gif create mode 100644 icons/stax_app_bitcoin_private.gif create mode 100644 icons/stax_app_bitcoin_testnet.gif create mode 100644 icons/stax_app_bitcoin_testnet_legacy.gif create mode 100644 icons/stax_app_dash.gif create mode 100644 icons/stax_app_digibyte.gif create mode 100644 icons/stax_app_dogecoin.gif create mode 100644 icons/stax_app_firo.gif create mode 100644 icons/stax_app_gamecredits.gif create mode 100644 icons/stax_app_horizen.gif create mode 100644 icons/stax_app_hydra.gif create mode 100644 icons/stax_app_hydra_testnet.gif create mode 100644 icons/stax_app_komodo.gif create mode 100644 icons/stax_app_lbry.gif create mode 100644 icons/stax_app_litecoin.gif create mode 100644 icons/stax_app_nix.gif create mode 100644 icons/stax_app_peercoin.gif create mode 100644 icons/stax_app_pivx.gif create mode 100644 icons/stax_app_qtum.gif create mode 100644 icons/stax_app_ravencoin.gif create mode 100644 icons/stax_app_resistance.gif create mode 100644 icons/stax_app_stealth.gif create mode 100644 icons/stax_app_stratis.gif create mode 100644 icons/stax_app_vertcoin.gif create mode 100644 icons/stax_app_viacoin.gif create mode 100644 icons/stax_app_xrhodium.gif create mode 100644 icons/stax_app_xsn.gif create mode 100644 icons/stax_app_zcash.gif create mode 100644 icons/stax_app_zclassic.gif diff --git a/glyphs/bitcoin_64px.gif b/glyphs/bitcoin_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..8679b3a13daae657076473216bc08b4192fff1f0 GIT binary patch literal 284 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1lD*os8%uP&B^-WCAOwQ&@Pt46tv^CH(F$F;e z9grH3J_e?%J^d?BzvW*%XUnbb&G+{F=4U&wqQ_y!Ox4b`tWVp*Yc3e2cE5>zYRUic zZ3EBbj~#ymC!bLhyx5~OpKWDmr_s3$3UA9aKG#jZbs^gs29&y6@jf0QmN>!^78yxI zF1J;WIVDzGbYGYHc&ci4)#h6dx*7Lun$1+TC9|?~&YUkNYJ5!Bxa<6!emdRvZA^9T ftXOH@&$8>RdHv!}t?fN`@7+H>dHwoe1_o;YPxpS- literal 0 HcmV?d00001 diff --git a/glyphs/bitcoin_cash_64px.gif b/glyphs/bitcoin_cash_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..8679b3a13daae657076473216bc08b4192fff1f0 GIT binary patch literal 284 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1lD*os8%uP&B^-WCAOwQ&@Pt46tv^CH(F$F;e z9grH3J_e?%J^d?BzvW*%XUnbb&G+{F=4U&wqQ_y!Ox4b`tWVp*Yc3e2cE5>zYRUic zZ3EBbj~#ymC!bLhyx5~OpKWDmr_s3$3UA9aKG#jZbs^gs29&y6@jf0QmN>!^78yxI zF1J;WIVDzGbYGYHc&ci4)#h6dx*7Lun$1+TC9|?~&YUkNYJ5!Bxa<6!emdRvZA^9T ftXOH@&$8>RdHv!}t?fN`@7+H>dHwoe1_o;YPxpS- literal 0 HcmV?d00001 diff --git a/glyphs/bitcoin_gold_64px.gif b/glyphs/bitcoin_gold_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..deb72f919566802617e4e782978c4ce1ee271150 GIT binary patch literal 283 zcmV+$0p$KiNk%w1VL$*t0Pq0-00030|NkNR1ONa4001HX3rTHZXJt)cXK7<=4rgI) zZDBnyE;KbXH8eE@ zyS3I%$#G&mbm!$g@7KQ5M-ylciMHssiBV|SNf`Px zD#tj-Rw{^k@_FD20ZYk>M_VB)W^1Rarz?S*dphKL_VZb6j46es%yikjG|4$F?Zpbr hw}y>)&C8|j-3snoJxg8gHjci|-tPVmA75Pn06PZ`f{FkD literal 0 HcmV?d00001 diff --git a/glyphs/bitcoin_legacy_64px.gif b/glyphs/bitcoin_legacy_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..8679b3a13daae657076473216bc08b4192fff1f0 GIT binary patch literal 284 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1lD*os8%uP&B^-WCAOwQ&@Pt46tv^CH(F$F;e z9grH3J_e?%J^d?BzvW*%XUnbb&G+{F=4U&wqQ_y!Ox4b`tWVp*Yc3e2cE5>zYRUic zZ3EBbj~#ymC!bLhyx5~OpKWDmr_s3$3UA9aKG#jZbs^gs29&y6@jf0QmN>!^78yxI zF1J;WIVDzGbYGYHc&ci4)#h6dx*7Lun$1+TC9|?~&YUkNYJ5!Bxa<6!emdRvZA^9T ftXOH@&$8>RdHv!}t?fN`@7+H>dHwoe1_o;YPxpS- literal 0 HcmV?d00001 diff --git a/glyphs/bitcoin_private_64px.gif b/glyphs/bitcoin_private_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..83b5e8436a13be17308f6e970f156c11deab8567 GIT binary patch literal 294 zcmV+>0ondXNk%w1VL$*t0Pq0-00030|NkNR1ONa4001HX3rTHZXJt)cXK7<=4rgI) zZDBnyE;KbXH8eEzYRUic zZ3EBbj~#ymC!bLhyx5~OpKWDmr_s3$3UA9aKG#jZbs^gs29&y6@jf0QmN>!^78yxI zF1J;WIVDzGbYGYHc&ci4)#h6dx*7Lun$1+TC9|?~&YUkNYJ5!Bxa<6!emdRvZA^9T ftXOH@&$8>RdHv!}t?fN`@7+H>dHwoe1_o;YPxpS- literal 0 HcmV?d00001 diff --git a/glyphs/bitcoin_testnet_legacy_64px.gif b/glyphs/bitcoin_testnet_legacy_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..8679b3a13daae657076473216bc08b4192fff1f0 GIT binary patch literal 284 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1lD*os8%uP&B^-WCAOwQ&@Pt46tv^CH(F$F;e z9grH3J_e?%J^d?BzvW*%XUnbb&G+{F=4U&wqQ_y!Ox4b`tWVp*Yc3e2cE5>zYRUic zZ3EBbj~#ymC!bLhyx5~OpKWDmr_s3$3UA9aKG#jZbs^gs29&y6@jf0QmN>!^78yxI zF1J;WIVDzGbYGYHc&ci4)#h6dx*7Lun$1+TC9|?~&YUkNYJ5!Bxa<6!emdRvZA^9T ftXOH@&$8>RdHv!}t?fN`@7+H>dHwoe1_o;YPxpS- literal 0 HcmV?d00001 diff --git a/glyphs/dash_64px.gif b/glyphs/dash_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..8460234f19d985a4832873062f6fba9e15b268f9 GIT binary patch literal 227 zcmZ?wbhEHbbYO5`_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyra3+RD^I`WUp!~at?teD_Wb5=d*m_gS?97>r?$O|X8PoFecPRTzwDO( zS#QnQZYHEFEFx=uG~j%2@guvy8!4GnZ8i()Tz~l2=ui^t&Yl}V9a(2256#QE*Kg5q z*=_mfDrVWg>S7uvmYd&5Ex8f;BCPdz#>Foh$DiC-cw>SKE9bVwDefjrRwBl$BD1`1 ZZa;PF)h{k-ZENr7?CS2>*?|lU)&OE1Vn6@@ literal 0 HcmV?d00001 diff --git a/glyphs/digibyte_64px.gif b/glyphs/digibyte_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..8d29383d1efff4b9dc248b76c7db5c73e65d989f GIT binary patch literal 279 zcmV+y0qFimNk%w1VL$*t0Pq0-00030|NkNR1ONa4001HX3rTHZXJt)cXK7<=4rgI) zZDBnyE;KbXH8eEr4P%!sD7pMS^U~^w zndmICw{iFUQ@0;?c}TzW=MadtF$i|2_hY#5CewJa2#M%7Sy3GT5 z$uzohI+J>kDHG3tK9y*UFbi)uxlxCM1T7)@59*%sE@k+JxMq1kF%w dEh7DFjh*d``mG(h>l!YOp02*m-mYE%06WF>f{y?I literal 0 HcmV?d00001 diff --git a/glyphs/dogecoin_64px.gif b/glyphs/dogecoin_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..056d89a7db8e977303cd89b724e50f678338266e GIT binary patch literal 266 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1lD*os8%uP&B^-WCAOwQ&@Pt46tv^CH(F$F;e z9grH3J_e@4J^d?BzvW*%XUnbb&G+{F=5KrCG3{CBGRXtm-rZis<8!^C=Ekq?_jcOF zzFC@ytZhbem1;{{J&Wv;RbProEM2!n>GfB$PkI|;-%aBY>OZJxdbBnz`+-E&k$-O= zq}$)Vu;&^(>&ER09x8z=3Oqiye_MFs`wPKLjuquI!_6uKJ!k9`WBX+$b^PJalagAi zUTItpoAqm!*z1O>aP6C2J8w5!nbQ4%`;PXV8AmE&rr30xv3af2VeA{5TiZK#?cTF@ N-~Q#j7s$Y14FJ!Uc@F>p literal 0 HcmV?d00001 diff --git a/glyphs/firo_64px.gif b/glyphs/firo_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..160d99677e6ee53647f448f53d13a7b9a55753ec GIT binary patch literal 225 zcmV<703QEGNk%w1VL$*t0Pp|+00030|NkNR1ONa4001li0000$06+i$0=R^a7t8Gr z<4UwriL-&u`+tzbjw>O^4JJv(}GQrLeSmYcfNzxM1bUsDV z%d}CgT(QRO%I8&q!=W*mr#zRtYP7UXWW$m2dBkjg2+vvFur?xdbJ@$#`{I}X`KjdEP z|8!(*-kG>E;||AUFBRdRtboOWHluf zDo46ODOia4n8n9>x>OYa3ku1|*_LUV7c08^%NFH&o5|%0jEXjU7O6bP{A=hJ-RK;V zQC(f4XtPaws1v?FU`Jy<^U4pX7FG^ dbqWzOY`73&u!kQ?wQ5Gu9-#$`bix$?06QRukbeLG literal 0 HcmV?d00001 diff --git a/glyphs/hydra_64px.gif b/glyphs/hydra_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..381b5198e8afaa68fe49e70f15e923a9b575322a GIT binary patch literal 525 zcmV+o0`mPwNk%w1VL$*t0Pz3-00030|Nj6000000A^8LV3IG5AEC2ui06+jh00091 zjE|`a5Dk}{v{Hz(-CSm@MBT_apYw#|I-QMYps~zauK3W1jMwdb(D8D?o^OW&1!23{ z=eW?NIy8+Gx~d|d*wHJ7+$yuD=+)dTQ@=&_*~1naf6Fb&Bu#2;NqC4$G*k!Z*D~X@ zw-hJD@D`V|NCcTUR%a=Rb}5F4v!~UR@_4A(=+>#!!#LWgDRjz%TFC(Rh+1JK2}nt| zIR*B+JGmJASDIJUHe9I&Q#%KnTtx}e`D@Mj13Q+;>T7K>Yoz@(Jr~7W>N~Ett!xgO zCmT)fNq?h?+51;t&v`EmC(^2Y)P%V(2Fl5XH;4@WlQj+skP@z-Njr#89*f^oavoZF zm(GkpNXG5~X9h$;j*Y}$?h|F*g1360r(Qf*?!CHKx_&orO7@*?N5 z7iNbTf+QrmanUX%oCcze1>@4Z`exs`yO$_y+#D^Ms)<`6?~>e-UnmXRIp(G)rLXp? P(fa4%+PnDPPyhfsJeu{4 literal 0 HcmV?d00001 diff --git a/glyphs/hydra_testnet_64px.gif b/glyphs/hydra_testnet_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..381b5198e8afaa68fe49e70f15e923a9b575322a GIT binary patch literal 525 zcmV+o0`mPwNk%w1VL$*t0Pz3-00030|Nj6000000A^8LV3IG5AEC2ui06+jh00091 zjE|`a5Dk}{v{Hz(-CSm@MBT_apYw#|I-QMYps~zauK3W1jMwdb(D8D?o^OW&1!23{ z=eW?NIy8+Gx~d|d*wHJ7+$yuD=+)dTQ@=&_*~1naf6Fb&Bu#2;NqC4$G*k!Z*D~X@ zw-hJD@D`V|NCcTUR%a=Rb}5F4v!~UR@_4A(=+>#!!#LWgDRjz%TFC(Rh+1JK2}nt| zIR*B+JGmJASDIJUHe9I&Q#%KnTtx}e`D@Mj13Q+;>T7K>Yoz@(Jr~7W>N~Ett!xgO zCmT)fNq?h?+51;t&v`EmC(^2Y)P%V(2Fl5XH;4@WlQj+skP@z-Njr#89*f^oavoZF zm(GkpNXG5~X9h$;j*Y}$?h|F*g1360r(Qf*?!CHKx_&orO7@*?N5 z7iNbTf+QrmanUX%oCcze1>@4Z`exs`yO$_y+#D^Ms)<`6?~>e-UnmXRIp(G)rLXp? P(fa4%+PnDPPyhfsJeu{4 literal 0 HcmV?d00001 diff --git a/glyphs/icon_back.gif b/glyphs/icon_back.gif index a2a7e6d4fa290e4875992d4024e988d14b91df26..f52f795da28e27d098cf4222443496bdcadc469f 100644 GIT binary patch delta 17 YcmebB;&%6Rv#?C$W8h=>Fp=9H03)^pF8}}l delta 17 YcmebB;&%6Rv#?C$W8hdNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLzyfl_c2vWW@lCe eifAy)PIhB{#KXhQ#mT|W#>&FX#5mcS#RvfYgeTnq delta 160 zcmaFP@s>l$-P6s&GLesgkD-Bq;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2FjlCZWlhOzMmklP54$FxpM#U{;*0#VpJCZn8V`BVleXP7Zc9Ru*O^MxgCK MS%7YsY|3H;0J!TdlmGw# diff --git a/glyphs/icon_coggle.gif b/glyphs/icon_coggle.gif index 01c43b2866d6fabca2409e2487292359cedd887c..a51e687f6f3c2c3e5ac8877d3b5a8632d255a55c 100644 GIT binary patch delta 129 zcmaFC@rXmq-P6s&GLesgkKqFY!~g&P85kH8f3g5cApM`aBDX*xC9xzCNdKRxWHT{7 zb>dNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLzyfl_c2vWW@lCe eifAy)PIhB{#KXhQ#mT|W#>&FX#5mcSMHc}1e<#iW delta 160 zcmaFF@q$Ci-P6s&GLesgkD-Bq;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2FjlCZWlhOzMmklP54$FxpM#U{;*0#VpJCZn8V`BVleXP7Zc9Ru*O^MxgCK MS%7YsY|5ew0J5+xg#Z8m diff --git a/glyphs/icon_crossmark.gif b/glyphs/icon_crossmark.gif index 2dcf9d9eebd7c09dddb2ab4b90cbda83c06b6ecd..c30bfe40efbce6cdc99fa21262ecfe1d97a6d955 100644 GIT binary patch delta 129 zcmaFO@svZ$-P6s&GLesgkKqFY!~g&P85kH8f3g5cApM`aBDX*xC9xzCNdKRxWHT{7 zb>dNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLzyfl_c2vWW@lCe eifAy)PIhB{#KXhQ#mT|W#>&FX#5mcS#Q*^Of+yDi delta 160 zcmaFL@tQ-)-P6s&GLesgkD-Bq;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2FjlCZWlhOzMmklP54$FxpM#U{;*0#VpJCZn8V`BVleXP7Zc9Ru*O^MxgCK MS%7YsY|3H)0Jd!{jsO4v diff --git a/glyphs/icon_dashboard.gif b/glyphs/icon_dashboard.gif index 5c305517f83a1d2b0b90e7028b4d28b9eb12d82b..adceb5ac8022d6a3cc708fd747e0a7533ff0403c 100644 GIT binary patch delta 151 zcmaFM@ti};-P6s&GLesgkKqFY!~g&P85kH8f3g5cApM`aBDX*xC9xzCNdKRxWHT{7 zb>dNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLz&Db_b}N`KE)I# z{l7#ZH7~_hsYuD*j`9D$zkh!J`uXGgx36D5f12#f{FH}>n~Rf!osE@+nTc_-HH#4d DI8QjQ delta 156 zcmaFP@s>l$-P6s&GLesgkD-Bq;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2FjdNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLzyfl_c2vWW@lCe eifAy)PIhB{#KXhQ#mT|W#>&FX#5mcSMH>M3eJ98O delta 160 zcmaFB@r*;s-P6s&GLesgkD-Bq;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2FjlCZWlhOzMmklP54$FxpM#U{;*0#VpJCZn8V`BVleXP7Zc9Ru*O^MxgCK MS%7YsY|5ey0I)JGe*gdg diff --git a/glyphs/icon_eye.gif b/glyphs/icon_eye.gif index df4bb829e6d06e0bde643b1b96fde45c093edef1..a2bd5a42c6494c166ab902b67b494d544bbdde03 100644 GIT binary patch delta 129 zcmaFG@q|Om-P6s&GLesgkKqFY!~g&P85kH8f3g5cApM`aBDX*xC9xzCNdKRxWHT{7 zb>dNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLzyfl_c2vWW@lCe eifAy)PIhB{#KXhQ#mT|W#>&FX#5mcSMIQkBfhW`e delta 160 zcmaFD@rpyq-P6s&GLesgkD-Bq;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2FjlCZWlhOzMmklP54$FxpM#U{;*0#VpJCZn8V`BVleXP7Zc9Ru*O^MxgCK MS%7YsY|5e!0JSbHivR!s diff --git a/glyphs/icon_validate_14.gif b/glyphs/icon_validate_14.gif index ccb5cabe38d16ff857d540b64742e4b8346a6949..0ceb67ebeaa261c6c2f3236a030222a56682acef 100644 GIT binary patch delta 129 zcmaFLai2rW-P6s&GLesgkKqFY!~g&P85kH8f3g5cApM`aBDX*xC9xzCNdKRxWHT{7 zb>dNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLzyfl_c2vWW@lCe eifAy)PIhB{#KXhQ#mT|W#>&FX#5mcSMGFA-d?&>K delta 160 zcmcc5@svZ!-P6s&GLesgkD-Bq;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2FjlCZWlhOzMmklP54$FxpM#U{;*0#VpJCZn8V`BVleXP7Zc9Ru*O^MxgCK MS%7YsY|5eq0Iu^bd;kCd diff --git a/glyphs/icon_warning.gif b/glyphs/icon_warning.gif index 08bd4a739c348f3655d195210e9f2d72e4f7c533..a3ee4bfcb4f7ea78f6f369fce3b991fbeee66486 100644 GIT binary patch delta 129 zcmaFG@q|Om-P6s&GLesgkKqFY!~g&P85kH8f3g5cApM`aBDX*xC9xzCNdKRxWHT{7 zb>dNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLzyfl_c2vWW@lCe eifAy)PIhB{#KXhQ#mT|W#>&FX#5mcSMIQkBfhW`e delta 160 zcmaFD@rpyq-P6s&GLesgkD-Bq;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2FjlCZWlhOzMmklP54$FxpM#U{;*0#VpJCZn8V`BVleXP7Zc9Ru*O^MxgCK MS%7YsY|5e!0JSbHivR!s diff --git a/glyphs/komodo_64px.gif b/glyphs/komodo_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..fdaf38b40169804b2d160eb57ed651528c9dc80a GIT binary patch literal 336 zcmV-W0k8f?Nk%w1VL$*t0Pq0-00030|NkNR1ONa4001HX3rTHZXJt)cXK7<=4rgI) zZDBnyE;KbXH8eEkdcg*r8f`;5@k+!tT8+fbk^^RD zZv9Q~kOpG>TmiqmZiPN9=Lh#EhzDp`I2M=y$0$a4hgi1gK-PF*Nx3IENs+0Uc;^Dj zM%pQwM|$}=%86RJaIx~Hg08(Vosu%bxfz-2yBgfO3tOy_LorhM_3prn1)6%7lhc;h|;v^W%$!(g{fm1N7?E3sp<6S z2CBtLT56g}N|>rD8p`-8v{aT8SvTam8>{Pc8-;4O%9>kC3tN2ZxtZ+C3>_`~(fmuD z!C9H?jLoEt>^=I-eSI9d3>FBEq1Sy5=dLIo|H7^=pJ)uP@7(_nFrdJJ1Su2%06RPL BjjjLy literal 0 HcmV?d00001 diff --git a/glyphs/litecoin_64px.gif b/glyphs/litecoin_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..6f0fc2d0903d6d63e7c51e1fa28d13448c14030e GIT binary patch literal 216 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1lD*os8%uP&B^-WCAOwQ&@Pt46tv^CH(F$F;e z9grH3J_e?VJ^d?BzvW*%XUnbb&G+{F=5KrCG3{BW*@0O_+PBm4b{bw}m# z`q#JA_rL!>z1+lOM|il$6pQkX8ywqq2y6a)A$mf5x@Xv;o0UHw-aIKe>t}jZ*Q`~$ NPThKy70SS14FJ#sV=Vvx literal 0 HcmV?d00001 diff --git a/glyphs/nanos_badge_bitcoin.gif b/glyphs/nanos_badge_bitcoin.gif index d43e12f59dd2c522385aa55c73167b4ce91b1bde..7b7a4bbc5bd10079d5bcafae898ff4a755e002e2 100644 GIT binary patch delta 30 lcmZ?qk#P5Pv#?C$W8h=>z`*eT|9=Js2F0H&3=9(mOaOkf2u%P0 delta 22 dcmeZq5pef(v#?C$W8hz`*eT|9=Js2F0H&3=9(mOaOkf2u%P0 delta 22 dcmeZq5pef(v#?C$W8hz`*eT|9=Js2F0H&3=9(mOaOkf2u%P0 delta 22 dcmeZq5pef(v#?C$W8hdNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLzyfl_c2vWW@lCe eifAy)PIhB{#KXhQ#mT|W#>&FX#5mcS#TWqpg(u(u delta 160 zcmaFC@s2~u-P6s&GLesgkD-Bq;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2FjWCZWlhOzMmklP54$FxpM#U{;*0#VpJCZn8V`BVleXP7Zc9Ru*O^MxgCK MS%7YsY|3H`0LGRr(*OVf diff --git a/glyphs/nanos_badge_bitcoin_testnet.gif b/glyphs/nanos_badge_bitcoin_testnet.gif index d43e12f59dd2c522385aa55c73167b4ce91b1bde..7b7a4bbc5bd10079d5bcafae898ff4a755e002e2 100644 GIT binary patch delta 30 lcmZ?qk#P5Pv#?C$W8h=>z`*eT|9=Js2F0H&3=9(mOaOkf2u%P0 delta 22 dcmeZq5pef(v#?C$W8hFp=9H03)^pF8}}l delta 17 YcmebB;&%6Rv#?C$W8hk#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6T_?(KH~rY diff --git a/glyphs/nanos_badge_dogecoin.gif b/glyphs/nanos_badge_dogecoin.gif index 4f97c60c7584861fa69581130e13854b9a1c0304..0082e36f1ae58265892cb9a4c032328fa146b463 100644 GIT binary patch delta 17 YcmebF=63gVv#?C$W8h=>Fp=8<03+B0G5`Po delta 17 YcmebF=63gVv#?C$W8hFp=8{03;j)H~;_u delta 17 YcmebE<#zXUv#?C$W8hz`*eT|9=Js2F0H&3=9(mOaOkf2u%P0 delta 22 dcmeZq5pef(v#?C$W8hFp=8<03+B0G5`Po delta 17 YcmebF=63gVv#?C$W8hk#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6TFp=8<03+B0G5`Po delta 17 YcmebF=63gVv#?C$W8hk#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6T0G)*@Pyhe` delta 161 zcmaFL@s>l$-P6s&GLesgkD-A91pfd3ulS!k!Z$#{C9xzCNZU-*vSCb}n3l?@F!8hk zqw&Po#ylx$R*6aZr6smXN(z&;7$Z4z@`|mBOM+6i=3X9{w1u(PqUFf%bSFev_H L0lH(dF^drZtK2PS diff --git a/glyphs/nanos_badge_qtum.gif b/glyphs/nanos_badge_qtum.gif index 0559f39d1d6bfc155b130def345fe52cd9ae3fbf..d138581c971f1a2ac3179a1a2eb7536a4ead8634 100644 GIT binary patch delta 150 zcmaFE@svZ$-P6s&GLesgkKqFY!~g&P85kH8f3g5cApM`aBDX*xC9xzCNdKRxWHT{7 zb>dNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD~tHqnMm03o(gI-ozv~ z`682p1WUW)Di$(qc{lYN=*u(7eSFf%buHe)dZ02jV7 AlmGw# delta 171 zcmaFL@rFam-P6s&GLesgkD-Bq;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2Fjz{v3b|9=Js2F0H&3=9(m3;})*2t@z@ delta 22 dcmeZt6ma)+voKHOW8hFp=9H03)^pF8}}l delta 17 YcmebB;&%6Rv#?C$W8hdNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLz&Dc_cAF>-T*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2Fj&FX#0a$eCkxO8 IlZ{zS04_%?#sB~S diff --git a/glyphs/nanos_badge_stratis.gif b/glyphs/nanos_badge_stratis.gif index bb0841bce802422ae01aff8954f7ca52f58a8ab4..ed974a27740344dc8e614df0e9087b9cc0c678b8 100644 GIT binary patch delta 17 YcmebA;db|Qv#?C$W8h=>Fp=9403-SYH2?qr delta 17 YcmebA;db|Qv#?C$W8hR diff --git a/glyphs/nanos_badge_vertcoin.gif b/glyphs/nanos_badge_vertcoin.gif index eea49cccf507810433c549a4b0ba5b85714d1083..028881e5c4fb80106198879e046ddd719c0f6c91 100644 GIT binary patch delta 152 zcmaFO@t8x)-P6s&GLesgkKqFY2>k#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6TdNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLz&Dc_cAF>-oWHE n`7@I~M?qq8c4`SwsTOnL};$o%uI}vtyv5K%oi-) delta 169 zcmaFD@rFam-P6s&GLesgkD-Bq;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2Fjz`*eT|9=Js2F0H&3=9(mOaOkf2u%P0 delta 22 dcmeZq5pef(voKHOW8hk#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6TFp=9H03)^pF8}}l delta 17 YcmebB;&%6Rv#?C$W8hdNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLzyfl_c2vWW@lCe eifAy)PIhB{#KXhQ#mT|W#>&FX#5mcS#TWqpg(u(u delta 160 zcmaFC@s2~u-P6s&GLesgkD-Bq;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2FjWCZWlhOzMmklP54$FxpM#U{;*0#VpJCZn8V`BVleXP7Zc9Ru*O^MxgCK MS%7YsY|3H`0LGRr(*OVf diff --git a/glyphs/nanos_icon_back.gif b/glyphs/nanos_icon_back.gif index a2a7e6d4fa290e4875992d4024e988d14b91df26..f52f795da28e27d098cf4222443496bdcadc469f 100644 GIT binary patch delta 17 YcmebB;&%6Rv#?C$W8h=>Fp=9H03)^pF8}}l delta 17 YcmebB;&%6Rv#?C$W8hdNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLz&Db_b}N`KE)I# z{l7#ZH7~_hsYuD*j`9D$zkh!J`uXGgx36D5f12#f{FH}>n~Rf!osE@+nTc_-HH#4d DI8QjQ delta 156 zcmaFP@s>l$-P6s&GLesgkD-Bq;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2FjN}%A5H2 z3;cUQ3S8@myjKjn92-jctZHaHi|nc~Oxrx@%zd2XjsX3Nf`+V(KvYFnJ_7t zY1vt78U{C-s=7J%N*K#YI(uq+8>kT~t9ysqhQ-T&Y literal 0 HcmV?d00001 diff --git a/glyphs/pivx_64px.gif b/glyphs/pivx_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..bc60554c4fefbbea75f957d772c5d347c6b09117 GIT binary patch literal 221 zcmZ?wbhEHbbYO5`_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrfEI>D^I`WUp!~at?teD_Wb5=d*m_gnI_Y#Q`@v(?fAr_{rT>-S*z14 z>k}Cb4=r4pv1HFAFVW2}YrLju&Uxd=8@YaCMrn6S%Fr$hT{(b2@BaQ7o0(b}Iy)M9-l=a2$=|qnOE!l< zl+!SkB1zR>_xST1U=0wy7o8`Lq{`T3XnFM(F9d(Rk%Jit!j~3&?T%WE+X= zyK5PgiU_>mD>2-vJQjysx#`UO%K4mZZ46Dl`}hF0%=*0-Tl}pV@k*YqE^6HFt{M*h zJ3pO D$i|hd literal 0 HcmV?d00001 diff --git a/glyphs/resistance_64px.gif b/glyphs/resistance_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..55d31c2145344acc8f087c97d995005b29ae0629 GIT binary patch literal 161 zcmZ?wbhEHbbYO5`_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrl_9&m8akGFP^jIR`=$6dw%n`J@T0LtaI6`Q`_EgAOGZY{af$zU+2F6 z(Y8^nZbli83kPZ zx%zeO7d9$I%{%s8c_`Ny?c1GPm;U%JZcdmRo@oAx-2kkNuP0x>jGiSs{EiJQ*N$7a zaR?XE%G0TwJ40$BZUdOCqO~cD3gbCrwXx$lXwxv_u)(Z}J(TxU!b#~;Tfvz6OwufJ NGpEj-JR=kU06Pi(s+Rx& literal 0 HcmV?d00001 diff --git a/glyphs/stratis_64px.gif b/glyphs/stratis_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..3dc9e4092aeccb010eb5cf8f1b1963fc7f23bd02 GIT binary patch literal 286 zcmV+(0pb2fNk%w1VL$*t0Pq0-00030|NkNR1ONa4001HX3rTHZXJt)cXK7<=4rgI) zZDBnyE;KbXH8eECapJnq)J08f=D=7=mo%gk4H z)%{gr)Ghi!9982*+&x7eLFEUyL|8^+cm$`oI7E|Xmt)r$7Fn6tVab@%hB@Y$McK)@ z2AVXfStlCcmj$^v7)n|QIB1$+i}-r$gSsmD+Z7yCbI2Q*>NqTWyg7T?eEHn8OdLI0 ktUSGglnnjseTI0={RmW=eXhRF-tPVmA1^;ozg_?UJH|MH(EtDd literal 0 HcmV?d00001 diff --git a/glyphs/vertcoin_64px.gif b/glyphs/vertcoin_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..a2a23ad240fb0d9768acebeb9e4d27ea075f85b7 GIT binary patch literal 241 zcmZ?wbhEHbbYO5`_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrd2)tD^I`WUp!~at?teD_Wb5=d*m_gS!Wx=gre8C()4BGi*xtyFx_lj z`rEhZkjHurMJ3r&s*hi!yjs+&W}3KHYLmqLuG5Pf4~VX4=P}uR;pDuE!)Cjd&$3`y z#drB({_o=ViypMIdKm2}y-_+tBUt0>v`5Dy#LZ7W@0cLooOYA(+RK?scP{4qbuq=t o%{;25z0-ufQgpTJjHpAaN~@KkU;pNo(XsJ~$*GYEVqmZa07Zjl_W%F@ literal 0 HcmV?d00001 diff --git a/glyphs/viacoin_64px.gif b/glyphs/viacoin_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..b5c888ace43f3dcd4886c74b9985c9cccf08b04a GIT binary patch literal 263 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1lD*os8%uP&B^-WCAOwQ&@Pt46tv^CH(F$F;e z9grH3J_e=(J^d?BzvW*%XUnbb&G+{F=5KrCG40t-#;lc0vEJMC)cZG-w_EOgWo`fa zPs4(!!WoW2@uxy2e=1>{9N76Lsy1Q$G~MvWXVnfJ`|;xihviL);EIM9kK1QfmfT!<(m-N`0hd-&$*Rod zU8k1bes;?^T>dbI1?# zSY3v{g;jaX;l9W1dWEvzX4DZx=rdSYc!mh{wU{&I_;S>cUYfFb)t9r}(s|!#OoAK&*jFFsBe6bAs9M(%atr0DA U4XC}%-R=Di9xgsk9#H@QJ8PkN00000 literal 0 HcmV?d00001 diff --git a/glyphs/xsn_64px.gif b/glyphs/xsn_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..9c08fee99d1c1f833865a2bf29a325988a53fa5f GIT binary patch literal 170 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1l>VQa)3bCU^SwR4`P&|O zOncV3?A57l@3@bD^11%4*WKYHq)$ literal 0 HcmV?d00001 diff --git a/glyphs/zcash.gif b/glyphs/zcash.gif new file mode 100644 index 0000000000000000000000000000000000000000..c3578a15bad138808011ea23d361b28511eafc4e GIT binary patch literal 219 zcmZ?wbhEHbbYO5`_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrYSxBD^I`WUp!~at?teD_Wb5=d*m_g8S|0@H&<%!-dV8b+^n4Bigi2w z@w3cpI+B!?;q%Vxl-l`CHExT7M7Ey#kf?e+cm1=ia)(2m zyQBGEZ|tf)8!oD0`Xl7T~SyQ0B>&Op)s^G8iOZ{*=rLwkrO$ Sa@VO_uYPe!Ylkv0SOWl3#9#mb literal 0 HcmV?d00001 diff --git a/glyphs/zcash_64px.gif b/glyphs/zcash_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..c3578a15bad138808011ea23d361b28511eafc4e GIT binary patch literal 219 zcmZ?wbhEHbbYO5`_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrYSxBD^I`WUp!~at?teD_Wb5=d*m_g8S|0@H&<%!-dV8b+^n4Bigi2w z@w3cpI+B!?;q%Vxl-l`CHExT7M7Ey#kf?e+cm1=ia)(2m zyQBGEZ|tf)8!oD0`Xl7T~SyQ0B>&Op)s^G8iOZ{*=rLwkrO$ Sa@VO_uYPe!Ylkv0SOWl3#9#mb literal 0 HcmV?d00001 diff --git a/glyphs/zclassic_64px.gif b/glyphs/zclassic_64px.gif new file mode 100644 index 0000000000000000000000000000000000000000..7491d7fe942cf218402abc7ea61756571af11262 GIT binary patch literal 311 zcmV-70m%MGNk%w1VL$*t0Pp|+00030|NkNR1ONa4001li0000$06+i$0{)DTsR->4 zJI|l$bjBQj#_%G?2^3~CYMk>#WIake7fmXex0E3^ibW7$|Tak1Uh}o zD5(mYTCZALW4nW9#bBvu97^lF=S17BjvEd0r(8ZGH}CQM*Zfz;_R=L-$5B{@wfAP2 zh^Xfn$rUJB$@0i_Sd@9R2-s-#32GUNIjK1cSn7!?qPpxdD~khri(8{hx@F6# zNK484O3WD?hHNKD$4mvCEA3|rtPIE3=U1zpmV^E59Wq2cu2xR%oNT=A*6a?CW*sk1 zZ-2iYys0nEKOCT4Hg&yxRTJ35AUK8H!VPq22O*??>>x%XQjuY?4>boVPCMr@707xI Jx3MSy06W|>j#K~u literal 0 HcmV?d00001 diff --git a/icons/nanos_app_bitcoin_cash.gif b/icons/nanos_app_bitcoin_cash.gif index 9fa736b194931ccf48c15dac65a4f8b2f865f3d3..fabc8a31d377ea7a9795fc95defc47b220f008bd 100644 GIT binary patch delta 151 zcmaFO@svZ$-P6s&GEsm*fZ+oJ!~g&P85kH8f3g5cApM`aBDX*xC9xzCNdKRxWHT{7 zb>dNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLz&Db_b}N`KE)I# z{l7#ZH7~_hsYuD*j`9D$zkh!J`uXGgx36D5f12#f{FH}>n~Rf!osE@+nTc_-HH!fN DI3YN# delta 156 zcmaFL@tQ-)-P6s&GEsm*fT4kb;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2Fj8^sX$( diff --git a/icons/nanos_app_bitcoin_gold.gif b/icons/nanos_app_bitcoin_gold.gif index 9fa736b194931ccf48c15dac65a4f8b2f865f3d3..fabc8a31d377ea7a9795fc95defc47b220f008bd 100644 GIT binary patch delta 151 zcmaFO@svZ$-P6s&GEsm*fZ+oJ!~g&P85kH8f3g5cApM`aBDX*xC9xzCNdKRxWHT{7 zb>dNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLz&Db_b}N`KE)I# z{l7#ZH7~_hsYuD*j`9D$zkh!J`uXGgx36D5f12#f{FH}>n~Rf!osE@+nTc_-HH!fN DI3YN# delta 156 zcmaFL@tQ-)-P6s&GEsm*fT4kb;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2Fj8^sX$( diff --git a/icons/nanos_app_bitcoin_legacy.gif b/icons/nanos_app_bitcoin_legacy.gif index 9fa736b194931ccf48c15dac65a4f8b2f865f3d3..fabc8a31d377ea7a9795fc95defc47b220f008bd 100644 GIT binary patch delta 151 zcmaFO@svZ$-P6s&GEsm*fZ+oJ!~g&P85kH8f3g5cApM`aBDX*xC9xzCNdKRxWHT{7 zb>dNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLz&Db_b}N`KE)I# z{l7#ZH7~_hsYuD*j`9D$zkh!J`uXGgx36D5f12#f{FH}>n~Rf!osE@+nTc_-HH!fN DI3YN# delta 156 zcmaFL@tQ-)-P6s&GEsm*fT4kb;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2Fj8^sX$( diff --git a/icons/nanos_app_bitcoin_private.gif b/icons/nanos_app_bitcoin_private.gif index 8eae073e5e35b11f019831b94a21a93154bb3d92..8f33da7b8b8e02bc4bdb41d0610bc9aea275333c 100644 GIT binary patch delta 129 zcmaFO@svZ$-P6s&GEsm*fZ+oJ2>k#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6TdNliO-CA(yS7b@=Hr>m6R0zPgZ4&oLtYCGx-gp732TOYD{{QLz&Db_b}N`KE)I# z{l7#ZH7~_hsYuD*j`9D$zkh!J`uXGgx36D5f12#f{FH}>n~Rf!osE@+nTc_-HH!fN DI3YN# delta 156 zcmaFL@tQ-)-P6s&GEsm*fT4kb;s5{t3=9m4|G6W40~A~mOA>*!%|tC5#?*;vsf-E} zPb)AQPke36lagkYn3P{yVymR2Fj8^sX$( diff --git a/icons/nanos_app_dash.gif b/icons/nanos_app_dash.gif index 77813957fa133980a15e8a74dc985aeef89092ff..fc2ac02673d29bbf5e9de21491e06bfc42df9dcf 100644 GIT binary patch delta 17 YcmZ>D<#zXUv#?AQU=U#VFp=8|03#>_Bme*a delta 17 YcmZ>D<#zXUv#?AQU=Uzvn8k#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6TB<97FSv#?AQU=U#VFp=9D03%8SCjbBd delta 17 YcmZ>B<97FSv#?AQU=Uzvn8k#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6TQgrupv#?AQU=Uzf$ix5y|NsBr($fP(ia%KxxfqxjCJGw@0O8mRxBvhE diff --git a/icons/nanos_app_hydra_testnet.gif b/icons/nanos_app_hydra_testnet.gif index ef5edfa3b5f5ca27c30eee4c9a494dad44a0e5d5..29a16ab6469347c4cbafd74d082d655c8a8b24ed 100644 GIT binary patch delta 25 ecmWG?5q9@Qgrupv#?AQU=Uzf$ix5y|NsBr($fP(ia%KxxfqxjCJGw@0O8mRxBvhE diff --git a/icons/nanos_app_komodo.gif b/icons/nanos_app_komodo.gif index c0c2536f3f47f68b22817835542aee14dde710d4..0145d1eca429cd7470a73f1f8719192da9ccd49e 100644 GIT binary patch delta 17 YcmebA;db|Qv#?AQU=U#VFp=9403;R!IRF3v delta 17 YcmebA;db|Qv#?AQU=Uzvn8@u203ucc$p8QV diff --git a/icons/nanos_app_lbry.gif b/icons/nanos_app_lbry.gif index 64a44ae3a14b1bbe1d20cc550415a2de3bb8c2ea..01446fcb9ca790c86db56ffab5ef824627f458e8 100644 GIT binary patch delta 150 zcmaFK@rXmq-P6s&GEsm*fZ+oJ2>k#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6T};$o%uI}vEm#Zz%&0lN delta 179 zcmaFF@sdNy-P6s&GEsm*fT4i_1pfd3ulS!k!Z$#{C9xzCNZU-*vSCb}n3l?@F!8hk zqw&Po#ylx$R*6aZr6smXN(z&;7$Z4z@`|mBOM+6};$o%uI|742nNlfG(SC$YKZpdQLrA diff --git a/icons/nanos_app_litecoin.gif b/icons/nanos_app_litecoin.gif index 6b13d811706a309e90cf52b911946828f3c2ffc3..ea6eca2734f12a6e7f31aa29f022150220e3f7d6 100644 GIT binary patch delta 17 YcmZ>E=63gVv#?AQU=U#VFp=8=03zfB9smFU delta 17 YcmZ>E=63gVv#?AQU=Uzvn8k#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6TE=63gVv#?AQU=U#VFp=8=03zfB9smFU delta 17 YcmZ>E=63gVv#?AQU=Uzvn8k#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6Ti=3X9{w1u(PqUFf%bSFev_H L0lH(dF^et$r|T_S diff --git a/icons/nanos_app_qtum.gif b/icons/nanos_app_qtum.gif index 7e2c908c38d2251c01112da4a3a05c466bb8efe3..26e7d77d2da9762b2b1a46b4086a0f74e9430ed7 100644 GIT binary patch delta 149 zcmaFC@sLBy-P6s&GEsm*fZ+oJ2>k#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6T)%|H+!nNt1h+=d!V}vM@6-PBvpP0sz<0F;V~k delta 176 zcmaFJ@q$Ci-P6s&GEsm*fT4i_1pfd3ulS!k!Z$#{C9xzCNZU-*vSCb}n3l?@F!8hk zqw&Po#ylx$R*6aZr6smXN(z&;7$Z4z@`|mBOM+6lXmxXv#?AQU=U#VzyJdO|NmF~$pU6h6xId+i&O|g delta 25 ecmZ>>6L$A>voKE-U=UzvU;u&t|Nl>v)&>AaUk0)O diff --git a/icons/nanos_app_resistance.gif b/icons/nanos_app_resistance.gif index e702f7793fcc1101a8eedb4553d62fc9575b5792..0f5ec19e6dfcea8963b8e1c45bf7423d45dc4997 100644 GIT binary patch delta 129 zcmaFC@rXmq-P6s&GEsm*fZ+oJ2>k#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6Tk#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6TcUobfW cMYWg}CVMmA=i=hzU}s}xVP;~SY|UZ}0CB=8^Z)<= delta 158 zcmaFH@s2~u-P6s&GEsm*fT4i_1pfd3ulS!k!Z$#{C9xzCNZU-*vSCb}n3l?@F!8hk zqw&Po#ylx$R*6aZr6smXN(z&;7$Z4z@`|mBOM+6};$o%uI|742nNlfR31K H%wh}xCS5GY diff --git a/icons/nanos_app_stratis.gif b/icons/nanos_app_stratis.gif index a1e85df6ddf337e016be0c87190eabafbf2e3376..819aedb255dd3b22bcfcfa42513306a74afa50ce 100644 GIT binary patch delta 17 YcmZ>F=XUpWv#?AQU=U#VFp=8^03&P!DgXcg delta 17 YcmZ>F=XUpWv#?AQU=Uzvn8k#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6Tk#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6T6XfJzXJchy SW@2PuQ2faPbkAgC7Ciut5ivpl diff --git a/icons/nanos_app_xrhodium.gif b/icons/nanos_app_xrhodium.gif index 8e9e2318b4fdc12defa215b7f99ee6677413a126..03a79af9da76076941c53e9e93ffb749f88dc29d 100644 GIT binary patch delta 38 pcmWFvQgHWlv#?AQU=U#V$iVRb|9=KB31le#WMSZ9V3??21ON$g4uAjv delta 38 pcmWFvQgHWlv#?AQU=Uzf$iVRb|9=KB31le#WMSlDV4A341ONfC4l@7% diff --git a/icons/nanos_app_xsn.gif b/icons/nanos_app_xsn.gif index 8819a7db107c077819614852997f757c4afe157a..b55e0ccff52e5c8c8f283b2c349a91162b695052 100644 GIT binary patch delta 28 hcmeBRwH9{wbh9u|6krfwXkY+=|Ns9_lvZc71^`^F2QB~r literal 648 zcmZ?wbhEHb6krfw_`m=HKY#vI{K*1l>VQa)3ZxN)4{^3rViZPPR-@vbW>1sj#ZZEyztRNmQuF&B-gas<2f`Ovz75wF0t1 z!um=IU?nBlwn~m52?day&iO^D3Z{Byy2*wnMhfPZdWL2OmPRHz3PuKo=K2Qa`i923 z28LD!W>&_Q3Q(YA$E9FXl#*r@;>0WrfRwK%ybv!En1KTiQPai+LfA{vy>sK#dJb(7|$>T>4 zAKbrp_s;EGH*Z|OcJ<2TOBXMkKX>-b=~E|996xsS$l*f=5A5H!chBx!J9li~wsp(q zO&d3?U$=J6>QyUOEMK;C$>K!|7tEhGch2ltGiOYnHg(G6NfRgZ_x1L4cXf8Ox3#u3 zH#IiY*VWckS5;P&mz9*?xfYiVkztEs9eD=8|-%gM?} iOG!$Ii;0Q|3keGF^YQXE=63gVv#?AQU=U#VFp=8=03zfB9smFU delta 17 YcmZ>E=63gVv#?AQU=Uzvn8k#5U-2gkn5p=myCSzhAtkXS5lH`^sAMxSK6TVQa)3#8IXksPAt^OIGtXA({qFrr3YjUkO5vuy2EGN( zsTr9bRYj@6RemAKRoTgwDN6QsTs9R}6}bhusU?XD6}dTi#a0!zN{K1?NvT#qHb_`s zNdc^+B->WW5hS4iveP-gC{@8!&rCPj(8Nf=+)~fb%)rvfL`T8Mz|dUZz+B(ZSl7VN z%D~LZ*ir!slHCStb$zJpq2r7wn`Z#B?VUc`sL;2dgaD?`9*7iAWdWaj57fXqxx$}cUkRZ`LiS)vcM1?W9} zxc`70cnGED0fVIo=zqrl|Nj2@{p;tC@87({PcxqRv3h4bgmo;iK$#u35cm<%;FYmM&SmXyJnS^XAT(J!|HS>C>i8nLKIYg#NzXp6;&Bj`p_Jmgc6$ zhWfhNn(C^`it@73lH#Jmg8aPPob0U3jP$hBl;otug!s7FnCPg;i14t`kl>)e0DnJU zA8#*D4|g|L7iT9&2YWkP8*3{|3v)A56JsMo1ARSR9c?X54RtkD6=fww1$jAH8EGj= f32`w|5n&-g0e(JS9&Rp94t6$H7G@?!1_o;YXcG2h diff --git a/icons/stax_app_bitcoin.gif b/icons/stax_app_bitcoin.gif new file mode 100644 index 0000000000000000000000000000000000000000..96b6eaae99217e09da23b19c10953593f180ba1c GIT binary patch literal 167 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyri7k;#)8@WirL1up8M>Jd3!hU^oa=zU6#G{T$v}@bn(O~<1-g`);|7z zQut@pTm>yNmAH}<)4QG)+BF^%Go86YX^Th}@9w8n>m2ew?_q9Vx>`HB=8cnTq^Xfj NfA*W*RVx@6tO57oL4E)L literal 0 HcmV?d00001 diff --git a/icons/stax_app_bitcoin_cash.gif b/icons/stax_app_bitcoin_cash.gif new file mode 100644 index 0000000000000000000000000000000000000000..fb318986e3d03436b7760e5e4143e4a78ed337d0 GIT binary patch literal 167 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyri7k;#)8@WirL1up8M>Jd3!hU^oa=zU6#G{T$v}@bn(O~<1-g`);|7z zQut@pTm>yNmAH}<)4QG)+BMop6i@e&*cz#~^;)jt%7@3ccOILxbeZXHo6kY`cen!5RP#j6(bX literal 0 HcmV?d00001 diff --git a/icons/stax_app_bitcoin_gold.gif b/icons/stax_app_bitcoin_gold.gif new file mode 100644 index 0000000000000000000000000000000000000000..13b06cf06943eb9e70d5e751ab162012b3d7ebfa GIT binary patch literal 171 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrj(w3MvmG1!IL*0dUj>Yos|2fH#WA4w=Iibk@ZTeYblR?vCeFT)%Pdn zGkRr-KH6YDOJ|z$+}Bf!>=tUMoUYjQ&BrPF`-#hO8&!;&v-Kv|W%6%*nxeKiXzT8I Sv5ybVvfcl3`G#-?25SJ30YfJd3!hU^oa=zU6#G{T$v}@bn(O~<1-g`);|7z zQut@pTm>yNmAH}<)4QG)+BF^%Go86YX^Th}@9w8n>m2ew?_q9Vx>`HB=8cnTq^Xfj NfA*W*RVx@6tO57oL4E)L literal 0 HcmV?d00001 diff --git a/icons/stax_app_bitcoin_private.gif b/icons/stax_app_bitcoin_private.gif new file mode 100644 index 0000000000000000000000000000000000000000..7dc5f6473d9fab7aaeb80028e252d91e051e4c9e GIT binary patch literal 171 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrj(w3&XaFB9?dS1^)xoK-pmo@_}uZK=Ctcd3s-s-E!PVFSfZ^z?{(_> zhPP4<^V2-$SUNa`ugZwBT(~;5!^|nk_g3y%=d*|E?rQ9av5l8Iv-pdabN%MvpL4E= RE!+EhL)!W6N5UBxtO4U|L8t%# literal 0 HcmV?d00001 diff --git a/icons/stax_app_bitcoin_testnet.gif b/icons/stax_app_bitcoin_testnet.gif new file mode 100644 index 0000000000000000000000000000000000000000..96b6eaae99217e09da23b19c10953593f180ba1c GIT binary patch literal 167 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyri7k;#)8@WirL1up8M>Jd3!hU^oa=zU6#G{T$v}@bn(O~<1-g`);|7z zQut@pTm>yNmAH}<)4QG)+BF^%Go86YX^Th}@9w8n>m2ew?_q9Vx>`HB=8cnTq^Xfj NfA*W*RVx@6tO57oL4E)L literal 0 HcmV?d00001 diff --git a/icons/stax_app_bitcoin_testnet_legacy.gif b/icons/stax_app_bitcoin_testnet_legacy.gif new file mode 100644 index 0000000000000000000000000000000000000000..96b6eaae99217e09da23b19c10953593f180ba1c GIT binary patch literal 167 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyri7k;#)8@WirL1up8M>Jd3!hU^oa=zU6#G{T$v}@bn(O~<1-g`);|7z zQut@pTm>yNmAH}<)4QG)+BF^%Go86YX^Th}@9w8n>m2ew?_q9Vx>`HB=8cnTq^Xfj NfA*W*RVx@6tO57oL4E)L literal 0 HcmV?d00001 diff --git a/icons/stax_app_dash.gif b/icons/stax_app_dash.gif new file mode 100644 index 0000000000000000000000000000000000000000..ff4c19b0caaddbe54936d6f21e1cb3108f0584ee GIT binary patch literal 163 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrkI}om8akGFP>w;T3_FFch_Fyxfgew Tndkqss$^gO_3I)*3=Gx)71c$) literal 0 HcmV?d00001 diff --git a/icons/stax_app_dogecoin.gif b/icons/stax_app_dogecoin.gif new file mode 100644 index 0000000000000000000000000000000000000000..edf8431fce3567a09cc62cf671478583f8117e73 GIT binary patch literal 185 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrlOwu2@9`rEN0$vOWSz&oa`H#N#9jNEJK%e hY-)G&lJ?I}61P~iNp)FkVEcR`GIjNos{A*G#<9`)_wLAt z&%D{N>T3Us9U2ARPbN$)l;fAp{QPCN(`2u;njIod{&x4aWM7lKoV8``jcs-@sd**t V^0^P+C~f`UGBs>^aUcVOH2@QuMtJ}L literal 0 HcmV?d00001 diff --git a/icons/stax_app_gamecredits.gif b/icons/stax_app_gamecredits.gif new file mode 100644 index 0000000000000000000000000000000000000000..d36e7a42f3c54509cf3624a9ce1abe0c44b37a9c GIT binary patch literal 173 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrnH{K#;QAgVL=OSbr;XuRXr!d7WFXvd{aic9$j(J_bR#X(! U^-XT`uUb_Y{!om0SpY*0NmqAbN~PV literal 0 HcmV?d00001 diff --git a/icons/stax_app_hydra.gif b/icons/stax_app_hydra.gif new file mode 100644 index 0000000000000000000000000000000000000000..810a8dd9f22756ea4e18de7bf956edde552cb186 GIT binary patch literal 159 zcmZ?wbhEHbRA5kG_{abP|Ns97(+r9~Ss1v0OdSvxB+tN9(9_S(IGaDQc;mIo+?-io z{}(*S=#W)aeYT@1Lt~rD<11U$E_ck-ULV`FH)!{QiC>tjGMq)VUd}f0o`0{XIq-#F zgr@54O+u}!Zhqf3TWtjGMq)VUd}f0o`0{XIq-#F zgr@54O+u}!Zhqf3TWq| zvx~8M+e5u0*7vlmk|%gZ&uf{VwyEogSMkkz(^7k#4#vLSp<@=_zAXKhYL)guKfdy1 iX>q34e;wJsZMnL~6cP7}&zi+6c6dDDm>IypU=0AawM?%7 literal 0 HcmV?d00001 diff --git a/icons/stax_app_lbry.gif b/icons/stax_app_lbry.gif new file mode 100644 index 0000000000000000000000000000000000000000..654b7d35206cf690b201d7b30156893b7095d16a GIT binary patch literal 163 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrkI}om8akGFP>Av81V4!&3m6q6{h8=95u|`Vz;(@(|SXH#oF%7duwaH z{<>LbuE-;J>gohTnYMJRX=SSxU2s{I*y);9ydc3 Jy$Az?H2~^3KU)9* literal 0 HcmV?d00001 diff --git a/icons/stax_app_litecoin.gif b/icons/stax_app_litecoin.gif new file mode 100644 index 0000000000000000000000000000000000000000..aecc5f2f1631efb17cc560ec23b3627fcf993b4d GIT binary patch literal 156 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrqG`Lm8a)2%uOl0#eDE?dSfEJ0hlh*mHH!b)iphVoSBT7_0%z C6+c)2 literal 0 HcmV?d00001 diff --git a/icons/stax_app_nix.gif b/icons/stax_app_nix.gif new file mode 100644 index 0000000000000000000000000000000000000000..75158fdf22227f677ca1bc4aeef06904ba40828a GIT binary patch literal 185 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrlKDH%G0ZRFE#s}lgc!k&U~%$LHpDI@n!0ndASodB^NI=sy&>-m%UE? z;7@@aF&#p)dE%X-6${)mo7T==DO9cdspsPNY4v4% zxBo~9X-w;SHZp(|l5lR)@BkKhE8G@a?>duU}j7YB4Za0|2Y& BJS_kK literal 0 HcmV?d00001 diff --git a/icons/stax_app_qtum.gif b/icons/stax_app_qtum.gif new file mode 100644 index 0000000000000000000000000000000000000000..c18be61b83b3f098dfbee0a4a652439dacd17b2a GIT binary patch literal 209 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrmmj;m8ajHZ(vCby0K=SMPX;e-Gh?hrBnN}f)Xm+9&F$FV)vC@dW+{t ze`fVuDSS5KjNo)#wZ5A*VY5PJgs$3{)p_{#`|aHM2OI(`&&;Z-$$nGb>6^QHhn3K) zp0o3Q%Y2YNzD&Vw#>VorvddSEuDCxtP=5SH>I|2oO0HrmMmtU%z06#>!YnAO>Q(>) GgEatNk67>k literal 0 HcmV?d00001 diff --git a/icons/stax_app_ravencoin.gif b/icons/stax_app_ravencoin.gif new file mode 100644 index 0000000000000000000000000000000000000000..4ce3d44f2642f963c2181fa50fa7b9d2abdee895 GIT binary patch literal 166 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrud%zm8akGFP^jIR&?VrkLGid_uP`6NK}Z=TJ?^t_rChM%+q!oD&`p7 zJ^8S~IMGS;&)1SI^MxgN*THQ Q%NOTt-8H{7kb%J(04}aQdVJ%!Sz;D>B#?o@8UVEwQ0)K! literal 0 HcmV?d00001 diff --git a/icons/stax_app_stratis.gif b/icons/stax_app_stratis.gif new file mode 100644 index 0000000000000000000000000000000000000000..4902f39060521d8a9cdd42518a5a2dcdfc34b285 GIT binary patch literal 171 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrj(xkm8WYTC^3tiir&0;wbpstkjaIqC4LKbb|rT#(R`EV$o=@3&dd9+ zKdfxvlv|dnBa|$)P1ZPE26^(>Q7Wq9)5vvexGgT#0B7s=Vs|!s}&epsje(9;eyYbIKSQtO3CrITio_ literal 0 HcmV?d00001 diff --git a/icons/stax_app_viacoin.gif b/icons/stax_app_viacoin.gif new file mode 100644 index 0000000000000000000000000000000000000000..567f620a6f884405d2ca3148596790eb014cbeda GIT binary patch literal 163 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrkI}om8TD^k6{vW+O?s!>e|~{4|cgF;eE@s^0a3Kt@YU+)B7-gnYo$# z?}HB3p;`*NMQXj4zT;e~xcJHn;R=(sO>6YRvxTNjYD?XaBlrB$tC!c0^BsHoKKgIb Jd1)>NYXB%(K4Jg> literal 0 HcmV?d00001 diff --git a/icons/stax_app_xrhodium.gif b/icons/stax_app_xrhodium.gif new file mode 100644 index 0000000000000000000000000000000000000000..a50943471ca3fa5d9a4e24e89624efbc9cd758be GIT binary patch literal 170 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrsSUfm8ajXZTTBiqx(MOudq!xyJz#wxjx5x3uGeC R{=N3N+ICm}mjDI^YXFX+L^uEd literal 0 HcmV?d00001 diff --git a/icons/stax_app_xsn.gif b/icons/stax_app_xsn.gif new file mode 100644 index 0000000000000000000000000000000000000000..08e35ffd1fcdad85944922f678a5352270cd3ce3 GIT binary patch literal 154 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrr@6bm8akGFP^jIR=50#T=(@13k;o-g4kXf%}d&~>Ba4NL7B=w#pQqh z{rpvCeL#WGlGwggiRmY59;Kb&_2_I&)ZQO6h0)lmRl AyZ`_I literal 0 HcmV?d00001 diff --git a/icons/stax_app_zcash.gif b/icons/stax_app_zcash.gif new file mode 100644 index 0000000000000000000000000000000000000000..5bef4a5acabfdada3d773598bdc908873d67f1d9 GIT binary patch literal 156 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrqG`Lm8WwV=B5ao>DJ0KE4f=4?K&+@Wv*6dt>=ln$!g0>d>2}XzdQZ5 z`el>TBBeANhRNQ^lRJE>s?IF@B6;MOL;t$%Tcge%dNi%*l~w-Q(5&cL6Ga&qtO0*z BI;#Kx literal 0 HcmV?d00001 diff --git a/icons/stax_app_zclassic.gif b/icons/stax_app_zclassic.gif new file mode 100644 index 0000000000000000000000000000000000000000..03002f8f8e88226eb777870f5d0bd8501337ab5e GIT binary patch literal 183 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrh=Y+4uRX8i=(y#b?V+e`zWM#?&sD=g{e Date: Thu, 1 Sep 2022 11:50:25 +0200 Subject: [PATCH 03/85] ui: move ui related code to dedicated file --- src/main.c | 685 ++------------------------------------------------ src/ui.h | 18 ++ src/ui_bagl.c | 543 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 576 insertions(+), 670 deletions(-) create mode 100644 src/ui.h create mode 100644 src/ui_bagl.c diff --git a/src/main.c b/src/main.c index 2436858e..8267a9ad 100644 --- a/src/main.c +++ b/src/main.c @@ -35,669 +35,13 @@ #include "handle_swap_sign_transaction.h" #include "handle_get_printable_amount.h" #include "handle_check_address.h" +#include "ui.h" #define __NAME3(a, b, c) a##b##c #define NAME3(a, b, c) __NAME3(a, b, c) -bagl_element_t tmp_element; - unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; -void ui_idle(void); - -ux_state_t G_ux; -bolos_ux_params_t G_ux_params; - -unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { - // user denied the transaction, tell the USB side - if (!btchip_bagl_user_action(0)) { - // redraw ui - ui_idle(); - } - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e) { - // user accepted the transaction, tell the USB side - if (!btchip_bagl_user_action(1)) { - // redraw ui - ui_idle(); - } - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int -io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e) { - // user denied the transaction, tell the USB side - btchip_bagl_user_action_message_signing(0); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int -io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { - // user accepted the transaction, tell the USB side - btchip_bagl_user_action_message_signing(1); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { - // user denied the transaction, tell the USB side - btchip_bagl_user_action_display(0); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { - // user accepted the transaction, tell the USB side - btchip_bagl_user_action_display(1); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int io_seproxyhal_touch_sign_cancel(const bagl_element_t *e) { - // user denied the transaction, tell the USB side - btchip_bagl_user_action_signtx(0, 0); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int io_seproxyhal_touch_sign_ok(const bagl_element_t *e) { - // user accepted the transaction, tell the USB side - btchip_bagl_user_action_signtx(1, 0); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} - - -unsigned int io_seproxyhal_touch_display_token_cancel(const bagl_element_t *e) { - // revoke previous valid token if there was one - btchip_context_D.has_valid_token = false; - // user denied the token, tell the USB side - btchip_bagl_user_action_display(0); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} - -unsigned int io_seproxyhal_touch_display_token_ok(const bagl_element_t *e) { - // Set the valid token flag - btchip_context_D.has_valid_token = true; - // user approved the token, tell the USB side - btchip_bagl_user_action_display(1); - // redraw ui - ui_idle(); - return 0; // DO NOT REDRAW THE BUTTON -} - -const char* settings_submenu_getter(unsigned int idx); -void settings_submenu_selector(unsigned int idx); - - -void settings_pubkey_export_change(unsigned int enabled) { - nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &enabled, 1); - ui_idle(); -} -////////////////////////////////////////////////////////////////////////////////////// -// Public keys export submenu: - -const char* const settings_pubkey_export_getter_values[] = { - "Auto Approval", - "Manual Approval", - "Back" -}; - -const char* settings_pubkey_export_getter(unsigned int idx) { - if (idx < ARRAYLEN(settings_pubkey_export_getter_values)) { - return settings_pubkey_export_getter_values[idx]; - } - return NULL; -} - -void settings_pubkey_export_selector(unsigned int idx) { - switch(idx) { - case 0: - settings_pubkey_export_change(0); - break; - case 1: - settings_pubkey_export_change(1); - break; - default: - ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector); - } -} - -////////////////////////////////////////////////////////////////////////////////////// -// Settings menu: - -const char* const settings_submenu_getter_values[] = { - "Public keys export", - "Back", -}; - -const char* settings_submenu_getter(unsigned int idx) { - if (idx < ARRAYLEN(settings_submenu_getter_values)) { - return settings_submenu_getter_values[idx]; - } - return NULL; -} - -void settings_submenu_selector(unsigned int idx) { - switch(idx) { - case 0: - ux_menulist_init_select(0, settings_pubkey_export_getter, settings_pubkey_export_selector, N_btchip.pubKeyRequestRestriction); - break; - default: - ui_idle(); - } -} - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_idle_flow_1_step, - nn, - { - "Application", - "is ready", - }); -UX_STEP_CB( - ux_idle_flow_2_step, - pb, - ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector), - { - &C_icon_coggle, - "Settings", - }); -UX_STEP_NOCB( - ux_idle_flow_3_step, - bn, - { - "Version", - APPVERSION, - }); -UX_STEP_CB( - ux_idle_flow_4_step, - pb, - os_sched_exit(-1), - { - &C_icon_dashboard_x, - "Quit", - }); -UX_FLOW(ux_idle_flow, - &ux_idle_flow_1_step, - &ux_idle_flow_2_step, - &ux_idle_flow_3_step, - &ux_idle_flow_4_step, - FLOW_LOOP -); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_sign_flow_1_step, - pnn, - { - &C_icon_certificate, - "Sign", - "message", - }); -UX_STEP_NOCB( - ux_sign_flow_2_step, - bnnn_paging, - { - .title = "Message hash", - .text = vars.tmp.fullAddress, - }); -UX_STEP_CB( - ux_sign_flow_3_step, - pbb, - io_seproxyhal_touch_message_signature_verify_ok(NULL), - { - &C_icon_validate_14, - "Sign", - "message", - }); -UX_STEP_CB( - ux_sign_flow_4_step, - pbb, - io_seproxyhal_touch_message_signature_verify_cancel(NULL), - { - &C_icon_crossmark, - "Cancel", - "signature", - }); - -UX_FLOW(ux_sign_flow, - &ux_sign_flow_1_step, - &ux_sign_flow_2_step, - &ux_sign_flow_3_step, - &ux_sign_flow_4_step -); - -////////////////////////////////////////////////////////////////////// - -UX_STEP_NOCB(ux_confirm_full_flow_1_step, - pnn, - { - &C_icon_eye, - "Review", - "transaction", - }); -UX_STEP_NOCB( - ux_confirm_full_flow_2_step, - bnnn_paging, - { - .title = "Amount", - .text = vars.tmp.fullAmount - }); -UX_STEP_NOCB( - ux_confirm_full_flow_3_step, - bnnn_paging, - { - .title = "Address", - .text = vars.tmp.fullAddress, - }); -UX_STEP_NOCB( - ux_confirm_full_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_CB( - ux_confirm_full_flow_5_step, - pbb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - "and send", - }); -UX_STEP_CB( - ux_confirm_full_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); -// confirm_full: confirm transaction / Amount: fullAmount / Address: fullAddress / Fees: feesAmount -UX_FLOW(ux_confirm_full_flow, - &ux_confirm_full_flow_1_step, - &ux_confirm_full_flow_2_step, - &ux_confirm_full_flow_3_step, - &ux_confirm_full_flow_4_step, - &ux_confirm_full_flow_5_step, - &ux_confirm_full_flow_6_step -); - -////////////////////////////////////////////////////////////////////// - -UX_STEP_NOCB( - ux_confirm_single_flow_1_step, - pnn, - { - &C_icon_eye, - "Review", - vars.tmp.feesAmount, // output # - }); -UX_STEP_NOCB( - ux_confirm_single_flow_2_step, - bnnn_paging, - { - .title = "Amount", - .text = vars.tmp.fullAmount, - }); -UX_STEP_NOCB( - ux_confirm_single_flow_3_step, - bnnn_paging, - { - .title = "Address", - .text = vars.tmp.fullAddress, - }); -UX_STEP_CB( - ux_confirm_single_flow_5_step, - pb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - }); -UX_STEP_CB( - ux_confirm_single_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); -// confirm_single: confirm output #x(feesAmount) / Amount: fullAmount / Address: fullAddress -UX_FLOW(ux_confirm_single_flow, - &ux_confirm_single_flow_1_step, - &ux_confirm_single_flow_2_step, - &ux_confirm_single_flow_3_step, - &ux_confirm_single_flow_5_step, - &ux_confirm_single_flow_6_step -); - -////////////////////////////////////////////////////////////////////// - -UX_STEP_NOCB( - ux_finalize_flow_1_step, - pnn, - { - &C_icon_eye, - "Confirm", - "transaction" - }); -UX_STEP_NOCB( - ux_finalize_flow_4_step, - bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_CB( - ux_finalize_flow_5_step, - pbb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - "and send" - }); -UX_STEP_CB( - ux_finalize_flow_6_step, - pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); -// finalize: confirm transaction / Fees: feesAmount -UX_FLOW(ux_finalize_flow, - &ux_finalize_flow_1_step, - &ux_finalize_flow_4_step, - &ux_finalize_flow_5_step, - &ux_finalize_flow_6_step -); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_display_public_flow_1_step, - pnn, - { - &C_icon_warning, - "The derivation", - "path is unusual!", - }); -UX_STEP_NOCB( - ux_display_public_flow_2_step, - bnnn_paging, - { - .title = "Derivation path", - .text = vars.tmp_warning.derivation_path, - }); -UX_STEP_CB( - ux_display_public_flow_3_step, - pnn, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject if you're", - "not sure", - }); -UX_STEP_NOCB( - ux_display_public_flow_4_step, - pnn, - { - &C_icon_validate_14, - "Approve derivation", - "path", - }); -UX_STEP_NOCB( - ux_display_public_flow_5_step, - bnnn_paging, - { - .title = "Address", - .text = (char *)G_io_apdu_buffer+200, - }); -UX_STEP_CB( - ux_display_public_flow_6_step, - pb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Approve", - }); -UX_STEP_CB( - ux_display_public_flow_7_step, - pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); - -UX_FLOW(ux_display_public_with_warning_flow, - &ux_display_public_flow_1_step, - &ux_display_public_flow_2_step, - &ux_display_public_flow_3_step, - &ux_display_public_flow_4_step, - FLOW_BARRIER, - &ux_display_public_flow_5_step, - &ux_display_public_flow_6_step, - &ux_display_public_flow_7_step -); - -UX_FLOW(ux_display_public_flow, - &ux_display_public_flow_5_step, - &ux_display_public_flow_6_step, - &ux_display_public_flow_7_step -); - - -////////////////////////////////////////////////////////////////////// -UX_STEP_CB( - ux_display_token_flow_1_step, - pbb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Confirm token", - (char *)G_io_apdu_buffer+200, - }); -UX_STEP_CB( - ux_display_token_flow_2_step, - pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); - -UX_FLOW(ux_display_token_flow, - &ux_display_token_flow_1_step, - &ux_display_token_flow_2_step -); - -////////////////////////////////////////////////////////////////////// -UX_STEP_CB( - ux_request_pubkey_approval_flow_1_step, - pbb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Export", - "public key?", - }); -UX_STEP_CB( - ux_request_pubkey_approval_flow_2_step, - pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); - -UX_FLOW(ux_request_pubkey_approval_flow, - &ux_request_pubkey_approval_flow_1_step, - &ux_request_pubkey_approval_flow_2_step -); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_request_change_path_approval_flow_1_step, - pbb, - { - &C_icon_eye, - "The change path", - "is unusual", - }); -UX_STEP_NOCB( - ux_request_change_path_approval_flow_2_step, - bnnn_paging, - { - .title = "Change path", - .text = vars.tmp_warning.derivation_path, - }); -UX_STEP_CB( - ux_request_change_path_approval_flow_3_step, - pbb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject if you're", - "not sure", - }); -UX_STEP_CB( - ux_request_change_path_approval_flow_4_step, - pb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Approve", - }); - -UX_FLOW(ux_request_change_path_approval_flow, - &ux_request_change_path_approval_flow_1_step, - &ux_request_change_path_approval_flow_2_step, - &ux_request_change_path_approval_flow_3_step, - &ux_request_change_path_approval_flow_4_step -); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_request_sign_path_approval_flow_1_step, - pbb, - { - &C_icon_eye, - "The sign path", - "is unusual", - }); -UX_STEP_NOCB( - ux_request_sign_path_approval_flow_2_step, - bnnn_paging, - { - .title = "Sign path", - .text = vars.tmp_warning.derivation_path, - }); -UX_STEP_CB( - ux_request_sign_path_approval_flow_3_step, - pbb, - io_seproxyhal_touch_sign_cancel(NULL), - { - &C_icon_crossmark, - "Reject if you're", - "not sure", - }); -UX_STEP_CB( - ux_request_sign_path_approval_flow_4_step, - pb, - io_seproxyhal_touch_sign_ok(NULL), - { - &C_icon_validate_14, - "Approve", - }); - -UX_FLOW(ux_request_sign_path_approval_flow, - &ux_request_sign_path_approval_flow_1_step, - &ux_request_sign_path_approval_flow_2_step, - &ux_request_sign_path_approval_flow_3_step, - &ux_request_sign_path_approval_flow_4_step -); - - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB( - ux_request_segwit_input_approval_flow_1_step, - pb, - { - .icon = &C_icon_warning, - .line1 = "Unverified inputs" - }); -UX_STEP_NOCB( - ux_request_segwit_input_approval_flow_2_step, - nn, - { - .line1 = "Update", - .line2 = " Ledger Live" - }); -UX_STEP_NOCB( - ux_request_segwit_input_approval_flow_3_step, - nn - , - { - .line1 = "or third party", - .line2 = "wallet software" - }); -UX_STEP_CB( - ux_request_segwit_input_approval_flow_4_step, - pb, - io_seproxyhal_touch_display_cancel(NULL), - { - .icon = &C_icon_crossmark, - .line1 = "Cancel" - }); -UX_STEP_CB( - ux_request_segwit_input_approval_flow_5_step, - pb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Continue" - }); - -UX_FLOW(ux_request_segwit_input_approval_flow, - &ux_request_segwit_input_approval_flow_1_step, - &ux_request_segwit_input_approval_flow_2_step, - &ux_request_segwit_input_approval_flow_3_step, - &ux_request_segwit_input_approval_flow_4_step, - &ux_request_segwit_input_approval_flow_5_step -); - - -void ui_idle(void) { - // reserve a display stack slot if none yet - if(G_ux.stack_count == 0) { - ux_stack_push(); - } - ux_flow_init(0, ux_idle_flow, NULL); -} - -// override point, but nothing more to do -void io_seproxyhal_display(const bagl_element_t *element) { - if ((element->component.type & (~BAGL_TYPE_FLAGS_MASK)) != BAGL_NONE) { - io_seproxyhal_display_default((bagl_element_t *)element); - } -} - unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { switch (channel & ~(IO_FLAGS)) { case CHANNEL_KEYBOARD: @@ -1065,11 +409,7 @@ unsigned int btchip_bagl_confirm_single_output() { return 0; } - snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "output #%d", - btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + - 1); - - ux_flow_init(0, ux_confirm_single_flow, NULL); + ui_confirm_single_flow(); return 1; } @@ -1082,7 +422,7 @@ unsigned int btchip_bagl_finalize_tx() { return 0; } - ux_flow_init(0, ux_finalize_flow, NULL); + ui_finalize_flow(); return 1; } @@ -1091,7 +431,7 @@ void btchip_bagl_confirm_message_signature() { return; } - ux_flow_init(0, ux_sign_flow, NULL); + ui_sign_message_flow(); } uint8_t set_key_path_to_display(unsigned char* keyPath) { @@ -1103,34 +443,39 @@ void btchip_bagl_display_public_key(uint8_t is_derivation_path_unusual) { // append a white space at the end of the address to avoid glitch on nano S strcat((char *)G_io_apdu_buffer + 200, " "); - ux_flow_init(0, is_derivation_path_unusual?ux_display_public_with_warning_flow:ux_display_public_flow, NULL); + if (is_derivation_path_unusual) { + ui_display_public_with_warning_flow(); + } + else { + ui_display_public_flow(); + } } void btchip_bagl_display_token() { - ux_flow_init(0, ux_display_token_flow, NULL); + ui_display_token_flow(); } void btchip_bagl_request_pubkey_approval() { - ux_flow_init(0, ux_request_pubkey_approval_flow, NULL); + ui_request_pubkey_approval_flow(); } void btchip_bagl_request_change_path_approval(unsigned char* change_path) { bip32_print_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); - ux_flow_init(0, ux_request_change_path_approval_flow, NULL); + ui_request_change_path_approval_flow(); } void btchip_bagl_request_sign_path_approval(unsigned char* change_path) { bip32_print_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); - ux_flow_init(0, ux_request_sign_path_approval_flow, NULL); + ui_request_sign_path_approval_flow(); } void btchip_bagl_request_segwit_input_approval() { - ux_flow_init(0, ux_request_segwit_input_approval_flow, NULL); + ui_request_segwit_input_approval_flow(); } diff --git a/src/ui.h b/src/ui.h new file mode 100644 index 00000000..fbbf828f --- /dev/null +++ b/src/ui.h @@ -0,0 +1,18 @@ +#pragma once + +#include "ux.h" + +void ui_idle_flow(void); +void ui_sign_message_flowflow(void); +void ui_confirm_full_flow(void); +void ui_confirm_single_flow(void); +void ui_finalize_flow(void); +void ui_display_public_with_warning_flow(void); +void ui_display_public_flow(void); +void ui_display_token_flow(void); +void ui_request_pubkey_approval_flow(void); +void ui_request_change_path_approval_flow(void); +void ui_request_sign_path_approval_flow(void); +void ui_request_segwit_input_approval_flow(void); +void ui_transaction_finish(void); +void ui_transaction_error(void); diff --git a/src/ui_bagl.c b/src/ui_bagl.c new file mode 100644 index 00000000..2edc9a59 --- /dev/null +++ b/src/ui_bagl.c @@ -0,0 +1,543 @@ +/******************************************************************************* + * Ledger App - Bitcoin Wallet + * (c) 2022 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ + +#ifdef HAVE_BAGL +////////////////////////////////////////////////////////////////////// +#include "btchip_display_variables.h" +#include "btchip_internal.h" +#include "ui.h" + +#include "btchip_bagl_extensions.h" + +bagl_element_t tmp_element; + +void ui_idle(void) { + if (G_ux.stack_count == 0) { + ux_stack_push(); + } +} +void settings_pubkey_export_change(unsigned int enabled) { + nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &enabled, 1); + ui_idle_flow(); +} + +static unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { + // user denied the transaction, tell the USB side + if (!btchip_bagl_user_action(0)) { + // redraw ui + ui_idle_flow(); + } + return 0; // DO NOT REDRAW THE BUTTON +} + +static unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e) { + // user accepted the transaction, tell the USB side + if (!btchip_bagl_user_action(1)) { + // redraw ui + ui_idle_flow(); + } + return 0; // DO NOT REDRAW THE BUTTON +} + +static unsigned int +io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e) { + // user denied the transaction, tell the USB side + btchip_bagl_user_action_message_signing(0); + // redraw ui + ui_idle_flow(); + return 0; // DO NOT REDRAW THE BUTTON +} + +static unsigned int +io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { + // user accepted the transaction, tell the USB side + btchip_bagl_user_action_message_signing(1); + // redraw ui + ui_idle_flow(); + return 0; // DO NOT REDRAW THE BUTTON +} + +static unsigned int +io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { + // user denied the transaction, tell the USB side + btchip_bagl_user_action_display(0); + // redraw ui + ui_idle_flow(); + return 0; // DO NOT REDRAW THE BUTTON +} + +static unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { + // user accepted the transaction, tell the USB side + btchip_bagl_user_action_display(1); + // redraw ui + ui_idle_flow(); + return 0; // DO NOT REDRAW THE BUTTON +} + +static unsigned int io_seproxyhal_touch_sign_cancel(const bagl_element_t *e) { + // user denied the transaction, tell the USB side + btchip_bagl_user_action_signtx(0, 0); + // redraw ui + ui_idle_flow(); + return 0; // DO NOT REDRAW THE BUTTON +} + +static unsigned int io_seproxyhal_touch_sign_ok(const bagl_element_t *e) { + // user accepted the transaction, tell the USB side + btchip_bagl_user_action_signtx(1, 0); + // redraw ui + ui_idle_flow(); + return 0; // DO NOT REDRAW THE BUTTON +} + +void io_seproxyhal_display(const bagl_element_t *element) { + if ((element->component.type & (~BAGL_TYPE_FLAGS_MASK)) != BAGL_NONE) { + io_seproxyhal_display_default((bagl_element_t *)element); + } +} +////////////////////////////////////////////////////////////////////////////////////// +// Public keys export submenu: + +const char *const settings_pubkey_export_getter_values[] = { + "Auto Approval", "Manual Approval", "Back"}; + +const char *settings_submenu_getter(unsigned int idx); +void settings_submenu_selector(unsigned int idx); + +const char *const settings_submenu_getter_values[] = { + "Public keys export", + "Back", +}; + +const char *settings_pubkey_export_getter(unsigned int idx) { + if (idx < ARRAYLEN(settings_pubkey_export_getter_values)) { + return settings_pubkey_export_getter_values[idx]; + } + return NULL; +} + +void settings_pubkey_export_selector(unsigned int idx) { + switch (idx) { + case 0: + settings_pubkey_export_change(0); + break; + case 1: + settings_pubkey_export_change(1); + break; + default: + ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector); + } +} + +const char *settings_submenu_getter(unsigned int idx) { + if (idx < ARRAYLEN(settings_submenu_getter_values)) { + return settings_submenu_getter_values[idx]; + } + return NULL; +} + +void settings_submenu_selector(unsigned int idx) { + switch (idx) { + case 0: + ux_menulist_init_select(0, settings_pubkey_export_getter, + settings_pubkey_export_selector, + N_btchip.pubKeyRequestRestriction); + break; + default: + ui_idle_flow(); + } +} + +UX_STEP_NOCB(ux_idle_flow_1_step, nn, + { + "Application", + "is ready", + }); +UX_STEP_CB(ux_idle_flow_2_step, pb, + ux_menulist_init(0, settings_submenu_getter, + settings_submenu_selector), + { + &C_icon_coggle, + "Settings", + }); +UX_STEP_NOCB(ux_idle_flow_3_step, bn, + { + "Version", + APPVERSION, + }); +UX_STEP_CB(ux_idle_flow_4_step, pb, os_sched_exit(-1), + { + &C_icon_dashboard_x, + "Quit", + }); +UX_FLOW(ux_idle_flow, &ux_idle_flow_1_step, &ux_idle_flow_2_step, + &ux_idle_flow_3_step, &ux_idle_flow_4_step, FLOW_LOOP); + +void ui_idle_flow(void) { ux_flow_init(0, ux_idle_flow, NULL); } + +////////////////////////////////////////////////////////////////////// +UX_STEP_NOCB(ux_sign_flow_1_step, pnn, + { + &C_icon_certificate, + "Sign", + "message", + }); +UX_STEP_NOCB(ux_sign_flow_2_step, bnnn_paging, + { + .title = "Message hash", + .text = vars.tmp.fullAddress, + }); +UX_STEP_CB(ux_sign_flow_3_step, pbb, + io_seproxyhal_touch_message_signature_verify_ok(NULL), + { + &C_icon_validate_14, + "Sign", + "message", + }); +UX_STEP_CB(ux_sign_flow_4_step, pbb, + io_seproxyhal_touch_message_signature_verify_cancel(NULL), + { + &C_icon_crossmark, + "Cancel", + "signature", + }); + +UX_FLOW(ux_sign_flow, &ux_sign_flow_1_step, &ux_sign_flow_2_step, + &ux_sign_flow_3_step, &ux_sign_flow_4_step); + +////////////////////////////////////////////////////////////////////// + +UX_STEP_NOCB(ux_confirm_full_flow_1_step, pnn, + { + &C_icon_eye, + "Review", + "transaction", + }); +UX_STEP_NOCB(ux_confirm_full_flow_2_step, bnnn_paging, + {.title = "Amount", .text = vars.tmp.fullAmount}); +UX_STEP_NOCB(ux_confirm_full_flow_3_step, bnnn_paging, + { + .title = "Address", + .text = vars.tmp.fullAddress, + }); +UX_STEP_NOCB(ux_confirm_full_flow_4_step, bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_CB(ux_confirm_full_flow_5_step, pbb, + io_seproxyhal_touch_verify_ok(NULL), + { + &C_icon_validate_14, + "Accept", + "and send", + }); +UX_STEP_CB(ux_confirm_full_flow_6_step, pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); +// confirm_full: confirm transaction / Amount: fullAmount / Address: fullAddress +// / Fees: feesAmount +UX_FLOW(ux_confirm_full_flow, &ux_confirm_full_flow_1_step, + &ux_confirm_full_flow_2_step, &ux_confirm_full_flow_3_step, + &ux_confirm_full_flow_4_step, &ux_confirm_full_flow_5_step, + &ux_confirm_full_flow_6_step); + +////////////////////////////////////////////////////////////////////// + +UX_STEP_NOCB(ux_confirm_single_flow_1_step, pnn, + { + &C_icon_eye, "Review", + vars.tmp.feesAmount, // output # + }); +UX_STEP_NOCB(ux_confirm_single_flow_2_step, bnnn_paging, + { + .title = "Amount", + .text = vars.tmp.fullAmount, + }); +UX_STEP_NOCB(ux_confirm_single_flow_3_step, bnnn_paging, + { + .title = "Address", + .text = vars.tmp.fullAddress, + }); +UX_STEP_CB(ux_confirm_single_flow_5_step, pb, + io_seproxyhal_touch_verify_ok(NULL), + { + &C_icon_validate_14, + "Accept", + }); +UX_STEP_CB(ux_confirm_single_flow_6_step, pb, + io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); +// confirm_single: confirm output #x(feesAmount) / Amount: fullAmount / Address: +// fullAddress +UX_FLOW(ux_confirm_single_flow, &ux_confirm_single_flow_1_step, + &ux_confirm_single_flow_2_step, &ux_confirm_single_flow_3_step, + &ux_confirm_single_flow_5_step, &ux_confirm_single_flow_6_step); + +////////////////////////////////////////////////////////////////////// + +UX_STEP_NOCB(ux_finalize_flow_1_step, pnn, + {&C_icon_eye, "Confirm", "transaction"}); +UX_STEP_NOCB(ux_finalize_flow_4_step, bnnn_paging, + { + .title = "Fees", + .text = vars.tmp.feesAmount, + }); +UX_STEP_CB(ux_finalize_flow_5_step, pbb, io_seproxyhal_touch_verify_ok(NULL), + {&C_icon_validate_14, "Accept", "and send"}); +UX_STEP_CB(ux_finalize_flow_6_step, pb, io_seproxyhal_touch_verify_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); +// finalize: confirm transaction / Fees: feesAmount +UX_FLOW(ux_finalize_flow, &ux_finalize_flow_1_step, &ux_finalize_flow_4_step, + &ux_finalize_flow_5_step, &ux_finalize_flow_6_step); + +////////////////////////////////////////////////////////////////////// +UX_STEP_NOCB(ux_display_public_flow_1_step, pnn, + { + &C_icon_warning, + "The derivation", + "path is unusual!", + }); +UX_STEP_NOCB(ux_display_public_flow_2_step, bnnn_paging, + { + .title = "Derivation path", + .text = vars.tmp_warning.derivation_path, + }); +UX_STEP_CB(ux_display_public_flow_3_step, pnn, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject if you're", + "not sure", + }); +UX_STEP_NOCB(ux_display_public_flow_4_step, pnn, + { + &C_icon_validate_14, + "Approve derivation", + "path", + }); +UX_STEP_NOCB(ux_display_public_flow_5_step, bnnn_paging, + { + .title = "Address", + .text = (char *)G_io_apdu_buffer + 200, + }); +UX_STEP_CB(ux_display_public_flow_6_step, pb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Approve", + }); +UX_STEP_CB(ux_display_public_flow_7_step, pb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); + +UX_FLOW(ux_display_public_with_warning_flow, &ux_display_public_flow_1_step, + &ux_display_public_flow_2_step, &ux_display_public_flow_3_step, + &ux_display_public_flow_4_step, FLOW_BARRIER, + &ux_display_public_flow_5_step, &ux_display_public_flow_6_step, + &ux_display_public_flow_7_step); + +UX_FLOW(ux_display_public_flow, &ux_display_public_flow_5_step, + &ux_display_public_flow_6_step, &ux_display_public_flow_7_step); + +////////////////////////////////////////////////////////////////////// +UX_STEP_CB(ux_display_token_flow_1_step, pbb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Confirm token", + (char *)G_io_apdu_buffer + 200, + }); +UX_STEP_CB(ux_display_token_flow_2_step, pb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); + +UX_FLOW(ux_display_token_flow, &ux_display_token_flow_1_step, + &ux_display_token_flow_2_step); + +////////////////////////////////////////////////////////////////////// +UX_STEP_CB(ux_request_pubkey_approval_flow_1_step, pbb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Export", + "public key?", + }); +UX_STEP_CB(ux_request_pubkey_approval_flow_2_step, pb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); + +UX_FLOW(ux_request_pubkey_approval_flow, + &ux_request_pubkey_approval_flow_1_step, + &ux_request_pubkey_approval_flow_2_step); + +////////////////////////////////////////////////////////////////////// +UX_STEP_NOCB(ux_request_change_path_approval_flow_1_step, pbb, + { + &C_icon_eye, + "The change path", + "is unusual", + }); +UX_STEP_NOCB(ux_request_change_path_approval_flow_2_step, bnnn_paging, + { + .title = "Change path", + .text = vars.tmp_warning.derivation_path, + }); +UX_STEP_CB(ux_request_change_path_approval_flow_3_step, pbb, + io_seproxyhal_touch_display_cancel(NULL), + { + &C_icon_crossmark, + "Reject if you're", + "not sure", + }); +UX_STEP_CB(ux_request_change_path_approval_flow_4_step, pb, + io_seproxyhal_touch_display_ok(NULL), + { + &C_icon_validate_14, + "Approve", + }); + +UX_FLOW(ux_request_change_path_approval_flow, + &ux_request_change_path_approval_flow_1_step, + &ux_request_change_path_approval_flow_2_step, + &ux_request_change_path_approval_flow_3_step, + &ux_request_change_path_approval_flow_4_step); + +////////////////////////////////////////////////////////////////////// +UX_STEP_NOCB(ux_request_sign_path_approval_flow_1_step, pbb, + { + &C_icon_eye, + "The sign path", + "is unusual", + }); +UX_STEP_NOCB(ux_request_sign_path_approval_flow_2_step, bnnn_paging, + { + .title = "Sign path", + .text = vars.tmp_warning.derivation_path, + }); +UX_STEP_CB(ux_request_sign_path_approval_flow_3_step, pbb, + io_seproxyhal_touch_sign_cancel(NULL), + { + &C_icon_crossmark, + "Reject if you're", + "not sure", + }); +UX_STEP_CB(ux_request_sign_path_approval_flow_4_step, pb, + io_seproxyhal_touch_sign_ok(NULL), + { + &C_icon_validate_14, + "Approve", + }); + +UX_FLOW(ux_request_sign_path_approval_flow, + &ux_request_sign_path_approval_flow_1_step, + &ux_request_sign_path_approval_flow_2_step, + &ux_request_sign_path_approval_flow_3_step, + &ux_request_sign_path_approval_flow_4_step); + +////////////////////////////////////////////////////////////////////// +UX_STEP_NOCB(ux_request_segwit_input_approval_flow_1_step, pb, + {.icon = &C_icon_warning, .line1 = "Unverified inputs"}); +UX_STEP_NOCB(ux_request_segwit_input_approval_flow_2_step, nn, + {.line1 = "Update", .line2 = " Ledger Live"}); +UX_STEP_NOCB(ux_request_segwit_input_approval_flow_3_step, nn, + {.line1 = "or third party", .line2 = "wallet software"}); +UX_STEP_CB(ux_request_segwit_input_approval_flow_4_step, pb, + io_seproxyhal_touch_display_cancel(NULL), + {.icon = &C_icon_crossmark, .line1 = "Cancel"}); +UX_STEP_CB(ux_request_segwit_input_approval_flow_5_step, pb, + io_seproxyhal_touch_display_ok(NULL), + {&C_icon_validate_14, "Continue"}); + +UX_FLOW(ux_request_segwit_input_approval_flow, + &ux_request_segwit_input_approval_flow_1_step, + &ux_request_segwit_input_approval_flow_2_step, + &ux_request_segwit_input_approval_flow_3_step, + &ux_request_segwit_input_approval_flow_4_step, + &ux_request_segwit_input_approval_flow_5_step); + +void ui_sign_message_flow(void) { ux_flow_init(0, ux_sign_flow, NULL); } + +void ui_confirm_single_flow(void) { + snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "output #%d", + btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + + 1); + ux_flow_init(0, ux_confirm_single_flow, NULL); +} + +void ui_finalize_flow(void) { ux_flow_init(0, ux_finalize_flow, NULL); } + +void ui_display_public_with_warning_flow(void) { + ux_flow_init(0, ux_display_public_with_warning_flow, NULL); +} + +void ui_display_public_flow(void) { + ux_flow_init(0, ux_display_public_flow, NULL); +} + +void ui_display_token_flow(void) { + ux_flow_init(0, ux_display_token_flow, NULL); +} + +void ui_request_pubkey_approval_flow(void) { + ux_flow_init(0, ux_request_pubkey_approval_flow, NULL); +} + +void ui_request_change_path_approval_flow(void) { + ux_flow_init(0, ux_request_change_path_approval_flow, NULL); +} + +void ui_request_sign_path_approval_flow(void) { + ux_flow_init(0, ux_request_sign_path_approval_flow, NULL); +} + +void ui_request_segwit_input_approval_flow(void) { + ux_flow_init(0, ux_request_segwit_input_approval_flow, NULL); +} + +void ui_idle_flow(void) { + if (G_ux.stack_count == 0) { + ux_stack_push(); + } + ux_flow_init(0, ux_idle_flow, NULL); +} + +void ui_transaction_error(void) { +} + +void ui_transaction_finish(void) { +} + +#endif // HAVE_BAGL From a37c20047ac6f8f88d905ad73005d425dbe6ea58 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 1 Sep 2022 11:52:32 +0200 Subject: [PATCH 04/85] Fatstacks: prepare for fatstack ui --- Makefile | 38 +++++++++++++++++++++++++------------- src/main.c | 15 +++++++++++++-- src/ui_bagl.c | 47 ----------------------------------------------- 3 files changed, 38 insertions(+), 62 deletions(-) diff --git a/Makefile b/Makefile index bef30d6c..45ec381b 100644 --- a/Makefile +++ b/Makefile @@ -204,6 +204,10 @@ APP_LOAD_PARAMS += $(APP_LOAD_FLAGS) ifeq ($(TARGET_NAME),TARGET_NANOS) ICONNAME=icons/nanos_app_$(COIN).gif +else ifeq ($(TARGET_NAME),TARGET_STAX) +ICONNAME=icons/stax_app_$(COIN).gif +DEFINES += COIN_ICON=C_$(COIN)_64px +DEFINES += COIN_ICON_BITMAP=C_$(COIN)_64px_bitmap else ICONNAME=icons/nanox_app_$(COIN).gif endif @@ -218,10 +222,9 @@ all: default ############ DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=300 -DEFINES += HAVE_BAGL HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U +DEFINES += HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=4 IO_HID_EP_LENGTH=64 HAVE_USB_APDU DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P) TCS_LOADER_PATCH_VERSION=0 -DEFINES += HAVE_UX_FLOW #WEBUSB_URL = www.ledgerwallet.com #DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=$(shell echo -n $(WEBUSB_URL) | wc -c) WEBUSB_URL=$(shell echo -n $(WEBUSB_URL) | sed -e "s/./\\\'\0\\\',/g") @@ -232,20 +235,27 @@ DEFINES += APPVERSION=\"$(APPVERSION)\" DEFINES += BLAKE_SDK -ifeq ($(TARGET_NAME),TARGET_NANOX) +ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX)) DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 DEFINES += HAVE_BLE_APDU # basic ledger apdu transport over BLE endif +ifeq ($(TARGET_NAME),TARGET_STAX) + DEFINES += NBGL_QRCODE +else + DEFINES += HAVE_BAGL HAVE_UX_FLOW + ifneq ($(TARGET_NAME),TARGET_NANOS) + DEFINES += HAVE_GLO096 + DEFINES += BAGL_WIDTH=128 BAGL_HEIGHT=64 + DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature + DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX + DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX + DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX + endif +endif + ifeq ($(TARGET_NAME),TARGET_NANOS) DEFINES += HAVE_WALLET_ID_SDK -else -DEFINES += HAVE_GLO096 -DEFINES += HAVE_BAGL BAGL_WIDTH=128 BAGL_HEIGHT=64 -DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature -DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX -DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX -DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX endif # Enabling debug PRINTF @@ -293,10 +303,12 @@ include $(BOLOS_SDK)/Makefile.glyphs ### variables processed by the common makefile.rules of the SDK to grab source files and include dirs APP_SOURCE_PATH += src -SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f qrcode -SDK_SOURCE_PATH += lib_ux +SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f +ifneq ($(TARGET_NAME),TARGET_STAX) +SDK_SOURCE_PATH += lib_ux +endif -ifeq ($(TARGET_NAME),TARGET_NANOX) +ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX)) SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl endif diff --git a/src/main.c b/src/main.c index 8267a9ad..c298bcc1 100644 --- a/src/main.c +++ b/src/main.c @@ -74,12 +74,16 @@ unsigned char io_event(unsigned char channel) { // can't have more than one tag in the reply, not supported yet. switch (G_io_seproxyhal_spi_buffer[0]) { +#ifdef HAVE_NBGL case SEPROXYHAL_TAG_FINGER_EVENT: UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); break; +#endif // HAVE_NBGL case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: +#ifdef HAVE_BAGL UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); +#endif // HAVE_BAGL break; case SEPROXYHAL_TAG_STATUS_EVENT: @@ -94,7 +98,12 @@ unsigned char io_event(unsigned char channel) { break; case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: +#ifdef HAVE_BAGL UX_DISPLAYED_EVENT({}); +#endif // HAVE_BAGL +#ifdef HAVE_NBGL + UX_DEFAULT_EVENT(); +#endif // HAVE_NBGL break; case SEPROXYHAL_TAG_TICKER_EVENT: @@ -529,7 +538,9 @@ void coin_main(btchip_altcoin_config_t *coin_config) { } for (;;) { + // Initialize the UX system UX_INIT(); + BEGIN_TRY { TRY { io_seproxyhal_init(); @@ -544,11 +555,11 @@ void coin_main(btchip_altcoin_config_t *coin_config) { USB_power(0); USB_power(1); - ui_idle(); + ui_idle_flow(); #ifdef HAVE_BLE BLE_power(0, NULL); - BLE_power(1, "Nano X"); + BLE_power(1, NULL); #endif // HAVE_BLE app_main(); diff --git a/src/ui_bagl.c b/src/ui_bagl.c index 2edc9a59..8a448601 100644 --- a/src/ui_bagl.c +++ b/src/ui_bagl.c @@ -25,11 +25,6 @@ bagl_element_t tmp_element; -void ui_idle(void) { - if (G_ux.stack_count == 0) { - ux_stack_push(); - } -} void settings_pubkey_export_change(unsigned int enabled) { nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &enabled, 1); ui_idle_flow(); @@ -187,8 +182,6 @@ UX_STEP_CB(ux_idle_flow_4_step, pb, os_sched_exit(-1), UX_FLOW(ux_idle_flow, &ux_idle_flow_1_step, &ux_idle_flow_2_step, &ux_idle_flow_3_step, &ux_idle_flow_4_step, FLOW_LOOP); -void ui_idle_flow(void) { ux_flow_init(0, ux_idle_flow, NULL); } - ////////////////////////////////////////////////////////////////////// UX_STEP_NOCB(ux_sign_flow_1_step, pnn, { @@ -221,46 +214,6 @@ UX_FLOW(ux_sign_flow, &ux_sign_flow_1_step, &ux_sign_flow_2_step, ////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_confirm_full_flow_1_step, pnn, - { - &C_icon_eye, - "Review", - "transaction", - }); -UX_STEP_NOCB(ux_confirm_full_flow_2_step, bnnn_paging, - {.title = "Amount", .text = vars.tmp.fullAmount}); -UX_STEP_NOCB(ux_confirm_full_flow_3_step, bnnn_paging, - { - .title = "Address", - .text = vars.tmp.fullAddress, - }); -UX_STEP_NOCB(ux_confirm_full_flow_4_step, bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_CB(ux_confirm_full_flow_5_step, pbb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - "and send", - }); -UX_STEP_CB(ux_confirm_full_flow_6_step, pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); -// confirm_full: confirm transaction / Amount: fullAmount / Address: fullAddress -// / Fees: feesAmount -UX_FLOW(ux_confirm_full_flow, &ux_confirm_full_flow_1_step, - &ux_confirm_full_flow_2_step, &ux_confirm_full_flow_3_step, - &ux_confirm_full_flow_4_step, &ux_confirm_full_flow_5_step, - &ux_confirm_full_flow_6_step); - -////////////////////////////////////////////////////////////////////// - UX_STEP_NOCB(ux_confirm_single_flow_1_step, pnn, { &C_icon_eye, "Review", From 52e0689ab1f1617145b194bf61973074b6eee2f3 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 12 Sep 2022 15:48:46 +0200 Subject: [PATCH 05/85] btchip_context: add buffer for coin logo in globals --- include/btchip_context.h | 9 ++++++++- src/main.c | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/btchip_context.h b/include/btchip_context.h index 2667b9d6..d199fea7 100644 --- a/include/btchip_context.h +++ b/include/btchip_context.h @@ -23,6 +23,10 @@ #include "cx.h" #include "btchip_secure_value.h" #include "btchip_filesystem_tx.h" +#ifdef HAVE_NBGL +#include "nbgl_types.h" +#endif // HAVE_NBGL + #define MAX_OUTPUT_TO_CHECK 100 #define MAX_COIN_ID 13 @@ -294,7 +298,10 @@ typedef struct btchip_altcoin_config_s { unsigned short p2pkh_version; unsigned short p2sh_version; unsigned char family; - //unsigned char* iconsuffix;// will use the icon provided on the stack (maybe) +#ifdef HAVE_NBGL + unsigned char img_raw[1024]; + nbgl_icon_details_t img_nbgl; +#endif // HAVE_NBGL char coinid[14]; // used coind id for message signature prefix char name[16]; // for ux displays char name_short[6]; // for unit in ux displays diff --git a/src/main.c b/src/main.c index c298bcc1..e0cb2e5e 100644 --- a/src/main.c +++ b/src/main.c @@ -510,6 +510,11 @@ void init_coin_config(btchip_altcoin_config_t *coin_config) { strcpy(coin_config->coinid, COIN_COINID); strcpy(coin_config->name, COIN_COINID_NAME); strcpy(coin_config->name_short, COIN_COINID_SHORT); +#ifdef HAVE_NBGL + memcpy(coin_config->img_raw, &COIN_ICON_BITMAP, sizeof(coin_config->img_raw)); + memcpy(&coin_config->img_nbgl, &COIN_ICON, sizeof(nbgl_icon_details_t)); + coin_config->img_nbgl.bitmap = coin_config->img_raw; +#endif // HAVE_NBGL #ifdef COIN_NATIVE_SEGWIT_PREFIX strcpy(coin_config->native_segwit_prefix_val, COIN_NATIVE_SEGWIT_PREFIX); coin_config->native_segwit_prefix = coin_config->native_segwit_prefix_val; From 1e18abb2de4f62c0571dfedc81abd8bd377fb582 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 12 Sep 2022 15:49:56 +0200 Subject: [PATCH 06/85] nbgl: add fatstacks related ui --- src/btchip_apdu_hash_input_finalize_full.c | 3 + src/btchip_apdu_hash_sign.c | 2 + src/main.c | 2 + src/ui_menu_nbgl.c | 98 +++++ src/ui_nbgl.c | 464 +++++++++++++++++++++ 5 files changed, 569 insertions(+) create mode 100644 src/ui_menu_nbgl.c create mode 100644 src/ui_nbgl.c diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index dfb1cd9c..6954ce33 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -485,6 +485,7 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( CATCH_ALL { sw = SW_TECHNICAL_DETAILS(0x0F); catch_discardTransaction: + ui_transaction_error(); btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; btchip_context_D.outLength = 0; @@ -520,6 +521,7 @@ unsigned short btchip_apdu_hash_input_finalize_full() { status = btchip_bagl_confirm_single_output(); } if (!status) { + ui_transaction_error(); btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; @@ -617,6 +619,7 @@ unsigned char btchip_bagl_user_action(unsigned char confirming) { if ((btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) || (sw != BTCHIP_SW_OK)) { + // we've finished the processing of the input btchip_apdu_hash_input_finalize_full_reset(); } diff --git a/src/btchip_apdu_hash_sign.c b/src/btchip_apdu_hash_sign.c index a9c86d03..9f5905d8 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/btchip_apdu_hash_sign.c @@ -202,6 +202,8 @@ void btchip_bagl_user_action_signtx(unsigned char confirming, unsigned char dire btchip_context_D.outLength = G_io_apdu_buffer[1] + 2; G_io_apdu_buffer[btchip_context_D.outLength++] = btchip_context_D.transactionSummary.sighashType; + ui_transaction_finish(); + } else { sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; btchip_context_D.outLength = 0; diff --git a/src/main.c b/src/main.c index e0cb2e5e..60d4a2a3 100644 --- a/src/main.c +++ b/src/main.c @@ -41,6 +41,8 @@ #define NAME3(a, b, c) __NAME3(a, b, c) unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; +bolos_ux_params_t G_ux_params; +ux_state_t G_ux; unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { switch (channel & ~(IO_FLAGS)) { diff --git a/src/ui_menu_nbgl.c b/src/ui_menu_nbgl.c new file mode 100644 index 00000000..784af224 --- /dev/null +++ b/src/ui_menu_nbgl.c @@ -0,0 +1,98 @@ +/******************************************************************************* + * Ledger App - Bitcoin Wallet + * (c) 2022 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ + +#ifdef HAVE_NBGL +#include "btchip_display_variables.h" +#include "btchip_internal.h" +#include "ui.h" + +#include "btchip_bagl_extensions.h" +#include "nbgl_use_case.h" + +#define NB_INFO_FIELDS 2 +#define PAGE_START 0 +#define NB_PAGE_SETTING 2 +#define IS_TOUCHABLE true + +#define NB_SETTINGS_SWITCHES 1 +#define SWITCH_PUBLIC_KEY_SET_TOKEN FIRST_USER_TOKEN + +static char text[20]; +static const char *const infoTypes[] = {"Version", "Developer"}; +static const char *const infoContents[] = {APPVERSION, "Ledger"}; + +static nbgl_layoutSwitch_t switches[NB_SETTINGS_SWITCHES]; + +static void quit_cb(void) { + os_sched_exit(-1); +} + +static void switch_public_key(void) { + uint8_t value = (N_btchip.pubKeyRequestRestriction != 0 ? 0 : 1); + nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &value, 1); +} + +static bool settings_navigation_cb(uint8_t page, nbgl_pageContent_t *content) { + if (page == 0) { + switches[0].text = "Public key export"; + switches[0].subText = "Auto / manual export mode"; + switches[0].token = SWITCH_PUBLIC_KEY_SET_TOKEN; + switches[0].tuneId = TUNE_TAP_CASUAL; + switches[0].initState = N_btchip.pubKeyRequestRestriction; + + content->type = SWITCHES_LIST; + content->switchesList.nbSwitches = NB_SETTINGS_SWITCHES; + content->switchesList.switches = (nbgl_layoutSwitch_t *)switches; + } else if (page == 1) { + content->type = INFOS_LIST; + content->infosList.nbInfos = NB_INFO_FIELDS; + content->infosList.infoTypes = (const char **)infoTypes; + content->infosList.infoContents = (const char **)infoContents; + } else { + return false; + } + return true; +} + +static void display_settings_menu(void); + +static void settings_control_cb(int token, uint8_t index) { + UNUSED(index); + switch (token) { + case SWITCH_PUBLIC_KEY_SET_TOKEN: + switch_public_key(); + break; + + default: + PRINTF("Should not happen !"); + break; + } +} + +static void display_settings_menu(void) { + snprintf(text, sizeof(text), "%s settings", G_coin_config->name); + + nbgl_useCaseSettings(text, PAGE_START, NB_PAGE_SETTING, IS_TOUCHABLE, + ui_idle_flow, settings_navigation_cb, + settings_control_cb); +} + +void ui_idle_flow(void) { + nbgl_useCaseHome(G_coin_config->name, &G_coin_config->img_nbgl, NULL, true, + display_settings_menu, quit_cb); +} +#endif // HAVE_NBGL diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c new file mode 100644 index 00000000..31d80e0f --- /dev/null +++ b/src/ui_nbgl.c @@ -0,0 +1,464 @@ +/******************************************************************************* + * Ledger App - Bitcoin Wallet + * (c) 2022 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ + +#ifdef HAVE_NBGL +#include "ui.h" +#include "nbgl_use_case.h" +#include "btchip_display_variables.h" +#include "btchip_internal.h" + +#include "btchip_bagl_extensions.h" + +typedef enum { + MESSAGE_TYPE, + TRANSACTION_TYPE +} flow_type_t; + + +typedef struct { + bool transaction_prompt_done; + char *prompt_cancel_message; + char *prompt; // text displayed in last transaction page + char *approved_status; // text displayed in confirmation page (after long press) + char *abandon_status; // text displayed in rejection page (after reject confirmed) + void (*approved_cb)(void); + void (*abandon_cb)(void); + nbgl_layoutTagValueList_t tagValueList; + nbgl_pageInfoLongPress_t infoLongPress; + nbgl_layoutTagValue_t tagValues[4]; + uint8_t nbPairs; +} UiContext_t; + +static nbgl_page_t *pageContext; +static UiContext_t uiContext = {.transaction_prompt_done = 0}; + +// User action callbacks +static void approved_user_action_callback(void) { + if (!btchip_bagl_user_action(1)) { + ui_idle_flow(); + } +} + +static void approved_user_action_processing_callback(void) { + if (!btchip_bagl_user_action(1)) { + nbgl_useCaseSpinner("Processing"); + } +} + +static void abandon_user_action_callback(void) { + if (!btchip_bagl_user_action(0)) { + ui_idle_flow(); + } +} + +static void approved_user_action_message_signing_callback(void) { + btchip_bagl_user_action_message_signing(1); + ui_idle_flow(); +} + +static void abandon_user_action_message_signing_callback(void) { + btchip_bagl_user_action_message_signing(0); + ui_idle_flow(); +} + +static void approved_user_action_display_processing_callback(void) { + btchip_bagl_user_action_display(1); + nbgl_useCaseSpinner("Processing"); +} + +static void approved_user_action_display_callback(void) { + btchip_bagl_user_action_display(1); + ui_idle_flow(); +} + +static void abandon_user_action_display_callback(void) { + btchip_bagl_user_action_display(0); + ui_idle_flow(); +} + +static void approved_user_action_signtx_callback(void) { + btchip_bagl_user_action_signtx(1, 0); + ui_idle_flow(); +} + +static void abandon_user_action_signtx_callback(void) { + btchip_bagl_user_action_signtx(0, 0); + ui_idle_flow(); +} + +static void releaseContext(void) { + if (pageContext != NULL) { + nbgl_pageRelease(pageContext); + pageContext = NULL; + } +} + +// Status +static void abandon_status(void) { + nbgl_useCaseStatus(uiContext.abandon_status, false, uiContext.abandon_cb); + uiContext.transaction_prompt_done = false; +} + +static void approved_status(void) { + nbgl_useCaseStatus(uiContext.approved_status, true, uiContext.approved_cb); + uiContext.transaction_prompt_done = false; +} + +static void status_callback(bool confirm) { + if (confirm) { + approved_status(); + } else { + abandon_status(); + } +} + +// Prompt Cancel +static void prompt_cancel(flow_type_t type) { + switch (type) { + case MESSAGE_TYPE: + nbgl_useCaseConfirm("Reject message", "", "Yes, Reject", + "Go back to message", abandon_status); + break; + + case TRANSACTION_TYPE: + nbgl_useCaseConfirm("Reject transaction", "", "Yes, Reject", + "Go back to transaction", abandon_status); + break; + } +} + +static void prompt_cancel_message(void) { + prompt_cancel(MESSAGE_TYPE); +} + +static void prompt_cancel_transaction(void) { + prompt_cancel(TRANSACTION_TYPE); +} + +static void transaction_review_callback(bool token) { + if (token) { + uiContext.approved_cb(); + } else { + prompt_cancel_transaction(); + } +} + +static void message_review_callback(bool token) { + if (token) { + approved_status(); + } else { + prompt_cancel_message(); + } +} + +// Continue Review +static void continue_review(flow_type_t type) { + uiContext.tagValueList.pairs = uiContext.tagValues; + uiContext.tagValueList.nbPairs = uiContext.nbPairs; + + uiContext.infoLongPress.icon = &G_coin_config->img_nbgl; + uiContext.infoLongPress.longPressText = "Hold to sign"; + uiContext.infoLongPress.longPressToken = 1; + uiContext.infoLongPress.tuneId = TUNE_TAP_CASUAL; + uiContext.infoLongPress.text = uiContext.prompt; + + switch (type) { + case MESSAGE_TYPE: + nbgl_useCaseStaticReview(&uiContext.tagValueList, &uiContext.infoLongPress, + "Cancel", message_review_callback); + break; + + case TRANSACTION_TYPE: + nbgl_useCaseStaticReview(&uiContext.tagValueList, &uiContext.infoLongPress, + "Cancel", transaction_review_callback); + break; + } +} + +static void continue_message_review(void) { + continue_review(MESSAGE_TYPE); +} + +static void continue_transaction_review(void) { + continue_review(TRANSACTION_TYPE); +} + +// UI Start +static void ui_start(void (*cb)(void), flow_type_t type) { + switch (type) { + case MESSAGE_TYPE: + nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, "Review\nmessage", "", + "Cancel", continue_message_review, + prompt_cancel_message); + break; + + case TRANSACTION_TYPE: + nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, "Review\ntransaction", "", + "Cancel", cb, prompt_cancel_transaction); + break; + } +} + +static void ui_transaction_start(void (*cb)(void)) { + uiContext.abandon_status = "Transaction\nrejected"; + uiContext.approved_status = "TRANSACTION\nCONFIRMED"; + uiContext.prompt_cancel_message = "Reject\nTransaction ?"; + uiContext.prompt = "Sign transaction"; + ui_start(cb, TRANSACTION_TYPE); +} + +static void ui_message_start(void) { + uiContext.abandon_status = "Message\nrejected"; + uiContext.approved_status = "MESSAGE\nSIGNED"; + uiContext.prompt_cancel_message = "Reject\nMessage ?"; + uiContext.prompt = "Sign message"; + ui_start(NULL, MESSAGE_TYPE); +} + +// Other callbacks +static void display_pubkey_callback(void) { + uiContext.tagValueList.pairs = uiContext.tagValues; + uiContext.tagValueList.nbPairs = uiContext.nbPairs; + + uiContext.infoLongPress.icon = &G_coin_config->img_nbgl; + uiContext.infoLongPress.longPressText = "Approve"; + uiContext.infoLongPress.longPressToken = 1; + uiContext.infoLongPress.tuneId = TUNE_TAP_CASUAL; + uiContext.infoLongPress.text = "Confirm\npublic key"; + + nbgl_useCaseStaticReviewLight(&uiContext.tagValueList, + &uiContext.infoLongPress, "Cancel", + status_callback); +} + +// Flow entry point +static void single_flow_callback(int token, uint8_t index) { + UNUSED(index); + transaction_review_callback(token); +} + +void ui_confirm_single_flow(void) { + uiContext.approved_cb = approved_user_action_processing_callback; + uiContext.abandon_cb = abandon_user_action_callback; + + if (!uiContext.transaction_prompt_done) { + uiContext.transaction_prompt_done = true; + + ui_transaction_start(ui_confirm_single_flow); + } else { + snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "#%d", + btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + + 1); + + uiContext.tagValues[0].item = "Output"; + uiContext.tagValues[0].value = vars.tmp.feesAmount; + + uiContext.tagValues[1].item = "Amount"; + uiContext.tagValues[1].value = vars.tmp.fullAmount; + + uiContext.tagValues[2].item = "Address"; + uiContext.tagValues[2].value = vars.tmp.fullAddress; + + uiContext.nbPairs = 3; + + nbgl_pageNavigationInfo_t info = { + .activePage = + btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs, + .nbPages = btchip_context_D.totalOutputs - 1, + .navType = NAV_WITH_TAP, + .progressIndicator = true, + .navWithTap.backButton = false, + .navWithTap.nextPageText = "Tap to continue", + .navWithTap.nextPageToken = 1, + .navWithTap.quitText = "Cancel", + .quitToken = 0, + .tuneId = TUNE_TAP_CASUAL}; + + nbgl_pageContent_t content = { + .type = TAG_VALUE_LIST, + .tagValueList.nbPairs = uiContext.nbPairs, + .tagValueList.pairs = (nbgl_layoutTagValue_t *)uiContext.tagValues}; + releaseContext(); + pageContext = + nbgl_pageDrawGenericContent(&single_flow_callback, &info, &content); + nbgl_refresh(); + } +} + +void ui_finalize_flow(void) { + uiContext.approved_cb = approved_user_action_processing_callback; + uiContext.abandon_cb = abandon_user_action_callback; + + uiContext.tagValues[0].item = "Fees"; + uiContext.tagValues[0].value = vars.tmp.feesAmount; + + uiContext.nbPairs = 1; + + nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, "Review fees", "", "Cancel", + continue_transaction_review, + prompt_cancel_transaction); +} + +void ui_request_change_path_approval_flow(void) { + uiContext.approved_cb = approved_user_action_display_processing_callback; + uiContext.abandon_cb = abandon_user_action_display_callback; + + if (!uiContext.transaction_prompt_done) { + uiContext.transaction_prompt_done = true; + + ui_transaction_start(ui_request_change_path_approval_flow); + } else { + nbgl_useCaseChoice(&C_round_warning_64px, "Unusual\nchange path", + vars.tmp_warning.derivation_path, "Continue", + "Reject if not sure", transaction_review_callback); + } +} + +void ui_request_segwit_input_approval_flow(void) { + uiContext.approved_cb = approved_user_action_processing_callback; + uiContext.abandon_cb = abandon_user_action_display_callback; + + if (!uiContext.transaction_prompt_done) { + uiContext.transaction_prompt_done = true; + + ui_transaction_start(ui_request_segwit_input_approval_flow); + } else { + nbgl_useCaseChoice(&C_round_warning_64px, "Unverified inputs", + "Update Ledger Live\nor third party software", + "Continue", "Reject if not sure", + transaction_review_callback); + } +} + +void ui_request_pubkey_approval_flow(void) { + uiContext.approved_cb = approved_user_action_processing_callback; + uiContext.abandon_cb = abandon_user_action_display_callback; + + if (!uiContext.transaction_prompt_done) { + uiContext.transaction_prompt_done = true; + + ui_transaction_start(ui_request_pubkey_approval_flow); + } else { + nbgl_useCaseChoice(&G_coin_config->img_nbgl, "Export public key", "", + "Approve", "Reject", transaction_review_callback); + } +} + +void ui_request_sign_path_approval_flow(void) { + uiContext.approved_cb = approved_user_action_signtx_callback; + uiContext.abandon_cb = abandon_user_action_signtx_callback; + + nbgl_useCaseChoice(&C_round_warning_64px, "Unusual\nsign path", + vars.tmp_warning.derivation_path, "Continue", + "Reject if not sure", transaction_review_callback); +} + +void ui_sign_message_flow(void) { + uiContext.approved_cb = approved_user_action_message_signing_callback; + uiContext.abandon_cb = abandon_user_action_message_signing_callback; + + uiContext.tagValues[0].item = "Message hash"; + uiContext.tagValues[0].value = vars.tmp.fullAddress; + + uiContext.nbPairs = 1; + + ui_message_start(); +} + +void ui_display_token_flow(void) { + uiContext.approved_cb = approved_user_action_display_callback; + uiContext.abandon_cb = abandon_user_action_display_callback; + uiContext.abandon_status = "Token\nrejected"; + uiContext.approved_status = "TOKEN\nCONFIRMED"; + + nbgl_useCaseChoice(&G_coin_config->img_nbgl, "Confirm token", + (char *)G_io_apdu_buffer + 200, "Approve", "Reject", + status_callback); +} + +static void unusual_derivation_cb(bool status) { + if (status) { + display_pubkey_callback(); + } else { + abandon_status(); + } +} +static void warn_unusual_derivation_path(void) { + nbgl_useCaseChoice(&C_round_warning_64px, "Unusual\nderivation path", "", + "Continue", "Reject if not sure", unusual_derivation_cb); +} + +static void prompt_public_key(bool warning) { + if (warning) { + nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, "Confirm\npublic key", "", + "Cancel", warn_unusual_derivation_path, + abandon_status); + } else { + nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, "Confirm\npublic key", "", + "Cancel", display_pubkey_callback, abandon_status); + } +} + +static void display_public_key(bool warning) { + uiContext.abandon_status = "Public key\nrejected"; + uiContext.approved_status = "PUBLIC KEY\nCONFIRMED"; + uiContext.prompt_cancel_message = "Reject\nPublic key?"; + + uiContext.tagValues[0].item = "Address"; + uiContext.tagValues[0].value = (char *)G_io_apdu_buffer + 200; + + uiContext.nbPairs = 1; + + if (warning) { + uiContext.approved_cb = approved_user_action_callback; + uiContext.abandon_cb = abandon_user_action_callback; + + uiContext.tagValues[1].item = "Derivation path"; + uiContext.tagValues[1].value = vars.tmp_warning.derivation_path; + + uiContext.nbPairs = 2; + } + + else { + uiContext.approved_cb = approved_user_action_display_callback; + uiContext.abandon_cb = abandon_user_action_display_callback; + } + prompt_public_key(warning); +} + +void ui_display_public_with_warning_flow(void) { + display_public_key(true); +} + +void ui_display_public_flow(void) { + display_public_key(false); +} + +void ui_transaction_finish(void) { + if (uiContext.transaction_prompt_done) { + uiContext.approved_status = "TRANSACTION\nCONFIRMED"; + uiContext.approved_cb = ui_idle_flow; + approved_status(); + } +} + +void ui_transaction_error(void) { + uiContext.abandon_status = "Transaction\nerror"; + uiContext.approved_cb = ui_idle_flow; + abandon_status(); +} +#endif // HAVE_NBGL From f536c4bf8bd9bfc5d81ab1d38d92c26ce48d6b8e Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 3 Apr 2023 17:16:47 +0200 Subject: [PATCH 07/85] tests: adapt for Stax --- tests/automations/accept.json | 30 +++++++++++++++++++++ tests/automations/accept_pubkey.json | 30 +++++++++++++++++++++ tests/automations/reject.json | 14 ++++++++++ tests/conftest.py | 13 ++++++--- tests/test_get_pubkey.py | 40 ++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 tests/automations/accept_pubkey.json diff --git a/tests/automations/accept.json b/tests/automations/accept.json index 150507c2..15f42e09 100644 --- a/tests/automations/accept.json +++ b/tests/automations/accept.json @@ -8,6 +8,25 @@ ["button", 2, false] ] }, + { + "regexp": "Tap to continue", + "actions": [ + ["finger", 55, 550, true], + ["finger", 55, 550, false] + ] + }, + { + "regexp": "Hold to sign", + "actions": [ + ["finger", 55, 550, true] + ] + }, + { + "regexp": "Processing|CONFIRMED", + "actions": [ + ["finger", 55, 550, false] + ] + }, { "text": "Accept", "actions": [ @@ -16,6 +35,17 @@ [ "button", 2, false ], [ "button", 1, false ] ] + }, + { + "regexp": "Approve", + "actions": [ + [ "button", 1, true ], + [ "button", 2, true ], + [ "button", 2, false ], + [ "button", 1, false ], + [ "finger", 55, 550, true], + [ "finger", 55, 550, false] + ] } ] } diff --git a/tests/automations/accept_pubkey.json b/tests/automations/accept_pubkey.json new file mode 100644 index 00000000..89920983 --- /dev/null +++ b/tests/automations/accept_pubkey.json @@ -0,0 +1,30 @@ +{ + "version": 1, + "rules": [ + { + "regexp": "Review|Amount|Address|Confirm|Fees|public key", + "actions": [ + ["button", 2, true], + ["button", 2, false], + ["finger", 55, 550, true], + ["finger", 55, 550, false] + ] + }, + { + "regexp": "Tap to continue", + "actions": [ + ["finger", 55, 550, true], + ["finger", 55, 550, false] + ] + }, + { + "regexp": "Approve", + "actions": [ + [ "button", 1, true ], + [ "button", 2, true ], + [ "button", 2, false ], + [ "button", 1, false ] + ] + } + ] +} diff --git a/tests/automations/reject.json b/tests/automations/reject.json index 50d04f48..7de1fd2a 100644 --- a/tests/automations/reject.json +++ b/tests/automations/reject.json @@ -8,6 +8,13 @@ ["button", 2, false] ] }, + { + "regexp": "Tap to continue", + "actions": [ + ["finger", 55, 550, true], + ["finger", 55, 550, false] + ] + }, { "text": "Reject", "actions": [ @@ -16,6 +23,13 @@ [ "button", 2, false ], [ "button", 1, false ] ] + }, + { + "regexp": "Cancel", + "actions": [ + ["finger", 55, 650, true], + ["finger", 55, 650, false] + ] } ] } diff --git a/tests/conftest.py b/tests/conftest.py index ce9311e6..b774f370 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,13 +16,20 @@ def pytest_addoption(parser): parser.addoption("--hid", action="store_true") + parser.addoption("--model", action="store", default="nanos") + + +@pytest.fixture +def model(pytestconfig): + return pytestconfig.getoption("model") + @pytest.fixture def hid(pytestconfig): return pytestconfig.getoption("hid") @pytest.fixture -def device(request, hid): +def device(request, hid, model): # If running on real hardware, nothing to do here if hid: yield @@ -35,8 +42,8 @@ def device(request, hid): base_args = [ speculos_executable, "./bitcoin-testnet-bin/app.elf", "-l", "Bitcoin Legacy:./bitcoin-bin/app.elf", - "--sdk", "2.0", - "--display", "headless" + "--display", "headless", + "--model", model ] # Look for the automation_file attribute in the test function, if present diff --git a/tests/test_get_pubkey.py b/tests/test_get_pubkey.py index 1dfa6939..dde1eb54 100644 --- a/tests/test_get_pubkey.py +++ b/tests/test_get_pubkey.py @@ -1,6 +1,8 @@ from bitcoin_client.bitcoin_base_cmd import AddrType +from utils import automation +@automation("automations/accept_pubkey.json") def test_get_public_key(cmd): # legacy address pub_key, addr, bip32_chain_code = cmd.get_public_key( @@ -40,3 +42,41 @@ def test_get_public_key(cmd): "648e4f638cabc4e4383fa3fe8348456e46fa56742dcf500a5b50dc1d403492f0") assert addr == "tb1qzdr7s2sr0dwmkwx033r4nujzk86u0cy6fmzfjk" assert bip32_chain_code == bytes.fromhex("efd851020a3827ba0d3fd4375910f0ed55dbe8c5d740b37559e993b1d623a956") + # legacy address + pub_key, addr, bip32_chain_code = cmd.get_public_key( + addr_type=AddrType.Legacy, + bip32_path="m/44'/1'/0'/0/0", + display=True + ) + + assert pub_key == bytes.fromhex("04" + "ee8608207e21028426f69e76447d7e3d5e077049f5e683c3136c2314762a4718" + "b45f5224b05ebbad09f43594b7bd8dc0eff4519a07cbab37ecc66e0001ab959a") + assert addr == "mz5vLWdM1wHVGSmXUkhKVvZbJ2g4epMXSm" + assert bip32_chain_code == bytes.fromhex("0322c8f681e7274e767cee09b8e41770e6d2afd504fd5f85dfaab3e1ff6cdfcc") + + # P2SH-P2WPKH address + pub_key, addr, bip32_chain_code = cmd.get_public_key( + addr_type=AddrType.P2SH_P2WPKH, + bip32_path="m/49'/1'/0'/0/0", + display=True + ) + + assert pub_key == bytes.fromhex("04" + "a80f007194d53d37f6f99539f635390588c4e1c328b098295f61af40d60cb28a" + "7b5649e8121c89148fbab7d693108654685b4e939d9c1bc55a71b43f389929fe") + assert addr == "2MyHkbusvLomaarGYMqyq7q9pSBYJRwWcsw" + assert bip32_chain_code == bytes.fromhex("dc699bc018541f456df1ebd4dea516a633a6260e0a701eba143449adc2ca63f3") + + # bech32 address + pub_key, addr, bip32_chain_code = cmd.get_public_key( + addr_type=AddrType.BECH32, + bip32_path="m/84'/1'/0'/0/0", + display=True + ) + + assert pub_key == bytes.fromhex("04" + "7cb75d34b005c4eb9f62bbf2c457d7638e813e757efcec8fa68677d950b63662" + "648e4f638cabc4e4383fa3fe8348456e46fa56742dcf500a5b50dc1d403492f0") + assert addr == "tb1qzdr7s2sr0dwmkwx033r4nujzk86u0cy6fmzfjk" + assert bip32_chain_code == bytes.fromhex("efd851020a3827ba0d3fd4375910f0ed55dbe8c5d740b37559e993b1d623a956") From 79dfc0d82c0fa358fa799e72c4be6768f32df2db Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 4 Apr 2023 15:55:54 +0200 Subject: [PATCH 08/85] glyphs: remove outdated blue glyphs --- glyphs/blue_badge_bitcoin.gif | Bin 362 -> 0 bytes glyphs/blue_badge_bitcoin_cash.gif | Bin 1420 -> 0 bytes glyphs/blue_badge_bitcoin_gold.gif | Bin 1420 -> 0 bytes glyphs/blue_badge_bitcoin_testnet.gif | Bin 362 -> 0 bytes glyphs/blue_badge_dash.gif | Bin 338 -> 0 bytes glyphs/blue_badge_digibyte.gif | Bin 369 -> 0 bytes glyphs/blue_badge_dogecoin.gif | Bin 363 -> 0 bytes glyphs/blue_badge_komodo.gif | Bin 386 -> 0 bytes glyphs/blue_badge_lbry.gif | Bin 375 -> 0 bytes glyphs/blue_badge_litecoin.gif | Bin 336 -> 0 bytes glyphs/blue_badge_peercoin.gif | Bin 361 -> 0 bytes glyphs/blue_badge_pivx.gif | Bin 344 -> 0 bytes glyphs/blue_badge_qtum.gif | Bin 445 -> 0 bytes glyphs/blue_badge_ravencoin.gif | Bin 1082 -> 0 bytes glyphs/blue_badge_resistance.gif | Bin 339 -> 0 bytes glyphs/blue_badge_stealth.gif | Bin 1460 -> 0 bytes glyphs/blue_badge_stratis.gif | Bin 363 -> 0 bytes glyphs/blue_badge_transaction.gif | Bin 339 -> 0 bytes glyphs/blue_badge_vertcoin.gif | Bin 1399 -> 0 bytes glyphs/blue_badge_viacoin.gif | Bin 362 -> 0 bytes glyphs/blue_badge_warning.gif | Bin 320 -> 0 bytes glyphs/blue_badge_xrhodium.gif | Bin 423 -> 0 bytes glyphs/blue_badge_zcash.gif | Bin 339 -> 0 bytes glyphs/blue_icon_toggle_reset.gif | Bin 225 -> 0 bytes glyphs/blue_icon_toggle_set.gif | Bin 227 -> 0 bytes icons/blue_app_bitcoin.gif | Bin 449 -> 0 bytes icons/blue_app_bitcoin_cash.gif | Bin 446 -> 0 bytes icons/blue_app_bitcoin_gold.gif | Bin 431 -> 0 bytes icons/blue_app_bitcoin_private.gif | Bin 445 -> 0 bytes icons/blue_app_bitcoin_testnet.gif | Bin 449 -> 0 bytes icons/blue_app_dash.gif | Bin 389 -> 0 bytes icons/blue_app_digibyte.gif | Bin 408 -> 0 bytes icons/blue_app_dogecoin.gif | Bin 427 -> 0 bytes icons/blue_app_firo.gif | Bin 1017 -> 0 bytes icons/blue_app_gamecredits.gif | Bin 1611 -> 0 bytes icons/blue_app_horizen.gif | Bin 654 -> 0 bytes icons/blue_app_komodo.gif | Bin 466 -> 0 bytes icons/blue_app_lbry.gif | Bin 1747 -> 0 bytes icons/blue_app_litecoin.gif | Bin 373 -> 0 bytes icons/blue_app_nix.gif | Bin 594 -> 0 bytes icons/blue_app_peercoin.gif | Bin 436 -> 0 bytes icons/blue_app_pivx.gif | Bin 395 -> 0 bytes icons/blue_app_qtum.gif | Bin 590 -> 0 bytes icons/blue_app_ravencoin.gif | Bin 1618 -> 0 bytes icons/blue_app_resistance.gif | Bin 1947 -> 0 bytes icons/blue_app_stealth.gif | Bin 498 -> 0 bytes icons/blue_app_stratis.gif | Bin 456 -> 0 bytes icons/blue_app_vertcoin.gif | Bin 397 -> 0 bytes icons/blue_app_viacoin.gif | Bin 433 -> 0 bytes icons/blue_app_xrhodium.gif | Bin 913 -> 0 bytes icons/blue_app_xsn.gif | Bin 1984 -> 0 bytes icons/blue_app_zcash.gif | Bin 399 -> 0 bytes icons/blue_app_zclassic.gif | Bin 509 -> 0 bytes 53 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 glyphs/blue_badge_bitcoin.gif delete mode 100644 glyphs/blue_badge_bitcoin_cash.gif delete mode 100644 glyphs/blue_badge_bitcoin_gold.gif delete mode 100644 glyphs/blue_badge_bitcoin_testnet.gif delete mode 100644 glyphs/blue_badge_dash.gif delete mode 100644 glyphs/blue_badge_digibyte.gif delete mode 100644 glyphs/blue_badge_dogecoin.gif delete mode 100644 glyphs/blue_badge_komodo.gif delete mode 100644 glyphs/blue_badge_lbry.gif delete mode 100644 glyphs/blue_badge_litecoin.gif delete mode 100644 glyphs/blue_badge_peercoin.gif delete mode 100644 glyphs/blue_badge_pivx.gif delete mode 100644 glyphs/blue_badge_qtum.gif delete mode 100644 glyphs/blue_badge_ravencoin.gif delete mode 100644 glyphs/blue_badge_resistance.gif delete mode 100644 glyphs/blue_badge_stealth.gif delete mode 100644 glyphs/blue_badge_stratis.gif delete mode 100644 glyphs/blue_badge_transaction.gif delete mode 100644 glyphs/blue_badge_vertcoin.gif delete mode 100644 glyphs/blue_badge_viacoin.gif delete mode 100644 glyphs/blue_badge_warning.gif delete mode 100644 glyphs/blue_badge_xrhodium.gif delete mode 100644 glyphs/blue_badge_zcash.gif delete mode 100644 glyphs/blue_icon_toggle_reset.gif delete mode 100644 glyphs/blue_icon_toggle_set.gif delete mode 100644 icons/blue_app_bitcoin.gif delete mode 100644 icons/blue_app_bitcoin_cash.gif delete mode 100644 icons/blue_app_bitcoin_gold.gif delete mode 100644 icons/blue_app_bitcoin_private.gif delete mode 100644 icons/blue_app_bitcoin_testnet.gif delete mode 100644 icons/blue_app_dash.gif delete mode 100644 icons/blue_app_digibyte.gif delete mode 100644 icons/blue_app_dogecoin.gif delete mode 100644 icons/blue_app_firo.gif delete mode 100644 icons/blue_app_gamecredits.gif delete mode 100644 icons/blue_app_horizen.gif delete mode 100644 icons/blue_app_komodo.gif delete mode 100644 icons/blue_app_lbry.gif delete mode 100644 icons/blue_app_litecoin.gif delete mode 100644 icons/blue_app_nix.gif delete mode 100644 icons/blue_app_peercoin.gif delete mode 100644 icons/blue_app_pivx.gif delete mode 100644 icons/blue_app_qtum.gif delete mode 100644 icons/blue_app_ravencoin.gif delete mode 100644 icons/blue_app_resistance.gif delete mode 100644 icons/blue_app_stealth.gif delete mode 100644 icons/blue_app_stratis.gif delete mode 100644 icons/blue_app_vertcoin.gif delete mode 100644 icons/blue_app_viacoin.gif delete mode 100644 icons/blue_app_xrhodium.gif delete mode 100644 icons/blue_app_xsn.gif delete mode 100644 icons/blue_app_zcash.gif delete mode 100644 icons/blue_app_zclassic.gif diff --git a/glyphs/blue_badge_bitcoin.gif b/glyphs/blue_badge_bitcoin.gif deleted file mode 100644 index df0c7abb17dd681f27c330874b790cc71c637e67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 362 zcmV-w0hRtoNk%w1VKM+R0FeLy-QC^o?d{CW%=!8GA^8LV00000EC2ui05SkF00092 zoR4`C00N^6s@j`e++5;sHQhJ@6bL@tbQ+AdqF1oCpSaobphD)p=m`KoUapv+d1O5z zveHCFpO)#Rr=up973EO-!CJWBYXo{OgUADKR;_R&R8A?R4S836h=?97U?lJtmnK*j z)`kbw>oyzPj&D?B-v0C{n%xdr$ zeIYyyvQC;PLFaxz8gCZ3YR5VQ_rly!vX7uQRB$F?6BMYSJaX?SN`z?5A{;S0dmh5^ zg3OjiD(L=w*@&s5Mpsu-MV!1H98obzBN+*veb!xuqW IASnOxV%Qmue&kg&dz0$52&wylyQNJ0T*r*nQ$s)DJWnQpS7v4w)U zrJkXwrG=4+j)IYap_#scrM{twu7RPIfu)s!p#l^r0c|TvNwW%aaf8|g1^l#~=$ z>Fbx5m+O@q>*W`v>l<2HTIw4Z=^Gj80#)c1SLT%@R_NvxE5l51Ni9w;$}A|!%+FH* znV6WAUs__T1av9H3%LbwWAlpjz~0eI&d=4aNG#Ad)H48i38v837r)ZnT)67ulAu(C zd$Af^98y`3svneEoL^d$oC;K~46>@g%DE^tu_V7JBtJg~7K#BG`6cQdFB2=9ZF3nBND}m`vLFl!>sTY(WatnYqyQCInmZhe+73JqD zfIV)NiQ6rvIL(9VO~LIJGn{($fsWA!MK4lx!-Rlo2*iXZULXga{8RIQX}$=UxEcTd z`}^njub)4@fBX97^QVs=-oJbM=Jl(WFP=Yp`sDGWhY#-GyL;#Mt(!NlU%Ptc@}-Lx z&YwGb=JctPCypOGdgSn-g9rBS+q-A?uAMu!Z`-%OrteG>WPn$Yr@}!9q`ulo&y1P0%+S^)NnwuIM>g#H2s;eq1%F9Yiii-*h z^7C?Yva>QX($i8?l9Lh>;^SgtqN5@s!oxyCf`bAB{QZ1=yuCa<+}&JVoShsU?CorA ztgS48acyd1Y-DJlucxb{t);1EF>tv&&SKd&Be*V z&c@2Z%*4pRp!k!80R(hF1gHdIVER9&zmidxUz%gpt=$ZFYW#V^ddvg47rUl)^qxPy zi|LG3W0dlzS^S!JPw#2k|6pl^_s5=Xi5@3e?xrbZguD{5ofdw2iuDYpT_@K%8LLgd z%x%n_TX20J#}6w#hU7PiKPOu~5Py7({gUIQWc7-|8xxJMs!!M~8j$(&kl3csj2X|r zPG~;Xxv?T3O7T@>vD6BwqU57RT$bA}I#*`SROK$by<=f|qV-SfJzRoo40hi>x#~?7 zo0SFgT}hwcR>r3y)++yfJ|VOAORQ=0+LgK+<*eWJ1jqzxzhwR~Wsxjn$~-so{0(bc z=QKpU5Zn@QBHpa|+cI6t70djbnUj=ey%y7)Db;Fy(ZFrZj_0z%6U0r~6n~~a5>;6k wHzViZrsGqJ-O6GnZhX&lZhFv%%+*VnTiNFo*Bo1%d9kg9PpCsqgMq;s0HpsJqyPW_ diff --git a/glyphs/blue_badge_bitcoin_gold.gif b/glyphs/blue_badge_bitcoin_gold.gif deleted file mode 100644 index 9a63e6d806e75f76a57e927ec155b5d298274ca0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1420 zcmZ?wbhEHbG-5Dfn8?6z|Ni}tA3vTsbLQvIpNjvvBYXoCToOwXfwYZ%ML}Y6c4~=2 zQfhi;o~_dR-TRdkGE;1o!cBb*d<&dYGcrA@ic*8C{6dnevXd=SlxV%Qmue&kg&dz0$52&wylyQNJ0T*r*nQ$s)DJWnQpS7v4w)U zrJkXwrG=4+j)IYap_#scrM{twu7RPIfu)s!p#l^r0c|TvNwW%aaf8|g1^l#~=$ z>Fbx5m+O@q>*W`v>l<2HTIw4Z=^Gj80#)c1SLT%@R_NvxE5l51Ni9w;$}A|!%+FH* znV6WAUs__T1av9H3%LbwWAlpjz~0eI&d=4aNG#Ad)H48i38v837r)ZnT)67ulAu(C zd$Af^98y`3svneEoL^d$oC;K~46>@g%DE^tu_V7JBtJg~7K#BG`6cQdFB2=9ZF3nBND}m`vLFl!>sTY(WatnYqyQCInmZhe+73JqD zfIV)NiQ6rvIL(9VO~LIJGn{($fsWA!MK4lx!-Rlo2*iXZULXga{8RIQX}$=UxEcTd z`}^njub)4@fBX97^QVs=-oJbM=Jl(WFP=Yp`sDGWhY#-GyL;#Mt(!NlU%Ptc@}-Lx z&YwGb=JctPCypOGdgSn-g9rBS+q-A?uAMu!Z`-%OrteG>WPn$Yr@}!9q`ulo&y1P0%+S^)NnwuIM>g#H2s;eq1%F9Yiii-*h z^7C?Yva>QX($i8?l9Lh>;^SgtqN5@s!oxyCf`bAB{QZ1=yuCa<+}&JVoShsU?CorA ztgS48acyd1Y-DJlucxb{t);1EF>tv&&SKd&Be*V z&c@2Z%*4pRp!k!80R(hF1gHdIVER9&zmidxUz%gpt=$ZFYW#V^ddvg47rUl)^qxPy zi|LG3W0dlzS^S!JPw#2k|6pl^_s5=Xi5@3e?xrbZguD{5ofdw2iuDYpT_@K%8LLgd z%x%n_TX20J#}6w#hU7PiKPOu~5Py7({gUIQWc7-|8xxJMs!!M~8j$(&kl3csj2X|r zPG~;Xxv?T3O7T@>vD6BwqU57RT$bA}I#*`SROK$by<=f|qV-SfJzRoo40hi>x#~?7 zo0SFgT}hwcR>r3y)++yfJ|VOAORQ=0+LgK+<*eWJ1jqzxzhwR~Wsxjn$~-so{0(bc z=QKpU5Zn@QBHpa|+cI6t70djbnUj=ey%y7)Db;Fy(ZFrZj_0z%6U0r~6n~~a5>;6k wHzViZrsGqJ-O6GnZhX&lZhFv%%+*VnTiNFo*Bo1%d9kg9PpCsqgMq;s0HpsJqyPW_ diff --git a/glyphs/blue_badge_bitcoin_testnet.gif b/glyphs/blue_badge_bitcoin_testnet.gif deleted file mode 100644 index df0c7abb17dd681f27c330874b790cc71c637e67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 362 zcmV-w0hRtoNk%w1VKM+R0FeLy-QC^o?d{CW%=!8GA^8LV00000EC2ui05SkF00092 zoR4`C00N^6s@j`e++5;sHQhJ@6bL@tbQ+AdqF1oCpSaobphD)p=m`KoUapv+d1O5z zveHCFpO)#Rr=up973EO-!CJWBYXo{OgUADKR;_R&R8A?R4S836h=?97U?lJtmnK*j z)`kbw>oyzPj&D?B-v0C{n%xdr$ zeIYyyvQC;PLFaxz8gCZ3YR5VQ_rly!vX7uQRB$F?6BMYSJaX?SN`z?5A{;S0dmh5^ zg3OjiD(L=w*@&s5Mpsu-MV!1H98obzBN+*veb!xuqW IASnOT=Nk%w1VKM+R0FeLy-QC^o?d{CW%=!8GA^8LV00000EC2ui05SkF00092 zoR4`C00N^6s@j`e++5;sHQhJ@6bL@tbQ+AdqF1oCpSaobphD)p=m`KoUapv+d1O5z zveHCFpO)#Rr=up973EO-!CJWBYXo{OgUADKR;_R&R8Dx1IGTMdScy3E?elC<*t-~)2Dn~z zt^UqT{dYZY;O-*7C^z@Jjt#ndi+Y3*Xh#e@XZ;ZVBUr}DE{8}YLSm>TRuLg1lYroW kXsU*cj~J=&8e+o6i<7d7kSu4;(8)|K;jEOD5=j97JH$q$8vpV!YA^8LV00000EC2ui05SkF00092 zoR4_`5dx!Qs@l6=+*|?-R?RkjOQS)78DgW#g0B#?7vR~*9P8Su6a9jNA<<%NX?n*5 zj;4e#n@$yINew+~mgh99@QSS9sG#!T+R{bn+P#nl*=(EmQ1?OeQT1J4!>1+JrY6FG z$dEPy1ZY5L(ILsv=mIhD1Twi9@r59TV_1fXh4H|6L~$Xgkal`RHg;xNs*`zhX&G_E zx|55s0SkvV9Jw3xR}p)$;YmD;^b6cMSL|yYrXt{6wcWLh>wp~%ose`z6YAJKPRt;! z>5VxfZzBh(J1IIi+uJHBZXY@>$y_Mf(@qu(f2$A*Y-p(9z(Th0QFO%c-@YwEqe9fW z#;uG*JQh0|;ApDkD3s{xb!6!gT$XcYDm8iWP(}_SJhIHN=^_Qtn<;3lh@q(HP%!j3 P!7zD99Hpa23IG5*o3X0! diff --git a/glyphs/blue_badge_dogecoin.gif b/glyphs/blue_badge_dogecoin.gif deleted file mode 100644 index 41769cc67ebdd39a762bb4d551b015bca3a1aa4b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 363 zcmV-x0hInnNk%w1VKM+R0FeLy-QC^p?(WRY%=!8GA^8LV00000EC2ui05SkF00092 zoR4`C00N^6s@j`e++5;sHQhJ@6bL@tbQ+AdqF1oCpSaobphD)p=m`KoUapv+d1O5z zveHCFpO)#Rr=up973EO-!CJWBYXo{OgUADKR;_R&R8DxEPJ2 zcH2wRD)7sC!6-aOOzRsaq^raG(V<#;tc`)V9dZ6GMSuU)G;`HGb&w~p06JEvTA)5dTV#6bKQdh^B*nyqU*5zW0b zGm)VefgVW~vC`0C8I*@YB4Ky35yCjlo)9|sr_xN2jZD~})WPJSdix~o+(DF)P%S`L J_(W0w06Su&taShY diff --git a/glyphs/blue_badge_komodo.gif b/glyphs/blue_badge_komodo.gif deleted file mode 100644 index 41466b8a58a16a754f330cb332670b388504e829..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 386 zcmV-|0e${QNk%w1VKM+R0FeLy-QC^o?d{CW%=!8GA^8LV00000EC2ui05SkF00092 zoR4`C00N^6s@j`e++5;sHQhJ@6bL@tbQ+AdqF1oCpSaobphD)p=m`KoUapv+d1O5z zveHCFpO)#Rr=up973EO-!CJWBYXo{OgUADK7Ss6c+z6EugxkndK1Af5B-F7tlVwS82+62)SJf9bY9@dasz8Upu*HaBr_$L&Nyg?XcEPoH zM_b5|2;ny}e2P(NdgsN_@~8`(yg<@iT7ev5I6zX|+0k9f>zJ)7@oFkiTYbywzT1g$6|Nym1R=_!EIY4j-*DGHNyN%fG|=F?bsiZq+Z!S@K(qnV3aS|sMX zu>fJPdpK%(e9&Pm;9Q$=dn9emNjp8P){XJx;{Uz$o-TOC`O`R)rknPm0 z={U`#yh$BZQhYa%N-BpfU8QWdQP|CQ%d~iL7c$UDAvrM#MR6{o7JTa%3~Io%C@Q8T VI>0i?tZFE%NuXLa5wk)806WH`v%3HQ diff --git a/glyphs/blue_badge_litecoin.gif b/glyphs/blue_badge_litecoin.gif deleted file mode 100644 index de0095b68b1e2ffd3d98831f8974dc292c239175..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 336 zcmV-W0k8f?Nk%w1VKM+R0FeLy-QC^p?(WRY%=!8GA^8LV00000EC2ui05SkF00092 zoR4`C00N^6s@j`e++5;sHQhJ@6bL@tbQ+AdqF1oCpSaobphD)p=m`KoUapv+d1O5z zveHCFpO)#Rr=up973EO-!CJWBYXo{OgUADKR;_R&RLXJ+K}DAdc?VHMd5MD4Vc69nB{ZU1!OBT8A;~x!qa_;# zlcvi7yAVm`1!}3MMLCFat3^k7y5cZRy{VA-7)C-eOJRDk&5iN6>=&MUSoaNQE-;78 zj#1vW9*-dRK58Eezt_KSL|+^>@x)ZAr>2;;e`T!5Bj^d@L4-TJAlf112dRu9Pb>}z i=E4=oLw8Krc;V_I7*yvvXe`)r7{E3SQnEl&0028oM3__n diff --git a/glyphs/blue_badge_peercoin.gif b/glyphs/blue_badge_peercoin.gif deleted file mode 100644 index 1c39643d7c79604413da52811a58a84c3e2cd99d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 361 zcmV-v0hazpNk%w1VKM+R0FeLy+}zyl?d{CW%=!8GA^8LV00000EC2ui05SkF00092 zoR4`C00N^6s@j`c++5;sY2DZX6bL@tbQ+9PqF1oCpBUNlphD)p=m`Ko-bPoXd1O6e z(b7akpOm diff --git a/glyphs/blue_badge_pivx.gif b/glyphs/blue_badge_pivx.gif deleted file mode 100644 index 62db7bdde37b4ccdaa838be057deb3e4e1490a9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 344 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 diff --git a/glyphs/blue_badge_stratis.gif b/glyphs/blue_badge_stratis.gif deleted file mode 100644 index a01878e4a59735c02c298a9ec8a0e6a187ffe677..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 363 zcmV-x0hInnNk%w1VKM+R0FeLy;Nal#@$t;e%=!8GA^8LV00000EC2ui05SkF00092 zoR4_{Ee{(As@l5%+I}?(^waZdN()bhe~3)7m4zR3Y*YzV*n~> zdw`pFG6|)kTJihYq}#A`RIJd^tDDR`?dU^i=pp26@#UZ=b_Y7Vj7%z+LA(&C%IGmBge#ZxpD&nPf_ JvQSb006X~@rJVo( diff --git a/glyphs/blue_badge_transaction.gif b/glyphs/blue_badge_transaction.gif deleted file mode 100644 index 131325d4a16f9889cb1efc0709cd4b7aa9130bc6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 339 zcmV-Z0j&NFMd%*x1a>%=!8GA^8LV00000EC2ui05SkF00092 zoR5hREiYOCs@j_v-26=pT3SbTUl;}^KxN|=pclZM;rq1mp+feKi|q!zh;Ddz2~ou* zQqg2Wj!y;611eIhR^M#Oy@4ybSvk_klS7D6(z$^-0J(YLSsJ?+R9qS8KJnC7t#Tga!SS_ z({QtMd#20f^Kh2xn(Q0vK-X64*_WCl4P8<_0r+KP***E}Jo`2Lq&V6~J_Kp79(b&? z=iX(USu3BW9U6bHPmN&5uihzG{E8s*cW(|REeQ$YLwILSIs;MeRK#P%j1nXyMKU4@ lQe}<@PzyRb3uBU-6&(4(u(UQ(-pdk)5=wy4fTV>206Uxbnu-7b diff --git a/glyphs/blue_badge_vertcoin.gif b/glyphs/blue_badge_vertcoin.gif deleted file mode 100644 index 2f47fc15b28126385e6cd5005ff43db65b394299..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1399 zcmZ?wbhEHbG-5Dfn8?6z@7}%l@86#}bLQvIpNjvvBYXoCToOwXfwYZ%ML}Y6c4~=2 zQfhi;o~_dR-TRdkGE;1o!cBb*d<&dYGcrA@ic*8C{6dnevXd=SlxV%Qmue&kg&dz0$52&wylyQNJ0T*r*nQ$s)DJWnQpS7v4w)U zrJkXwrG=4+j)IYap_#scrM{twu7RPIfu)s!p#l^r0c|TvNwW%aaf8|g1^l#~=$ z>Fbx5m+O@q>*W`v>l<2HTIw4Z=^Gj80#)c1SLT%@R_NvxE5l51Ni9w;$}A|!%+FH* znV6WAUs__T1av9H3%LbwWAlpjz~0eI&d=4aNG#Ad)H48i38v837r)ZnT)67ulAu(C zd$Af^98y`3svneEoL^d$oC;K~46>@g%DE^tu_V7JBtJg~7K#BG`6cQdFBG;}q0 zbaZpJFt9Lnv;Z=UEev6LUGkGlb5rw5V0u#!dM$D41to~w0-((eiaKZd}bLY&SHFL)FX;Y_6o-}bne_wA;cUNaeds}Nub5mnOeO+x$ zbya0Wd0A;maZzDGeqL@)c2;IadRl5qa#CVKd|YfybW~(Scvxsia8O`?zn`yqc->fwKTJNN{{!T1kJOI$156H~5c9ZQ?BqQrIWjk4=k zr&TsI?4Bm}!%^k(h0gV}p4n}7KB@5Jh;9+ zdGhh}u&v4-+cQ>7tWaIq%HEO4T$P@_>*L0&7E6B}j520Ysxr*pQLG)_^))24$x;ron%b_$Tb=sa=*a!v l8t(2TCn|y__GOBQnM825^!Mg$3x&q89fm$Q-nhz=6%e;cW;H6kg@r<@% zNXZ1J&YeSId+;m;$=VtwJ*13eiKT^J=lN z2Z<|m;V41pR;OfDZs7BPI4GF3E I7%2b%J6UX}L;wH) diff --git a/glyphs/blue_badge_warning.gif b/glyphs/blue_badge_warning.gif deleted file mode 100644 index 37c7ed5be288fe1dd7a23bbf46eb94cab3ed9df7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 320 zcmV-G0l)r7Nk%w1VKM+R0HFi`>FMd%*x1a>%=!8GEC2ui05SkF00091oR5hREiYOC zs@j_v-26=pT3SbTUl;}^KxN|=pclZM;rq1mp+feKi|q!zh;Ddz2~ou*Qqg2Wj!y;6 z11eIhR^M#Oy@4xU8RM6QRC>-7cE`?)WpUt~_=e}{`@1xPbS03q#|Mbi(~|g9H*_VW z##kt$_E^<8l(;B)80fKyIEnJu!-YBI5y{!M(_t!#;(7@iBD>1v^YGe<^qDiuYZn2U zNsIAldCN(m>e#RqtBWT99VT{|Y+X!!;CJ)vDQ$4-7F_NmSZzUm?8iO>u4g__rhQQ) z;%#q`ey^`Bh*bhD`v@81QBPYGLq@DA3FSi_JQ!63d62lE$gdhO8ZT~P(Q)1r93@Ji Su}8Ax$%08Fz=(&W0027+FP5+X diff --git a/glyphs/blue_badge_xrhodium.gif b/glyphs/blue_badge_xrhodium.gif deleted file mode 100644 index 5a581020c45d3a111d53c2ae8af8a67764cafd4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 423 zcmV;Y0a*S=Nk%w1VKM+R0Kx_U_xJbD&(GJ_*XQTw@9*#5-{1fL|NsC0A^8LW3IGQH zEC2ui05SkF000C22)f)nMTkIyEW_!|+n7}-T3Kgm1URmuK%8(f3d7qF-&nvL(UzxN z$i`d9Dz4%p71}9PN#zY%q)IndlL~m%43MT{pbM)wy%jEb^QEX4;PpwR0SV+h`>jIM zutEZ7J$wv$9e*Qzbrg4S6p9Xri5)%^3vG>uk|J6ZP9SfQAr4Gw9heFgWutzq9IB`% zoM@^YphuyiwGM5Tr=B2?t-Bts8;HGu(2U%n0dDiKoWt02R10IX$V^AA9* zZU+r6#Nutq(L0O*i^V|^ui`6j8Xs}Az(C=-R49A(BdJm#OFVN-G8l<-QAUfVdh!aY zL5xscf_%<93REYDEO?-HV)PP5shdS4Ry`&!DG!B==y{O0bd9yJkZ_QliSz0@3tO)U R*+he>mk9DMh~Zj!r+O6`8cGhrPvqegZN|$*g>VpDak>#5i7g#WL4x! zh)c_HimHm_Mano#>{GZV@#&fAL%DMqDh0t1$$U9|J%F57;$YjAwk$dh{^#9o=u_lq zVBYE8uHN0H8l3)wa+Z7!RKyg=LC`5vWC%AA4XVrepW2R=jZ47`T76<|IEzHA^8LV00000EC2ui03ZMo000Dzut`ajNH6QXlTgGYHbual z=oS2p@Hr>=Y?x*0!CneV{8Cb2UlrYbRkT6QDgxWI!9gq*06JE~1l$0M&>}L>STr|?VH8@(Es)oYV7nDO zEa41+93?z1>BoT$JvHfM<{=Z=T%6tbe5aEk1(Xg( z2#SY;Ye|ZwriuUudr%x%r>}|vt4JNLs0j%Ix`m}=QM076GKr{wG^GMF38lcs$jZXT zGS49c#Ea6?$hy0w49(84rcT+~;-vr!2c~xA)FRiR>-W{@>mU3;5b*ae z;DZ4SykP<71092h3~=#Mqz+0gEay(?OEO>-l8mTs7-1=qCEmPF3lbVKFsNdtNRt%# z`f_4Wp+m$(enIgsN(zQOLHKDL@81d6&XA^-q8p@Yhz diff --git a/icons/blue_app_bitcoin_cash.gif b/icons/blue_app_bitcoin_cash.gif deleted file mode 100644 index adcfbb63b65ad22d519a11128caa0eeb6750ea26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 446 zcmV;v0YUypNk%w1VKM+R0J8u9i@j|2`1RN5%*5Wc>hk2G%7~G`bK~yYz1geF;l7;5 zf${b3tk0GC`T76<|Ao3_EC2ui05SkF000F4u*pf=5{M}Sp8p^S7z%?3OQo(&kQ8Ao z&t8!P>^c~9?|X(pZbE?lj=cgQci`*MYrr)U z>vclXjeElj`}*QdI0POC4r5;!eSd+2WEqEm4}yeV8c+ra2?P!cmJ1FC0}NgpPznyE zrl+MRCyGy;gs&85g90S*Y# z(+&j+-rouZvue`7sOQAm9_Ht$z3RXm0Q2+)N)7?l#m-T@>JR*8K>8O@#z1(~XaKmD z4Ph`D0H8S_=R;o)U<5L1)MzTwkrB6Z+MV)vgaoAl10PR21B>=O+G7E*kAHp#T4q(O}$S{};&CZ|!*4Nem zlme#H545A38cPl;g(vAp7Lx?J(d#+BAP-9B>Pm zser?W4ha@K^~u~hgG@$HVZZ=^LXLlA4ru7sgajQ2b{;T@#ihi_lq(B_G4ZlPOhGBD zSaU|Q3W|I1K6qghlm{FZsET$_Gl7{>5M(9*^){4(l&4FvP*C#p$qgYzj{uR7W7>eI ZV_CS+MPp6c3KueX%1FY5RuvHd06S<6yq^F7 diff --git a/icons/blue_app_bitcoin_private.gif b/icons/blue_app_bitcoin_private.gif deleted file mode 100644 index 3d528fc3ded15c87a3885a81ed7483740141f1c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 445 zcmV;u0Yd&qNk%w1VKM+R0J9GO*4W|l^7WylxhF4R|NsAnil#zIbX{YJb$XgLJZh7d zu*JvJuCc@9;)=Bx|#=EDipvXi{lO~(YJ@gigh zio9pba9}#cOVxl?EUeW^Hfv(M3!64L=maa7FG2Zgzy*j$;K#FKkNh1_$F7h-A@^=1 zB-BykftN6u1z9*CAsP`#3UuU&W<-^hphz%$Crbi9rXSP@gUX_e8LBMQNSK24N|p)# nx(ICrmOW(&IsmcRSjGQGp7ERk;)}#>_dQZ3F;2-T1gA diff --git a/icons/blue_app_bitcoin_testnet.gif b/icons/blue_app_bitcoin_testnet.gif deleted file mode 100644 index beec02c64712b55c2f5d219f2c28ed0ee1b67642..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 449 zcmV;y0Y3gmNk%w1VKM+R0J8u9|NQv<+o%2Y>HfM<{=Z=T%6tbe5aEk1(Xg( z2#SY;Ye|ZwriuUudr%x%r>}|vt4JNLs0j%Ix`m}=QM076GKr{wG^GMF38lcs$jZXT zGS49c#Ea6?$hy0w49(84rcT+~;-vr!2c~xA)FRiR>-W{@>mU3;5b*ae z;DZ4SykP<71092h3~=#Mqz+0gEay(?OEO>-l8mTs7-1=qCEmPF3lbVKFsNdtNRt%# z`f_4Wp+m$(enIgsN(zQOLHKDL@81d6&XA^-q8p@Yhz diff --git a/icons/blue_app_dash.gif b/icons/blue_app_dash.gif deleted file mode 100644 index abf0fd0e8b4eec4a76b8e6c4db5f82e6c62d812b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 389 zcmV;00eb#NNk%w1VKM+R0J8u9XsgZh_W0N5?wG{dsLtVfw9)17^agpZLX^K9g0wY` zyGfbCSD?oE`T76<{{VHYEC2ui05SkF000F4u*pfAA%&@Qp8p_tBnndyMy0MzFd$(p z&mJ-atm-Co?|X?`P9lK)jy;4RC*UEUv&2%>gj!|NO2BySeh|3Hz)SuNCIM&Jn+T8B z<#U4z?;#I-#Mn*gQ&=I7|>1e(!&;;E?Qd;svHZ+z?Zo2yXPF$)C(3LHof00MtKMu2-l zVj+?e4v(0K_~QgcA1E&NNI^?u4GH%;JerY^M&yS!VoZ9FL$YH;Fcqq3%tA$tLz*j! jyquC_N39@XhLC*m$3{@06)t4hfH2005+_m&i2wjQ#;2`q diff --git a/icons/blue_app_digibyte.gif b/icons/blue_app_digibyte.gif deleted file mode 100644 index 2ec2174ee569cca0aa402504df24e17ee924846a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 408 zcmV;J0cZY4Nk%w1VKM+R0J8u9Z=A}m#^KxL@SM8ZR*Atqc(^Zavyigafv3>O+3V5W z>+bUQdlf^sOQU4x5~v zo(?HgivtOzrl+O?odTDbK?VQ}pspVPDlJ$J0JI&EXCDKAyat=C9)-LQ0JAR0ypaPp zzR3>@4u>zr$pj7zH<}65!AC813&xnTyDZDP)Z7a!29XZY)CiIuu(A%nysGO$1hCc( zTe1S5I+3Hcpfr6_L2fl(7Gg$shJgcz|j0suRK Cw6g{P diff --git a/icons/blue_app_dogecoin.gif b/icons/blue_app_dogecoin.gif deleted file mode 100644 index 880ca163a5b4e98626d9af3f479a2ec3ba314115..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 427 zcmV;c0aX4+Nk%w1VKM+R0J8u9#qQVj`S)himxJ4@spiGD>doi&?Qhnd-1Fz}_wt8>1_lTW zwvcnOj-$*Xkg?w2;U5Cyy9WTvj|=d42i(FQ%grFqkJ0tLGSv=}4e}S_*CPY5b!)9kqG8L{EJ=&$hlb}>`9Kp$?NDChIgp~2>!l@V= VW4%(ikYR($86!%ZNKqsL06Sj3z1#o* diff --git a/icons/blue_app_firo.gif b/icons/blue_app_firo.gif deleted file mode 100644 index 4d11cc865196af71e95be215e7c231ecd035fe4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1017 zcmZ?wbhEHbG-5Df_{P96TSj-btlk_s{W1zN+a$P0NK^ zR*ST)7wg+CF>qL72tg&tbUSGNX=IV{NH*UYXefQn{ho2rl{ru|nmlrR;zyI+4!^dwQ zKm7orZ{L4?`}XVm_n$w1{{8dk@87=+g8(T0WC6QE2SkG6gn|8ELts;LOQ46jw!D}i z8$)0Jgb8edV)EMN9<8%x2l^OEF-=^wcnOn~kw41Batf=ReJssn(|$ zCw2ANm6=woV!qU*D!cSU^V5f#Y#urRWfxMFlqSkdP~P4UvcT<$qM+}Kro;^=7*d(K zBx)9Rw;kMfxN!WISH(NMT%Z!}j#CPZtAORrvf{IlL7OIh))W>ug*NR|PI%3s6$4WqI^cm}3!_ zO1I0yS64YF2rP*9H_S+F3}Wag4H0g34C)MGm-#5dxg=sy2&ezU52sW&cs!Wot*B8L z!Y?|p>16IAjSYu`S-&1=@R(^562z;ssM)!5Nes&bJ!OV(A;KcZHU+4EI`D{rC$2K$ ziwh6$q(}S~hb#)51TIUeuyFl&`{|s*1r6h~oYxYP51HMqG3GGhV7q!o?ZA?iK8C9v uJW|s?x8ji3#Nty<-MTFmOkVRCW;AilpCdErgwng0MxLtEQ?;Zqle1Gx6p~WYGxKbf-tXS8q>!0n zs}yePYv5bpoSKp8QB{;0T;&&%T$P<{nWAKGr(jcIRgqhen_7~nP?4LHS8P>btCX0M zpOk6^WP^nDl@!2AO0sR096=HaAUmD&i&7O#^~`jW4NXiH%q{f{&5TVfEp-%(3=A#w z4J`BxjdcyptV|57jEoeZKnZADQA(Oskc%7CE+EfVDWjyMz)D}gyu4hm+*mKaC|%#s z($Z4jz)0W7NEfI=x41H|B(Xv_uUHvof=g;~a#3bMNoIbY0?5R~r2NtnTP2`NAzsKW zfE$}vtOxdvUUGh}ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+Zo zqU2Pda%GTJ1y;^Qsfi`|MIrh5Ij~R+$jC3rFV4s>P;hnzg_@;;hHqkWW*$gT6RgYE z*UB@mxFj(zIn~p}Rtad1US?*Bm7$TNiKDBrqlg_E<9rKOR%vAL0(i>Z^F z0Zgw;esXDUYF-IUZwf-M6HdLL1d&?+wAm%KD6=dz#jPkmR{`vCt4u6zaRH`YXCMZe zXN27?5WOi_+yd1L@&|Uk`as9%gQ6EHx?w`VGz4P86EBbhPyVTSz%*Y3Ox%qB|NZ^* z``6DO-@kqR^7+%p5AWZ-ee?R&%NNg|J$>@{(ZdJ#@7=v~`_|1H*RNf@a{1E53+K6ZM9qnzcEzM1h4fS=kHPuy>73F26CB;RB1^Ico zIoVm68R==MDalER3Gs2UG0{A;Cd`0selzKHgrQ9`0_gF3wJl4)%7oHr7^_ z7UpKACdNjF2KsusI@(&A8tQ7QD#}WV3i5KYGSX6#65?W_BEmv~0{ncuJltHI9PDhY zEX+)d3=E1tSr|Y-2Sk8M83vaB6HZ#rm2T8%Jn%a~!>%KcrPDMZC!3Yk{M?uAHcd_j z;jh`c+>;AeOFB2S1qD3#snYEDFwiC{-OKsF!)VR6>jrNdZfs-gYIZ*(W-9m0YvIPc z+qoS_y2Ks!yl-&gim}OTY%kE~2<^z_ZRTTT?``0&o=~u zPvf|Ftj^`(qsNcKHz{xD+&`u4WW@ zi`~HnM;0>(D0`jRAaH+s<<~c+Ssg7hmR>T~>?=-8<4v*iW#`gK4!d~KvzeoCrS;QK zi#k{><34V#)L7D6#m@7A=gH(7r{}q^7n%DsciD`kA16gMaxu-in9pw1#AQ_y%$d)l z)+M|9s3xyB>$^q`vCX>ErPtHx0k#eCZ;gF{Z5Kbqr@p$uEP zh)=iVZKVUMK`AFqq&O}dPH=0UXK&nydO1?-* wU6KxmM1`kG@VvK=Tbb;=I#%%VO1KL@@>hxQSa7g`$52`DiN(T0?ko(}0NT7@w*UYD diff --git a/icons/blue_app_horizen.gif b/icons/blue_app_horizen.gif deleted file mode 100644 index 9828e14bac7f94407599492b3a6ec6db72af4700..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 654 zcmV;90&)FENk%w1VKM+R0J8u9M^$vr(%KXzPBB1ZWN?aqiJ$NB^WWj-k(#XP>+YYX zwvLvmz{Sw{`T76<{{$C8A^8LV00000EC2ui05SkF000F4u*pf=Q3Q;~yZ_w)5Xw=V zXp<}(=)T~vB5d7*DFKtuPrci?XvX8ZH2BrMzAT1`G1lQ&!*D59xR>{2W88j zcX}W&iUAj{kca{D1;Qi`un!oD4BFE`v3}_)irw)~fju8H^>Hxc^8&(^b{A3%bjg+F*kC9U>dHPoCtMilfWPZwZ>AzT?}NFW<_h(%GsgAjsn oMG8Yy_?Uz#+%R7*J~SA_3f@&AgNQ*;a6twoCNn|_DMkPQJKh@+L;wH) diff --git a/icons/blue_app_komodo.gif b/icons/blue_app_komodo.gif deleted file mode 100644 index 57586bbf44cfcb268a37a473dcb508c467eabed2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 466 zcmV;@0WJPVNk%w1VKM+R0J8u9M00bcyu5v#ortBSV2FtG_V(uN?9|=eag~*rva;>) z@ZIF(xys7<`T76<|1e}^A^8LV00000EC2ui05SkF000F4u*pf=34*-MyZ3|;993yH z%K&_A%L2o4mdfDXcsD4sbga4H4L~{tgh*V#bVxc~#fbv=ta1RniOtI03?_@N_#ta- z$JTFyihcqtVgy2bvBC@vhe2h`JhdU%ZmkZl_P zm5dB?4+w#b1#Dvig9QPo4*&t5d7EvEc?mfQj+_L71wyitVx|g7Q`I9OcqD(9>g$ zS*LB?1byq`Ob|44+8m-GHtiL%RvpS^L(?nIuOPvHIN5Tr(8V0f-77=R3*d+ I!4UueJLMnkaMm6T-LDmj8A6hL-5=NF|anChA7CL5ZVDwtd98JZcJSX$~R7#SE^ z=o?t*8yf2xnpv3`SQ!~9K!Fm_wxX0Ys~{IQs9ivwtx`rwNr9EVetCJhUb(Seeo?x< zp{1pzzJZaxk&!M?g>G?WUP)qwZeFo6%mkOz;^d;tf|AVqJOz-6iAnjTCALaHmqNUd zTL3pUuUHT49lhlIT>Xl~0)0b01CW(sS9KFoU6f0*pM@LszXA>h!6GuZsS4&G{M+-+|Cl@12R|_K} zH$#|Sm;B_?+|;}hnBEkGUQ?WUK?x$a0BEyIYEfocYKmJ?ey#%8<5rni+~Q>BXl!Bb z=7!TesNNJTZUO7HFfhQWS0CsYeNglwMK??cn1(=1c;W?e;K@HV518hQfQg&&|G&R~ ze*gOUo>*T>t-)5G1()y3J#(ZSx%*2db( z(!$)#)Wq1x&_G{LS4Ue*Q$t-%RYh4zQ9)i#Rz_M%QbJrzR76-vP=KG0mxr5+lY^a& zm4%s!k%2++Ckq1z=zs`NDZ{|>f5S=3x!KASCeQny@I!=M$)JlhAcxzcxuGN}w_4?( z$$?uz>lqhrFp$Xen3%ZHf<BIo#IV*ydrdYm!`|VcvDI)<*wF z0vqmDOi*0-fsu{1vPqtsC6F(>xvS8zv8%aNtgOqushW$IV`_z)%j`Th9%jz@$pwsD zOq{M2+)Rv>IV_rDD_1Y|kJ^SD+>AdwFUOACt_F?dKh~u`&MV5>QFuXj?Y%=`5K$9haO{*uwVgOjPEd ze@1&E(}tUqeUeV;ib+fmI{9Rl;@rDTEUVj}T;XO-n5B`R&@3}^u{#gPf~kF(9CdsQ zEh&q+yI4y-Y|{1wr)gWo37yq6J?X`*%fKG6uV&g--RtvAf=vpJnH`+W%^(s{8ywWJ zJg@G)oW!w)RNEdV9^MQ~rkD-Ky}5R5bf3hCJ-mgw62_ipEu`AhXS_-D{Bz< zxsnH5+6zP%I`N!gWY!e7QaK<~a^OjDyOM~~(Kh8t95Zbcf&y+Os~COk7I9$N%+<(R ix0OZ4Pr+kx_mO~B2KHBqfoB<6SPTx7*}E_>SOWmSoQ?zl diff --git a/icons/blue_app_litecoin.gif b/icons/blue_app_litecoin.gif deleted file mode 100644 index 62441b87131be98f0b42ec73c9ab9a88a010d8f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 373 zcmV-*0gC=dNk%w1VKM+R0J8u9&CSjB_V)bz{MOdi?d|R2;^Nxc+Vu4F^78V~(9rPk z@aN~}-{0T)`T76<|IEzHEC2ui05SkF000F4u*peVAjOOXp8p^SB!f{9L8Y$NGK6p} zd&82l>XOWS?Bqd|E>ZWu6=cl-%T0#$N1aTBY_ zX70NS4$Re;I~k)NXZl_mdjf=LUK?Wx4vP)~9czzW1&j^~W0745lnj7Jij--cGn0&# zqCT38oTogWj3@#ItRVn3l#~Ut9tH;jx3{^v3cr*Xn5VHBxq&=L|qapDJXO9ex7hB4z2i)u*I1_6^ZEQ_tlZ1w z^Ki1>s?qEE`T76<|3I14A^8LV00000EC2ui05SkF000F4u*pdqU}e3{yZ1}M099!= z!Ek(R%N|2;mZ@vsT|7&Gf&VuH=|lh;Zv+$I$aD=S0bg_4F~}x^mO-HC7K{r*m#}IL zpsho|!Dbh6g*F@UZC$f0g`3O9yAo^x0t^Ta2vQ$s4P_n&eH?lY2`*NKWq=NK9|smK z3v5+|Q7w@gkPZS)3@wXcnE^!WTrw*>T z4x=2*t1hlB43D>K2xS0llN^{!RL|oZke2I7u1*KdkG}P6W4*9;|uz=muqrfDWZO z80gZ&fMB;i{;SCWVlg=id0ynmhQUOhkX-Mfgvh$`HIJ)#JKd$JUdL!BlM>Y>kXL^uI&ML`_!rFb?}y< zT|O4~LVQG)LqY&nYTKB*(N2y-4_6xKCKm|-gU)8wOnY7&3U;1VqVoW6;|Yb|R diff --git a/icons/blue_app_peercoin.gif b/icons/blue_app_peercoin.gif deleted file mode 100644 index 337538f9a4d00b5739c8e7a813f4f6179d28cc82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 436 zcmV;l0ZaZzNk%w1VKM+R0J8u9==18U-L>)e^Gms5me!($(3Eq?gu>{_W5IUV@7z4I zR=wlI%j?nk`T76<|245sEC2ui05SkF000F4u*pdqSj3>Ap8p`I42VH2K&7sY5FlYJ z&mIy8>>3Po?|XwlZUTV)jy*(*mEa+tvq547a6+%4!IEOcdOwIt;7k4pB?4>NJHR!@ z>+-o9_l5!W^(9}%@W~lS0SN~I8ER`9NCys$jsO7$aT|+{mW==e9bX)kmzM$sUzS> zuaUMR(|(L=#}HFQ8Y7@6$frtDLvu)JNL(2(@KXnc2`w diff --git a/icons/blue_app_pivx.gif b/icons/blue_app_pivx.gif deleted file mode 100644 index 3f3a94bb22a3cc9136a64e626c3fdd65ba4568d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 395 zcmV;60d)RHNk%w1VKM+R0J8u9^z-!S=j(B2gRrW(Sxjx5m8fW4drUrJjDwoh)7pP^ zkHfyoq@Az%`T76<|3)}nEC2ui05SkF000F4u*peVSVb9fp8p_t5Qb7LL8Yz@FbH8R z&z>*<>^cy1?|XznZW4g~jy*w&mEa+tGeTk&a6+#k!jfXddOw27;7k4pB>-#LOTab8 z>+-o9_l5)Y^#x1l`}-YV7+4DqhKGg$0|rP#bw*h6PU? zp&tki0G2+irvVNMryv3hwzsyVAceZK4+WEl03idEzBL2M%E=7G4!y@mu(Hud0*0>D zG6t}4+EE1n4hh-50tx8pu!ak2)v3Yb)ZZSd2@3cM0_EDNp7cHZ0SwqF6h9vV>x}S{ zFb)ZZ1?!Z6_%DtLig`|W8R3o$ih(^qQqTbjMuInzX3%sT*k-~>l4mB21Q@156_Q$3 pG+{Y~MG<;RhL~JgCx}oAE@qao;pV7K3>r)w8ByZI78Vfz06XHZr9A)u diff --git a/icons/blue_app_qtum.gif b/icons/blue_app_qtum.gif deleted file mode 100644 index 4c0194c377b31d9b99b157bc0c26ec6365216fca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 590 zcmV-U0hz+~>V(7NU$Wdsr`I~5)bjcKz2EVc&FHV# z?Q^@|%jWd@`T76<|1Fx)A^8LV00000EC2ui05SkF000F4u*peV5R1IcyZ6K*1XXD^ zz)*Z_%N7H0mZ@vsT|7&Hf&VuH>7)P}Zwgc3$aD=S0AF+3F~}wZs+Kc=ZoiLf7Od?y zR%B|y(o8tsa5zGGyc`RGxc&{$95F@%2Mz}cgi>w?0B>VJ89xSw4h$=KMFejP1_*Bq zbT@vWiw+4Km<|hz2wZ~)p8(u54FeH6 zK(hfMf2QKXj- z&>6zFCF(^710W8PnE)a}0E2o>$pf-3K{97crqq*CB{?z$2BGbs3>D5Cf(L`y)X9fB z2ly@?aBPf$B#tcPwh*Lmo0L2hN0oXYaZZa6MhMV-);40CK8U@2;vnLPfpH*BdkB2@ z!-yse5(pQNa_8;eZg!~8qJCT<7Pyhe` diff --git a/icons/blue_app_ravencoin.gif b/icons/blue_app_ravencoin.gif deleted file mode 100644 index 3ff36c21246a6e25a5aa1e3d1aceba6a0bdb3631..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1618 zcmdVZi96E`0KoCz=Gu%mq((gAX^yv2t`6^8-fcOnH=%4LMQVgRLPh5`$J~v`5z-rZ znPXd{T-h9Jmu$2}CWhpwTr*efecwOh{XU<6;p^t%de|}04zL530YJW_D5J7_#4^`Q znXxI=mtu;2LUSEF<9|CtqBeEA1!Ueys}V_L9lU|ChvjF&@*F%9B8V05-VZvSA)OA% z@d6dBN>e#RBUW)wsHEipSQNMKd!8F9i#xEk{*xyfCYLmy4bMMzA>H?S{-S(kV{>zPW$oLneCpdmC4(Pu zvm~Rak?~eU$fhfm%IeqMv=*VqWwP+&n0#ra=1n)+FFmuksko|R=Eou_uc3oKNPgCm zSJpNpn_gXAJ?xX@axt^HQ(Rcl&VDaVd)g@I8;MG+JRO{ijVP>be7~evO~_?*3I^Z4 z>u>3jBt5BTcS~pImzp~z8AVN>$7b+Z^u#CiHGv|J^=-ZOr{Ygu$=-Jy zA48%X#iX2zES#90lSn7x(rSCeqch(Z4|*j!VN&{sCa&Yly|3lcTY4JX`xfO(!=qE9 zUuG~71&ype&U-0eG^9{0e;636WN`0i)}08-MxINx{gYT#&yx&}FE6iHxN!g1%vM!F z0Kf$H0{`~k697aBC?Uq~b6Wrq2y(&J24Gc?bapv8mokwAHIM;d#i5Pu)YmqS$#$og zaZl+YO6NGbE?`ZIAYKlK2j&ytHUcR(nx&?XB5Bkn<7I8wDerbHI~?CAz@~qLc+^ zXY8w;0*%q;TSJ0j47mCicU>cQ080zv1mfRuywrSgbhObrhNwl{#5+ZS+%f9f>e)(; z>In(K80*-Luv`t|LxN9ib7knH8KOEzhmvsPSpeuON*tg3 z*|FWt*v?qgW#mAVAh&F9A;L)Y(m>=n27WutBz9yj34Xr_g~-6+acp(;5!&&Xu=30N zy(h^)f}w{#n4RPt;SpqFZ|rU2XCkl>ClRS2AS3E6O+`=FX0&T3QF?W22;2q@&co^a z>avp}WibnlF6v;^J{8C`5p~FE6(iCJjb-#VdK&6i58OaO9to8zE{HrlF-;4PZVH5i zb(^Er;rWF2U1s6!9)?*_hQU=vch34+!?2MkFwCYG&?QV)h3$2_iMDVKs=lEL3ePFM zUM65er*;Mznt!F(kkBH5Pq5=(X?{e z*1yBKTW;pRe@Ry}U~qw_b-Vot65IgsKY)t-y1)3gimMh!0!6fVAHb;8B*aQ*#Cm|b fb*zm#*M6R!rm-u(^cZx<_{PEWsOLI5!0-P6a8)o7 diff --git a/icons/blue_app_resistance.gif b/icons/blue_app_resistance.gif deleted file mode 100644 index 6b9609878fc56dad9abfb1d16a82ad8ba94cbb65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1947 zcmc)J`9Ir-9|!P69SIRZb*Oeyv?{8YsFl{08d~Zaaa7$m(<+s?B9RHIjka5BI$uY9 z=V&L6c2w6!h3dj66*)-aC}}X_DB|co`Ti5%*W>xq`|*Cf-@m-y-?_Qid>d{FvIK3i zKtKXPtWel^)QRzE)Od_3fE{y+9b?9hJt6erFP0B6n*7)~nS0w>jla}Dqv=b9_$I>3#S<__Sd zUF6=l#7+0$rh9VJFLN`zxis3!pjAO^6*%o4KSIF3d&SX*-YI}v%go(HP_6w)Xug2cm7#}=y{{4 z8H-$KfP=Li2rOA|Jf#f1!xz)ZWq&^i@X0==h-NoMA2-GG zn_|({qIhcwu&}-Ik5sZOU0so`N~CLm)t&XVoejYH&gYHY&Ck1ATf5s^d)wQ4Qh;=C z2e1R!-`(Bc1MKbpFJFMjuJHd9@H8wmsIsBZtnHAa! zjRu*@I%E$6g6xC95It9_5P>|eA%)b?s_*EX&$NTxt*z=UIfR3hx6a@B`dr2njE-CD ztgA`J`ucWTVX>ONcBI_O`{+AA8=udx8tDE;30`TRW&HtqfqC@w`6vyToJNgrp;xUF znbO0od~BJAh=6!EjyFToMEw?!h2A6indb7$&x!EEd6W>?vHGW1o?FXr(6;IpCSUue zt(@FCFr-SS91%OXdtID<3%%*EZi!H?>c5JM;}3MU#dP6mQen+nQ<+h{Z&PULS*ZH+ zK$>UZ7W!R@n!b~WKUi^wqUl0)T{mGAJJ{FN>2m0g5x>q4*IsO{og=9j^!%pCagI`| z>hZa^pA`3)$+3zTjW%8WIytD-&oe|%(l~P&j?6Vb!)U=U9!0Rs58Sd~9E=m@E5e;i z(e;^Oj6|O$^#V9fq(7#iLWw9vztWTI(~YS@PE!mjt6j8iV@WVwV?*Q^yn1_u>~}%i z8*IXIjVv`e@Q@$}HIhFWMK$Ok(6##TsM`lrB6a7nC_ZrAR}k5IGRI_IP$U5iF^wO1HJxgBf3gjzx7 z#p+4z`Ix4#b4{pcs)X)*WIs0Yo!li?G6`x(4K{1{DtdvEce8p=Ff!471J?X(UGU45 zITzbxV>QEk2F$oWV$jrdfbeURg6&Sjo38W2QJQ)K;kVEgPZCgJ9Yikm)d##@nWplk zh(XJuFo(s+!p0{ECakN!hjfG<;c?26E?kOCoI@qQB}?i5fh0pBRgK|{iW6!9f{)~@ zsMC|zN1@v)Md%^ZRgjLSjrRqugs-L!d0JL7&Dr;)G%$)K^!afg1Unc;2g~cPyy^8` z5|TY}hU3o^>ac6j*E^@K5p`Z-)0jrTB-OYbe-u{ZqH^CQ-8t^e>;vC=7fe+#`mreu z)8Y|Fa6NsP6>4jsVO7@R6ri9^@xvTccQWd<8v$#0NoW|wc~NH3hbt+R z`#_iF)Hk&lN<{rB;2euR4 zrtXsNL!cINwH*U_*4H)uMl0Dq6$x?g>`$y07CLMp)iT&bt$KQ&^^5n)!CP`i{}L&o b?7+q042l|l7~$1$3nkfcJPJl2K(_w^EKs0n diff --git a/icons/blue_app_stealth.gif b/icons/blue_app_stealth.gif deleted file mode 100644 index 30e1733e3c8724d1b540b3753f7401f509abbb5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 498 zcmVIcZY|E%F4=1OG_0M75n@9o12?4F)`ZO z+ODpyU|?YR`T76<{{R30EC2ui05SkF000F4u*peVSfV8Jy8qx~B!#d9RjM`sl7w&! zCkU{r11ImiINTG(t4G`=6gPsd$b=aPD#fx%{TPsyVRh?CR0iCz=O+P7#Z`l?fk2}X z679B75PJjSfx`g~U$_YbdwT?OO&D7O2Mz&yjRyjWbxnbL0|x*A2YL>LR2oeJgfx75 zE`kn`OdCa&sSgR525JW{qMe2^XEL{*4-2mkq6;0as%{+$4sFGZItGne2o4I!9t@ox zz{kQ4#2tbR)*i}r35+4p4+YfY*V(}0AlSs=?jC}o)iBDU1os};0dOEM1h#>b06tKL zM@FN43Kybt*e;?#f-w#{NO&(_#Ss0cvH`^QFP=ef5A5A52W#R7b?hKoBdIM|hhg|I zj#I|0Wq@buI!u%4rq_^dH&Mbu#cju~7{*}9qGfATkrAOrOⅇ>MD*zTwThv$!e1l zi54|t2607& olF1#O+z>MP2oMQ5A{t=)nS~2?G!B=ha3KRLCL>Cm_#6QMJK|l<`Tzg` diff --git a/icons/blue_app_stratis.gif b/icons/blue_app_stratis.gif deleted file mode 100644 index 3121749c6c1873fb059f9db3c6385f8d1260d615..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 456 zcmV;(0XP0fNk%w1VKM+R0J8u9akSs__xT}>&D-nti^AmT^Z7uV(+h>mv)1fbsM(*( z=g8vntJCcH`T76<{{Vr>EC2ui05SkF000F4u*peVK_nS*p8p_t2u4C6MWwDypcr8+ z&z_+KtQrsk?f)JD0henGV8Eo$Fvu->%IHk6SPh`kY)H_g1d!VB$3T=2#OM!U62PXz z0;1ymR!G3~u)&glU;1enX#xxb03Bi(Vgd>djt&KfVH#ROkCzSu30fOc2Sb>lno=A} z2LJ`3s*VeIK8Qc3sjIXO2(D-gwY!d+bd0>KqkzD{j*+l{4+03h$jTn4PzKGaJBR?j zd8iK8HM*AyPzeL9xMAGKk`D>G;@_98eV>=lAO_%$!^*|_zSNiYDMQpRQ$9$N4kUX6 z?Aw~{QR5mFtjcJa>17~u(&I+%|r z{vc6_fUu8BN-S#h$X*r`g9@z+a{^iz6i&6IkQr6Ro(6NOCb84PjaC_PCYke%`+veatgIg|p zP)3Pjmb#<)`T76<{{UVnEC2ui05SkF000F4u*pfA38Sb(p8p_797-_+My0L|z$9TT z&tAd+?8+Q;?|TPEZi0aQj=cmTC*UEUvx8uTa6+%4!?I$;dOwK@<4gVsB>-#Ld%!iu z>+-o9_l6Di^(9}%@W~l}F$4$$9W)w(Aq)-<3OyT&9}10dG#ru-1Og5Shcusx1C0xr zM+c1orbnCxYO68@jRk@W0-=`x4yu0(l}7;%X}yi4KC%u2e{Bv12+gk|1`YzE1_}zg z)iaEal84C3F}}&L58b6A&z|Ol&>-E9<`0zAlfUyG;hLQ6U${tuIY= zs|<-R_1=*w0ch456McAQKyl?-c{wB=PbYd4L3tusb?s1;Q%Pd|E>VWu2 z(=oILFa@!bcmM(A<)#eg=Gh7A0peb|#PjsK&SU`y`unsO{E_?iIokFBk}MCj1`>>6 z3Kca6))qpE^rD%>8QEM!8*|MHv`Y?VdUY8=CK<&sB*^@_M5crqTBE#}P!oU^nGWaKft(LM~-*Uaf;wH!5MECBG=m>oZ=#nAddoxw+!Si zN8U2zehV1~vM|WKMnK7fG6F^GQL-6jUbmt=9Odz-NPs3Dl|P|sH>!R{wE*?|p-YAC zFq*S*ITLM%(RK`1g)kh2K?0)~9a414a9xh;3UsN^U4-s3m^Cn0!&(hX6Z%?UGr(rV zU>63vG1P^jUX0wqhz+9ycw)zsdwBK`FGex(6qC;|ISz*dFDLMN5^r9@`5&B9a5~|7 z1J_%)r{Q+Pcb|ezLeWx*9$4?8fnV3nEJ3of{2#qU_2%6SV_DqB?UKi-AG*e!ntqhGUz5-S98>S;S|E z+ny2rxL&xIw$MHPlnLwSwLH5UqeDUlZ{+-rL{^ z7BM0#>>OL%?T1pMI*1)&NTdzQzWJTMNO4QaV??OLVzx@Hq;ZN@FMG#Phwod@Ez!hj K7pU_I+4KqKJQYX) diff --git a/icons/blue_app_xsn.gif b/icons/blue_app_xsn.gif deleted file mode 100644 index 68e9e43a6f81b43d8e87435b4318da7993625b7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1984 zcmZ?wbhEHbG-5Df_}<0<1dNP~OiWD7%*-q-EUc`oY;0`o?ChMJoLpR7JUl%7{QQD~ zfgwtm8XB6Knp#>~IyyRfdV2c$`i6#vMn*=)#>S?mre{6YxeBfbLPyMJ9qB<`STYpT)1e_qQ#3BFIlo=>C&ak zmMvSpeEEtMD^{&qwQk+IZQHi(*s){h&YineQ(-XU?2IfBxdd zi`TAQyK&>jty{Nl-@bk4&YgSr?mc?+=<(ynPo6w^`t<3G7cXAEeEI6tt9S3-efaR< z^XJcBzkdDx{ris}KYsrF`S0Jq|NsAkVr3N2B?J_IvViT;0g<3Q!NBp4ftORp<3fOf ziFeh84F?n$8`=ew?R*X#VCt6hzQCe&V&h^(r<4MT2_Bo4crsg@5cqUr;{-7-wd7M% zJRH3hr!oD!FyrLr=R9^guQOhFmZY^=$^OpKIA!vz&5o7(W`@_+CB3tmcZS^6nt0m5 zNqk2aYeC}Dg@(z;y96tg*WQq3d6eg|fMeNqOl}Z|`96XLN#&hiad70hy2!DB(Ox=pbCqL`8{P;Jg zgM*2GI>T-GX_Za?9yVysQ*1l2S*`pRSKWdw>Y7UD=W@PuO<_?Ce8YZ`qmp5hQ-h$W z0lT7yM@gex3(LU=*-bATn_QS8967|q?O2@TD|-Th7(#hI9ctw{GO?XQFm*#bL&%;$ zhX&>u6WuukXC7!5onR|+K*WvZ1&f@5O9_*Fi$KxQR0fsd6hl5^K#ci_rNVN?y~SR!_rC8tE-B3B%b=tKqw8$@QCa&nFk**Y$Tf%PFTXB`v3Op69m=X{`Z`$l>P5|!?i-J|^Uk}r zf!(i7WD{${OWzHwVK=0VPDm)7Z4HuWZn=HY(M#jVgw;l}0T*4pGFoyS7!?0=NB9OP zxFnV&0%;rjih{)C?9>v4q}24xJX@vryZ0+8WTx0Eg`4^s_!c;)W@LI)6{QAO`Gq7` zWhYyvDB0U_*;H6noE6C(w4OFcs~14|@hD&O3a#3bMNoIbY0?5q7r2NtnTO}oZkR|$1TY%ovhx-r6frn6P9xzyn zfc|Iv|L^ag-@ktT`2Owdm(QO*et7@x?VH!HUcPw#?CF!oj~+g_fA8*{+qZ7sxPI;G zmCKhdUO0d5?3vT2PM$b^?C6ohhYlXtzi;oJ-Me<~*uHJ+md%?sZdku=?V8oAR<2mS zZ0VB4ixw`JKX2}w*|TQOm_BXll*yAOPU!FJ?dk67>}YRmZE0?5Y^blRt*Nf6tSB!l zEh#Q4EXdEx&B@Nn%t%j5O-W8lOo)$*jfswmj0g`44G9hk4Dk2!_3`%d^l*1`b#Zob zbg;LxwXwFcv@ka_H8D0aG|<=6)zQ|{)KFJbRZ&(_RFIdGm64W`ln@sa6%iH^6yWFM U<>BVyEiA5rOf8}`T76<|1pouEC2ui05SkF000F4u*pfA7$u=_p8p_t1V~a0LZz+^p&(%_ z&mN)>?8*dm?|T78ZnA*=jy=R82jC%}vjAYVa6+%4z_Mb*dOwH?<4gVsB?N2P8^ARb z>$O7CjeEla`}$HoAP^m77-a(v4g+NwWd?=@Wg2Awh5%(7R|o@{jD`*X2A^iF#@Ip0Q2+!W8Su|%vi`j`TBYaugw_WQc?v&w?1G;Ns>N8*Y|XxR7B(zi%W=pfDN%06X8-wfq18 diff --git a/icons/blue_app_zclassic.gif b/icons/blue_app_zclassic.gif deleted file mode 100644 index 950aad7585ae290f2fe48dd00d12177fc789ef10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 509 zcmVA9x!*UZvtKIgEQ{Pptl-qzro zeecS;_v_~Q`T76<|Ic7CA^8LV00000EC2ui05SkF000F4u*peVB5J(NyZ3`aBvolP zi~xLW%K`#(mZ@vsT|7&Pf&VuH=|lh;Zv<1~$aD=S3}18FF~}wYs+J>wP63BSVLZl2 zf!D0ja9}vz@VH~4`E?sB-~l0bjNNhtc{TtRKmZAG3jt>vFo17rHWxntd~XMhECY}W zND4TXZwZ4q2XLM)88@PHnm7t@2QGCs1#bmZv2V3Zy9faT!o$SGuL5rYRFHkm4n0Y55MVoxEdapb_whl;h6XMn zAVafefmBU);q1^YTOWx{0P#!cQ_jwuZ=z^HwxHyXZn>_lq{Zsef`h7L(E^(C5-B6- z{;9%9=u$nb8#tjtvZRu~H;Xhqij%Je38x?S^!c+FuOkU{gS0712gn@;U&7QR!05=8 z27z0Oq@YwX4l5PfTApNr>}C&1PW1R(<;jT}q;>3oqN3%a)uJ)51QKGz>IeWk?yuvu From 5f1b709a72a159d09aa30133552a2b61fbbeed64 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 5 Apr 2023 16:46:08 +0200 Subject: [PATCH 09/85] workflows: update ci for stax --- .github/workflows/ci-workflow.yml | 45 +++++++++++++++++++---- .github/workflows/guidelines_enforcer.yml | 23 ++++++++++++ 2 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/guidelines_enforcer.yml diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index f8d7a9e2..6fd8555c 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -1,10 +1,30 @@ name: CI -on: [push, pull_request] +on: + workflow_dispatch: + push: + branches: + - master + pull_request: + branches: + - master + jobs: job_build: name: Compilation + strategy: + matrix: + include: + - model: nanos + SDK: "$NANOS_SDK" + - model: nanox + SDK: "$NANOX_SDK" + - model: nanosp + SDK: "$NANOSP_SDK" + - model: stax + SDK: "$STAX_SDK" + runs-on: ubuntu-latest container: @@ -16,24 +36,32 @@ jobs: - name: Build run: | - make && mv bin/ bitcoin-bin/ + make BOLOS_SDK=${{ matrix.SDK }} && mv bin/ bitcoin-bin/ make clean - make COIN=bitcoin_testnet_legacy && mv bin/ bitcoin-testnet-bin/ + make COIN=bitcoin_testnet_legacy BOLOS_SDK=${{ matrix.SDK }} && mv bin/ bitcoin-testnet-bin/ - name: Upload Bitcoin app binary uses: actions/upload-artifact@v2 with: - name: bitcoin-app + name: bitcoin-app-${{ matrix.model }} path: bitcoin-bin - name: Upload Bitcoin Testnet app binary uses: actions/upload-artifact@v2 with: - name: bitcoin-testnet-app + name: bitcoin-testnet-app-${{ matrix.model }} path: bitcoin-testnet-bin job_test: name: Tests + strategy: + matrix: + include: + - model: nanos + - model: nanox + - model: nanosp + - model: stax + needs: job_build runs-on: ubuntu-latest @@ -55,15 +83,16 @@ jobs: - name: Download Bitcoin app binary uses: actions/download-artifact@v2 with: - name: bitcoin-app + name: bitcoin-app-${{matrix.model}} path: tests/bitcoin-bin - name: Download Bitcoin Testnet app binary uses: actions/download-artifact@v2 with: - name: bitcoin-testnet-app + name: bitcoin-testnet-app-${{ matrix.model }} path: tests/bitcoin-testnet-bin - name: Run tests run: | - cd tests && pip install -r requirements.txt && SPECULOS=/speculos/speculos.py pytest + cd tests && pip install -r requirements.txt && SPECULOS=/speculos/speculos.py pytest --model=${{ matrix.model }} + diff --git a/.github/workflows/guidelines_enforcer.yml b/.github/workflows/guidelines_enforcer.yml new file mode 100644 index 00000000..fdaf9f27 --- /dev/null +++ b/.github/workflows/guidelines_enforcer.yml @@ -0,0 +1,23 @@ +name: Ensure compliance with Ledger guidelines + +# This workflow is mandatory in all applications +# It calls a reusable workflow guidelines_enforcer developed by Ledger's internal developer team. +# The successful completion of the reusable workflow is a mandatory step for an app to be available on the Ledger +# application store. +# +# More information on the guidelines can be found in the repository: +# LedgerHQ/ledger-app-workflows/ + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + guidelines_enforcer: + name: Call Ledger guidelines_enforcer + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_guidelines_enforcer.yml@v1 From ed5aa70dce4ee6f1da81c980a0b66eef32ee541a Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 5 Apr 2023 17:10:19 +0200 Subject: [PATCH 10/85] [clean] Follow Ledger guidelines --- Makefile | 2 +- src/main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 45ec381b..31acb8b2 100644 --- a/Makefile +++ b/Makefile @@ -259,7 +259,7 @@ DEFINES += HAVE_WALLET_ID_SDK endif # Enabling debug PRINTF -DEBUG:=0 +DEBUG ?= 0 ifneq ($(DEBUG),0) ifeq ($(TARGET_NAME),TARGET_NANOS) DEFINES += HAVE_PRINTF PRINTF=screen_printf diff --git a/src/main.c b/src/main.c index 60d4a2a3..483a52f3 100644 --- a/src/main.c +++ b/src/main.c @@ -94,7 +94,7 @@ unsigned char io_event(unsigned char channel) { SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { THROW(EXCEPTION_IO_RESET); } - // no break is intentional + __attribute__((fallthrough)); default: UX_DEFAULT_EVENT(); break; From ac4949bab3f8d8bea7df0550004eb3f7ad1bc527 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 12 Apr 2023 14:37:44 +0200 Subject: [PATCH 11/85] gitignore: remove glyphs --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 2d733b59..02bb6dc8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,6 @@ bin debug dep obj -src/glyphs.c -src/glyphs.h *.pyc .idea .vscode From 8f886a4f5df75467bc0e6aaae3853b1e5650940c Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 12 Apr 2023 14:38:14 +0200 Subject: [PATCH 12/85] Makefile: bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 31acb8b2..2450e9bf 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS) APPVERSION_M=2 APPVERSION_N=1 -APPVERSION_P=0 +APPVERSION_P=1 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APP_LOAD_FLAGS=--appFlags 0xa50 From 98be477cab4bc9a97fae3cf32eedd1be7376fab8 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 13 Apr 2023 15:10:52 +0200 Subject: [PATCH 13/85] clang: add fallthrough attributes --- src/btchip_apdu_get_wallet_public_key.c | 1 + src/btchip_transaction.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/btchip_apdu_get_wallet_public_key.c b/src/btchip_apdu_get_wallet_public_key.c index 6ad50418..87073d2e 100644 --- a/src/btchip_apdu_get_wallet_public_key.c +++ b/src/btchip_apdu_get_wallet_public_key.c @@ -73,6 +73,7 @@ unsigned short btchip_apdu_get_wallet_public_key() { if (!(G_coin_config->native_segwit_prefix)) { return BTCHIP_SW_INCORRECT_P1_P2; } + __attribute__((fallthrough)); case P2_LEGACY: case P2_SEGWIT: break; diff --git a/src/btchip_transaction.c b/src/btchip_transaction.c index 63ffc070..da2545b7 100644 --- a/src/btchip_transaction.c +++ b/src/btchip_transaction.c @@ -300,7 +300,7 @@ void transaction_parse(unsigned char parseMode) { btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; - // no break is intentional + __attribute__((fallthrough)); } case BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT: { @@ -565,7 +565,7 @@ void transaction_parse(unsigned char parseMode) { btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; - // no break is intentional + __attribute__((fallthrough)); } case BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { unsigned char dataAvailable; @@ -753,7 +753,7 @@ void transaction_parse(unsigned char parseMode) { btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; - // no break is intentional + __attribute__((fallthrough)); } case BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT: { if (btchip_context_D.transactionContext @@ -790,7 +790,7 @@ void transaction_parse(unsigned char parseMode) { btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; - // no break is intentional + __attribute__((fallthrough)); } case BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { unsigned char dataAvailable; From 4d195ca3ed03ac90b27ed4de8c8180f8d45b2ac2 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 21 Apr 2023 14:33:24 +0200 Subject: [PATCH 14/85] ui_nbgl: pubkey flow uses useCase --- src/ui_nbgl.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 31d80e0f..77a0a154 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -231,18 +231,15 @@ static void ui_message_start(void) { // Other callbacks static void display_pubkey_callback(void) { - uiContext.tagValueList.pairs = uiContext.tagValues; - uiContext.tagValueList.nbPairs = uiContext.nbPairs; - - uiContext.infoLongPress.icon = &G_coin_config->img_nbgl; - uiContext.infoLongPress.longPressText = "Approve"; - uiContext.infoLongPress.longPressToken = 1; - uiContext.infoLongPress.tuneId = TUNE_TAP_CASUAL; - uiContext.infoLongPress.text = "Confirm\npublic key"; + if (uiContext.nbPairs == 1) { + nbgl_useCaseAddressConfirmation(uiContext.tagValues[0].value, status_callback); + } + else { + uiContext.tagValueList.pairs = &uiContext.tagValues[1]; + uiContext.tagValueList.nbPairs = 1; - nbgl_useCaseStaticReviewLight(&uiContext.tagValueList, - &uiContext.infoLongPress, "Cancel", - status_callback); + nbgl_useCaseAddressConfirmationExt(uiContext.tagValues[0].value, status_callback, &uiContext.tagValueList.pairs); + } } // Flow entry point From 8c1b3163e485171cc82840de6fd989c77e07c71b Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 21 Apr 2023 14:35:01 +0200 Subject: [PATCH 15/85] Makefile: bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2450e9bf..23448c04 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS) APPVERSION_M=2 APPVERSION_N=1 -APPVERSION_P=1 +APPVERSION_P=2 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APP_LOAD_FLAGS=--appFlags 0xa50 From 98f31b1836ef8dcdc469d2c01985a6e2fd61487c Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 26 May 2023 20:19:47 +0200 Subject: [PATCH 16/85] ui_nbgl: change some wordings --- src/ui_nbgl.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 77a0a154..f9e85197 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -43,6 +43,7 @@ typedef struct { uint8_t nbPairs; } UiContext_t; +static char text[40]; static nbgl_page_t *pageContext; static UiContext_t uiContext = {.transaction_prompt_done = 0}; @@ -207,7 +208,8 @@ static void ui_start(void (*cb)(void), flow_type_t type) { break; case TRANSACTION_TYPE: - nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, "Review\ntransaction", "", + snprintf(text, sizeof(text), "Review transaction\nto send %s", G_coin_config->name); + nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, text, "", "Cancel", cb, prompt_cancel_transaction); break; } @@ -400,20 +402,22 @@ static void warn_unusual_derivation_path(void) { } static void prompt_public_key(bool warning) { + snprintf(text, sizeof(text), "Verify %s\naddress", G_coin_config->name); + if (warning) { - nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, "Confirm\npublic key", "", + nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, text, "", "Cancel", warn_unusual_derivation_path, abandon_status); } else { - nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, "Confirm\npublic key", "", + nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, text, "", "Cancel", display_pubkey_callback, abandon_status); } } static void display_public_key(bool warning) { - uiContext.abandon_status = "Public key\nrejected"; - uiContext.approved_status = "PUBLIC KEY\nCONFIRMED"; - uiContext.prompt_cancel_message = "Reject\nPublic key?"; + uiContext.abandon_status = "Address verification\ncancelled"; + uiContext.approved_status = "ADDRESS\nVERIFIED"; + uiContext.prompt_cancel_message = "Reject\nAddress?"; uiContext.tagValues[0].item = "Address"; uiContext.tagValues[0].value = (char *)G_io_apdu_buffer + 200; From 96fe2efadcd370e9566f8e01aa4c6ddbc336147c Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 26 May 2023 12:55:58 +0200 Subject: [PATCH 17/85] Clang: fix warnings --- Makefile | 6 +++- include/btchip.h | 1 + src/btchip.c | 6 ++-- src/btchip_apdu_get_coin_version.c | 4 +-- src/btchip_apdu_get_trusted_input.c | 2 +- src/btchip_apdu_get_wallet_public_key.c | 12 +++---- src/btchip_apdu_hash_input_finalize_full.c | 25 +++++++------- src/btchip_apdu_hash_input_start.c | 2 +- src/btchip_apdu_hash_sign.c | 3 +- src/btchip_apdu_setup.c | 2 +- src/btchip_apdu_sign_message.c | 8 ++--- src/btchip_base58.c | 8 ++--- src/btchip_bcd.c | 1 - src/btchip_context.c | 4 +-- src/btchip_helpers.c | 38 +++++++++++----------- src/btchip_transaction.c | 20 ++++++------ src/cashaddr.c | 2 +- src/handle_check_address.c | 3 +- src/handle_get_printable_amount.c | 6 ++-- src/main.c | 30 +++++++++-------- src/ui.h | 2 +- src/ui_bagl.c | 8 +++++ src/ui_nbgl.c | 10 +++--- 23 files changed, 110 insertions(+), 93 deletions(-) diff --git a/Makefile b/Makefile index 23448c04..3d6dcf13 100644 --- a/Makefile +++ b/Makefile @@ -302,7 +302,11 @@ LDLIBS += -lm -lgcc -lc include $(BOLOS_SDK)/Makefile.glyphs ### variables processed by the common makefile.rules of the SDK to grab source files and include dirs -APP_SOURCE_PATH += src +APP_SOURCE_PATH += src + +APP_SOURCE_PATH += ${BOLOS_SDK}/lib_standard_app/format.h +APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/format.c + SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f ifneq ($(TARGET_NAME),TARGET_STAX) SDK_SOURCE_PATH += lib_ux diff --git a/include/btchip.h b/include/btchip.h index d303a17a..03d108dc 100644 --- a/include/btchip.h +++ b/include/btchip.h @@ -25,6 +25,7 @@ #include "stdlib.h" #include "stdbool.h" +#include "string.h" #define L_DEBUG_NOPREFIX(x) diff --git a/src/btchip.c b/src/btchip.c index 9b40a012..23236a84 100644 --- a/src/btchip.c +++ b/src/btchip.c @@ -48,7 +48,7 @@ void handleGetWalletId(volatile unsigned short *tx) { // pubkey -> sha512 cx_hash_sha512(pub.W, sizeof(pub.W), t, sizeof(t)); // ! cookie ! - os_memmove(G_io_apdu_buffer, t, 64); + memmove(G_io_apdu_buffer, t, 64); btchip_context_D.sw = 0x9000; *tx = 64; } @@ -145,7 +145,7 @@ void app_dispatch(void) { } void app_main(void) { - os_memset(G_io_apdu_buffer, 0, 255); // paranoia + memset(G_io_apdu_buffer, 0, 255); // paranoia // Process the incoming APDUs @@ -154,7 +154,7 @@ void app_main(void) { btchip_context_D.io_flags = 0; for (;;) { - // os_memset(G_io_apdu_buffer, 0, 255); // paranoia + // memset(G_io_apdu_buffer, 0, 255); // paranoia if (btchip_context_D.called_from_swap && vars.swap_data.should_exit) { btchip_context_D.io_flags |= IO_RETURN_AFTER_TX; diff --git a/src/btchip_apdu_get_coin_version.c b/src/btchip_apdu_get_coin_version.c index 4da85742..7da3b8ab 100644 --- a/src/btchip_apdu_get_coin_version.c +++ b/src/btchip_apdu_get_coin_version.c @@ -37,11 +37,11 @@ unsigned short btchip_apdu_get_coin_version() { G_io_apdu_buffer[offset++] = G_coin_config->p2sh_version; G_io_apdu_buffer[offset++] = G_coin_config->family; G_io_apdu_buffer[offset++] = strlen(G_coin_config->coinid); - os_memmove(G_io_apdu_buffer + offset, G_coin_config->coinid, + memmove(G_io_apdu_buffer + offset, G_coin_config->coinid, strlen(G_coin_config->coinid)); offset += strlen(G_coin_config->coinid); G_io_apdu_buffer[offset++] = strlen(G_coin_config->name_short); - os_memmove(G_io_apdu_buffer + offset, G_coin_config->name_short, + memmove(G_io_apdu_buffer + offset, G_coin_config->name_short, strlen(G_coin_config->name_short)); offset += strlen(G_coin_config->name_short); btchip_context_D.outLength = offset; diff --git a/src/btchip_apdu_get_trusted_input.c b/src/btchip_apdu_get_trusted_input.c index cc46f4be..a5b3d6d9 100644 --- a/src/btchip_apdu_get_trusted_input.c +++ b/src/btchip_apdu_get_trusted_input.c @@ -84,7 +84,7 @@ unsigned short btchip_apdu_get_trusted_input() { btchip_write_u32_le(G_io_apdu_buffer + 4 + 32, btchip_context_D.transactionTargetInput); - os_memmove(G_io_apdu_buffer + 4 + 32 + 4, + memmove(G_io_apdu_buffer + 4 + 32 + 4, btchip_context_D.transactionContext.transactionAmount, 8); cx_hmac_sha256((uint8_t *)N_btchip.bkp.trustedinput_key, diff --git a/src/btchip_apdu_get_wallet_public_key.c b/src/btchip_apdu_get_wallet_public_key.c index 87073d2e..8055eb09 100644 --- a/src/btchip_apdu_get_wallet_public_key.c +++ b/src/btchip_apdu_get_wallet_public_key.c @@ -37,7 +37,7 @@ int get_public_key_chain_code(unsigned char* keyPath, bool uncompressedPublicKey keyLength = 33; } - os_memmove(publicKey, public_key.W, + memmove(publicKey, public_key.W, sizeof(public_key.W)); return keyLength; } @@ -48,7 +48,7 @@ unsigned short btchip_apdu_get_wallet_public_key() { ((N_btchip.bkp.config.options & BTCHIP_OPTION_UNCOMPRESSED_KEYS) != 0); uint32_t request_token; unsigned char chainCode[32]; - uint8_t is_derivation_path_unusual; + uint8_t is_derivation_path_unusual = 0; bool display = (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_DISPLAY); bool display_request_token = N_btchip.pubKeyRequestRestriction && (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_REQUEST_TOKEN) && G_io_apdu_media == IO_APDU_MEDIA_U2F; @@ -167,7 +167,7 @@ unsigned short btchip_apdu_get_wallet_public_key() { } // output chain code - os_memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, + memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, sizeof(chainCode)); btchip_context_D.outLength = 1 + 65 + 1 + keyLength + sizeof(chainCode); @@ -182,18 +182,18 @@ unsigned short btchip_apdu_get_wallet_public_key() { return BTCHIP_SW_INCORRECT_DATA; } // Hax, avoid wasting space - os_memmove(G_io_apdu_buffer + 200, G_io_apdu_buffer + 67, keyLength); + memmove(G_io_apdu_buffer + 200, G_io_apdu_buffer + 67, keyLength); G_io_apdu_buffer[200 + keyLength] = '\0'; btchip_context_D.io_flags |= IO_ASYNCH_REPLY; btchip_bagl_display_public_key(is_derivation_path_unusual); } // If the token requested has already been approved in a previous call, the source is trusted so don't ask for approval again else if(display_request_token && - (!btchip_context_D.has_valid_token || os_memcmp(&request_token, btchip_context_D.last_token, 4))) + (!btchip_context_D.has_valid_token || memcmp(&request_token, btchip_context_D.last_token, 4))) { // disable the has_valid_token flag and store the new token btchip_context_D.has_valid_token = false; - os_memcpy(btchip_context_D.last_token, &request_token, 4); + memcpy(btchip_context_D.last_token, &request_token, 4); // Hax, avoid wasting space snprintf((char *)G_io_apdu_buffer + 200, 9, "%08X", request_token); G_io_apdu_buffer[200 + 8] = '\0'; diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index 6954ce33..cb17e49d 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -21,6 +21,7 @@ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #include "btchip_bagl_extensions.h" +#include "ui.h" #define FINALIZE_P1_MORE 0x00 #define FINALIZE_P1_LAST 0x80 @@ -34,7 +35,7 @@ void btchip_apdu_hash_input_finalize_full_reset(void) { btchip_context_D.currentOutputOffset = 0; btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; - os_memset(btchip_context_D.totalOutputAmount, 0, + memset(btchip_context_D.totalOutputAmount, 0, sizeof(btchip_context_D.totalOutputAmount)); btchip_context_D.changeOutputFound = 0; btchip_set_check_internal_structure_integrity(1); @@ -84,7 +85,7 @@ static bool check_output_displayable() { : isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); if (!isP2sh && - os_memcmp(btchip_context_D.currentOutput + 8 + addressOffset, + memcmp(btchip_context_D.currentOutput + 8 + addressOffset, btchip_context_D.tmpCtx.output.changeAddress, 20) == 0) { changeFound = true; @@ -92,10 +93,10 @@ static bool check_output_displayable() { unsigned char changeSegwit[22]; changeSegwit[0] = 0x00; changeSegwit[1] = 0x14; - os_memmove(changeSegwit + 2, + memmove(changeSegwit + 2, btchip_context_D.tmpCtx.output.changeAddress, 20); btchip_public_key_hash160(changeSegwit, 22, changeSegwit); - if (os_memcmp(btchip_context_D.currentOutput + 8 + addressOffset, + if (memcmp(btchip_context_D.currentOutput + 8 + addressOffset, changeSegwit, 20) == 0) { if (G_coin_config->flags & FLAG_SEGWIT_CHANGE_SUPPORT) { changeFound = true; @@ -209,7 +210,7 @@ bool handle_output_state() { } if (discardSize != 0) { - os_memmove(btchip_context_D.currentOutput, + memmove(btchip_context_D.currentOutput, btchip_context_D.currentOutput + discardSize, btchip_context_D.currentOutputOffset - discardSize); btchip_context_D.currentOutputOffset -= discardSize; @@ -292,14 +293,14 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; } - os_memset(transactionSummary, 0, + memset(transactionSummary, 0, sizeof(btchip_transaction_summary_t)); if (G_io_apdu_buffer[ISO_OFFSET_CDATA] == 0x00) { // Called with no change path, abort, should be prevented on // the client side goto return_OK; } - os_memmove(transactionSummary->keyPath, + memmove(transactionSummary->keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); @@ -350,7 +351,7 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( sw = BTCHIP_SW_INCORRECT_DATA; goto discardTransaction; } - os_memmove(btchip_context_D.currentOutput + + memmove(btchip_context_D.currentOutput + btchip_context_D.currentOutputOffset, G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength); btchip_context_D.currentOutputOffset += apduLength; @@ -425,7 +426,7 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( if (btchip_context_D.transactionContext.firstSigned) { if (!btchip_context_D.tmpCtx.output.changeInitialized) { - os_memset(transactionSummary, 0, + memset(transactionSummary, 0, sizeof(btchip_transaction_summary_t)); } @@ -452,7 +453,7 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( // (this is done to keep the transaction counter limit per session // synchronized) if (btchip_context_D.transactionContext.firstSigned) { - os_memmove(transactionSummary->authorizationHash, + memmove(transactionSummary->authorizationHash, authorizationHash, sizeof(transactionSummary->authorizationHash)); goto return_OK; @@ -490,7 +491,7 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( BTCHIP_TRANSACTION_NONE; btchip_context_D.outLength = 0; - os_memmove(G_io_apdu_buffer, btchip_context_D.currentOutput, + memmove(G_io_apdu_buffer, btchip_context_D.currentOutput, btchip_context_D.currentOutputOffset); btchip_context_D.outLength = btchip_context_D.currentOutputOffset; } @@ -546,7 +547,7 @@ unsigned char btchip_bagl_user_action(unsigned char confirming) { } while (btchip_context_D.remainingOutputs != 0) { - os_memmove(btchip_context_D.currentOutput, + memmove(btchip_context_D.currentOutput, btchip_context_D.currentOutput + btchip_context_D.discardSize, btchip_context_D.currentOutputOffset - diff --git a/src/btchip_apdu_hash_input_start.c b/src/btchip_apdu_hash_input_start.c index a2e7bfb9..d7119c55 100644 --- a/src/btchip_apdu_hash_input_start.c +++ b/src/btchip_apdu_hash_input_start.c @@ -110,7 +110,7 @@ unsigned short btchip_apdu_hash_input_start() { btchip_context_D.segwitParsedOnce = 0; btchip_set_check_internal_structure_integrity(1); // Initialize for screen pairing - os_memset(&btchip_context_D.tmpCtx.output, 0, + memset(&btchip_context_D.tmpCtx.output, 0, sizeof(btchip_context_D.tmpCtx.output)); btchip_context_D.tmpCtx.output.changeAccepted = 1; // Reset segwitWarningSeen flag to prevent displaying the warning for each diff --git a/src/btchip_apdu_hash_sign.c b/src/btchip_apdu_hash_sign.c index 9f5905d8..cf8cf440 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/btchip_apdu_hash_sign.c @@ -19,6 +19,7 @@ #include "btchip_apdu_constants.h" #include "btchip_bagl_extensions.h" #include "btchip_display_variables.h" +#include "ui.h" #define SIGHASH_ALL 0x01 @@ -96,7 +97,7 @@ unsigned short btchip_apdu_hash_sign() { CLOSE_TRY; goto catch_discardTransaction; } - os_memmove(btchip_context_D.transactionSummary.keyPath, + memmove(btchip_context_D.transactionSummary.keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; diff --git a/src/btchip_apdu_setup.c b/src/btchip_apdu_setup.c index 8d51e933..f7d8db87 100644 --- a/src/btchip_apdu_setup.c +++ b/src/btchip_apdu_setup.c @@ -27,7 +27,7 @@ void btchip_autosetup() { btchip_config_t config; unsigned char i; unsigned char tmp[32]; - os_memset(&config, 0, sizeof(btchip_config_t)); + memset(&config, 0, sizeof(btchip_config_t)); config.options |= BTCHIP_OPTION_DETERMINISTIC_SIGNATURE; config.options |= BTCHIP_OPTION_SKIP_2FA_P2SH; // TODO : remove when // supporting multi output diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index 2c28376a..9d1ad3e5 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -86,7 +86,7 @@ unsigned short btchip_apdu_sign_message_internal() { unsigned char chunkLength; unsigned char messageLength[3]; unsigned char messageLengthSize; - os_memset(&btchip_context_D.transactionSummary, 0, + memset(&btchip_context_D.transactionSummary, 0, sizeof(btchip_transaction_summary_t)); if (G_io_apdu_buffer[offset] > MAX_BIP32_PATH) { PRINTF("Invalid path\n"); @@ -98,7 +98,7 @@ unsigned short btchip_apdu_sign_message_internal() { G_coin_config->p2pkh_version; btchip_context_D.transactionSummary.payToScriptHashVersion = G_coin_config->p2sh_version; - os_memmove( + memmove( btchip_context_D.transactionSummary.keyPath, G_io_apdu_buffer + offset, MAX_BIP32_PATH_LENGTH); offset += (4 * G_io_apdu_buffer[offset]) + 1; @@ -217,7 +217,7 @@ unsigned short btchip_apdu_sign_message_internal() { sw = SW_TECHNICAL_DETAILS(0x0F); } discard : { - os_memset(&btchip_context_D.transactionSummary, 0, + memset(&btchip_context_D.transactionSummary, 0, sizeof(btchip_transaction_summary_t)); } FINALLY { @@ -265,7 +265,7 @@ unsigned short btchip_compute_hash() { sw = SW_TECHNICAL_DETAILS(0x0F); } FINALLY { - os_memset(&btchip_context_D.transactionSummary, 0, + memset(&btchip_context_D.transactionSummary, 0, sizeof(btchip_transaction_summary_t)); } } diff --git a/src/btchip_base58.c b/src/btchip_base58.c index 8f89417f..2f19b0f6 100644 --- a/src/btchip_base58.c +++ b/src/btchip_base58.c @@ -31,7 +31,7 @@ int btchip_decode_base58(const char *in, size_t length, if ((length > MAX_DEC_INPUT_SIZE) || (length < 2)) { return -1; } - os_memmove(tmp, in, length); + memmove(tmp, in, length); PRINTF("To decode\n%.*H\n",length,tmp); for (i = 0; i < length; i++) { if (in[i] >= sizeof(BASE58TABLE)) { @@ -70,7 +70,7 @@ int btchip_decode_base58(const char *in, size_t length, return -1; } - os_memmove(out, buffer + j - zeroCount, length); + memmove(out, buffer + j - zeroCount, length); PRINTF("Decoded\n%.*H\n",length,out); *outlen = length; return 0; @@ -99,7 +99,7 @@ int btchip_encode_base58(const unsigned char *in, size_t length, *outlen = outputSize; return -1; } - os_memset(out, 0, outputSize); + memset(out, 0, outputSize); stopAt = outputSize - 1; for (startAt = zeroCount; startAt < length; startAt++) { int carry = in[startAt]; @@ -134,7 +134,7 @@ int btchip_encode_base58(const unsigned char *in, size_t length, for (i = *outlen - 1; (int)i >= 0; --i) out[i] = BASE58ALPHABET[out[i - distance]]; } - os_memset(out, BASE58ALPHABET[0], zeroCount); + memset(out, BASE58ALPHABET[0], zeroCount); // PRINTF("Length encoded %d\n", i); // PRINTF("Encoded\n%.*H\n",i,out); return 0; diff --git a/src/btchip_bcd.c b/src/btchip_bcd.c index bbb4ff2e..df35eefb 100644 --- a/src/btchip_bcd.c +++ b/src/btchip_bcd.c @@ -79,7 +79,6 @@ btchip_convert_hex_amount_to_displayable_no_globals(unsigned char *amount, unsig workOffset = offset; for (i = 0; i < LOOP2; i++) { unsigned char allZero = 1; - unsigned char j; for (j = i; j < LOOP2; j++) { if (scratch[workOffset + j] != 0) { allZero = 0; diff --git a/src/btchip_context.c b/src/btchip_context.c index fc782dfa..0aeec435 100644 --- a/src/btchip_context.c +++ b/src/btchip_context.c @@ -25,12 +25,12 @@ void btchip_autosetup(void); void btchip_context_init() { PRINTF("Context init\n"); PRINTF("Backup size %d\n", sizeof(N_btchip.bkp)); - os_memset(&btchip_context_D, 0, sizeof(btchip_context_D)); + memset(&btchip_context_D, 0, sizeof(btchip_context_D)); SB_SET(btchip_context_D.halted, 0); btchip_context_D.called_from_swap = 0; btchip_context_D.currentOutputOffset = 0; btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; - os_memset(btchip_context_D.totalOutputAmount, 0, + memset(btchip_context_D.totalOutputAmount, 0, sizeof(btchip_context_D.totalOutputAmount)); btchip_context_D.changeOutputFound = 0; btchip_context_D.segwitWarningSeen = 0; diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index a7131b0c..25dd03f0 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -60,25 +60,25 @@ const unsigned char ZEN_OUTPUT_SCRIPT_POST[] = { unsigned char btchip_output_script_is_regular(unsigned char *buffer) { if (G_coin_config->native_segwit_prefix) { - if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || - (os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, + (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { return 1; } } if (G_coin_config->kind == COIN_KIND_HORIZEN) { - if ((os_memcmp(buffer, ZEN_OUTPUT_SCRIPT_PRE, + if ((memcmp(buffer, ZEN_OUTPUT_SCRIPT_PRE, sizeof(ZEN_OUTPUT_SCRIPT_PRE)) == 0) && - (os_memcmp(buffer + sizeof(ZEN_OUTPUT_SCRIPT_PRE) + 20, + (memcmp(buffer + sizeof(ZEN_OUTPUT_SCRIPT_PRE) + 20, ZEN_OUTPUT_SCRIPT_POST, sizeof(ZEN_OUTPUT_SCRIPT_POST)) == 0)) { return 1; } } else { - if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) && - (os_memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, + (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, TRANSACTION_OUTPUT_SCRIPT_POST, sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { return 1; @@ -89,17 +89,17 @@ unsigned char btchip_output_script_is_regular(unsigned char *buffer) { unsigned char btchip_output_script_is_p2sh(unsigned char *buffer) { if (G_coin_config->kind == COIN_KIND_HORIZEN) { - if ((os_memcmp(buffer, ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, + if ((memcmp(buffer, ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && - (os_memcmp(buffer + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, + (memcmp(buffer + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { return 1; } } else { - if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && - (os_memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, + (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { return 1; @@ -110,9 +110,9 @@ unsigned char btchip_output_script_is_p2sh(unsigned char *buffer) { unsigned char btchip_output_script_is_native_witness(unsigned char *buffer) { if (G_coin_config->native_segwit_prefix) { - if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || - (os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, + (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { return 1; } @@ -222,7 +222,7 @@ void btchip_compute_checksum(unsigned char* in, unsigned short inlen, unsigned c cx_hash_sha256(checksumBuffer, 32, checksumBuffer, 32); PRINTF("Checksum\n%.*H\n",4,checksumBuffer); - os_memmove(output, checksumBuffer, 4); + memmove(output, checksumBuffer, 4); } unsigned short btchip_public_key_to_encoded_base58( @@ -245,7 +245,7 @@ unsigned short btchip_public_key_to_encoded_base58( tmpBuffer[0] = version; } } else { - os_memmove(tmpBuffer, in, 20 + versionSize); + memmove(tmpBuffer, in, 20 + versionSize); } btchip_compute_checksum(tmpBuffer, 20 + versionSize, tmpBuffer + 20 + versionSize); @@ -283,7 +283,7 @@ unsigned short btchip_decode_base58_address(unsigned char *in, cx_sha256_init(&hash); cx_hash(&hash.header, CX_LAST, hashBuffer, 32, hashBuffer, 32); - if (os_memcmp(out + outlen - 4, hashBuffer, 4)) { + if (memcmp(out + outlen - 4, hashBuffer, 4)) { PRINTF("Hash checksum mismatch\n%.*H\n",sizeof(hashBuffer),hashBuffer); THROW(INVALID_CHECKSUM); } @@ -328,7 +328,7 @@ void btchip_private_derive_keypair(unsigned char *bip32Path, io_seproxyhal_io_heartbeat(); - os_memset(u.privateComponent, 0, sizeof(u.privateComponent)); + memset(u.privateComponent, 0, sizeof(u.privateComponent)); } /* @@ -471,11 +471,11 @@ void btchip_transaction_add_output(unsigned char *hash160Address, btchip_swap_bytes(btchip_context_D.tmp, amount, 8); btchip_context_D.tmp += 8; } - os_memmove(btchip_context_D.tmp, (void *)pre, sizePre); + memmove(btchip_context_D.tmp, (void *)pre, sizePre); btchip_context_D.tmp += sizePre; - os_memmove(btchip_context_D.tmp, hash160Address, 20); + memmove(btchip_context_D.tmp, hash160Address, 20); btchip_context_D.tmp += 20; - os_memmove(btchip_context_D.tmp, (void *)post, sizePost); + memmove(btchip_context_D.tmp, (void *)post, sizePost); btchip_context_D.tmp += sizePost; } diff --git a/src/btchip_transaction.c b/src/btchip_transaction.c index da2545b7..63c4ecd9 100644 --- a/src/btchip_transaction.c +++ b/src/btchip_transaction.c @@ -157,7 +157,7 @@ void transaction_parse(unsigned char parseMode) { btchip_context_D.transactionContext .transactionCurrentInputOutput = 0; btchip_context_D.transactionContext.scriptRemaining = 0; - os_memset( + memset( btchip_context_D.transactionContext.transactionAmount, 0, sizeof(btchip_context_D.transactionContext .transactionAmount)); @@ -166,7 +166,7 @@ void transaction_parse(unsigned char parseMode) { if (btchip_context_D.usingOverwinter) { if (btchip_context_D.segwitParsedOnce) { uint8_t parameters[16]; - os_memmove(parameters, OVERWINTER_PARAM_SIGHASH, 16); + memmove(parameters, OVERWINTER_PARAM_SIGHASH, 16); if (G_coin_config->kind == COIN_KIND_ZCLASSIC) { btchip_write_u32_le(parameters + 12, CONSENSUS_BRANCH_ID_ZCLASSIC); } @@ -214,7 +214,7 @@ void transaction_parse(unsigned char parseMode) { cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.nExpiryHeight, sizeof(btchip_context_D.nExpiryHeight), NULL, 0); if (btchip_context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { unsigned char valueBalance[8]; - os_memset(valueBalance, 0, sizeof(valueBalance)); + memset(valueBalance, 0, sizeof(valueBalance)); cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, valueBalance, sizeof(valueBalance), NULL, 0); // sapling valueBalance } cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.sigHashType, sizeof(btchip_context_D.sigHashType), NULL, 0); @@ -254,7 +254,7 @@ void transaction_parse(unsigned char parseMode) { // Parse the beginning of the transaction // Version check_transaction_available(4); - os_memmove(btchip_context_D.transactionVersion, + memmove(btchip_context_D.transactionVersion, btchip_context_D.transactionBufferPointer, 4); transaction_offset_increase(4); @@ -262,7 +262,7 @@ void transaction_parse(unsigned char parseMode) { TRUSTED_INPUT_OVERWINTER) { // nVersionGroupId check_transaction_available(4); - os_memmove(btchip_context_D.nVersionGroupId, + memmove(btchip_context_D.nVersionGroupId, btchip_context_D.transactionBufferPointer, 4); transaction_offset_increase(4); } @@ -448,7 +448,7 @@ void transaction_parse(unsigned char parseMode) { transaction_offset_increase(36); btchip_context_D.transactionHashOption = 0; check_transaction_available(8); // save amount - os_memmove( + memmove( btchip_context_D.inputValue, btchip_context_D.transactionBufferPointer, 8); @@ -490,7 +490,7 @@ void transaction_parse(unsigned char parseMode) { } // Handle non-segwit TrustedInput (i.e. InputHashStart 1st APDU's P2==00 & data[0]==0x01) else if (trustedInputFlag && !btchip_context_D.usingSegwit) { - os_memmove( + memmove( trustedInput, btchip_context_D.transactionBufferPointer + 2, trustedInputLength - 8); @@ -700,10 +700,10 @@ void transaction_parse(unsigned char parseMode) { sizeof(hashedSequence), hashedSequence, 32); } - os_memmove( + memmove( btchip_context_D.segwit.cache.hashedPrevouts, hashedPrevouts, sizeof(hashedPrevouts)); - os_memmove( + memmove( btchip_context_D.segwit.cache.hashedSequence, hashedSequence, sizeof(hashedSequence)); PRINTF("hashPrevout\n%.*H\n",32,btchip_context_D.segwit.cache.hashedPrevouts); @@ -774,7 +774,7 @@ void transaction_parse(unsigned char parseMode) { .transactionCurrentInputOutput == btchip_context_D.transactionTargetInput)) { // Save the amount - os_memmove(btchip_context_D.transactionContext + memmove(btchip_context_D.transactionContext .transactionAmount, btchip_context_D.transactionBufferPointer, 8); diff --git a/src/cashaddr.c b/src/cashaddr.c index 45a95706..fb14ad30 100644 --- a/src/cashaddr.c +++ b/src/cashaddr.c @@ -117,7 +117,7 @@ int cashaddr_encode(uint8_t *hash, const size_t hash_length, uint8_t *addr, } tmp[0] = version_byte; - os_memmove(tmp + 1, hash, hash_length); + memmove(tmp + 1, hash, hash_length); convert_bits(payload, &payload_length, 5, tmp, hash_length + 1, 8, 1); create_checksum(payload, payload_length, diff --git a/src/handle_check_address.c b/src/handle_check_address.c index df4f2e59..23f25530 100644 --- a/src/handle_check_address.c +++ b/src/handle_check_address.c @@ -25,6 +25,7 @@ bool derive_private_key(unsigned char* serialized_path, unsigned char serialized bool derive_compressed_public_key( unsigned char* serialized_path, unsigned char serialized_path_length, unsigned char* public_key, unsigned char public_key_length) { + UNUSED(public_key_length); cx_ecfp_private_key_t privKey; if (!derive_private_key(serialized_path, serialized_path_length, &privKey)) return false; @@ -32,7 +33,7 @@ bool derive_compressed_public_key( cx_ecfp_generate_pair(BTCHIP_CURVE, &pubKey, &privKey, 1); btchip_compress_public_key_value(pubKey.W); - os_memcpy(public_key, pubKey.W, 33); + memcpy(public_key, pubKey.W, 33); return true; } diff --git a/src/handle_get_printable_amount.c b/src/handle_get_printable_amount.c index 2bc5a807..79bfc885 100644 --- a/src/handle_get_printable_amount.c +++ b/src/handle_get_printable_amount.c @@ -9,10 +9,10 @@ int handle_get_printable_amount( get_printable_amount_parameters_t* params, btch return 0; } unsigned char amount[8]; - os_memset(amount, 0, 8); - os_memcpy(amount + (8 - params->amount_length), params->amount, params->amount_length); + memset(amount, 0, 8); + memcpy(amount + (8 - params->amount_length), params->amount, params->amount_length); unsigned char coin_name_length = strlen(config->name_short); - os_memmove(params->printable_amount, config->name_short, coin_name_length); + memmove(params->printable_amount, config->name_short, coin_name_length); params->printable_amount[coin_name_length] = ' '; int res_length = btchip_convert_hex_amount_to_displayable_no_globals(amount, config->flags, (uint8_t *)params->printable_amount + coin_name_length + 1); params->printable_amount[res_length + coin_name_length + 1] = '\0'; diff --git a/src/main.c b/src/main.c index 483a52f3..b6ec3069 100644 --- a/src/main.c +++ b/src/main.c @@ -36,6 +36,7 @@ #include "handle_get_printable_amount.h" #include "handle_check_address.h" #include "ui.h" +#include "format.h" #define __NAME3(a, b, c) a##b##c #define NAME3(a, b, c) __NAME3(a, b, c) @@ -71,6 +72,7 @@ unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { } unsigned char io_event(unsigned char channel) { + UNUSED(channel); // nothing done with the event, throw an error on the transport layer if // needed @@ -157,7 +159,7 @@ uint8_t check_fee_swap() { uint8_t prepare_fees() { if (btchip_context_D.transactionContext.relaxed) { - os_memmove(vars.tmp.feesAmount, "UNKNOWN", 7); + memmove(vars.tmp.feesAmount, "UNKNOWN", 7); vars.tmp.feesAmount[7] = '\0'; } else { unsigned char fees[8]; @@ -168,7 +170,7 @@ uint8_t prepare_fees() { fees, btchip_context_D.transactionContext.transactionAmount, btchip_context_D.totalOutputAmount); if (borrow && G_coin_config->kind == COIN_KIND_KOMODO) { - os_memmove(vars.tmp.feesAmount, "REWARD", 6); + memmove(vars.tmp.feesAmount, "REWARD", 6); vars.tmp.feesAmount[6] = '\0'; } else { @@ -176,7 +178,7 @@ uint8_t prepare_fees() { PRINTF("Error : Fees not consistent"); goto error; } - os_memmove(vars.tmp.feesAmount, G_coin_config->name_short, + memmove(vars.tmp.feesAmount, G_coin_config->name_short, strlen(G_coin_config->name_short)); vars.tmp.feesAmount[strlen(G_coin_config->name_short)] = ' '; btchip_context_D.tmp = @@ -198,17 +200,17 @@ uint8_t prepare_fees() { void get_address_from_output_script(unsigned char* script, int script_size, char* out, int out_size) { if (btchip_output_script_is_op_return(script)) { - strcpy(out, "OP_RETURN"); + strncpy(out, "OP_RETURN", out_size); return; } if ((G_coin_config->kind == COIN_KIND_QTUM || G_coin_config->kind == COIN_KIND_HYDRA) && btchip_output_script_is_op_create(script, script_size)) { - strcpy(out, "OP_CREATE"); + strncpy(out, "OP_CREATE", out_size); return; } if ((G_coin_config->kind == COIN_KIND_QTUM || G_coin_config->kind == COIN_KIND_HYDRA) && btchip_output_script_is_op_call(script, script_size)) { - strcpy(out, "OP_CALL"); + strncpy(out, "OP_CALL", out_size); return; } if (btchip_output_script_is_native_witness(script)) { @@ -239,7 +241,7 @@ void get_address_from_output_script(unsigned char* script, int script_size, char versionSize = 1; address[0] = version; } - os_memmove(address + versionSize, script + addressOffset, 20); + memmove(address + versionSize, script + addressOffset, 20); // Prepare address if (btchip_context_D.usingCashAddr) { @@ -273,8 +275,8 @@ uint8_t prepare_single_output() { // Handle Omni simple send if ((btchip_context_D.currentOutput[offset + 2] == 0x14) && - (os_memcmp(btchip_context_D.currentOutput + offset + 3, "omni", 4) == 0) && - (os_memcmp(btchip_context_D.currentOutput + offset + 3 + 4, "\0\0\0\0", 4) == 0)) { + (memcmp(btchip_context_D.currentOutput + offset + 3, "omni", 4) == 0) && + (memcmp(btchip_context_D.currentOutput + offset + 3 + 4, "\0\0\0\0", 4) == 0)) { uint8_t headerLength; uint32_t omniAssetId = btchip_read_u32(btchip_context_D.currentOutput + offset + 3 + 4 + 4, 1, 0); switch(omniAssetId) { @@ -297,7 +299,7 @@ uint8_t prepare_single_output() { vars.tmp.fullAmount[textSize + headerLength] = '\0'; } else { - os_memmove(vars.tmp.fullAmount, G_coin_config->name_short, + memmove(vars.tmp.fullAmount, G_coin_config->name_short, strlen(G_coin_config->name_short)); vars.tmp.fullAmount[strlen(G_coin_config->name_short)] = ' '; btchip_context_D.tmp = @@ -317,7 +319,7 @@ uint8_t prepare_message_signature() { cx_hash(&btchip_context_D.transactionHashAuthorization.header, CX_LAST, (uint8_t*)vars.tmp.fullAmount, 0, buffer, 32); - snprintf(vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress), "%.*H", buffer); + format_hex((const uint8_t*) vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress), (char*) buffer, sizeof(buffer)); return 1; } @@ -358,7 +360,7 @@ unsigned int btchip_silent_confirm_single_output() { break; } - os_memmove(btchip_context_D.currentOutput, + memmove(btchip_context_D.currentOutput, btchip_context_D.currentOutput + btchip_context_D.discardSize, btchip_context_D.currentOutputOffset - @@ -452,7 +454,7 @@ uint8_t set_key_path_to_display(unsigned char* keyPath) { void btchip_bagl_display_public_key(uint8_t is_derivation_path_unusual) { // append a white space at the end of the address to avoid glitch on nano S - strcat((char *)G_io_apdu_buffer + 200, " "); + strlcat((char *)G_io_apdu_buffer + 200, " ", sizeof(G_io_apdu_buffer) - 200); if (is_derivation_path_unusual) { ui_display_public_with_warning_flow(); @@ -503,7 +505,7 @@ void app_exit(void) { } void init_coin_config(btchip_altcoin_config_t *coin_config) { - os_memset(coin_config, 0, sizeof(btchip_altcoin_config_t)); + memset(coin_config, 0, sizeof(btchip_altcoin_config_t)); coin_config->bip44_coin_type = BIP44_COIN_TYPE; coin_config->bip44_coin_type2 = BIP44_COIN_TYPE_2; coin_config->p2pkh_version = COIN_P2PKH_VERSION; diff --git a/src/ui.h b/src/ui.h index fbbf828f..ee63bab7 100644 --- a/src/ui.h +++ b/src/ui.h @@ -3,7 +3,7 @@ #include "ux.h" void ui_idle_flow(void); -void ui_sign_message_flowflow(void); +void ui_sign_message_flow(void); void ui_confirm_full_flow(void); void ui_confirm_single_flow(void); void ui_finalize_flow(void); diff --git a/src/ui_bagl.c b/src/ui_bagl.c index 8a448601..c5cf3fa4 100644 --- a/src/ui_bagl.c +++ b/src/ui_bagl.c @@ -31,6 +31,7 @@ void settings_pubkey_export_change(unsigned int enabled) { } static unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { + UNUSED(e); // user denied the transaction, tell the USB side if (!btchip_bagl_user_action(0)) { // redraw ui @@ -40,6 +41,7 @@ static unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { } static unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e) { + UNUSED(e); // user accepted the transaction, tell the USB side if (!btchip_bagl_user_action(1)) { // redraw ui @@ -50,6 +52,7 @@ static unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e) { static unsigned int io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e) { + UNUSED(e); // user denied the transaction, tell the USB side btchip_bagl_user_action_message_signing(0); // redraw ui @@ -59,6 +62,7 @@ io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e) { static unsigned int io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { + UNUSED(e); // user accepted the transaction, tell the USB side btchip_bagl_user_action_message_signing(1); // redraw ui @@ -68,6 +72,7 @@ io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { static unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { + UNUSED(e); // user denied the transaction, tell the USB side btchip_bagl_user_action_display(0); // redraw ui @@ -76,6 +81,7 @@ io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { } static unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { + UNUSED(e); // user accepted the transaction, tell the USB side btchip_bagl_user_action_display(1); // redraw ui @@ -84,6 +90,7 @@ static unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { } static unsigned int io_seproxyhal_touch_sign_cancel(const bagl_element_t *e) { + UNUSED(e); // user denied the transaction, tell the USB side btchip_bagl_user_action_signtx(0, 0); // redraw ui @@ -92,6 +99,7 @@ static unsigned int io_seproxyhal_touch_sign_cancel(const bagl_element_t *e) { } static unsigned int io_seproxyhal_touch_sign_ok(const bagl_element_t *e) { + UNUSED(e); // user accepted the transaction, tell the USB side btchip_bagl_user_action_signtx(1, 0); // redraw ui diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index f9e85197..d4eb3aff 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -31,10 +31,10 @@ typedef enum { typedef struct { bool transaction_prompt_done; - char *prompt_cancel_message; - char *prompt; // text displayed in last transaction page - char *approved_status; // text displayed in confirmation page (after long press) - char *abandon_status; // text displayed in rejection page (after reject confirmed) + const char *prompt_cancel_message; + const char *prompt; // text displayed in last transaction page + const char *approved_status; // text displayed in confirmation page (after long press) + const char *abandon_status; // text displayed in rejection page (after reject confirmed) void (*approved_cb)(void); void (*abandon_cb)(void); nbgl_layoutTagValueList_t tagValueList; @@ -240,7 +240,7 @@ static void display_pubkey_callback(void) { uiContext.tagValueList.pairs = &uiContext.tagValues[1]; uiContext.tagValueList.nbPairs = 1; - nbgl_useCaseAddressConfirmationExt(uiContext.tagValues[0].value, status_callback, &uiContext.tagValueList.pairs); + nbgl_useCaseAddressConfirmationExt(uiContext.tagValues[0].value, status_callback, &uiContext.tagValueList); } } From 47f31e94394846be5abf637334a6aecc791140a8 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 26 May 2023 20:20:07 +0200 Subject: [PATCH 18/85] ui_nbgl: unify transaction flow --- src/ui_nbgl.c | 84 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 10 deletions(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index d4eb3aff..76d7e5e2 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -28,6 +28,12 @@ typedef enum { TRANSACTION_TYPE } flow_type_t; +enum { + CANCEL_TOKEN, + CONFIRM_TOKEN, + BACK_TOKEN, +}; + typedef struct { bool transaction_prompt_done; @@ -111,11 +117,13 @@ static void releaseContext(void) { // Status static void abandon_status(void) { nbgl_useCaseStatus(uiContext.abandon_status, false, uiContext.abandon_cb); + releaseContext(); uiContext.transaction_prompt_done = false; } static void approved_status(void) { nbgl_useCaseStatus(uiContext.approved_status, true, uiContext.approved_cb); + releaseContext(); uiContext.transaction_prompt_done = false; } @@ -152,12 +160,57 @@ static void prompt_cancel_transaction(void) { static void transaction_review_callback(bool token) { if (token) { + releaseContext(); uiContext.approved_cb(); } else { prompt_cancel_transaction(); } } +static void transaction_finish_callback(int token, uint8_t index) { + (void) index; + switch (token) { + case CANCEL_TOKEN: + prompt_cancel_transaction(); + break; + case CONFIRM_TOKEN: + releaseContext(); + uiContext.approved_cb(); + break; + case BACK_TOKEN: + ui_finalize_flow(); + break; + } +} + +static void transaction_fee_callback(int token, uint8_t index) { + (void) index; + if (token) { + releaseContext(); + nbgl_pageNavigationInfo_t info = {.activePage = 0, + .nbPages = 0, + .navType = NAV_WITH_TAP, + .progressIndicator = true, + .navWithTap.backButton = true, + .navWithTap.backToken = BACK_TOKEN, + .navWithTap.nextPageText = NULL, + .navWithTap.quitText = "Reject transaction", + .quitToken = CANCEL_TOKEN, + .tuneId = TUNE_TAP_CASUAL}; + + nbgl_pageContent_t content = {.type = INFO_LONG_PRESS, + .infoLongPress.icon = &G_coin_config->img_nbgl, + .infoLongPress.text = "Sign transaction\nto send Bitcoin?", + .infoLongPress.longPressText = "Hold to sign", + .infoLongPress.longPressToken = CONFIRM_TOKEN, + .infoLongPress.tuneId = TUNE_TAP_NEXT}; + + pageContext = nbgl_pageDrawGenericContent(&transaction_finish_callback, &info, &content); + } else { + prompt_cancel_transaction(); + } +} + static void message_review_callback(bool token) { if (token) { approved_status(); @@ -194,10 +247,6 @@ static void continue_message_review(void) { continue_review(MESSAGE_TYPE); } -static void continue_transaction_review(void) { - continue_review(TRANSACTION_TYPE); -} - // UI Start static void ui_start(void (*cb)(void), flow_type_t type) { switch (type) { @@ -275,9 +324,8 @@ void ui_confirm_single_flow(void) { uiContext.nbPairs = 3; nbgl_pageNavigationInfo_t info = { - .activePage = - btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs, - .nbPages = btchip_context_D.totalOutputs - 1, + .activePage = 0, + .nbPages = 0, .navType = NAV_WITH_TAP, .progressIndicator = true, .navWithTap.backButton = false, @@ -307,9 +355,25 @@ void ui_finalize_flow(void) { uiContext.nbPairs = 1; - nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, "Review fees", "", "Cancel", - continue_transaction_review, - prompt_cancel_transaction); + nbgl_pageNavigationInfo_t info = {.activePage = 0, + .nbPages = 0, + .navType = NAV_WITH_TAP, + .progressIndicator = true, + .navWithTap.backButton = false, + .navWithTap.nextPageText = "Tap to continue", + .navWithTap.nextPageToken = 1, + .navWithTap.quitText = "Reject transaction", + .quitToken = 0, + .tuneId = TUNE_TAP_CASUAL}; + + nbgl_pageContent_t content = { + .type = TAG_VALUE_LIST, + .tagValueList.nbPairs = uiContext.nbPairs, + .tagValueList.pairs = (nbgl_layoutTagValue_t *)uiContext.tagValues + }; + + pageContext = nbgl_pageDrawGenericContent(&transaction_fee_callback, &info, &content); + nbgl_refresh(); } void ui_request_change_path_approval_flow(void) { From 0ca5e104646cc95755ddb4da70bf289a0103afd2 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 30 May 2023 11:41:50 +0200 Subject: [PATCH 19/85] Makefile: improve file inclusion from SDK --- Makefile | 2 +- src/main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3d6dcf13..c7b414ab 100644 --- a/Makefile +++ b/Makefile @@ -304,8 +304,8 @@ include $(BOLOS_SDK)/Makefile.glyphs ### variables processed by the common makefile.rules of the SDK to grab source files and include dirs APP_SOURCE_PATH += src -APP_SOURCE_PATH += ${BOLOS_SDK}/lib_standard_app/format.h APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/format.c +INCLUDES_PATH += ${BOLOS_SDK} SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f ifneq ($(TARGET_NAME),TARGET_STAX) diff --git a/src/main.c b/src/main.c index b6ec3069..607a68a9 100644 --- a/src/main.c +++ b/src/main.c @@ -36,7 +36,7 @@ #include "handle_get_printable_amount.h" #include "handle_check_address.h" #include "ui.h" -#include "format.h" +#include "lib_standard_app/format.h" #define __NAME3(a, b, c) a##b##c #define NAME3(a, b, c) __NAME3(a, b, c) From baf09dffeef465cb7a643a2c831e18a546e11fde Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 30 May 2023 11:43:06 +0200 Subject: [PATCH 20/85] ui_nbgl: replace empty strings by NULL --- src/ui_nbgl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 76d7e5e2..a62660cb 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -139,12 +139,12 @@ static void status_callback(bool confirm) { static void prompt_cancel(flow_type_t type) { switch (type) { case MESSAGE_TYPE: - nbgl_useCaseConfirm("Reject message", "", "Yes, Reject", + nbgl_useCaseConfirm("Reject message", NULL, "Yes, Reject", "Go back to message", abandon_status); break; case TRANSACTION_TYPE: - nbgl_useCaseConfirm("Reject transaction", "", "Yes, Reject", + nbgl_useCaseConfirm("Reject transaction", NULL, "Yes, Reject", "Go back to transaction", abandon_status); break; } @@ -251,14 +251,14 @@ static void continue_message_review(void) { static void ui_start(void (*cb)(void), flow_type_t type) { switch (type) { case MESSAGE_TYPE: - nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, "Review\nmessage", "", + nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, "Review\nmessage", NULL, "Cancel", continue_message_review, prompt_cancel_message); break; case TRANSACTION_TYPE: snprintf(text, sizeof(text), "Review transaction\nto send %s", G_coin_config->name); - nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, text, "", + nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, text, NULL, "Cancel", cb, prompt_cancel_transaction); break; } @@ -416,7 +416,7 @@ void ui_request_pubkey_approval_flow(void) { ui_transaction_start(ui_request_pubkey_approval_flow); } else { - nbgl_useCaseChoice(&G_coin_config->img_nbgl, "Export public key", "", + nbgl_useCaseChoice(&G_coin_config->img_nbgl, "Export public key", NULL, "Approve", "Reject", transaction_review_callback); } } @@ -461,7 +461,7 @@ static void unusual_derivation_cb(bool status) { } } static void warn_unusual_derivation_path(void) { - nbgl_useCaseChoice(&C_round_warning_64px, "Unusual\nderivation path", "", + nbgl_useCaseChoice(&C_round_warning_64px, "Unusual\nderivation path", NULL, "Continue", "Reject if not sure", unusual_derivation_cb); } @@ -469,11 +469,11 @@ static void prompt_public_key(bool warning) { snprintf(text, sizeof(text), "Verify %s\naddress", G_coin_config->name); if (warning) { - nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, text, "", + nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, text, NULL, "Cancel", warn_unusual_derivation_path, abandon_status); } else { - nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, text, "", + nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, text, NULL, "Cancel", display_pubkey_callback, abandon_status); } } From 270052fe434e5b4fd4b3f92c6a104770d097f067 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 30 May 2023 15:45:44 +0200 Subject: [PATCH 21/85] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c7b414ab..090450f5 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS) APPVERSION_M=2 APPVERSION_N=1 -APPVERSION_P=2 +APPVERSION_P=3 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APP_LOAD_FLAGS=--appFlags 0xa50 From 9fc54a640695625e0d67c975ad072cdea14227ea Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 31 May 2023 13:47:55 +0200 Subject: [PATCH 22/85] ui_nbgl: Use coin name instead of hardcoded string --- src/ui_nbgl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index a62660cb..8e5589ae 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -187,6 +187,7 @@ static void transaction_fee_callback(int token, uint8_t index) { (void) index; if (token) { releaseContext(); + snprintf(text, sizeof(text), "Sign transaction\nto send %s", G_coin_config->name); nbgl_pageNavigationInfo_t info = {.activePage = 0, .nbPages = 0, .navType = NAV_WITH_TAP, @@ -200,7 +201,7 @@ static void transaction_fee_callback(int token, uint8_t index) { nbgl_pageContent_t content = {.type = INFO_LONG_PRESS, .infoLongPress.icon = &G_coin_config->img_nbgl, - .infoLongPress.text = "Sign transaction\nto send Bitcoin?", + .infoLongPress.text = text, .infoLongPress.longPressText = "Hold to sign", .infoLongPress.longPressToken = CONFIRM_TOKEN, .infoLongPress.tuneId = TUNE_TAP_NEXT}; From 30e227d2e555823cae760b274bf4993078327b3e Mon Sep 17 00:00:00 2001 From: Francois Beutin Date: Wed, 21 Jun 2023 14:28:24 +0200 Subject: [PATCH 23/85] Erase BSS when started in SWAP mode --- src/handle_swap_sign_transaction.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/handle_swap_sign_transaction.c b/src/handle_swap_sign_transaction.c index 40479c4f..a332f8ae 100644 --- a/src/handle_swap_sign_transaction.c +++ b/src/handle_swap_sign_transaction.c @@ -22,6 +22,11 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti // input {0xEE, 0x00, 0xFF} should be stored like {0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x00, 0xFF} memcpy(stack_data.amount + 8 - sign_transaction_params->amount_length, sign_transaction_params->amount, sign_transaction_params->amount_length); memcpy(stack_data.fees + 8 - sign_transaction_params->fee_amount_length, sign_transaction_params->fee_amount, sign_transaction_params->fee_amount_length); + + // Erase values inherited from Exchange app + os_explicit_zero_BSS_segment(); + + // Copy from stack back to global data segment memcpy(&vars.swap_data, &stack_data, sizeof(stack_data)); return true; } @@ -45,4 +50,4 @@ void handle_swap_sign_transaction(btchip_altcoin_config_t *config) { BLE_power(1, "Nano X"); #endif // HAVE_BLE app_main(); -} \ No newline at end of file +} From cbaed7c817dd04502d84156b972ea762862b459f Mon Sep 17 00:00:00 2001 From: Francois Beutin Date: Thu, 22 Jun 2023 09:33:30 +0200 Subject: [PATCH 24/85] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 090450f5..3e962c01 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS) APPVERSION_M=2 APPVERSION_N=1 -APPVERSION_P=3 +APPVERSION_P=4 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APP_LOAD_FLAGS=--appFlags 0xa50 From 12d0723b634a737d3778bfd544d90678b38bfabc Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 4 Jul 2023 18:10:57 +0200 Subject: [PATCH 25/85] Makefile: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3e962c01..a1e57a8a 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS) APPVERSION_M=2 APPVERSION_N=1 -APPVERSION_P=4 +APPVERSION_P=5 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APP_LOAD_FLAGS=--appFlags 0xa50 From c97223825cd938fe21b39d61e373900e083591a1 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 17 Jul 2023 11:18:31 +0200 Subject: [PATCH 26/85] Settings: Update according to latest guidelines --- src/ui_menu_nbgl.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ui_menu_nbgl.c b/src/ui_menu_nbgl.c index 784af224..35cca5c0 100644 --- a/src/ui_menu_nbgl.c +++ b/src/ui_menu_nbgl.c @@ -26,7 +26,7 @@ #define NB_INFO_FIELDS 2 #define PAGE_START 0 #define NB_PAGE_SETTING 2 -#define IS_TOUCHABLE true +#define IS_TOUCHABLE false #define NB_SETTINGS_SWITCHES 1 #define SWITCH_PUBLIC_KEY_SET_TOKEN FIRST_USER_TOKEN @@ -48,6 +48,11 @@ static void switch_public_key(void) { static bool settings_navigation_cb(uint8_t page, nbgl_pageContent_t *content) { if (page == 0) { + content->type = INFOS_LIST; + content->infosList.nbInfos = NB_INFO_FIELDS; + content->infosList.infoTypes = (const char **)infoTypes; + content->infosList.infoContents = (const char **)infoContents; + } else if (page == 1) { switches[0].text = "Public key export"; switches[0].subText = "Auto / manual export mode"; switches[0].token = SWITCH_PUBLIC_KEY_SET_TOKEN; @@ -57,11 +62,6 @@ static bool settings_navigation_cb(uint8_t page, nbgl_pageContent_t *content) { content->type = SWITCHES_LIST; content->switchesList.nbSwitches = NB_SETTINGS_SWITCHES; content->switchesList.switches = (nbgl_layoutSwitch_t *)switches; - } else if (page == 1) { - content->type = INFOS_LIST; - content->infosList.nbInfos = NB_INFO_FIELDS; - content->infosList.infoTypes = (const char **)infoTypes; - content->infosList.infoContents = (const char **)infoContents; } else { return false; } From 6b19e4ad3e78375115de159c9196d6d4761f62ff Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 17 Jul 2023 11:19:05 +0200 Subject: [PATCH 27/85] stax: update some wording --- src/ui_nbgl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 8e5589ae..58c7ed26 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -187,7 +187,7 @@ static void transaction_fee_callback(int token, uint8_t index) { (void) index; if (token) { releaseContext(); - snprintf(text, sizeof(text), "Sign transaction\nto send %s", G_coin_config->name); + snprintf(text, sizeof(text), "Sign transaction\nto send %s?", G_coin_config->name); nbgl_pageNavigationInfo_t info = {.activePage = 0, .nbPages = 0, .navType = NAV_WITH_TAP, From 9ddc6138f535a18e348f2e8d5003d378e2158cff Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 17 Jul 2023 17:57:52 +0200 Subject: [PATCH 28/85] icons: update with new design for stax --- glyphs/bitcoin_64px.gif | Bin 284 -> 674 bytes glyphs/bitcoin_cash_64px.gif | Bin 284 -> 674 bytes glyphs/bitcoin_gold_64px.gif | Bin 283 -> 674 bytes glyphs/bitcoin_legacy_64px.gif | Bin 284 -> 674 bytes glyphs/bitcoin_private_64px.gif | Bin 294 -> 674 bytes glyphs/bitcoin_testnet_64px.gif | Bin 284 -> 674 bytes glyphs/bitcoin_testnet_legacy_64px.gif | Bin 284 -> 674 bytes glyphs/dogecoin_64px.gif | Bin 266 -> 616 bytes icons/stax_app_bitcoin.gif | Bin 167 -> 347 bytes icons/stax_app_bitcoin_cash.gif | Bin 167 -> 347 bytes icons/stax_app_bitcoin_gold.gif | Bin 171 -> 347 bytes icons/stax_app_bitcoin_legacy.gif | Bin 167 -> 347 bytes icons/stax_app_bitcoin_private.gif | Bin 171 -> 347 bytes icons/stax_app_bitcoin_testnet.gif | Bin 167 -> 347 bytes icons/stax_app_bitcoin_testnet_legacy.gif | Bin 167 -> 347 bytes icons/stax_app_dogecoin.gif | Bin 185 -> 335 bytes 16 files changed, 0 insertions(+), 0 deletions(-) diff --git a/glyphs/bitcoin_64px.gif b/glyphs/bitcoin_64px.gif index 8679b3a13daae657076473216bc08b4192fff1f0..db706c4cc429474f8d0abdedd57bf432b4065602 100644 GIT binary patch literal 674 zcmV;T0$u$_Nk%w1VL$*t0J8u9ot>R&X=$&ouZxR|Sy@?ndU_2F4N6K%!otELA|g9G zI~EoeE-o(K-roQJ{{R30A^8LV00000EC2ui06+jh000F4(8)=wy*TU5yZ>M)j-=HH z#gQye`z(x72xUDr1!K5;?=pjiEhHf9d`RR$INUT8$!K)h!~~AgtS?ZdG!oh{a=~m4 zu;O&fP-q6!@E*7Jj@w)FQT=|;g9>*HMGSWXAq{A1Z4L-63500|WgRScG!6qTG!1)N z2_KzVl`aMoP!CK8YJM3FX$uYw04fg*6D+n8V3Cs;s$vQi4NQ#>1QM=r!5Yb8h8YM2 z2oeBxm%eHX1OOcaqiM$&&2YIK-fEHgJ6z@^x6@1|)5a2;Z zo|u9a1n}WTVHc@h>%!=h0O-!7aV`QPOB2u3oq7}hs`=2!D9r(bc1}_l=wq6_G$3!? zVR)l}f?W(~PWTlD)<26PFlw>zQG|eRVTjrxIY3$lo@$iF(dl5-{7DqXWfzTZIMOiF? zu9!=+0PvomJIUsR=scoAET9aI&tZm3(3)B%$jot$o2cDmQL%7B?MNpsCV-H24Ab&q zr2%`A1iP5{w&T+SB6{20i%ACpH6J^Ufl%B}e_5~x3W0DKC?JC6HBkU}2pSNe4GqYK zU;^Xm!5|L?DA+^;aq;n27vh8%2?3IkXu<%{wZ=dJ8LF6&O$>aq06sIsDC3Si_UPk} I7(@U7JJbdega7~l literal 284 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1lD*os8%uP&B^-WCAOwQ&@Pt46tv^CH(F$F;e z9grH3J_e?%J^d?BzvW*%XUnbb&G+{F=4U&wqQ_y!Ox4b`tWVp*Yc3e2cE5>zYRUic zZ3EBbj~#ymC!bLhyx5~OpKWDmr_s3$3UA9aKG#jZbs^gs29&y6@jf0QmN>!^78yxI zF1J;WIVDzGbYGYHc&ci4)#h6dx*7Lun$1+TC9|?~&YUkNYJ5!Bxa<6!emdRvZA^9T ftXOH@&$8>RdHv!}t?fN`@7+H>dHwoe1_o;YPxpS- diff --git a/glyphs/bitcoin_cash_64px.gif b/glyphs/bitcoin_cash_64px.gif index 8679b3a13daae657076473216bc08b4192fff1f0..db706c4cc429474f8d0abdedd57bf432b4065602 100644 GIT binary patch literal 674 zcmV;T0$u$_Nk%w1VL$*t0J8u9ot>R&X=$&ouZxR|Sy@?ndU_2F4N6K%!otELA|g9G zI~EoeE-o(K-roQJ{{R30A^8LV00000EC2ui06+jh000F4(8)=wy*TU5yZ>M)j-=HH z#gQye`z(x72xUDr1!K5;?=pjiEhHf9d`RR$INUT8$!K)h!~~AgtS?ZdG!oh{a=~m4 zu;O&fP-q6!@E*7Jj@w)FQT=|;g9>*HMGSWXAq{A1Z4L-63500|WgRScG!6qTG!1)N z2_KzVl`aMoP!CK8YJM3FX$uYw04fg*6D+n8V3Cs;s$vQi4NQ#>1QM=r!5Yb8h8YM2 z2oeBxm%eHX1OOcaqiM$&&2YIK-fEHgJ6z@^x6@1|)5a2;Z zo|u9a1n}WTVHc@h>%!=h0O-!7aV`QPOB2u3oq7}hs`=2!D9r(bc1}_l=wq6_G$3!? zVR)l}f?W(~PWTlD)<26PFlw>zQG|eRVTjrxIY3$lo@$iF(dl5-{7DqXWfzTZIMOiF? zu9!=+0PvomJIUsR=scoAET9aI&tZm3(3)B%$jot$o2cDmQL%7B?MNpsCV-H24Ab&q zr2%`A1iP5{w&T+SB6{20i%ACpH6J^Ufl%B}e_5~x3W0DKC?JC6HBkU}2pSNe4GqYK zU;^Xm!5|L?DA+^;aq;n27vh8%2?3IkXu<%{wZ=dJ8LF6&O$>aq06sIsDC3Si_UPk} I7(@U7JJbdega7~l literal 284 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1lD*os8%uP&B^-WCAOwQ&@Pt46tv^CH(F$F;e z9grH3J_e?%J^d?BzvW*%XUnbb&G+{F=4U&wqQ_y!Ox4b`tWVp*Yc3e2cE5>zYRUic zZ3EBbj~#ymC!bLhyx5~OpKWDmr_s3$3UA9aKG#jZbs^gs29&y6@jf0QmN>!^78yxI zF1J;WIVDzGbYGYHc&ci4)#h6dx*7Lun$1+TC9|?~&YUkNYJ5!Bxa<6!emdRvZA^9T ftXOH@&$8>RdHv!}t?fN`@7+H>dHwoe1_o;YPxpS- diff --git a/glyphs/bitcoin_gold_64px.gif b/glyphs/bitcoin_gold_64px.gif index deb72f919566802617e4e782978c4ce1ee271150..db706c4cc429474f8d0abdedd57bf432b4065602 100644 GIT binary patch literal 674 zcmV;T0$u$_Nk%w1VL$*t0J8u9ot>R&X=$&ouZxR|Sy@?ndU_2F4N6K%!otELA|g9G zI~EoeE-o(K-roQJ{{R30A^8LV00000EC2ui06+jh000F4(8)=wy*TU5yZ>M)j-=HH z#gQye`z(x72xUDr1!K5;?=pjiEhHf9d`RR$INUT8$!K)h!~~AgtS?ZdG!oh{a=~m4 zu;O&fP-q6!@E*7Jj@w)FQT=|;g9>*HMGSWXAq{A1Z4L-63500|WgRScG!6qTG!1)N z2_KzVl`aMoP!CK8YJM3FX$uYw04fg*6D+n8V3Cs;s$vQi4NQ#>1QM=r!5Yb8h8YM2 z2oeBxm%eHX1OOcaqiM$&&2YIK-fEHgJ6z@^x6@1|)5a2;Z zo|u9a1n}WTVHc@h>%!=h0O-!7aV`QPOB2u3oq7}hs`=2!D9r(bc1}_l=wq6_G$3!? zVR)l}f?W(~PWTlD)<26PFlw>zQG|eRVTjrxIY3$lo@$iF(dl5-{7DqXWfzTZIMOiF? zu9!=+0PvomJIUsR=scoAET9aI&tZm3(3)B%$jot$o2cDmQL%7B?MNpsCV-H24Ab&q zr2%`A1iP5{w&T+SB6{20i%ACpH6J^Ufl%B}e_5~x3W0DKC?JC6HBkU}2pSNe4GqYK zU;^Xm!5|L?DA+^;aq;n27vh8%2?3IkXu<%{wZ=dJ8LF6&O$>aq06sIsDC3Si_UPk} I7(@U7JJbdega7~l literal 283 zcmV+$0p$KiNk%w1VL$*t0Pq0-00030|NkNR1ONa4001HX3rTHZXJt)cXK7<=4rgI) zZDBnyE;KbXH8eE@ zyS3I%$#G&mbm!$g@7KQ5M-ylciMHssiBV|SNf`Px zD#tj-Rw{^k@_FD20ZYk>M_VB)W^1Rarz?S*dphKL_VZb6j46es%yikjG|4$F?Zpbr hw}y>)&C8|j-3snoJxg8gHjci|-tPVmA75Pn06PZ`f{FkD diff --git a/glyphs/bitcoin_legacy_64px.gif b/glyphs/bitcoin_legacy_64px.gif index 8679b3a13daae657076473216bc08b4192fff1f0..db706c4cc429474f8d0abdedd57bf432b4065602 100644 GIT binary patch literal 674 zcmV;T0$u$_Nk%w1VL$*t0J8u9ot>R&X=$&ouZxR|Sy@?ndU_2F4N6K%!otELA|g9G zI~EoeE-o(K-roQJ{{R30A^8LV00000EC2ui06+jh000F4(8)=wy*TU5yZ>M)j-=HH z#gQye`z(x72xUDr1!K5;?=pjiEhHf9d`RR$INUT8$!K)h!~~AgtS?ZdG!oh{a=~m4 zu;O&fP-q6!@E*7Jj@w)FQT=|;g9>*HMGSWXAq{A1Z4L-63500|WgRScG!6qTG!1)N z2_KzVl`aMoP!CK8YJM3FX$uYw04fg*6D+n8V3Cs;s$vQi4NQ#>1QM=r!5Yb8h8YM2 z2oeBxm%eHX1OOcaqiM$&&2YIK-fEHgJ6z@^x6@1|)5a2;Z zo|u9a1n}WTVHc@h>%!=h0O-!7aV`QPOB2u3oq7}hs`=2!D9r(bc1}_l=wq6_G$3!? zVR)l}f?W(~PWTlD)<26PFlw>zQG|eRVTjrxIY3$lo@$iF(dl5-{7DqXWfzTZIMOiF? zu9!=+0PvomJIUsR=scoAET9aI&tZm3(3)B%$jot$o2cDmQL%7B?MNpsCV-H24Ab&q zr2%`A1iP5{w&T+SB6{20i%ACpH6J^Ufl%B}e_5~x3W0DKC?JC6HBkU}2pSNe4GqYK zU;^Xm!5|L?DA+^;aq;n27vh8%2?3IkXu<%{wZ=dJ8LF6&O$>aq06sIsDC3Si_UPk} I7(@U7JJbdega7~l literal 284 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1lD*os8%uP&B^-WCAOwQ&@Pt46tv^CH(F$F;e z9grH3J_e?%J^d?BzvW*%XUnbb&G+{F=4U&wqQ_y!Ox4b`tWVp*Yc3e2cE5>zYRUic zZ3EBbj~#ymC!bLhyx5~OpKWDmr_s3$3UA9aKG#jZbs^gs29&y6@jf0QmN>!^78yxI zF1J;WIVDzGbYGYHc&ci4)#h6dx*7Lun$1+TC9|?~&YUkNYJ5!Bxa<6!emdRvZA^9T ftXOH@&$8>RdHv!}t?fN`@7+H>dHwoe1_o;YPxpS- diff --git a/glyphs/bitcoin_private_64px.gif b/glyphs/bitcoin_private_64px.gif index 83b5e8436a13be17308f6e970f156c11deab8567..db706c4cc429474f8d0abdedd57bf432b4065602 100644 GIT binary patch literal 674 zcmV;T0$u$_Nk%w1VL$*t0J8u9ot>R&X=$&ouZxR|Sy@?ndU_2F4N6K%!otELA|g9G zI~EoeE-o(K-roQJ{{R30A^8LV00000EC2ui06+jh000F4(8)=wy*TU5yZ>M)j-=HH z#gQye`z(x72xUDr1!K5;?=pjiEhHf9d`RR$INUT8$!K)h!~~AgtS?ZdG!oh{a=~m4 zu;O&fP-q6!@E*7Jj@w)FQT=|;g9>*HMGSWXAq{A1Z4L-63500|WgRScG!6qTG!1)N z2_KzVl`aMoP!CK8YJM3FX$uYw04fg*6D+n8V3Cs;s$vQi4NQ#>1QM=r!5Yb8h8YM2 z2oeBxm%eHX1OOcaqiM$&&2YIK-fEHgJ6z@^x6@1|)5a2;Z zo|u9a1n}WTVHc@h>%!=h0O-!7aV`QPOB2u3oq7}hs`=2!D9r(bc1}_l=wq6_G$3!? zVR)l}f?W(~PWTlD)<26PFlw>zQG|eRVTjrxIY3$lo@$iF(dl5-{7DqXWfzTZIMOiF? zu9!=+0PvomJIUsR=scoAET9aI&tZm3(3)B%$jot$o2cDmQL%7B?MNpsCV-H24Ab&q zr2%`A1iP5{w&T+SB6{20i%ACpH6J^Ufl%B}e_5~x3W0DKC?JC6HBkU}2pSNe4GqYK zU;^Xm!5|L?DA+^;aq;n27vh8%2?3IkXu<%{wZ=dJ8LF6&O$>aq06sIsDC3Si_UPk} I7(@U7JJbdega7~l literal 294 zcmV+>0ondXNk%w1VL$*t0Pq0-00030|NkNR1ONa4001HX3rTHZXJt)cXK7<=4rgI) zZDBnyE;KbXH8eER&X=$&ouZxR|Sy@?ndU_2F4N6K%!otELA|g9G zI~EoeE-o(K-roQJ{{R30A^8LV00000EC2ui06+jh000F4(8)=wy*TU5yZ>M)j-=HH z#gQye`z(x72xUDr1!K5;?=pjiEhHf9d`RR$INUT8$!K)h!~~AgtS?ZdG!oh{a=~m4 zu;O&fP-q6!@E*7Jj@w)FQT=|;g9>*HMGSWXAq{A1Z4L-63500|WgRScG!6qTG!1)N z2_KzVl`aMoP!CK8YJM3FX$uYw04fg*6D+n8V3Cs;s$vQi4NQ#>1QM=r!5Yb8h8YM2 z2oeBxm%eHX1OOcaqiM$&&2YIK-fEHgJ6z@^x6@1|)5a2;Z zo|u9a1n}WTVHc@h>%!=h0O-!7aV`QPOB2u3oq7}hs`=2!D9r(bc1}_l=wq6_G$3!? zVR)l}f?W(~PWTlD)<26PFlw>zQG|eRVTjrxIY3$lo@$iF(dl5-{7DqXWfzTZIMOiF? zu9!=+0PvomJIUsR=scoAET9aI&tZm3(3)B%$jot$o2cDmQL%7B?MNpsCV-H24Ab&q zr2%`A1iP5{w&T+SB6{20i%ACpH6J^Ufl%B}e_5~x3W0DKC?JC6HBkU}2pSNe4GqYK zU;^Xm!5|L?DA+^;aq;n27vh8%2?3IkXu<%{wZ=dJ8LF6&O$>aq06sIsDC3Si_UPk} I7(@U7JJbdega7~l literal 284 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1lD*os8%uP&B^-WCAOwQ&@Pt46tv^CH(F$F;e z9grH3J_e?%J^d?BzvW*%XUnbb&G+{F=4U&wqQ_y!Ox4b`tWVp*Yc3e2cE5>zYRUic zZ3EBbj~#ymC!bLhyx5~OpKWDmr_s3$3UA9aKG#jZbs^gs29&y6@jf0QmN>!^78yxI zF1J;WIVDzGbYGYHc&ci4)#h6dx*7Lun$1+TC9|?~&YUkNYJ5!Bxa<6!emdRvZA^9T ftXOH@&$8>RdHv!}t?fN`@7+H>dHwoe1_o;YPxpS- diff --git a/glyphs/bitcoin_testnet_legacy_64px.gif b/glyphs/bitcoin_testnet_legacy_64px.gif index 8679b3a13daae657076473216bc08b4192fff1f0..db706c4cc429474f8d0abdedd57bf432b4065602 100644 GIT binary patch literal 674 zcmV;T0$u$_Nk%w1VL$*t0J8u9ot>R&X=$&ouZxR|Sy@?ndU_2F4N6K%!otELA|g9G zI~EoeE-o(K-roQJ{{R30A^8LV00000EC2ui06+jh000F4(8)=wy*TU5yZ>M)j-=HH z#gQye`z(x72xUDr1!K5;?=pjiEhHf9d`RR$INUT8$!K)h!~~AgtS?ZdG!oh{a=~m4 zu;O&fP-q6!@E*7Jj@w)FQT=|;g9>*HMGSWXAq{A1Z4L-63500|WgRScG!6qTG!1)N z2_KzVl`aMoP!CK8YJM3FX$uYw04fg*6D+n8V3Cs;s$vQi4NQ#>1QM=r!5Yb8h8YM2 z2oeBxm%eHX1OOcaqiM$&&2YIK-fEHgJ6z@^x6@1|)5a2;Z zo|u9a1n}WTVHc@h>%!=h0O-!7aV`QPOB2u3oq7}hs`=2!D9r(bc1}_l=wq6_G$3!? zVR)l}f?W(~PWTlD)<26PFlw>zQG|eRVTjrxIY3$lo@$iF(dl5-{7DqXWfzTZIMOiF? zu9!=+0PvomJIUsR=scoAET9aI&tZm3(3)B%$jot$o2cDmQL%7B?MNpsCV-H24Ab&q zr2%`A1iP5{w&T+SB6{20i%ACpH6J^Ufl%B}e_5~x3W0DKC?JC6HBkU}2pSNe4GqYK zU;^Xm!5|L?DA+^;aq;n27vh8%2?3IkXu<%{wZ=dJ8LF6&O$>aq06sIsDC3Si_UPk} I7(@U7JJbdega7~l literal 284 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1lD*os8%uP&B^-WCAOwQ&@Pt46tv^CH(F$F;e z9grH3J_e?%J^d?BzvW*%XUnbb&G+{F=4U&wqQ_y!Ox4b`tWVp*Yc3e2cE5>zYRUic zZ3EBbj~#ymC!bLhyx5~OpKWDmr_s3$3UA9aKG#jZbs^gs29&y6@jf0QmN>!^78yxI zF1J;WIVDzGbYGYHc&ci4)#h6dx*7Lun$1+TC9|?~&YUkNYJ5!Bxa<6!emdRvZA^9T ftXOH@&$8>RdHv!}t?fN`@7+H>dHwoe1_o;YPxpS- diff --git a/glyphs/dogecoin_64px.gif b/glyphs/dogecoin_64px.gif index 056d89a7db8e977303cd89b724e50f678338266e..4bede53532c941dca1d0e8d7df99526b00015990 100644 GIT binary patch literal 616 zcmV-u0+;gtP&i%LpL3=9lM)j-(X; z#gHIR`yj_+06}R>L2(dn@4E*9;}!x8c)w(FFeGjm2c=ZXbY21m!H649iK?0bWngt3w zb9+x~10P0gj2r`^hpA)-p{gQjWB?khWTPVhiAuN^406390AmD`76QN(1qjRt2?qs@ z6bfT+7g21%4tGn^4gtGAt|oKZ+-2UCQpFa-$rR`46#-+k74f$f>Ph1i*i+UhEGT!6 zi@gcdwrF$k57q>HNfcB-wk3guN7)Kitl(}60t;*Z2mlxmxKUEE;%QNdH2xL(=Gib*m5X==?_B` z1Z`PhL2O2NTg+4#xCPXNj$F5G2{<8~kAoAyQI!C(2OtU*w;1!cS8h|V6&fnZ8n*DV zX3hrCxDa>>;(2y?m0++li8rlhMFg0tPy<{p3pha2@$w_gLC#433Qj> zj)#DO!CxFO*gEKddMoq&5Re>y_U(|+z}FuYaR3;wzyT^nR={KfHt67k5JpHs1OPk9 C0{c1u literal 266 zcmZ?wbhEHbbYO5`_`m=H|NsA2{K*1lD*os8%uP&B^-WCAOwQ&@Pt46tv^CH(F$F;e z9grH3J_e@4J^d?BzvW*%XUnbb&G+{F=5KrCG3{CBGRXtm-rZis<8!^C=Ekq?_jcOF zzFC@ytZhbem1;{{J&Wv;RbProEM2!n>GfB$PkI|;-%aBY>OZJxdbBnz`+-E&k$-O= zq}$)Vu;&^(>&ER09x8z=3Oqiye_MFs`wPKLjuquI!_6uKJ!k9`WBX+$b^PJalagAi zUTItpoAqm!*z1O>aP6C2J8w5!nbQ4%`;PXV8AmE&rr30xv3af2VeA{5TiZK#?cTF@ N-~Q#j7s$Y14FJ!Uc@F>p diff --git a/icons/stax_app_bitcoin.gif b/icons/stax_app_bitcoin.gif index 96b6eaae99217e09da23b19c10953593f180ba1c..99915d7c503448a7e83c319804a6207cd9b33693 100644 GIT binary patch literal 347 zcmV-h0i^y%Nk%w1VITk?0J8u9Sy@?WX=$CEo#Nu+i;Ih|udjM~dP+)4!otE978W8R zB0M}i3=9k|E-wH7{{R30A^8LV00000EC2ui03ZM$000F4(8)=wz1WTd6nhWT077OC z!3VBv5)5W#sBFC^L@WVzUjwm&Z@4;Sc*8(|2(%E0j{)LQ5cqPGL83<>92Sn5qu^t} zCd=MgQZP7>y#QtFYi5N#v&1@7NCpd74hS?X1v^XutE`+ulz0i02y~?qpf(MS61)i$lE8>H4Ouiskv&ah zH3tY4Rfm5*lmne03^{8Qq%9PWH6;vg0s;jD$2M{k+-g$=15k|N4w)*UL0~HJi6acWdv1G*v06VXtbgBRV literal 167 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyri7k;#)8@WirL1up8M>Jd3!hU^oa=zU6#G{T$v}@bn(O~<1-g`);|7z zQut@pTm>yNmAH}<)4QG)+BF^%Go86YX^Th}@9w8n>m2ew?_q9Vx>`HB=8cnTq^Xfj NfA*W*RVx@6tO57oL4E)L diff --git a/icons/stax_app_bitcoin_cash.gif b/icons/stax_app_bitcoin_cash.gif index fb318986e3d03436b7760e5e4143e4a78ed337d0..99915d7c503448a7e83c319804a6207cd9b33693 100644 GIT binary patch literal 347 zcmV-h0i^y%Nk%w1VITk?0J8u9Sy@?WX=$CEo#Nu+i;Ih|udjM~dP+)4!otE978W8R zB0M}i3=9k|E-wH7{{R30A^8LV00000EC2ui03ZM$000F4(8)=wz1WTd6nhWT077OC z!3VBv5)5W#sBFC^L@WVzUjwm&Z@4;Sc*8(|2(%E0j{)LQ5cqPGL83<>92Sn5qu^t} zCd=MgQZP7>y#QtFYi5N#v&1@7NCpd74hS?X1v^XutE`+ulz0i02y~?qpf(MS61)i$lE8>H4Ouiskv&ah zH3tY4Rfm5*lmne03^{8Qq%9PWH6;vg0s;jD$2M{k+-g$=15k|N4w)*UL0~HJi6acWdv1G*v06VXtbgBRV literal 167 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyri7k;#)8@WirL1up8M>Jd3!hU^oa=zU6#G{T$v}@bn(O~<1-g`);|7z zQut@pTm>yNmAH}<)4QG)+BMop6i@e&*cz#~^;)jt%7@3ccOILxbeZXHo6kY`cen!5RP#j6(bX diff --git a/icons/stax_app_bitcoin_gold.gif b/icons/stax_app_bitcoin_gold.gif index 13b06cf06943eb9e70d5e751ab162012b3d7ebfa..99915d7c503448a7e83c319804a6207cd9b33693 100644 GIT binary patch literal 347 zcmV-h0i^y%Nk%w1VITk?0J8u9Sy@?WX=$CEo#Nu+i;Ih|udjM~dP+)4!otE978W8R zB0M}i3=9k|E-wH7{{R30A^8LV00000EC2ui03ZM$000F4(8)=wz1WTd6nhWT077OC z!3VBv5)5W#sBFC^L@WVzUjwm&Z@4;Sc*8(|2(%E0j{)LQ5cqPGL83<>92Sn5qu^t} zCd=MgQZP7>y#QtFYi5N#v&1@7NCpd74hS?X1v^XutE`+ulz0i02y~?qpf(MS61)i$lE8>H4Ouiskv&ah zH3tY4Rfm5*lmne03^{8Qq%9PWH6;vg0s;jD$2M{k+-g$=15k|N4w)*UL0~HJi6acWdv1G*v06VXtbgBRV literal 171 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrj(w3MvmG1!IL*0dUj>Yos|2fH#WA4w=Iibk@ZTeYblR?vCeFT)%Pdn zGkRr-KH6YDOJ|z$+}Bf!>=tUMoUYjQ&BrPF`-#hO8&!;&v-Kv|W%6%*nxeKiXzT8I Sv5ybVvfcl3`G#-?25SJ30Yf92Sn5qu^t} zCd=MgQZP7>y#QtFYi5N#v&1@7NCpd74hS?X1v^XutE`+ulz0i02y~?qpf(MS61)i$lE8>H4Ouiskv&ah zH3tY4Rfm5*lmne03^{8Qq%9PWH6;vg0s;jD$2M{k+-g$=15k|N4w)*UL0~HJi6acWdv1G*v06VXtbgBRV literal 167 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyri7k;#)8@WirL1up8M>Jd3!hU^oa=zU6#G{T$v}@bn(O~<1-g`);|7z zQut@pTm>yNmAH}<)4QG)+BF^%Go86YX^Th}@9w8n>m2ew?_q9Vx>`HB=8cnTq^Xfj NfA*W*RVx@6tO57oL4E)L diff --git a/icons/stax_app_bitcoin_private.gif b/icons/stax_app_bitcoin_private.gif index 7dc5f6473d9fab7aaeb80028e252d91e051e4c9e..99915d7c503448a7e83c319804a6207cd9b33693 100644 GIT binary patch literal 347 zcmV-h0i^y%Nk%w1VITk?0J8u9Sy@?WX=$CEo#Nu+i;Ih|udjM~dP+)4!otE978W8R zB0M}i3=9k|E-wH7{{R30A^8LV00000EC2ui03ZM$000F4(8)=wz1WTd6nhWT077OC z!3VBv5)5W#sBFC^L@WVzUjwm&Z@4;Sc*8(|2(%E0j{)LQ5cqPGL83<>92Sn5qu^t} zCd=MgQZP7>y#QtFYi5N#v&1@7NCpd74hS?X1v^XutE`+ulz0i02y~?qpf(MS61)i$lE8>H4Ouiskv&ah zH3tY4Rfm5*lmne03^{8Qq%9PWH6;vg0s;jD$2M{k+-g$=15k|N4w)*UL0~HJi6acWdv1G*v06VXtbgBRV literal 171 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyrj(w3&XaFB9?dS1^)xoK-pmo@_}uZK=Ctcd3s-s-E!PVFSfZ^z?{(_> zhPP4<^V2-$SUNa`ugZwBT(~;5!^|nk_g3y%=d*|E?rQ9av5l8Iv-pdabN%MvpL4E= RE!+EhL)!W6N5UBxtO4U|L8t%# diff --git a/icons/stax_app_bitcoin_testnet.gif b/icons/stax_app_bitcoin_testnet.gif index 96b6eaae99217e09da23b19c10953593f180ba1c..99915d7c503448a7e83c319804a6207cd9b33693 100644 GIT binary patch literal 347 zcmV-h0i^y%Nk%w1VITk?0J8u9Sy@?WX=$CEo#Nu+i;Ih|udjM~dP+)4!otE978W8R zB0M}i3=9k|E-wH7{{R30A^8LV00000EC2ui03ZM$000F4(8)=wz1WTd6nhWT077OC z!3VBv5)5W#sBFC^L@WVzUjwm&Z@4;Sc*8(|2(%E0j{)LQ5cqPGL83<>92Sn5qu^t} zCd=MgQZP7>y#QtFYi5N#v&1@7NCpd74hS?X1v^XutE`+ulz0i02y~?qpf(MS61)i$lE8>H4Ouiskv&ah zH3tY4Rfm5*lmne03^{8Qq%9PWH6;vg0s;jD$2M{k+-g$=15k|N4w)*UL0~HJi6acWdv1G*v06VXtbgBRV literal 167 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyri7k;#)8@WirL1up8M>Jd3!hU^oa=zU6#G{T$v}@bn(O~<1-g`);|7z zQut@pTm>yNmAH}<)4QG)+BF^%Go86YX^Th}@9w8n>m2ew?_q9Vx>`HB=8cnTq^Xfj NfA*W*RVx@6tO57oL4E)L diff --git a/icons/stax_app_bitcoin_testnet_legacy.gif b/icons/stax_app_bitcoin_testnet_legacy.gif index 96b6eaae99217e09da23b19c10953593f180ba1c..99915d7c503448a7e83c319804a6207cd9b33693 100644 GIT binary patch literal 347 zcmV-h0i^y%Nk%w1VITk?0J8u9Sy@?WX=$CEo#Nu+i;Ih|udjM~dP+)4!otE978W8R zB0M}i3=9k|E-wH7{{R30A^8LV00000EC2ui03ZM$000F4(8)=wz1WTd6nhWT077OC z!3VBv5)5W#sBFC^L@WVzUjwm&Z@4;Sc*8(|2(%E0j{)LQ5cqPGL83<>92Sn5qu^t} zCd=MgQZP7>y#QtFYi5N#v&1@7NCpd74hS?X1v^XutE`+ulz0i02y~?qpf(MS61)i$lE8>H4Ouiskv&ah zH3tY4Rfm5*lmne03^{8Qq%9PWH6;vg0s;jD$2M{k+-g$=15k|N4w)*UL0~HJi6acWdv1G*v06VXtbgBRV literal 167 zcmZ?wbhEHbRA5kG_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyri7k;#)8@WirL1up8M>Jd3!hU^oa=zU6#G{T$v}@bn(O~<1-g`);|7z zQut@pTm>yNmAH}<)4QG)+BF^%Go86YX^Th}@9w8n>m2ew?_q9Vx>`HB=8cnTq^Xfj NfA*W*RVx@6tO57oL4E)L diff --git a/icons/stax_app_dogecoin.gif b/icons/stax_app_dogecoin.gif index edf8431fce3567a09cc62cf671478583f8117e73..578c4f1833259f339c3115459405161058016a4c 100644 GIT binary patch literal 335 zcmV-V0kHl@Nk%w1VITk?0J8u9i;IhTdU{z|S+TLPX=!Plot-W&E=o#DA|fIT3=Hb( z>g((478VxP*4F?3{{R30A^8LV00000EC2ui03ZM$000F1(8)=wz1XTDPo0_ZWG&}5*}VDw;>0l;cYEGPsY_7b)c zC|n!1!LF29UP)nyHGmR_vAs6f(ItBz3|LJ+fPW5wAO;c&HV6_lYKL%N4rzB1J_Tb6 zYym4+2sWBM0Ap+opdfvTqz;lbbvBlxa1ypxlq-;>EQ}6Fx~?p(12#*?V!H;d4nj30 z4hpfMjcf`Og)Lyq7y#906ART3W8(vgH|GwkHBj(GITpf6K1&zS_BKW)_4^O-nb-m_ h!4w@58W6zLg+Mlh6$%J2pdtYR0Rt>S+!!MQ06X3 hY-)G&lJ?I}61P~iNp)FkVEc Date: Tue, 18 Jul 2023 15:02:27 +0200 Subject: [PATCH 29/85] handleGetWalletId: use no-throw crypto api --- src/btchip.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/btchip.c b/src/btchip.c index 23236a84..6a4a127d 100644 --- a/src/btchip.c +++ b/src/btchip.c @@ -36,21 +36,26 @@ unsigned int const U_os_perso_seed_cookie[] = { 0xc1a551c5, }; -void handleGetWalletId(volatile unsigned short *tx) { +int handleGetWalletId(volatile unsigned short *tx) { unsigned char t[64]; cx_ecfp_256_private_key_t priv; cx_ecfp_256_public_key_t pub; // seed => priv key - os_perso_derive_node_bip32(CX_CURVE_256K1, U_os_perso_seed_cookie, 2, t, NULL); + if (os_derive_bip32_no_throw(CX_CURVE_256K1, U_os_perso_seed_cookie, 2, t, NULL)) { + return -1; + } // priv key => pubkey cx_ecdsa_init_private_key(CX_CURVE_256K1, t, 32, &priv); - cx_ecfp_generate_pair(CX_CURVE_256K1, &pub, &priv, 1); + if (cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1, &pub, &priv, 1)) { + return -1; + } // pubkey -> sha512 cx_hash_sha512(pub.W, sizeof(pub.W), t, sizeof(t)); // ! cookie ! memmove(G_io_apdu_buffer, t, 64); btchip_context_D.sw = 0x9000; *tx = 64; + return 0; } #endif // HAVE_WALLET_ID_SDK @@ -70,7 +75,9 @@ void app_dispatch(void) { #ifndef HAVE_WALLET_ID_SDK if ((G_io_apdu_buffer[ISO_OFFSET_CLA] == COMMON_CLA) && (G_io_apdu_buffer[ISO_OFFSET_INS] == COMMON_INS_GET_WALLET_ID)) { - handleGetWalletId(&btchip_context_D.outLength); + if (handleGetWalletId(&btchip_context_D.outLength)) { + goto fail; + } goto sendSW; } From 2d2bf0a59ec9c8590004655379e2dd2f74251a1d Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 18 Jul 2023 15:09:47 +0200 Subject: [PATCH 30/85] btchip.c: remove try/catch --- src/btchip.c | 121 ++++++++++++++++++++++++--------------------------- 1 file changed, 57 insertions(+), 64 deletions(-) diff --git a/src/btchip.c b/src/btchip.c index 6a4a127d..fcaa8d4f 100644 --- a/src/btchip.c +++ b/src/btchip.c @@ -69,86 +69,79 @@ void app_dispatch(void) { btchip_context_D.outLength = 0; btchip_context_D.io_flags = 0; - BEGIN_TRY { - TRY { - #ifndef HAVE_WALLET_ID_SDK - if ((G_io_apdu_buffer[ISO_OFFSET_CLA] == COMMON_CLA) && (G_io_apdu_buffer[ISO_OFFSET_INS] == COMMON_INS_GET_WALLET_ID)) { + if ((G_io_apdu_buffer[ISO_OFFSET_CLA] == COMMON_CLA) && (G_io_apdu_buffer[ISO_OFFSET_INS] == COMMON_INS_GET_WALLET_ID)) { if (handleGetWalletId(&btchip_context_D.outLength)) { goto fail; } goto sendSW; - } + } #endif - // If halted, then notify - SB_CHECK(btchip_context_D.halted); - if (SB_GET(btchip_context_D.halted)) { - btchip_context_D.sw = BTCHIP_SW_HALTED; - goto sendSW; - } - - cla = G_io_apdu_buffer[ISO_OFFSET_CLA]; - ins = G_io_apdu_buffer[ISO_OFFSET_INS]; - for (dispatched = 0; dispatched < DISPATCHER_APDUS; dispatched++) { - if ((cla == DISPATCHER_CLA[dispatched]) && - (ins == DISPATCHER_INS[dispatched])) { - break; - } - } - if (dispatched == DISPATCHER_APDUS) { - btchip_context_D.sw = BTCHIP_SW_INS_NOT_SUPPORTED; - goto sendSW; - } - if (DISPATCHER_DATA_IN[dispatched]) { - if (G_io_apdu_buffer[ISO_OFFSET_LC] == 0x00 || - btchip_context_D.inLength - 5 == 0) { - btchip_context_D.sw = BTCHIP_SW_INCORRECT_LENGTH; - goto sendSW; - } - // notify we need to receive data - // io_exchange(CHANNEL_APDU | IO_RECEIVE_DATA, 0); - } - // call the apdu handler - btchip_context_D.sw = ((apduProcessingFunction)PIC( + // If halted, then notify + SB_CHECK(btchip_context_D.halted); + if (SB_GET(btchip_context_D.halted)) { + btchip_context_D.sw = BTCHIP_SW_TECHNICAL_PROBLEM; + goto sendSW; + } + + cla = G_io_apdu_buffer[ISO_OFFSET_CLA]; + ins = G_io_apdu_buffer[ISO_OFFSET_INS]; + for (dispatched = 0; dispatched < DISPATCHER_APDUS; dispatched++) { + if ((cla == DISPATCHER_CLA[dispatched]) && + (ins == DISPATCHER_INS[dispatched])) { + break; + } + } + if (dispatched == DISPATCHER_APDUS) { + btchip_context_D.sw = BTCHIP_SW_INS_NOT_SUPPORTED; + goto sendSW; + } + if (DISPATCHER_DATA_IN[dispatched]) { + if (G_io_apdu_buffer[ISO_OFFSET_LC] == 0x00 || + btchip_context_D.inLength - 5 == 0) { + btchip_context_D.sw = BTCHIP_SW_INCORRECT_LENGTH; + goto sendSW; + } + // notify we need to receive data + // io_exchange(CHANNEL_APDU | IO_RECEIVE_DATA, 0); + } + // call the apdu handler + btchip_context_D.sw = ((apduProcessingFunction)PIC( DISPATCHER_FUNCTIONS[dispatched]))(); -// an APDU has been replied. request for power off time extension from the -// common ux + // an APDU has been replied. request for power off time extension from the + // common ux #ifdef IO_APP_ACTIVITY - IO_APP_ACTIVITY(); + IO_APP_ACTIVITY(); #endif // IO_APP_ACTIVITY - sendSW: - if (btchip_context_D.called_from_swap) { - btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; - if(btchip_context_D.sw != BTCHIP_SW_OK) { - vars.swap_data.should_exit = 1; - } - } - // prepare SW after replied data - G_io_apdu_buffer[btchip_context_D.outLength] = - (btchip_context_D.sw >> 8); - G_io_apdu_buffer[btchip_context_D.outLength + 1] = - (btchip_context_D.sw & 0xff); - btchip_context_D.outLength += 2; - } - CATCH(EXCEPTION_IO_RESET) { - THROW(EXCEPTION_IO_RESET); +sendSW: + if (btchip_context_D.called_from_swap) { + btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; + if(btchip_context_D.sw != BTCHIP_SW_OK) { + vars.swap_data.should_exit = 1; } - CATCH_OTHER(e) { - // uncaught exception detected - G_io_apdu_buffer[0] = 0x6F; - btchip_context_D.outLength = 2; - G_io_apdu_buffer[1] = e; - // we caught something suspicious - SB_SET(btchip_context_D.halted, 1); - } - FINALLY; } - END_TRY; + // prepare SW after replied data + G_io_apdu_buffer[btchip_context_D.outLength] = + (btchip_context_D.sw >> 8); + G_io_apdu_buffer[btchip_context_D.outLength + 1] = + (btchip_context_D.sw & 0xff); + btchip_context_D.outLength += 2; + return; + +#ifndef HAVE_WALLET_ID_SDK +fail: + // uncaught exception detected + G_io_apdu_buffer[0] = 0x6F; + btchip_context_D.outLength = 2; + G_io_apdu_buffer[1] = 0x00; + // we caught something suspicious + SB_SET(btchip_context_D.halted, 1); +#endif } void app_main(void) { From f597f469e4b72e922fdc7ccfe1a05b4dcaed2d87 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 18 Jul 2023 15:20:36 +0200 Subject: [PATCH 31/85] btchip_private_derive_keypair: use no-throw apis and handle return code --- include/btchip_helpers.h | 2 +- src/btchip_apdu_get_wallet_public_key.c | 8 +++++++- src/btchip_apdu_hash_input_finalize_full.c | 4 +++- src/btchip_apdu_sign_message.c | 8 +++++--- src/btchip_helpers.c | 13 ++++++++----- 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/include/btchip_helpers.h b/include/btchip_helpers.h index a99504b7..9e47f21f 100644 --- a/include/btchip_helpers.h +++ b/include/btchip_helpers.h @@ -65,7 +65,7 @@ unsigned short btchip_decode_base58_address(unsigned char *in, unsigned char *out, unsigned short outlen); -void btchip_private_derive_keypair(unsigned char *bip32Path, +int btchip_private_derive_keypair(unsigned char *bip32Path, unsigned char derivePublic, unsigned char *out_chainCode, cx_ecfp_private_key_t * private_key, diff --git a/src/btchip_apdu_get_wallet_public_key.c b/src/btchip_apdu_get_wallet_public_key.c index 8055eb09..9b84ac5b 100644 --- a/src/btchip_apdu_get_wallet_public_key.c +++ b/src/btchip_apdu_get_wallet_public_key.c @@ -28,7 +28,9 @@ int get_public_key_chain_code(unsigned char* keyPath, bool uncompressedPublicKey cx_ecfp_private_key_t private_key; cx_ecfp_public_key_t public_key; int keyLength = 0; - btchip_private_derive_keypair(keyPath, 1, chainCode, &private_key, &public_key); + if (btchip_private_derive_keypair(keyPath, 1, chainCode, &private_key, &public_key)) { + return 0; + } // Then encode it if (uncompressedPublicKeys) { keyLength = 65; @@ -119,6 +121,10 @@ unsigned short btchip_apdu_get_wallet_public_key() { G_io_apdu_buffer[0] = 65; keyLength = get_public_key_chain_code(G_io_apdu_buffer + ISO_OFFSET_CDATA, uncompressedPublicKeys, G_io_apdu_buffer + 1, chainCode); + if (keyLength == 0) { + return BTCHIP_SW_TECHNICAL_PROBLEM; + } + if (cashAddr) { uint8_t tmp[20]; btchip_public_key_hash160(G_io_apdu_buffer + 1, // IN diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index cb17e49d..01771d65 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -221,7 +221,9 @@ bool handle_output_state() { void get_public_key(unsigned char* keyPath, cx_ecfp_public_key_t* public_key) { cx_ecfp_private_key_t private_key; - btchip_private_derive_keypair(keyPath, 1, NULL, &private_key, public_key); + if (btchip_private_derive_keypair(keyPath, 1, NULL, &private_key, public_key)) { + return -1; + } } // out should be 32 bytes, even only 20 bytes is significant for output diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index 9d1ad3e5..6dcf1c37 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -251,9 +251,6 @@ unsigned short btchip_compute_hash() { cx_sha256_init(&btchip_context_D.transactionHashFull.sha256); cx_hash(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, hash, 32, hash, 32); - btchip_private_derive_keypair( - btchip_context_D.transactionSummary.keyPath, 0, - NULL, &private_key, NULL); btchip_sign_finalhash( &private_key, hash, sizeof(hash), // IN G_io_apdu_buffer, 100, // OUT @@ -265,6 +262,11 @@ unsigned short btchip_compute_hash() { sw = SW_TECHNICAL_DETAILS(0x0F); } FINALLY { + if (btchip_private_derive_keypair( + btchip_context_D.transactionSummary.keyPath, 0, + NULL, &private_key, NULL)) { + goto discard; + } memset(&btchip_context_D.transactionSummary, 0, sizeof(btchip_transaction_summary_t)); } diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index 25dd03f0..9fc7a02a 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -291,7 +291,7 @@ unsigned short btchip_decode_base58_address(unsigned char *in, return outlen; } -void btchip_private_derive_keypair(unsigned char *bip32Path, +int btchip_private_derive_keypair(unsigned char *bip32Path, unsigned char derivePublic, unsigned char *out_chainCode, cx_ecfp_private_key_t * private_key, @@ -300,7 +300,7 @@ void btchip_private_derive_keypair(unsigned char *bip32Path, unsigned char i; union { unsigned int bip32PathInt[MAX_BIP32_PATH]; - unsigned char privateComponent[32]; + unsigned char privateComponent[64]; } u; bip32PathLength = bip32Path[0]; @@ -315,20 +315,23 @@ void btchip_private_derive_keypair(unsigned char *bip32Path, io_seproxyhal_io_heartbeat(); - os_perso_derive_node_bip32(CX_CURVE_256K1, u.bip32PathInt, bip32PathLength, - u.privateComponent, out_chainCode); + if (os_derive_bip32_no_throw(CX_CURVE_256K1, u.bip32PathInt, bip32PathLength, + u.privateComponent, out_chainCode)) { + return -1; + } cx_ecdsa_init_private_key(BTCHIP_CURVE, u.privateComponent, 32, private_key); if (derivePublic) { - cx_ecfp_generate_pair(BTCHIP_CURVE, public_key, + cx_ecfp_generate_pair_no_throw(BTCHIP_CURVE, public_key, private_key, 1); } io_seproxyhal_io_heartbeat(); memset(u.privateComponent, 0, sizeof(u.privateComponent)); + return 0; } /* From 0178db39b0131cf37924c7765e8a9707079f7c6d Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 18 Jul 2023 15:25:02 +0200 Subject: [PATCH 32/85] get_pubkey: use no-throw crypto API --- src/btchip_apdu_hash_input_finalize_full.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index 01771d65..a6cd059b 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -219,18 +219,21 @@ bool handle_output_state() { return processed; } -void get_public_key(unsigned char* keyPath, cx_ecfp_public_key_t* public_key) { +int get_public_key(unsigned char* keyPath, cx_ecfp_public_key_t* public_key) { cx_ecfp_private_key_t private_key; if (btchip_private_derive_keypair(keyPath, 1, NULL, &private_key, public_key)) { return -1; } + return 0; } // out should be 32 bytes, even only 20 bytes is significant for output -void get_pubkey_hash160(unsigned char* keyPath, unsigned char* out) { +int get_pubkey_hash160(unsigned char* keyPath, unsigned char* out) { cx_ecfp_public_key_t public_key; int keyLength; - get_public_key(keyPath, &public_key); + if (get_public_key(keyPath, &public_key)) { + return -1; + } if (((N_btchip.bkp.config.options & BTCHIP_OPTION_UNCOMPRESSED_KEYS) != 0)) { keyLength = 65; @@ -243,6 +246,7 @@ void get_pubkey_hash160(unsigned char* keyPath, unsigned char* out) { keyLength, // INLEN out // OUT ); + return 0; } unsigned short btchip_apdu_hash_input_finalize_full_internal( @@ -280,6 +284,10 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( btchip_set_check_internal_structure_integrity(0); if (btchip_context_D.transactionContext.transactionState != BTCHIP_TRANSACTION_PRESIGN_READY) { + if (get_pubkey_hash160(transactionSummary->keyPath, btchip_context_D.tmpCtx.output.changeAddress)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; } @@ -306,7 +314,6 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); - get_pubkey_hash160(transactionSummary->keyPath, btchip_context_D.tmpCtx.output.changeAddress); PRINTF("Change address = %.*H\n", 20, btchip_context_D.tmpCtx.output.changeAddress); btchip_context_D.tmpCtx.output.changeInitialized = 1; From 05b29f77310c667cddddf7605884dac354ae2cb0 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 18 Jul 2023 15:30:23 +0200 Subject: [PATCH 33/85] btchip_sign_finalhash: use no-throw api --- include/btchip_helpers.h | 2 +- src/btchip_apdu_hash_sign.c | 3 ++- src/btchip_apdu_sign_message.c | 11 ++++++----- src/btchip_helpers.c | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/btchip_helpers.h b/include/btchip_helpers.h index 9e47f21f..85eec799 100644 --- a/include/btchip_helpers.h +++ b/include/btchip_helpers.h @@ -83,7 +83,7 @@ void btchip_swap_bytes(unsigned char *target, unsigned char *source, void btchip_sign_finalhash(void *keyContext, unsigned char *in, unsigned short inlen, - unsigned char *out, unsigned short outlen, + unsigned char *out, size_t* outlen, unsigned char rfc6979); void btchip_transaction_add_output(unsigned char *hash160Address, diff --git a/src/btchip_apdu_hash_sign.c b/src/btchip_apdu_hash_sign.c index cf8cf440..9f0bb67a 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/btchip_apdu_hash_sign.c @@ -195,9 +195,10 @@ void btchip_bagl_user_action_signtx(unsigned char confirming, unsigned char dire } PRINTF("Hash2\n%.*H\n", sizeof(hash), hash); // Sign + size_t out_len = sizeof(G_io_apdu_buffer); btchip_sign_finalhash( &private_key, hash, sizeof(hash), - G_io_apdu_buffer, sizeof(G_io_apdu_buffer), + G_io_apdu_buffer, &out_len, ((N_btchip.bkp.config.options & BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index 6dcf1c37..531c9678 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -251,11 +251,6 @@ unsigned short btchip_compute_hash() { cx_sha256_init(&btchip_context_D.transactionHashFull.sha256); cx_hash(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, hash, 32, hash, 32); - btchip_sign_finalhash( - &private_key, hash, sizeof(hash), // IN - G_io_apdu_buffer, 100, // OUT - ((N_btchip.bkp.config.options & - BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); btchip_context_D.outLength = G_io_apdu_buffer[1] + 2; } CATCH_ALL { @@ -267,6 +262,12 @@ unsigned short btchip_compute_hash() { NULL, &private_key, NULL)) { goto discard; } + size_t out_len = 100; + btchip_sign_finalhash( + &private_key, hash, sizeof(hash), // IN + G_io_apdu_buffer, &out_len, // OUT + ((N_btchip.bkp.config.options & + BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); memset(&btchip_context_D.transactionSummary, 0, sizeof(btchip_transaction_summary_t)); } diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index 9fc7a02a..fa3414b2 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -485,12 +485,12 @@ void btchip_transaction_add_output(unsigned char *hash160Address, void btchip_sign_finalhash(void *keyContext, unsigned char *in, unsigned short inlen, - unsigned char *out, unsigned short outlen, + unsigned char *out, size_t* outlen, unsigned char rfc6979) { io_seproxyhal_io_heartbeat(); unsigned int info = 0; - cx_ecdsa_sign((cx_ecfp_private_key_t *)keyContext, + cx_ecdsa_sign_no_throw((cx_ecfp_private_key_t *)keyContext, CX_LAST | (rfc6979 ? CX_RND_RFC6979 : CX_RND_TRNG), CX_SHA256, in, inlen, out, outlen, &info); if (info & CX_ECCINFO_PARITY_ODD) { From df512fca74620508a8755afe2ef2f8a5cdea2252 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 18 Jul 2023 15:31:59 +0200 Subject: [PATCH 34/85] handle_check_address: use no-throw api --- src/handle_check_address.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/handle_check_address.c b/src/handle_check_address.c index 23f25530..c094e9ef 100644 --- a/src/handle_check_address.c +++ b/src/handle_check_address.c @@ -9,14 +9,16 @@ #include bool derive_private_key(unsigned char* serialized_path, unsigned char serialized_path_length, cx_ecfp_private_key_t* privKey) { - unsigned char privateComponent[32]; + unsigned char privateComponent[64]; bip32_path_t path; if (!parse_serialized_path(&path, serialized_path, serialized_path_length)) { PRINTF("Can't parse path\n"); return false; } - os_perso_derive_node_bip32(CX_CURVE_256K1, path.path, path.length, - privateComponent, NULL); + if (os_derive_bip32_no_throw(CX_CURVE_256K1, path.path, path.length, + privateComponent, NULL)) { + return false; + } cx_ecdsa_init_private_key(BTCHIP_CURVE, privateComponent, 32, privKey); return true; } @@ -31,7 +33,10 @@ bool derive_compressed_public_key( return false; cx_ecfp_public_key_t pubKey; - cx_ecfp_generate_pair(BTCHIP_CURVE, &pubKey, &privKey, 1); + if (cx_ecfp_generate_pair_no_throw(BTCHIP_CURVE, &pubKey, &privKey, 1)) { + return false; + } + btchip_compress_public_key_value(pubKey.W); memcpy(public_key, pubKey.W, 33); return true; From 371a0b87543078ff5481b3960d52eb476d257a2e Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 18 Jul 2023 15:38:23 +0200 Subject: [PATCH 35/85] btchip_transaction: use no-throw crypto API --- src/btchip_transaction.c | 195 +++++++++++++++++++++++++++------------ 1 file changed, 137 insertions(+), 58 deletions(-) diff --git a/src/btchip_transaction.c b/src/btchip_transaction.c index 63c4ecd9..9cd29e61 100644 --- a/src/btchip_transaction.c +++ b/src/btchip_transaction.c @@ -87,17 +87,17 @@ void transaction_offset(unsigned char value) { if ((btchip_context_D.transactionHashOption & TRANSACTION_HASH_FULL) != 0) { PRINTF("--- ADD TO HASH FULL:\n%.*H\n", value, btchip_context_D.transactionBufferPointer); if (btchip_context_D.usingOverwinter) { - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.transactionBufferPointer, value, NULL, 0); + cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.transactionBufferPointer, value, NULL, 0); } else { - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, 0, + cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, btchip_context_D.transactionBufferPointer, value, NULL, 0); } } if ((btchip_context_D.transactionHashOption & TRANSACTION_HASH_AUTHORIZATION) != 0) { PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", value, btchip_context_D.transactionBufferPointer); - cx_hash(&btchip_context_D.transactionHashAuthorization.header, 0, + cx_hash_no_throw(&btchip_context_D.transactionHashAuthorization.header, 0, btchip_context_D.transactionBufferPointer, value, NULL, 0); } } @@ -175,24 +175,36 @@ void transaction_parse(unsigned char parseMode) { btchip_context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING ? (G_coin_config->zcash_consensus_branch_id != 0 ? G_coin_config->zcash_consensus_branch_id : CONSENSUS_BRANCH_ID_SAPLING) : CONSENSUS_BRANCH_ID_OVERWINTER); } - cx_blake2b_init2(&btchip_context_D.transactionHashFull.blake2b, 256, NULL, 0, parameters, 16); + if (cx_blake2b_init2_no_throw(&btchip_context_D.transactionHashFull.blake2b, 256, NULL, 0, parameters, 16)) { + goto fail; + } } } else { - cx_sha256_init(&btchip_context_D.transactionHashFull.sha256); + if (cx_sha256_init_no_throw(&btchip_context_D.transactionHashFull.sha256)) { + goto fail; + } + } + if (cx_sha256_init_no_throw( + &btchip_context_D.transactionHashAuthorization)) { + goto fail; } - cx_sha256_init( - &btchip_context_D.transactionHashAuthorization); if (btchip_context_D.usingSegwit) { btchip_context_D.transactionHashOption = 0; if (!btchip_context_D.segwitParsedOnce) { if (btchip_context_D.usingOverwinter) { - cx_blake2b_init2(&btchip_context_D.segwit.hash.hashPrevouts.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_PREVOUTS, 16); - cx_blake2b_init2(&btchip_context_D.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_SEQUENCE, 16); + if (cx_blake2b_init2_no_throw(&btchip_context_D.segwit.hash.hashPrevouts.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_PREVOUTS, 16)) { + goto fail; + } + if (cx_blake2b_init2_no_throw(&btchip_context_D.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_SEQUENCE, 16)) { + goto fail; + } } else { - cx_sha256_init( - &btchip_context_D.segwit.hash.hashPrevouts.sha256); + if (cx_sha256_init_no_throw( + &btchip_context_D.segwit.hash.hashPrevouts.sha256)) { + goto fail; + } } } else { PRINTF("Resume SegWit hash\n"); @@ -200,54 +212,87 @@ void transaction_parse(unsigned char parseMode) { PRINTF("SEGWIT HashedPrevouts\n%.*H\n",sizeof(btchip_context_D.segwit.cache.hashedPrevouts),btchip_context_D.segwit.cache.hashedPrevouts); PRINTF("SEGWIT HashedSequence\n%.*H\n",sizeof(btchip_context_D.segwit.cache.hashedSequence),btchip_context_D.segwit.cache.hashedSequence); if (btchip_context_D.usingOverwinter) { - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.transactionVersion, sizeof(btchip_context_D.transactionVersion), NULL, 0); - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.nVersionGroupId, sizeof(btchip_context_D.nVersionGroupId), NULL, 0); - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.segwit.cache.hashedPrevouts, sizeof(btchip_context_D.segwit.cache.hashedPrevouts), NULL, 0); - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.segwit.cache.hashedSequence, sizeof(btchip_context_D.segwit.cache.hashedSequence), NULL, 0); - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.segwit.cache.hashedOutputs, sizeof(btchip_context_D.segwit.cache.hashedOutputs), NULL, 0); - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0); + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.transactionVersion, sizeof(btchip_context_D.transactionVersion), NULL, 0)) { + goto fail; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.nVersionGroupId, sizeof(btchip_context_D.nVersionGroupId), NULL, 0)) { + goto fail; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.segwit.cache.hashedPrevouts, sizeof(btchip_context_D.segwit.cache.hashedPrevouts), NULL, 0)) { + goto fail; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.segwit.cache.hashedSequence, sizeof(btchip_context_D.segwit.cache.hashedSequence), NULL, 0)) { + goto fail; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.segwit.cache.hashedOutputs, sizeof(btchip_context_D.segwit.cache.hashedOutputs), NULL, 0)) { + goto fail; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { + goto fail; + } if (btchip_context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0); // sapling hashShieldedSpends - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0); // sapling hashShieldedOutputs + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { // sapling hashShieldedSpend) + goto fail; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { // sapling hashShieldedOutputs + goto fail; + } + + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.nLockTime, sizeof(btchip_context_D.nLockTime), NULL, 0)) { + goto fail; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.nExpiryHeight, sizeof(btchip_context_D.nExpiryHeight), NULL, 0)) { + goto fail; } - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.nLockTime, sizeof(btchip_context_D.nLockTime), NULL, 0); - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.nExpiryHeight, sizeof(btchip_context_D.nExpiryHeight), NULL, 0); if (btchip_context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { unsigned char valueBalance[8]; memset(valueBalance, 0, sizeof(valueBalance)); - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, valueBalance, sizeof(valueBalance), NULL, 0); // sapling valueBalance + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, valueBalance, sizeof(valueBalance), NULL, 0)) { // sapling valueBalance + goto fail; + } + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.sigHashType, sizeof(btchip_context_D.sigHashType), NULL, 0)) { + goto fail; } - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.sigHashType, sizeof(btchip_context_D.sigHashType), NULL, 0); } else { PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(btchip_context_D.transactionVersion), btchip_context_D.transactionVersion); - cx_hash( + if (cx_hash_no_throw( &btchip_context_D.transactionHashFull.sha256.header, 0, btchip_context_D.transactionVersion, sizeof(btchip_context_D.transactionVersion), - NULL, 0); + NULL, 0)) { + goto fail; + } PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(btchip_context_D.segwit.cache.hashedPrevouts), btchip_context_D.segwit.cache.hashedPrevouts); - cx_hash( + if (cx_hash_no_throw( &btchip_context_D.transactionHashFull.sha256.header, 0, btchip_context_D.segwit.cache.hashedPrevouts, sizeof(btchip_context_D.segwit.cache .hashedPrevouts), - NULL, 0); + NULL, 0)) { + goto fail; + } PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(btchip_context_D.segwit.cache.hashedSequence), btchip_context_D.segwit.cache.hashedSequence); - cx_hash( + if (cx_hash_no_throw( &btchip_context_D.transactionHashFull.sha256.header, 0, btchip_context_D.segwit.cache.hashedSequence, sizeof(btchip_context_D.segwit.cache .hashedSequence), - NULL, 0); + NULL, 0)) { + goto fail; + } PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", sizeof(btchip_context_D.segwit.cache), (unsigned char *)&btchip_context_D.segwit.cache); - cx_hash(&btchip_context_D + if (cx_hash_no_throw(&btchip_context_D .transactionHashAuthorization.header, 0, (unsigned char *)&btchip_context_D .segwit.cache, sizeof(btchip_context_D.segwit.cache), - NULL, 0); + NULL, 0)) { + goto fail; + } } } } @@ -414,15 +459,19 @@ void transaction_parse(unsigned char parseMode) { 36); // prevout : 32 hash + 4 index if (!btchip_context_D.segwitParsedOnce) { if (btchip_context_D.usingOverwinter) { - cx_hash(&btchip_context_D.segwit.hash.hashPrevouts.blake2b.header, 0, btchip_context_D.transactionBufferPointer, 36, NULL, 0); + if (cx_hash_no_throw(&btchip_context_D.segwit.hash.hashPrevouts.blake2b.header, 0, btchip_context_D.transactionBufferPointer, 36, NULL, 0)) { + goto fail; + } } else { - cx_hash( + if (cx_hash_no_throw( &btchip_context_D.segwit.hash.hashPrevouts .sha256.header, 0, btchip_context_D.transactionBufferPointer, - 36, NULL, 0); + 36, NULL, 0)) { + goto fail; + } } transaction_offset_increase(36); check_transaction_available(8); // update amount @@ -609,14 +658,18 @@ void transaction_parse(unsigned char parseMode) { // Append the saved value PRINTF("SEGWIT Add value\n%.*H\n",8,btchip_context_D.inputValue); if (btchip_context_D.usingOverwinter) { - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.inputValue, 8, NULL, 0); + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.inputValue, 8, NULL, 0)) { + goto fail; + } } else { PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(btchip_context_D.inputValue), btchip_context_D.inputValue); - cx_hash(&btchip_context_D + if (cx_hash_no_throw(&btchip_context_D .transactionHashFull.sha256.header, 0, btchip_context_D.inputValue, 8, - NULL, 0); + NULL, 0)) { + goto fail; + } } } } @@ -626,15 +679,19 @@ void transaction_parse(unsigned char parseMode) { if (btchip_context_D.usingSegwit && !btchip_context_D.segwitParsedOnce) { if (btchip_context_D.usingOverwinter) { - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.transactionBufferPointer, 4, NULL, 0); + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.transactionBufferPointer, 4, NULL, 0)) { + goto fail; + } } else { PRINTF("--- ADD TO HASH FULL:\n%.*H\n", 4, btchip_context_D.transactionBufferPointer); - cx_hash(&btchip_context_D.transactionHashFull + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull .sha256.header, 0, btchip_context_D.transactionBufferPointer, - 4, NULL, 0); + 4, NULL, 0)) { + goto fail; + } } } transaction_offset_increase(4); @@ -675,29 +732,45 @@ void transaction_parse(unsigned char parseMode) { unsigned char hashedSequence[32]; // Flush the cache if (btchip_context_D.usingOverwinter) { - cx_hash(&btchip_context_D.segwit.hash.hashPrevouts.blake2b.header, CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32); - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, hashedSequence, 0, hashedSequence, 32); + if (cx_hash_no_throw(&btchip_context_D.segwit.hash.hashPrevouts.blake2b.header, CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32)) { + goto fail; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, hashedSequence, 0, hashedSequence, 32)) { + goto fail; + } } else { - cx_hash(&btchip_context_D.segwit.hash.hashPrevouts + if (cx_hash_no_throw(&btchip_context_D.segwit.hash.hashPrevouts .sha256.header, - CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32); - cx_sha256_init( - &btchip_context_D.segwit.hash.hashPrevouts.sha256); - cx_hash(&btchip_context_D.segwit.hash.hashPrevouts + CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32)) { + goto fail; + } + if (cx_sha256_init_no_throw( + &btchip_context_D.segwit.hash.hashPrevouts.sha256)) { + goto fail; + } + if (cx_hash_no_throw(&btchip_context_D.segwit.hash.hashPrevouts .sha256.header, CX_LAST, hashedPrevouts, - sizeof(hashedPrevouts), hashedPrevouts, 32); - cx_hash(&btchip_context_D.transactionHashFull + sizeof(hashedPrevouts), hashedPrevouts, 32)) { + goto fail; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull .sha256.header, - CX_LAST, hashedSequence, 0, hashedSequence, 32); - cx_sha256_init( - &btchip_context_D.transactionHashFull.sha256); + CX_LAST, hashedSequence, 0, hashedSequence, 32)) { + goto fail; + } + if (cx_sha256_init_no_throw( + &btchip_context_D.transactionHashFull.sha256)) { + goto fail; + } PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(hashedSequence), hashedSequence); - cx_hash(&btchip_context_D.transactionHashFull + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull .sha256.header, CX_LAST, hashedSequence, - sizeof(hashedSequence), hashedSequence, 32); + sizeof(hashedSequence), hashedSequence, 32)) { + goto fail; + } } memmove( @@ -713,12 +786,14 @@ void transaction_parse(unsigned char parseMode) { btchip_context_D.segwitParsedOnce) { if (!btchip_context_D.usingOverwinter) { PRINTF("SEGWIT hashedOutputs\n%.*H\n",sizeof(btchip_context_D.segwit.cache.hashedOutputs),btchip_context_D.segwit.cache.hashedOutputs); - cx_hash( + if (cx_hash_no_throw( &btchip_context_D.transactionHashFull.sha256.header, 0, btchip_context_D.segwit.cache.hashedOutputs, sizeof(btchip_context_D.segwit.cache .hashedOutputs), - NULL, 0); + NULL, 0)) { + goto fail; + } } btchip_context_D.transactionContext .transactionState = @@ -728,11 +803,15 @@ void transaction_parse(unsigned char parseMode) { .transactionState = BTCHIP_TRANSACTION_PRESIGN_READY; if (btchip_context_D.usingOverwinter) { - cx_blake2b_init2(&btchip_context_D.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_OUTPUTS, 16); + if (cx_blake2b_init2_no_throw(&btchip_context_D.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_OUTPUTS, 16)) { + goto fail; + } } else if (btchip_context_D.usingSegwit) { - cx_sha256_init(&btchip_context_D.transactionHashFull.sha256); + if (cx_sha256_init_no_throw(&btchip_context_D.transactionHashFull.sha256)) { + goto fail; + } } } continue; From 243023d36094537e0da2656b3bada5ed7fc6468e Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 18 Jul 2023 15:42:13 +0200 Subject: [PATCH 36/85] btchip_apdu_hash_input_finalize_full: use no_throw api --- src/btchip_apdu_hash_input_finalize_full.c | 394 +++++++++++---------- src/btchip_apdu_hash_sign.c | 211 ++++++----- 2 files changed, 308 insertions(+), 297 deletions(-) diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index a6cd059b..02328bad 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -279,237 +279,257 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( } // Check state - BEGIN_TRY { - TRY { - btchip_set_check_internal_structure_integrity(0); - if (btchip_context_D.transactionContext.transactionState != - BTCHIP_TRANSACTION_PRESIGN_READY) { + btchip_set_check_internal_structure_integrity(0); + if (btchip_context_D.transactionContext.transactionState != + BTCHIP_TRANSACTION_PRESIGN_READY) { + sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } + + if (p1 == FINALIZE_P1_CHANGEINFO) { + if (!btchip_context_D.transactionContext.firstSigned) { + // Already validated, should be prevented on the client side +return_OK: + return BTCHIP_SW_OK; + } + if (!btchip_context_D.tmpCtx.output.changeAccepted) { + sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } + memset(transactionSummary, 0, + sizeof(btchip_transaction_summary_t)); + if (G_io_apdu_buffer[ISO_OFFSET_CDATA] == 0x00) { + // Called with no change path, abort, should be prevented on + // the client side + goto return_OK; + } + memmove(transactionSummary->keyPath, + G_io_apdu_buffer + ISO_OFFSET_CDATA, + MAX_BIP32_PATH_LENGTH); + if (get_pubkey_hash160(transactionSummary->keyPath, btchip_context_D.tmpCtx.output.changeAddress)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discardTransaction; } + PRINTF("Change address = %.*H\n", 20, btchip_context_D.tmpCtx.output.changeAddress); + + btchip_context_D.tmpCtx.output.changeInitialized = 1; + btchip_context_D.tmpCtx.output.changeAccepted = 0; + + // if the bip44 change path provided is not canonical or its index are unsual, ask for user approval + if(bip44_derivation_guard(transactionSummary->keyPath, true)) { + if (btchip_context_D.called_from_swap) { + PRINTF("In swap mode only standart path is allowed\n"); sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; } + btchip_context_D.io_flags |= IO_ASYNCH_REPLY; + btchip_context_D.outputParsingState = BTCHIP_BIP44_CHANGE_PATH_VALIDATION; + btchip_bagl_request_change_path_approval(transactionSummary->keyPath); + } - if (p1 == FINALIZE_P1_CHANGEINFO) { - if (!btchip_context_D.transactionContext.firstSigned) { - // Already validated, should be prevented on the client side - return_OK: - CLOSE_TRY; - return BTCHIP_SW_OK; - } - if (!btchip_context_D.tmpCtx.output.changeAccepted) { - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - memset(transactionSummary, 0, - sizeof(btchip_transaction_summary_t)); - if (G_io_apdu_buffer[ISO_OFFSET_CDATA] == 0x00) { - // Called with no change path, abort, should be prevented on - // the client side - goto return_OK; - } - memmove(transactionSummary->keyPath, - G_io_apdu_buffer + ISO_OFFSET_CDATA, - MAX_BIP32_PATH_LENGTH); - - PRINTF("Change address = %.*H\n", 20, btchip_context_D.tmpCtx.output.changeAddress); - - btchip_context_D.tmpCtx.output.changeInitialized = 1; - btchip_context_D.tmpCtx.output.changeAccepted = 0; - - // if the bip44 change path provided is not canonical or its index are unsual, ask for user approval - if(bip44_derivation_guard(transactionSummary->keyPath, true)) { - if (btchip_context_D.called_from_swap) { - PRINTF("In swap mode only standart path is allowed\n"); - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_context_D.outputParsingState = BTCHIP_BIP44_CHANGE_PATH_VALIDATION; - btchip_bagl_request_change_path_approval(transactionSummary->keyPath); - } + goto return_OK; + } - goto return_OK; + // Always update the transaction & authorization hashes with the + // given data + // For SegWit, this has been reset to hold hashOutputs + if (!btchip_context_D.segwitParsedOnce) { + if ((int)(apduLength - hashOffset) < 0) { + sw = BTCHIP_SW_INCORRECT_DATA; + goto discardTransaction; + } + if (btchip_context_D.usingOverwinter) { + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, apduLength - hashOffset, NULL, 0)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; } - - // Always update the transaction & authorization hashes with the - // given data - // For SegWit, this has been reset to hold hashOutputs - if (!btchip_context_D.segwitParsedOnce) { - if ((int)(apduLength - hashOffset) < 0) { - sw = BTCHIP_SW_INCORRECT_DATA; - goto discardTransaction; - } - if (btchip_context_D.usingOverwinter) { - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, 0, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, apduLength - hashOffset, NULL, 0); - } - else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", apduLength - hashOffset, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset); - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, 0, + } + else { + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", apduLength - hashOffset, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset); + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, - apduLength - hashOffset, NULL, 0); - } + apduLength - hashOffset, NULL, 0)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; } + } + } - if (btchip_context_D.transactionContext.firstSigned) { - if ((btchip_context_D.currentOutputOffset + apduLength) > - sizeof(btchip_context_D.currentOutput)) { - PRINTF("Output is too long to be checked\n"); - sw = BTCHIP_SW_INCORRECT_DATA; - goto discardTransaction; - } - memmove(btchip_context_D.currentOutput + - btchip_context_D.currentOutputOffset, - G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength); - btchip_context_D.currentOutputOffset += apduLength; - - while (handle_output_state() && - (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) - ; - - // Finalize the TX if necessary - - if ((btchip_context_D.remainingOutputs == 0) && - (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) { - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_context_D.outputParsingState = - BTCHIP_OUTPUT_FINALIZE_TX; - } - } + if (btchip_context_D.transactionContext.firstSigned) { + if ((btchip_context_D.currentOutputOffset + apduLength) > + sizeof(btchip_context_D.currentOutput)) { + PRINTF("Output is too long to be checked\n"); + sw = BTCHIP_SW_INCORRECT_DATA; + goto discardTransaction; + } + memmove(btchip_context_D.currentOutput + + btchip_context_D.currentOutputOffset, + G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength); + btchip_context_D.currentOutputOffset += apduLength; - if (G_io_apdu_buffer[ISO_OFFSET_P1] == FINALIZE_P1_MORE) { - if (!btchip_context_D.usingSegwit) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", apduLength, G_io_apdu_buffer + ISO_OFFSET_CDATA); - cx_hash( + while (handle_output_state() && + (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) + ; + + // Finalize the TX if necessary + + if ((btchip_context_D.remainingOutputs == 0) && + (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) { + btchip_context_D.io_flags |= IO_ASYNCH_REPLY; + btchip_context_D.outputParsingState = + BTCHIP_OUTPUT_FINALIZE_TX; + } + } + + if (G_io_apdu_buffer[ISO_OFFSET_P1] == FINALIZE_P1_MORE) { + if (!btchip_context_D.usingSegwit) { + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", apduLength, G_io_apdu_buffer + ISO_OFFSET_CDATA); + if (cx_hash_no_throw( &btchip_context_D.transactionHashAuthorization.header, 0, G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength, - NULL, 0); - } - G_io_apdu_buffer[0] = 0x00; - btchip_context_D.outLength = 1; - btchip_context_D.tmpCtx.output.multipleOutput = 1; - goto return_OK; + NULL, 0)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; } + } + G_io_apdu_buffer[0] = 0x00; + btchip_context_D.outLength = 1; + btchip_context_D.tmpCtx.output.multipleOutput = 1; + goto return_OK; + } - if (!btchip_context_D.usingSegwit) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", apduLength, G_io_apdu_buffer + ISO_OFFSET_CDATA); - cx_hash(&btchip_context_D.transactionHashAuthorization.header, - CX_LAST, G_io_apdu_buffer + ISO_OFFSET_CDATA, - apduLength, authorizationHash, 32); - } + if (!btchip_context_D.usingSegwit) { + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", apduLength, G_io_apdu_buffer + ISO_OFFSET_CDATA); + if (cx_hash_no_throw(&btchip_context_D.transactionHashAuthorization.header, + CX_LAST, G_io_apdu_buffer + ISO_OFFSET_CDATA, + apduLength, authorizationHash, 32)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + } - if (btchip_context_D.usingSegwit) { - if (!btchip_context_D.segwitParsedOnce) { - if (btchip_context_D.usingOverwinter) { - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, btchip_context_D.segwit.cache.hashedOutputs, 0, btchip_context_D.segwit.cache.hashedOutputs, 32); - } - else { - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, + if (btchip_context_D.usingSegwit) { + if (!btchip_context_D.segwitParsedOnce) { + if (btchip_context_D.usingOverwinter) { + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, btchip_context_D.segwit.cache.hashedOutputs, 0, btchip_context_D.segwit.cache.hashedOutputs, 32)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + } + else { + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, btchip_context_D.segwit.cache.hashedOutputs, 0, - btchip_context_D.segwit.cache.hashedOutputs, 32); - cx_sha256_init(&btchip_context_D.transactionHashFull.sha256); - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, + btchip_context_D.segwit.cache.hashedOutputs, 32)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + if (cx_sha256_init_no_throw(&btchip_context_D.transactionHashFull.sha256)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, btchip_context_D.segwit.cache.hashedOutputs, sizeof(btchip_context_D.segwit.cache.hashedOutputs), - btchip_context_D.segwit.cache.hashedOutputs, 32); - } - PRINTF("hashOutputs\n%.*H\n",32,btchip_context_D.segwit.cache.hashedOutputs); - cx_hash( + btchip_context_D.segwit.cache.hashedOutputs, 32)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + } + PRINTF("hashOutputs\n%.*H\n",32,btchip_context_D.segwit.cache.hashedOutputs); + if (cx_hash_no_throw( &btchip_context_D.transactionHashAuthorization.header, - CX_LAST, G_io_apdu_buffer, 0, authorizationHash, 32); - PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); - } else { - cx_hash( + CX_LAST, G_io_apdu_buffer, 0, authorizationHash, 32)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); + } else { + if (cx_hash_no_throw( &btchip_context_D.transactionHashAuthorization.header, CX_LAST, (unsigned char *)&btchip_context_D.segwit.cache, sizeof(btchip_context_D.segwit.cache), - authorizationHash, 32); - PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); - } + authorizationHash, 32)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; } + PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); + } + } - if (btchip_context_D.transactionContext.firstSigned) { - if (!btchip_context_D.tmpCtx.output.changeInitialized) { - memset(transactionSummary, 0, - sizeof(btchip_transaction_summary_t)); - } + if (btchip_context_D.transactionContext.firstSigned) { + if (!btchip_context_D.tmpCtx.output.changeInitialized) { + memset(transactionSummary, 0, + sizeof(btchip_transaction_summary_t)); + } - transactionSummary->payToAddressVersion = - G_coin_config->p2pkh_version; - transactionSummary->payToScriptHashVersion = - G_coin_config->p2sh_version; + transactionSummary->payToAddressVersion = + G_coin_config->p2pkh_version; + transactionSummary->payToScriptHashVersion = + G_coin_config->p2sh_version; - // Generate new nonce + // Generate new nonce - cx_rng(transactionSummary->transactionNonce, 8); - } + cx_rng(transactionSummary->transactionNonce, 8); + } - G_io_apdu_buffer[0] = 0x00; - target++; + G_io_apdu_buffer[0] = 0x00; + target++; - *target = 0x00; - target++; + *target = 0x00; + target++; - btchip_context_D.outLength = (target - G_io_apdu_buffer); + btchip_context_D.outLength = (target - G_io_apdu_buffer); - // Check that the input being signed is part of the same - // transaction, otherwise abort - // (this is done to keep the transaction counter limit per session - // synchronized) - if (btchip_context_D.transactionContext.firstSigned) { - memmove(transactionSummary->authorizationHash, - authorizationHash, - sizeof(transactionSummary->authorizationHash)); - goto return_OK; - } else { - if (btchip_secure_memcmp( - authorizationHash, - transactionSummary->authorizationHash, - sizeof(transactionSummary->authorizationHash))) { - PRINTF("Authorization hash not matching, aborting\n"); - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; - discardTransaction: - CLOSE_TRY; - goto catch_discardTransaction; - } - } + // Check that the input being signed is part of the same + // transaction, otherwise abort + // (this is done to keep the transaction counter limit per session + // synchronized) + if (btchip_context_D.transactionContext.firstSigned) { + memmove(transactionSummary->authorizationHash, + authorizationHash, + sizeof(transactionSummary->authorizationHash)); + goto return_OK; + } else { + if (btchip_secure_memcmp( + authorizationHash, + transactionSummary->authorizationHash, + sizeof(transactionSummary->authorizationHash))) { + PRINTF("Authorization hash not matching, aborting\n"); + sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } - if (btchip_context_D.usingSegwit && + if (btchip_context_D.usingSegwit && !btchip_context_D.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - btchip_context_D.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; - } else { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_SIGN_READY; - } - sw = BTCHIP_SW_OK; - } - CATCH_ALL { - sw = SW_TECHNICAL_DETAILS(0x0F); - catch_discardTransaction: - ui_transaction_error(); + // This input cannot be signed when using segwit - just restart. + btchip_context_D.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; - btchip_context_D.outLength = 0; - - memmove(G_io_apdu_buffer, btchip_context_D.currentOutput, - btchip_context_D.currentOutputOffset); - btchip_context_D.outLength = btchip_context_D.currentOutputOffset; - } - FINALLY { - btchip_apdu_hash_input_finalize_full_reset(); - return sw; + } else { + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_SIGN_READY; } + sw = BTCHIP_SW_OK; } - END_TRY; + btchip_apdu_hash_input_finalize_full_reset(); + return sw; + +discardTransaction: + btchip_apdu_hash_input_finalize_full_reset(); + ui_transaction_error(); + btchip_context_D.transactionContext.transactionState = + BTCHIP_TRANSACTION_NONE; + btchip_context_D.outLength = 0; + + memmove(G_io_apdu_buffer, btchip_context_D.currentOutput, + btchip_context_D.currentOutputOffset); + btchip_context_D.outLength = btchip_context_D.currentOutputOffset; + return sw; } unsigned short btchip_apdu_hash_input_finalize_full() { diff --git a/src/btchip_apdu_hash_sign.c b/src/btchip_apdu_hash_sign.c index 9f0bb67a..d27722c1 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/btchip_apdu_hash_sign.c @@ -29,7 +29,7 @@ unsigned short btchip_apdu_hash_sign() { unsigned char dataBuffer[8]; unsigned char authorizationLength; unsigned char *parameters = G_io_apdu_buffer + ISO_OFFSET_CDATA; - unsigned short sw; + unsigned short sw = SW_TECHNICAL_DETAILS(0xF); SB_CHECK(N_btchip.bkp.config.operationMode); switch (SB_GET(N_btchip.bkp.config.operationMode)) { @@ -51,125 +51,116 @@ unsigned short btchip_apdu_hash_sign() { } // Check state - BEGIN_TRY { - TRY { - btchip_set_check_internal_structure_integrity(0); - - // Zcash special - store parameters for later - - if ((btchip_context_D.usingOverwinter) && - (!btchip_context_D.overwinterSignReady) && - (btchip_context_D.segwitParsedOnce) && - (btchip_context_D.transactionContext.transactionState == BTCHIP_TRANSACTION_NONE)) { - unsigned long int expiryHeight; - parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; - authorizationLength = *(parameters++); - parameters += authorizationLength; - lockTime = btchip_read_u32(parameters, 1, 0); - parameters += 4; - sighashType = *(parameters++); - expiryHeight = btchip_read_u32(parameters, 1, 0); - btchip_write_u32_le(btchip_context_D.nLockTime, lockTime); - btchip_write_u32_le(btchip_context_D.sigHashType, sighashType); - btchip_write_u32_le(btchip_context_D.nExpiryHeight, expiryHeight); - btchip_context_D.overwinterSignReady = 1; - CLOSE_TRY; - return BTCHIP_SW_OK; - } + btchip_set_check_internal_structure_integrity(0); + + // Zcash special - store parameters for later + + if ((btchip_context_D.usingOverwinter) && + (!btchip_context_D.overwinterSignReady) && + (btchip_context_D.segwitParsedOnce) && + (btchip_context_D.transactionContext.transactionState == BTCHIP_TRANSACTION_NONE)) { + unsigned long int expiryHeight; + parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; + authorizationLength = *(parameters++); + parameters += authorizationLength; + lockTime = btchip_read_u32(parameters, 1, 0); + parameters += 4; + sighashType = *(parameters++); + expiryHeight = btchip_read_u32(parameters, 1, 0); + btchip_write_u32_le(btchip_context_D.nLockTime, lockTime); + btchip_write_u32_le(btchip_context_D.sigHashType, sighashType); + btchip_write_u32_le(btchip_context_D.nExpiryHeight, expiryHeight); + btchip_context_D.overwinterSignReady = 1; + return BTCHIP_SW_OK; + } - if (btchip_context_D.transactionContext.transactionState != - BTCHIP_TRANSACTION_SIGN_READY) { - PRINTF("Invalid transaction state %d\n", btchip_context_D.transactionContext.transactionState); - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } + if (btchip_context_D.transactionContext.transactionState != + BTCHIP_TRANSACTION_SIGN_READY) { + PRINTF("Invalid transaction state %d\n", btchip_context_D.transactionContext.transactionState); + sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } - if (btchip_context_D.usingOverwinter && !btchip_context_D.overwinterSignReady) { - PRINTF("Overwinter not ready to sign\n"); - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } + if (btchip_context_D.usingOverwinter && !btchip_context_D.overwinterSignReady) { + PRINTF("Overwinter not ready to sign\n"); + sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } - // Read parameters - if (G_io_apdu_buffer[ISO_OFFSET_CDATA] > MAX_BIP32_PATH) { - sw = BTCHIP_SW_INCORRECT_DATA; - discardTransaction: - CLOSE_TRY; - goto catch_discardTransaction; - } - memmove(btchip_context_D.transactionSummary.keyPath, - G_io_apdu_buffer + ISO_OFFSET_CDATA, - MAX_BIP32_PATH_LENGTH); - parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; - authorizationLength = *(parameters++); - parameters += authorizationLength; - lockTime = btchip_read_u32(parameters, 1, 0); - parameters += 4; - sighashType = *(parameters++); - btchip_context_D.transactionSummary.sighashType = sighashType; - - if (((N_btchip.bkp.config.options & - BTCHIP_OPTION_FREE_SIGHASHTYPE) == 0)) { - // if bitcoin cash OR forkid is set, then use the fork id - if (G_coin_config->kind == COIN_KIND_BITCOIN_CASH || - (G_coin_config->forkid)) { + // Read parameters + if (G_io_apdu_buffer[ISO_OFFSET_CDATA] > MAX_BIP32_PATH) { + sw = BTCHIP_SW_INCORRECT_DATA; + goto discardTransaction; + } + memmove(btchip_context_D.transactionSummary.keyPath, + G_io_apdu_buffer + ISO_OFFSET_CDATA, + MAX_BIP32_PATH_LENGTH); + parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; + authorizationLength = *(parameters++); + parameters += authorizationLength; + lockTime = btchip_read_u32(parameters, 1, 0); + parameters += 4; + sighashType = *(parameters++); + btchip_context_D.transactionSummary.sighashType = sighashType; + + if (((N_btchip.bkp.config.options & + BTCHIP_OPTION_FREE_SIGHASHTYPE) == 0)) { + // if bitcoin cash OR forkid is set, then use the fork id + if (G_coin_config->kind == COIN_KIND_BITCOIN_CASH || + (G_coin_config->forkid)) { #define SIGHASH_FORKID 0x40 - if (sighashType != (SIGHASH_ALL | SIGHASH_FORKID)) { - sw = BTCHIP_SW_INCORRECT_DATA; - goto discardTransaction; - } - sighashType |= (G_coin_config->forkid << 8); - } else { - if (sighashType != SIGHASH_ALL) { - sw = BTCHIP_SW_INCORRECT_DATA; - goto discardTransaction; - } - } - } - - // Finalize the hash - if (!btchip_context_D.usingOverwinter) { - btchip_write_u32_le(dataBuffer, lockTime); - btchip_write_u32_le(dataBuffer + 4, sighashType); - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(dataBuffer), dataBuffer); - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, 0, - dataBuffer, sizeof(dataBuffer), NULL, 0); - } - - // Check if the path needs to be enforced - if (!enforce_bip44_coin_type(btchip_context_D.transactionSummary.keyPath, false)) { - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_bagl_request_sign_path_approval(btchip_context_D.transactionSummary.keyPath); - } - else { - // Sign immediately - btchip_bagl_user_action_signtx(1, 1); + if (sighashType != (SIGHASH_ALL | SIGHASH_FORKID)) { + sw = BTCHIP_SW_INCORRECT_DATA; + goto discardTransaction; } - sw = BTCHIP_SW_OK; - if (btchip_context_D.called_from_swap) { - // if we signed all outputs we should exit, - // but only after sending response, so lets raise the - // vars.swap_data.should_exit flag and check it on timer later - vars.swap_data.alreadySignedInputs++; - if (vars.swap_data.alreadySignedInputs >= vars.swap_data.totalNumberOfInputs) { - vars.swap_data.should_exit = 1; - } + sighashType |= (G_coin_config->forkid << 8); + } else { + if (sighashType != SIGHASH_ALL) { + sw = BTCHIP_SW_INCORRECT_DATA; + goto discardTransaction; } - - // Then discard the transaction and reply } - CATCH_ALL { - sw = SW_TECHNICAL_DETAILS(0xF); - catch_discardTransaction: - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + } + + // Finalize the hash + if (!btchip_context_D.usingOverwinter) { + btchip_write_u32_le(dataBuffer, lockTime); + btchip_write_u32_le(dataBuffer + 4, sighashType); + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(dataBuffer), dataBuffer); + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + dataBuffer, sizeof(dataBuffer), NULL, 0)) { + goto discardTransaction; } - FINALLY { - btchip_set_check_internal_structure_integrity(1); - return sw; + } + + // Check if the path needs to be enforced + if (!enforce_bip44_coin_type(btchip_context_D.transactionSummary.keyPath, false)) { + btchip_context_D.io_flags |= IO_ASYNCH_REPLY; + btchip_bagl_request_sign_path_approval(btchip_context_D.transactionSummary.keyPath); + } + else { + // Sign immediately + btchip_bagl_user_action_signtx(1, 1); + } + sw = BTCHIP_SW_OK; + if (btchip_context_D.called_from_swap) { + // if we signed all outputs we should exit, + // but only after sending response, so lets raise the + // vars.swap_data.should_exit flag and check it on timer later + vars.swap_data.alreadySignedInputs++; + if (vars.swap_data.alreadySignedInputs >= vars.swap_data.totalNumberOfInputs) { + vars.swap_data.should_exit = 1; } } - END_TRY; + + // Then discard the transaction and reply + btchip_set_check_internal_structure_integrity(1); + return sw; + + discardTransaction: + btchip_set_check_internal_structure_integrity(1); + btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; + return sw; } void btchip_bagl_user_action_signtx(unsigned char confirming, unsigned char direct) { From 1874bf224a0ed88714f64a793557ea539e5fac52 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 18 Jul 2023 15:54:51 +0200 Subject: [PATCH 37/85] btchip_apdu_sign_message: use no-throw api --- src/btchip_apdu_sign_message.c | 85 ++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index 531c9678..83b3cd12 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -120,18 +120,8 @@ unsigned short btchip_apdu_sign_message_internal() { goto discard; } btchip_context_D.hashedMessageLength = 0; - cx_sha256_init(&btchip_context_D.transactionHashFull.sha256); - cx_sha256_init( - &btchip_context_D.transactionHashAuthorization); chunkLength = strlen(G_coin_config->coinid) + SIGNMAGIC_LENGTH; - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, 0, - &chunkLength, 1, NULL, 0); - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, 0, - (uint8_t *)G_coin_config->coinid, - strlen(G_coin_config->coinid), NULL, 0); - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, 0, - (unsigned char *)SIGNMAGIC, SIGNMAGIC_LENGTH, NULL, 0); if (btchip_context_D.transactionSummary.messageLength < 0xfd) { messageLength[0] = @@ -148,8 +138,6 @@ unsigned short btchip_apdu_sign_message_internal() { 0xff); messageLengthSize = 3; } - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, 0, - messageLength, messageLengthSize, NULL, 0); chunkLength = apduLength - (offset - ISO_OFFSET_CDATA); if ((btchip_context_D.hashedMessageLength + chunkLength) > btchip_context_D.transactionSummary.messageLength) { @@ -158,11 +146,42 @@ unsigned short btchip_apdu_sign_message_internal() { CLOSE_TRY; goto discard; } - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, 0, - G_io_apdu_buffer + offset, chunkLength, NULL, 0); - cx_hash( + if (cx_sha256_init_no_throw(&btchip_context_D.transactionHashFull.sha256)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discard; + } + if (cx_sha256_init_no_throw( + &btchip_context_D.transactionHashAuthorization)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discard; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + &chunkLength, 1, NULL, 0)) { + goto discard; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + (uint8_t *)G_coin_config->coinid, + strlen(G_coin_config->coinid), NULL, 0)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discard; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + (unsigned char *)SIGNMAGIC, SIGNMAGIC_LENGTH, NULL, 0)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discard; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + messageLength, messageLengthSize, NULL, 0)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discard; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + G_io_apdu_buffer + offset, chunkLength, NULL, 0)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discard; + } + if (cx_hash_no_throw( &btchip_context_D.transactionHashAuthorization.header, - 0, G_io_apdu_buffer + offset, chunkLength, NULL, 0); btchip_context_D.hashedMessageLength += chunkLength; G_io_apdu_buffer[0] = 0x00; if (btchip_context_D.hashedMessageLength == @@ -180,11 +199,17 @@ unsigned short btchip_apdu_sign_message_internal() { CLOSE_TRY; goto discard; } - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, 0, - G_io_apdu_buffer + offset, apduLength, NULL, 0); - cx_hash( + 0, G_io_apdu_buffer + offset, chunkLength, NULL, 0)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discard; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + G_io_apdu_buffer + offset, apduLength, NULL, 0)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discard; + } + if (cx_hash_no_throw( &btchip_context_D.transactionHashAuthorization.header, - 0, G_io_apdu_buffer + offset, apduLength, NULL, 0); btchip_context_D.hashedMessageLength += apduLength; G_io_apdu_buffer[0] = 0x00; if (btchip_context_D.hashedMessageLength == @@ -195,6 +220,10 @@ unsigned short btchip_apdu_sign_message_internal() { btchip_context_D.outLength = 1; } } + 0, G_io_apdu_buffer + offset, apduLength, NULL, 0)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discard; + } } else { if ((btchip_context_D.transactionSummary.messageLength == 0) || (btchip_context_D.hashedMessageLength != @@ -246,17 +275,23 @@ unsigned short btchip_compute_hash() { btchip_context_D.outLength = 0; BEGIN_TRY { TRY { - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, hash, - 0, hash, 32); - cx_sha256_init(&btchip_context_D.transactionHashFull.sha256); - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, hash, - 32, hash, 32); btchip_context_D.outLength = G_io_apdu_buffer[1] + 2; } CATCH_ALL { sw = SW_TECHNICAL_DETAILS(0x0F); } FINALLY { + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, hash, + 0, hash, 32)) { + goto discard; + } + if (cx_sha256_init_no_throw(&btchip_context_D.transactionHashFull.sha256)) { + goto discard; + } + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, hash, + 32, hash, 32)) { + goto discard; + } if (btchip_private_derive_keypair( btchip_context_D.transactionSummary.keyPath, 0, NULL, &private_key, NULL)) { From 20722a4dc389f2b9f739c086eb8637586393f6be Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 18 Jul 2023 15:56:14 +0200 Subject: [PATCH 38/85] btchip_apdu_sign_message: remove try/catch --- src/btchip_apdu_sign_message.c | 237 +++++++++++++++------------------ 1 file changed, 108 insertions(+), 129 deletions(-) diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index 83b3cd12..9f1ca06f 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -79,73 +79,43 @@ unsigned short btchip_apdu_sign_message_internal() { return BTCHIP_SW_SECURITY_STATUS_NOT_SATISFIED; } - BEGIN_TRY { - TRY { - if (p1 == P1_PREPARE) { - if ((p2 == P2_FIRST) || (p2 == P2_LEGACY)) { - unsigned char chunkLength; - unsigned char messageLength[3]; - unsigned char messageLengthSize; - memset(&btchip_context_D.transactionSummary, 0, - sizeof(btchip_transaction_summary_t)); - if (G_io_apdu_buffer[offset] > MAX_BIP32_PATH) { - PRINTF("Invalid path\n"); - sw = BTCHIP_SW_INCORRECT_DATA; - CLOSE_TRY; - goto discard; - } - btchip_context_D.transactionSummary.payToAddressVersion = - G_coin_config->p2pkh_version; - btchip_context_D.transactionSummary.payToScriptHashVersion = - G_coin_config->p2sh_version; - memmove( - btchip_context_D.transactionSummary.keyPath, - G_io_apdu_buffer + offset, MAX_BIP32_PATH_LENGTH); - offset += (4 * G_io_apdu_buffer[offset]) + 1; - if (p2 == P2_LEGACY) { - btchip_context_D.transactionSummary.messageLength = - G_io_apdu_buffer[offset]; - offset++; - } else { - btchip_context_D.transactionSummary.messageLength = - (G_io_apdu_buffer[offset] << 8) | - (G_io_apdu_buffer[offset + 1]); - offset += 2; - } - if (btchip_context_D.transactionSummary.messageLength == - 0) { - PRINTF("Null message length\n"); - sw = BTCHIP_SW_INCORRECT_DATA; - CLOSE_TRY; - goto discard; - } - btchip_context_D.hashedMessageLength = 0; - chunkLength = - strlen(G_coin_config->coinid) + SIGNMAGIC_LENGTH; - if (btchip_context_D.transactionSummary.messageLength < - 0xfd) { - messageLength[0] = - btchip_context_D.transactionSummary.messageLength; - messageLengthSize = 1; - } else { - messageLength[0] = 0xfd; - messageLength[1] = - (btchip_context_D.transactionSummary.messageLength & - 0xff); - messageLength[2] = ((btchip_context_D.transactionSummary - .messageLength >> - 8) & - 0xff); - messageLengthSize = 3; - } - chunkLength = apduLength - (offset - ISO_OFFSET_CDATA); - if ((btchip_context_D.hashedMessageLength + chunkLength) > - btchip_context_D.transactionSummary.messageLength) { - PRINTF("Invalid data length\n"); - sw = BTCHIP_SW_INCORRECT_DATA; - CLOSE_TRY; - goto discard; - } + if (p1 == P1_PREPARE) { + if ((p2 == P2_FIRST) || (p2 == P2_LEGACY)) { + unsigned char chunkLength; + unsigned char messageLength[3]; + unsigned char messageLengthSize; + memset(&btchip_context_D.transactionSummary, 0, + sizeof(btchip_transaction_summary_t)); + if (G_io_apdu_buffer[offset] > MAX_BIP32_PATH) { + PRINTF("Invalid path\n"); + sw = BTCHIP_SW_INCORRECT_DATA; + goto discard; + } + btchip_context_D.transactionSummary.payToAddressVersion = + G_coin_config->p2pkh_version; + btchip_context_D.transactionSummary.payToScriptHashVersion = + G_coin_config->p2sh_version; + memmove( + btchip_context_D.transactionSummary.keyPath, + G_io_apdu_buffer + offset, MAX_BIP32_PATH_LENGTH); + offset += (4 * G_io_apdu_buffer[offset]) + 1; + if (p2 == P2_LEGACY) { + btchip_context_D.transactionSummary.messageLength = + G_io_apdu_buffer[offset]; + offset++; + } else { + btchip_context_D.transactionSummary.messageLength = + (G_io_apdu_buffer[offset] << 8) | + (G_io_apdu_buffer[offset + 1]); + offset += 2; + } + if (btchip_context_D.transactionSummary.messageLength == + 0) { + PRINTF("Null message length\n"); + sw = BTCHIP_SW_INCORRECT_DATA; + goto discard; + } + btchip_context_D.hashedMessageLength = 0; if (cx_sha256_init_no_throw(&btchip_context_D.transactionHashFull.sha256)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; @@ -155,6 +125,8 @@ unsigned short btchip_apdu_sign_message_internal() { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } + chunkLength = + strlen(G_coin_config->coinid) + SIGNMAGIC_LENGTH; if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, &chunkLength, 1, NULL, 0)) { goto discard; @@ -170,11 +142,34 @@ unsigned short btchip_apdu_sign_message_internal() { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } + if (btchip_context_D.transactionSummary.messageLength < + 0xfd) { + messageLength[0] = + btchip_context_D.transactionSummary.messageLength; + messageLengthSize = 1; + } else { + messageLength[0] = 0xfd; + messageLength[1] = + (btchip_context_D.transactionSummary.messageLength & + 0xff); + messageLength[2] = ((btchip_context_D.transactionSummary + .messageLength >> + 8) & + 0xff); + messageLengthSize = 3; + } if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, messageLength, messageLengthSize, NULL, 0)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } + chunkLength = apduLength - (offset - ISO_OFFSET_CDATA); + if ((btchip_context_D.hashedMessageLength + chunkLength) > + btchip_context_D.transactionSummary.messageLength) { + PRINTF("Invalid data length\n"); + sw = BTCHIP_SW_INCORRECT_DATA; + goto discard; + } if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, G_io_apdu_buffer + offset, chunkLength, NULL, 0)) { sw = SW_TECHNICAL_DETAILS(0x0F); @@ -182,27 +177,26 @@ unsigned short btchip_apdu_sign_message_internal() { } if (cx_hash_no_throw( &btchip_context_D.transactionHashAuthorization.header, - btchip_context_D.hashedMessageLength += chunkLength; - G_io_apdu_buffer[0] = 0x00; - if (btchip_context_D.hashedMessageLength == - btchip_context_D.transactionSummary.messageLength) { - G_io_apdu_buffer[1] = 0x00; - btchip_context_D.outLength = 2; - } else { - btchip_context_D.outLength = 1; - } - } else { - if ((btchip_context_D.hashedMessageLength + apduLength) > - btchip_context_D.transactionSummary.messageLength) { - PRINTF("Invalid data length\n"); - sw = BTCHIP_SW_INCORRECT_DATA; - CLOSE_TRY; - goto discard; - } 0, G_io_apdu_buffer + offset, chunkLength, NULL, 0)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } + btchip_context_D.hashedMessageLength += chunkLength; + G_io_apdu_buffer[0] = 0x00; + if (btchip_context_D.hashedMessageLength == + btchip_context_D.transactionSummary.messageLength) { + G_io_apdu_buffer[1] = 0x00; + btchip_context_D.outLength = 2; + } else { + btchip_context_D.outLength = 1; + } + } else { + if ((btchip_context_D.hashedMessageLength + apduLength) > + btchip_context_D.transactionSummary.messageLength) { + PRINTF("Invalid data length\n"); + sw = BTCHIP_SW_INCORRECT_DATA; + goto discard; + } if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, G_io_apdu_buffer + offset, apduLength, NULL, 0)) { sw = SW_TECHNICAL_DETAILS(0x0F); @@ -210,50 +204,41 @@ unsigned short btchip_apdu_sign_message_internal() { } if (cx_hash_no_throw( &btchip_context_D.transactionHashAuthorization.header, - btchip_context_D.hashedMessageLength += apduLength; - G_io_apdu_buffer[0] = 0x00; - if (btchip_context_D.hashedMessageLength == - btchip_context_D.transactionSummary.messageLength) { - G_io_apdu_buffer[1] = 0x00; - btchip_context_D.outLength = 2; - } else { - btchip_context_D.outLength = 1; - } - } 0, G_io_apdu_buffer + offset, apduLength, NULL, 0)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } + btchip_context_D.hashedMessageLength += apduLength; + G_io_apdu_buffer[0] = 0x00; + if (btchip_context_D.hashedMessageLength == + btchip_context_D.transactionSummary.messageLength) { + G_io_apdu_buffer[1] = 0x00; + btchip_context_D.outLength = 2; } else { - if ((btchip_context_D.transactionSummary.messageLength == 0) || - (btchip_context_D.hashedMessageLength != - btchip_context_D.transactionSummary.messageLength)) { - PRINTF("Invalid length to sign\n"); - sw = BTCHIP_SW_INCORRECT_DATA; - CLOSE_TRY; - goto discard; - } - if (checkBitId(btchip_context_D.transactionSummary.keyPath) != BITID_NONE) { - sw = btchip_compute_hash(); - } else { - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - CLOSE_TRY; - return BTCHIP_SW_OK; - } + btchip_context_D.outLength = 1; } } - CATCH_ALL { - sw = SW_TECHNICAL_DETAILS(0x0F); + } else { + if ((btchip_context_D.transactionSummary.messageLength == 0) || + (btchip_context_D.hashedMessageLength != + btchip_context_D.transactionSummary.messageLength)) { + PRINTF("Invalid length to sign\n"); + sw = BTCHIP_SW_INCORRECT_DATA; + goto discard; } - discard : { - memset(&btchip_context_D.transactionSummary, 0, - sizeof(btchip_transaction_summary_t)); - } - FINALLY { - return sw; + if (checkBitId(btchip_context_D.transactionSummary.keyPath) != BITID_NONE) { + sw = btchip_compute_hash(); + } else { + btchip_context_D.io_flags |= IO_ASYNCH_REPLY; + return BTCHIP_SW_OK; } } - END_TRY; + return sw; + + discard : + memset(&btchip_context_D.transactionSummary, 0, + sizeof(btchip_transaction_summary_t)); + return sw; } unsigned short btchip_apdu_sign_message() { @@ -273,14 +258,6 @@ unsigned short btchip_compute_hash() { cx_ecfp_private_key_t private_key; btchip_context_D.outLength = 0; - BEGIN_TRY { - TRY { - btchip_context_D.outLength = G_io_apdu_buffer[1] + 2; - } - CATCH_ALL { - sw = SW_TECHNICAL_DETAILS(0x0F); - } - FINALLY { if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, hash, 0, hash, 32)) { goto discard; @@ -303,12 +280,14 @@ unsigned short btchip_compute_hash() { G_io_apdu_buffer, &out_len, // OUT ((N_btchip.bkp.config.options & BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); + btchip_context_D.outLength = G_io_apdu_buffer[1] + 2; memset(&btchip_context_D.transactionSummary, 0, sizeof(btchip_transaction_summary_t)); - } - } - END_TRY; return sw; + + discard: + sw = SW_TECHNICAL_DETAILS(0x0F); + return sw; } void btchip_bagl_user_action_message_signing(unsigned char confirming) { From 4c614319f87fe74f0342bf87b499fe6b677921b7 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 18 Jul 2023 16:59:52 +0200 Subject: [PATCH 39/85] crypto calls: use no throw api --- src/btchip_apdu_get_trusted_input.c | 6 ++++-- src/btchip_apdu_hash_sign.c | 8 ++++---- src/btchip_helpers.c | 10 +++++----- src/main.c | 6 ++++-- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/btchip_apdu_get_trusted_input.c b/src/btchip_apdu_get_trusted_input.c index a5b3d6d9..e550c7a8 100644 --- a/src/btchip_apdu_get_trusted_input.c +++ b/src/btchip_apdu_get_trusted_input.c @@ -73,8 +73,10 @@ unsigned short btchip_apdu_get_trusted_input() { return BTCHIP_SW_INCORRECT_DATA; } - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, - (unsigned char *)NULL, 0, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32); + if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, + (unsigned char *)NULL, 0, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32)) { + return BTCHIP_SW_TECHNICAL_PROBLEM; + } // Otherwise prepare cx_rng(G_io_apdu_buffer, 8); diff --git a/src/btchip_apdu_hash_sign.c b/src/btchip_apdu_hash_sign.c index d27722c1..78613b87 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/btchip_apdu_hash_sign.c @@ -172,17 +172,17 @@ void btchip_bagl_user_action_signtx(unsigned char confirming, unsigned char dire // Fetch the private key btchip_private_derive_keypair(btchip_context_D.transactionSummary.keyPath, 0, NULL, &private_key, NULL); if (btchip_context_D.usingOverwinter) { - cx_hash(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, hash, 0, hash, 32); + cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, hash, 0, hash, 32); } else { cx_sha256_t localHash; - cx_hash(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, + cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, hash, 0, hash, 32); PRINTF("Hash1\n%.*H\n", sizeof(hash), hash); // Rehash - cx_sha256_init(&localHash); - cx_hash(&localHash.header, CX_LAST, hash, sizeof(hash), hash, 32); + cx_sha256_init_no_throw(&localHash); + cx_hash_no_throw(&localHash.header, CX_LAST, hash, sizeof(hash), hash, 32); } PRINTF("Hash2\n%.*H\n", sizeof(hash), hash); // Sign diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index fa3414b2..4eead266 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -213,7 +213,7 @@ void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, unsigned char buffer[32]; cx_hash_sha256(in, inlen, buffer, 32); cx_ripemd160_init(&riprip); - cx_hash(&riprip.header, CX_LAST, buffer, 32, out, 20); + cx_hash_no_throw(&riprip.header, CX_LAST, buffer, 32, out, 20); } void btchip_compute_checksum(unsigned char* in, unsigned short inlen, unsigned char * output) { @@ -278,10 +278,10 @@ unsigned short btchip_decode_base58_address(unsigned char *in, outlen = outputLen; // Compute hash to verify address - cx_sha256_init(&hash); - cx_hash(&hash.header, CX_LAST, out, outlen - 4, hashBuffer, 32); - cx_sha256_init(&hash); - cx_hash(&hash.header, CX_LAST, hashBuffer, 32, hashBuffer, 32); + cx_sha256_init_no_throw(&hash); + cx_hash_no_throw(&hash.header, CX_LAST, out, outlen - 4, hashBuffer, 32); + cx_sha256_init_no_throw(&hash); + cx_hash_no_throw(&hash.header, CX_LAST, hashBuffer, 32, hashBuffer, 32); if (memcmp(out + outlen - 4, hashBuffer, 4)) { PRINTF("Hash checksum mismatch\n%.*H\n",sizeof(hashBuffer),hashBuffer); diff --git a/src/main.c b/src/main.c index 607a68a9..7ca52aa4 100644 --- a/src/main.c +++ b/src/main.c @@ -316,8 +316,10 @@ uint8_t prepare_single_output() { uint8_t prepare_message_signature() { uint8_t buffer[32]; - cx_hash(&btchip_context_D.transactionHashAuthorization.header, CX_LAST, - (uint8_t*)vars.tmp.fullAmount, 0, buffer, 32); + if (cx_hash_no_throw(&btchip_context_D.transactionHashAuthorization.header, CX_LAST, + (uint8_t*)vars.tmp.fullAmount, 0, buffer, 32)) { + return 0; + } format_hex((const uint8_t*) vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress), (char*) buffer, sizeof(buffer)); return 1; From 2b98d5fb26c3a29758ece964f3e13cb3b9adb7f7 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 24 Jul 2023 17:00:15 +0200 Subject: [PATCH 40/85] [clean] remove HAVE_WALLET_ID_SDK related code --- Makefile | 4 ---- src/btchip.c | 53 ---------------------------------------------------- 2 files changed, 57 deletions(-) diff --git a/Makefile b/Makefile index a1e57a8a..652d58ff 100644 --- a/Makefile +++ b/Makefile @@ -254,10 +254,6 @@ else endif endif -ifeq ($(TARGET_NAME),TARGET_NANOS) -DEFINES += HAVE_WALLET_ID_SDK -endif - # Enabling debug PRINTF DEBUG ?= 0 ifneq ($(DEBUG),0) diff --git a/src/btchip.c b/src/btchip.c index fcaa8d4f..3b7eb229 100644 --- a/src/btchip.c +++ b/src/btchip.c @@ -27,38 +27,6 @@ #define BTCHIP_TECHNICAL_NOT_IMPLEMENTED 0x99 #define COMMON_CLA 0xB0 -#define COMMON_INS_GET_WALLET_ID 0x04 - -#ifndef HAVE_WALLET_ID_SDK - -unsigned int const U_os_perso_seed_cookie[] = { - 0xda7aba5e, - 0xc1a551c5, -}; - -int handleGetWalletId(volatile unsigned short *tx) { - unsigned char t[64]; - cx_ecfp_256_private_key_t priv; - cx_ecfp_256_public_key_t pub; - // seed => priv key - if (os_derive_bip32_no_throw(CX_CURVE_256K1, U_os_perso_seed_cookie, 2, t, NULL)) { - return -1; - } - // priv key => pubkey - cx_ecdsa_init_private_key(CX_CURVE_256K1, t, 32, &priv); - if (cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1, &pub, &priv, 1)) { - return -1; - } - // pubkey -> sha512 - cx_hash_sha512(pub.W, sizeof(pub.W), t, sizeof(t)); - // ! cookie ! - memmove(G_io_apdu_buffer, t, 64); - btchip_context_D.sw = 0x9000; - *tx = 64; - return 0; -} - -#endif // HAVE_WALLET_ID_SDK void app_dispatch(void) { unsigned char cla; @@ -69,17 +37,6 @@ void app_dispatch(void) { btchip_context_D.outLength = 0; btchip_context_D.io_flags = 0; -#ifndef HAVE_WALLET_ID_SDK - - if ((G_io_apdu_buffer[ISO_OFFSET_CLA] == COMMON_CLA) && (G_io_apdu_buffer[ISO_OFFSET_INS] == COMMON_INS_GET_WALLET_ID)) { - if (handleGetWalletId(&btchip_context_D.outLength)) { - goto fail; - } - goto sendSW; - } - -#endif - // If halted, then notify SB_CHECK(btchip_context_D.halted); if (SB_GET(btchip_context_D.halted)) { @@ -132,16 +89,6 @@ void app_dispatch(void) { (btchip_context_D.sw & 0xff); btchip_context_D.outLength += 2; return; - -#ifndef HAVE_WALLET_ID_SDK -fail: - // uncaught exception detected - G_io_apdu_buffer[0] = 0x6F; - btchip_context_D.outLength = 2; - G_io_apdu_buffer[1] = 0x00; - // we caught something suspicious - SB_SET(btchip_context_D.halted, 1); -#endif } void app_main(void) { From 086667035ba13245e5272ce54cd684c643294814 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 24 Jul 2023 17:24:09 +0200 Subject: [PATCH 41/85] [Clean]: btchip_apdu_get_trusted_input: remove useless cast --- src/btchip_apdu_get_trusted_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/btchip_apdu_get_trusted_input.c b/src/btchip_apdu_get_trusted_input.c index e550c7a8..38d6f644 100644 --- a/src/btchip_apdu_get_trusted_input.c +++ b/src/btchip_apdu_get_trusted_input.c @@ -74,7 +74,7 @@ unsigned short btchip_apdu_get_trusted_input() { } if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, - (unsigned char *)NULL, 0, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32)) { + NULL, 0, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32)) { return BTCHIP_SW_TECHNICAL_PROBLEM; } From 09cb67a988195d7c7fd446687e995cbc8d2560a4 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 24 Jul 2023 17:24:37 +0200 Subject: [PATCH 42/85] hash256: use single function instead of init and hash --- src/btchip_apdu_hash_sign.c | 4 +--- src/btchip_apdu_sign_message.c | 8 +++----- src/btchip_helpers.c | 8 +++----- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/btchip_apdu_hash_sign.c b/src/btchip_apdu_hash_sign.c index 78613b87..be2903f1 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/btchip_apdu_hash_sign.c @@ -175,14 +175,12 @@ void btchip_bagl_user_action_signtx(unsigned char confirming, unsigned char dire cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, hash, 0, hash, 32); } else { - cx_sha256_t localHash; cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, hash, 0, hash, 32); PRINTF("Hash1\n%.*H\n", sizeof(hash), hash); // Rehash - cx_sha256_init_no_throw(&localHash); - cx_hash_no_throw(&localHash.header, CX_LAST, hash, sizeof(hash), hash, 32); + cx_hash_sha256(hash, sizeof(hash), hash, 32); } PRINTF("Hash2\n%.*H\n", sizeof(hash), hash); // Sign diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index 9f1ca06f..3e794f82 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -262,13 +262,11 @@ unsigned short btchip_compute_hash() { 0, hash, 32)) { goto discard; } - if (cx_sha256_init_no_throw(&btchip_context_D.transactionHashFull.sha256)) { - goto discard; - } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, hash, - 32, hash, 32)) { + + if (cx_hash_sha256(hash, sizeof(hash), hash, 32)) { goto discard; } + if (btchip_private_derive_keypair( btchip_context_D.transactionSummary.keyPath, 0, NULL, &private_key, NULL)) { diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index 4eead266..c8c75957 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -270,7 +270,6 @@ unsigned short btchip_decode_base58_address(unsigned char *in, unsigned char *out, unsigned short outlen) { unsigned char hashBuffer[32]; - cx_sha256_t hash; size_t outputLen = outlen; if (btchip_decode_base58((char *)in, inlen, out, &outputLen) < 0) { THROW(EXCEPTION); @@ -278,10 +277,9 @@ unsigned short btchip_decode_base58_address(unsigned char *in, outlen = outputLen; // Compute hash to verify address - cx_sha256_init_no_throw(&hash); - cx_hash_no_throw(&hash.header, CX_LAST, out, outlen - 4, hashBuffer, 32); - cx_sha256_init_no_throw(&hash); - cx_hash_no_throw(&hash.header, CX_LAST, hashBuffer, 32, hashBuffer, 32); + cx_hash_sha256(out, outlen - 4, hashBuffer, 32); + + cx_hash_sha256(hashBuffer, 32, hashBuffer, 32); if (memcmp(out + outlen - 4, hashBuffer, 4)) { PRINTF("Hash checksum mismatch\n%.*H\n",sizeof(hashBuffer),hashBuffer); From c2a3d3c108f60a4fa18f36e03c4138df8094dd91 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 26 Jul 2023 19:37:48 +0200 Subject: [PATCH 43/85] btchip_sign_finalhash: use path instead of private key to generate signature --- Makefile | 2 +- include/btchip_helpers.h | 2 +- src/btchip_apdu_get_wallet_public_key.c | 2 +- src/btchip_apdu_hash_input_finalize_full.c | 5 ++-- src/btchip_apdu_hash_sign.c | 4 ++- src/btchip_apdu_sign_message.c | 4 ++- src/btchip_helpers.c | 34 +++++++++++++++++----- 7 files changed, 38 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 652d58ff..852c0a39 100644 --- a/Makefile +++ b/Makefile @@ -301,7 +301,7 @@ include $(BOLOS_SDK)/Makefile.glyphs APP_SOURCE_PATH += src APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/format.c -INCLUDES_PATH += ${BOLOS_SDK} +APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/crypto_helpers.c SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f ifneq ($(TARGET_NAME),TARGET_STAX) diff --git a/include/btchip_helpers.h b/include/btchip_helpers.h index 85eec799..309d6117 100644 --- a/include/btchip_helpers.h +++ b/include/btchip_helpers.h @@ -81,7 +81,7 @@ unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned cha void btchip_swap_bytes(unsigned char *target, unsigned char *source, unsigned char size); -void btchip_sign_finalhash(void *keyContext, +int btchip_sign_finalhash(unsigned char *path, size_t path_len, unsigned char *in, unsigned short inlen, unsigned char *out, size_t* outlen, unsigned char rfc6979); diff --git a/src/btchip_apdu_get_wallet_public_key.c b/src/btchip_apdu_get_wallet_public_key.c index 9b84ac5b..7b2ad10d 100644 --- a/src/btchip_apdu_get_wallet_public_key.c +++ b/src/btchip_apdu_get_wallet_public_key.c @@ -119,7 +119,7 @@ unsigned short btchip_apdu_get_wallet_public_key() { unsigned char bip44_enforced = enforce_bip44_coin_type(G_io_apdu_buffer + ISO_OFFSET_CDATA, true); G_io_apdu_buffer[0] = 65; - keyLength = get_public_key_chain_code(G_io_apdu_buffer + ISO_OFFSET_CDATA, uncompressedPublicKeys, G_io_apdu_buffer + 1, chainCode); + keyLength = get_public_key_chain_code(G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH, uncompressedPublicKeys, G_io_apdu_buffer + 1, chainCode); if (keyLength == 0) { return BTCHIP_SW_TECHNICAL_PROBLEM; diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index 02328bad..7cedcb23 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -22,6 +22,7 @@ #include "btchip_apdu_constants.h" #include "btchip_bagl_extensions.h" #include "ui.h" +#include "lib_standard_app/crypto_helpers.h" #define FINALIZE_P1_MORE 0x00 #define FINALIZE_P1_LAST 0x80 @@ -228,7 +229,7 @@ int get_public_key(unsigned char* keyPath, cx_ecfp_public_key_t* public_key) { } // out should be 32 bytes, even only 20 bytes is significant for output -int get_pubkey_hash160(unsigned char* keyPath, unsigned char* out) { +int get_pubkey_hash160(unsigned char* keyPath, size_t keyPath_len, unsigned char* out) { cx_ecfp_public_key_t public_key; int keyLength; if (get_public_key(keyPath, &public_key)) { @@ -307,7 +308,7 @@ unsigned short btchip_apdu_hash_input_finalize_full_internal( G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); - if (get_pubkey_hash160(transactionSummary->keyPath, btchip_context_D.tmpCtx.output.changeAddress)) { + if (get_pubkey_hash160(transactionSummary->keyPath, sizeof(transactionSummary->keyPath), btchip_context_D.tmpCtx.output.changeAddress)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discardTransaction; } diff --git a/src/btchip_apdu_hash_sign.c b/src/btchip_apdu_hash_sign.c index be2903f1..996724f4 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/btchip_apdu_hash_sign.c @@ -186,7 +186,9 @@ void btchip_bagl_user_action_signtx(unsigned char confirming, unsigned char dire // Sign size_t out_len = sizeof(G_io_apdu_buffer); btchip_sign_finalhash( - &private_key, hash, sizeof(hash), + btchip_context_D.transactionSummary.keyPath, + sizeof(btchip_context_D.transactionSummary.keyPath), + hash, sizeof(hash), G_io_apdu_buffer, &out_len, ((N_btchip.bkp.config.options & BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index 3e794f82..aaed9eaa 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -274,7 +274,9 @@ unsigned short btchip_compute_hash() { } size_t out_len = 100; btchip_sign_finalhash( - &private_key, hash, sizeof(hash), // IN + btchip_context_D.transactionSummary.keyPath, + sizeof(btchip_context_D.transactionSummary.keyPath), + hash, sizeof(hash), // IN G_io_apdu_buffer, &out_len, // OUT ((N_btchip.bkp.config.options & BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index c8c75957..f5cdf1e8 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -17,6 +17,7 @@ #include "btchip_internal.h" #include "btchip_apdu_constants.h" +#include "lib_standard_app/crypto_helpers.h" const unsigned char TRANSACTION_OUTPUT_SCRIPT_PRE[] = { 0x19, 0x76, 0xA9, @@ -481,19 +482,36 @@ void btchip_transaction_add_output(unsigned char *hash160Address, } -void btchip_sign_finalhash(void *keyContext, - unsigned char *in, unsigned short inlen, +int btchip_sign_finalhash(unsigned char* path, size_t path_len, unsigned char *in, unsigned short inlen, unsigned char *out, size_t* outlen, unsigned char rfc6979) { - io_seproxyhal_io_heartbeat(); unsigned int info = 0; - cx_ecdsa_sign_no_throw((cx_ecfp_private_key_t *)keyContext, - CX_LAST | (rfc6979 ? CX_RND_RFC6979 : CX_RND_TRNG), - CX_SHA256, in, inlen, out, outlen, &info); - if (info & CX_ECCINFO_PARITY_ODD) { - out[0] |= 0x01; + + io_seproxyhal_io_heartbeat(); + + bip32_path_t bip32Path; + bip32Path.length = path[0]; + + if (!parse_serialized_path(&bip32Path, path, path_len)) { + return -1; + } + + if (bip32_derive_ecdsa_sign_hash_256( + CX_CURVE_SECP256K1, + bip32Path.path, + bip32Path.length, + CX_LAST | (rfc6979 ? CX_RND_RFC6979 : CX_RND_TRNG), + CX_SHA256, + in, + inlen, + out, + outlen, + &info) != CX_OK) { + return -1; } io_seproxyhal_io_heartbeat(); + return 0; } + From cc2b72f7032225af872e5e757062edc29897caef Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 26 Jul 2023 19:39:36 +0200 Subject: [PATCH 44/85] btchip_get_public_key: derive public key directly from path --- include/btchip_ecc.h | 2 - include/btchip_helpers.h | 7 +-- src/btchip_apdu_get_wallet_public_key.c | 16 +++--- src/btchip_apdu_hash_input_finalize_full.c | 10 +--- src/btchip_helpers.c | 64 +++++++--------------- src/handle_check_address.c | 27 ++------- 6 files changed, 35 insertions(+), 91 deletions(-) diff --git a/include/btchip_ecc.h b/include/btchip_ecc.h index e6ada21c..de126401 100644 --- a/include/btchip_ecc.h +++ b/include/btchip_ecc.h @@ -21,8 +21,6 @@ #include "os.h" -#define BTCHIP_CURVE CX_CURVE_256K1 - void btchip_compress_public_key_value(unsigned char *value); #endif diff --git a/include/btchip_helpers.h b/include/btchip_helpers.h index 309d6117..21c67a6a 100644 --- a/include/btchip_helpers.h +++ b/include/btchip_helpers.h @@ -65,12 +65,6 @@ unsigned short btchip_decode_base58_address(unsigned char *in, unsigned char *out, unsigned short outlen); -int btchip_private_derive_keypair(unsigned char *bip32Path, - unsigned char derivePublic, - unsigned char *out_chainCode, - cx_ecfp_private_key_t * private_key, - cx_ecfp_public_key_t* public_key); - unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_path); unsigned char enforce_bip44_coin_type(unsigned char *bip32Path, bool for_pubkey); unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned char max_out_len); @@ -94,5 +88,6 @@ unsigned char btchip_secure_memcmp(const void *buf1, const void *buf2, unsigned char btchip_decrease_2fa(void); void btchip_reset_2fa(void); void btchip_reset_token(void); +int btchip_get_public_key(unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode); #endif diff --git a/src/btchip_apdu_get_wallet_public_key.c b/src/btchip_apdu_get_wallet_public_key.c index 7b2ad10d..74f49bea 100644 --- a/src/btchip_apdu_get_wallet_public_key.c +++ b/src/btchip_apdu_get_wallet_public_key.c @@ -24,23 +24,23 @@ #include "cashaddr.h" #include "btchip_apdu_get_wallet_public_key.h" -int get_public_key_chain_code(unsigned char* keyPath, bool uncompressedPublicKeys, unsigned char* publicKey, unsigned char* chainCode) { - cx_ecfp_private_key_t private_key; - cx_ecfp_public_key_t public_key; +int get_public_key_chain_code(unsigned char* keyPath, size_t keyPath_len, bool uncompressedPublicKeys, unsigned char* publicKey, unsigned char* chainCode) { + uint8_t public_key[65]; int keyLength = 0; - if (btchip_private_derive_keypair(keyPath, 1, chainCode, &private_key, &public_key)) { - return 0; + + if (btchip_get_public_key(keyPath, keyPath_len, public_key, chainCode)) { + return keyLength; } // Then encode it if (uncompressedPublicKeys) { keyLength = 65; } else { - btchip_compress_public_key_value(public_key.W); + btchip_compress_public_key_value(public_key); keyLength = 33; } - memmove(publicKey, public_key.W, - sizeof(public_key.W)); + memmove(publicKey, public_key, + sizeof(public_key)); return keyLength; } diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index 7cedcb23..8c12d49e 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -220,19 +220,11 @@ bool handle_output_state() { return processed; } -int get_public_key(unsigned char* keyPath, cx_ecfp_public_key_t* public_key) { - cx_ecfp_private_key_t private_key; - if (btchip_private_derive_keypair(keyPath, 1, NULL, &private_key, public_key)) { - return -1; - } - return 0; -} - // out should be 32 bytes, even only 20 bytes is significant for output int get_pubkey_hash160(unsigned char* keyPath, size_t keyPath_len, unsigned char* out) { cx_ecfp_public_key_t public_key; int keyLength; - if (get_public_key(keyPath, &public_key)) { + if (btchip_get_public_key(keyPath, keyPath_len, public_key.W, NULL)) { return -1; } if (((N_btchip.bkp.config.options & diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index f5cdf1e8..24c87ce4 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -290,49 +290,6 @@ unsigned short btchip_decode_base58_address(unsigned char *in, return outlen; } -int btchip_private_derive_keypair(unsigned char *bip32Path, - unsigned char derivePublic, - unsigned char *out_chainCode, - cx_ecfp_private_key_t * private_key, - cx_ecfp_public_key_t* public_key) { - unsigned char bip32PathLength; - unsigned char i; - union { - unsigned int bip32PathInt[MAX_BIP32_PATH]; - unsigned char privateComponent[64]; - } u; - - bip32PathLength = bip32Path[0]; - if (bip32PathLength > MAX_BIP32_PATH) { - THROW(INVALID_PARAMETER); - } - bip32Path++; - for (i = 0; i < bip32PathLength; i++) { - u.bip32PathInt[i] = btchip_read_u32(bip32Path, 1, 0); - bip32Path += 4; - } - - io_seproxyhal_io_heartbeat(); - - if (os_derive_bip32_no_throw(CX_CURVE_256K1, u.bip32PathInt, bip32PathLength, - u.privateComponent, out_chainCode)) { - return -1; - } - - cx_ecdsa_init_private_key(BTCHIP_CURVE, u.privateComponent, 32, - private_key); - - if (derivePublic) { - cx_ecfp_generate_pair_no_throw(BTCHIP_CURVE, public_key, - private_key, 1); - } - - io_seproxyhal_io_heartbeat(); - - memset(u.privateComponent, 0, sizeof(u.privateComponent)); - return 0; -} - /* Checks if the values of a derivation path are within "normal" (arbitrary) ranges: Account < 100, change == 1 or 0, address index < 50000 @@ -515,3 +472,24 @@ int btchip_sign_finalhash(unsigned char* path, size_t path_len, unsigned char *i return 0; } +int btchip_get_public_key(unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode) { + + bip32_path_t bip32Path; + + if (!parse_serialized_path(&bip32Path, keyPath, keyPath_len)) { + return -1; + } + + if (bip32_derive_get_pubkey_256( + CX_CURVE_SECP256K1, + bip32Path.path, + bip32Path.length, + raw_pubkey, + chainCode, + CX_SHA512) != CX_OK) + { + return -1; + } + + return 0; +} diff --git a/src/handle_check_address.c b/src/handle_check_address.c index c094e9ef..6ecbb3b0 100644 --- a/src/handle_check_address.c +++ b/src/handle_check_address.c @@ -8,37 +8,18 @@ #include "segwit_addr.h" #include -bool derive_private_key(unsigned char* serialized_path, unsigned char serialized_path_length, cx_ecfp_private_key_t* privKey) { - unsigned char privateComponent[64]; - bip32_path_t path; - if (!parse_serialized_path(&path, serialized_path, serialized_path_length)) { - PRINTF("Can't parse path\n"); - return false; - } - if (os_derive_bip32_no_throw(CX_CURVE_256K1, path.path, path.length, - privateComponent, NULL)) { - return false; - } - cx_ecdsa_init_private_key(BTCHIP_CURVE, privateComponent, 32, privKey); - return true; -} - - bool derive_compressed_public_key( unsigned char* serialized_path, unsigned char serialized_path_length, unsigned char* public_key, unsigned char public_key_length) { UNUSED(public_key_length); - cx_ecfp_private_key_t privKey; - if (!derive_private_key(serialized_path, serialized_path_length, &privKey)) - return false; - cx_ecfp_public_key_t pubKey; + uint8_t pubKey[65]; - if (cx_ecfp_generate_pair_no_throw(BTCHIP_CURVE, &pubKey, &privKey, 1)) { + if (btchip_get_public_key(serialized_path, serialized_path_length, pubKey, NULL)){ return false; } - btchip_compress_public_key_value(pubKey.W); - memcpy(public_key, pubKey.W, 33); + btchip_compress_public_key_value(pubKey); + memcpy(public_key, pubKey, 33); return true; } From 7815af31ed555b273c01ce51cc951d4dcb5c2bc8 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 26 Jul 2023 19:40:05 +0200 Subject: [PATCH 45/85] btchip_private_derive_keypair: remove useless calls --- src/btchip_apdu_hash_sign.c | 3 --- src/btchip_apdu_sign_message.c | 6 ------ 2 files changed, 9 deletions(-) diff --git a/src/btchip_apdu_hash_sign.c b/src/btchip_apdu_hash_sign.c index 996724f4..8e006af9 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/btchip_apdu_hash_sign.c @@ -164,13 +164,10 @@ unsigned short btchip_apdu_hash_sign() { } void btchip_bagl_user_action_signtx(unsigned char confirming, unsigned char direct) { - cx_ecfp_private_key_t private_key; unsigned short sw = BTCHIP_SW_OK; // confirm and finish the apdu exchange //spaghetti if (confirming) { unsigned char hash[32]; - // Fetch the private key - btchip_private_derive_keypair(btchip_context_D.transactionSummary.keyPath, 0, NULL, &private_key, NULL); if (btchip_context_D.usingOverwinter) { cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, hash, 0, hash, 32); } diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index aaed9eaa..cb40317a 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -255,7 +255,6 @@ unsigned short btchip_apdu_sign_message() { unsigned short btchip_compute_hash() { unsigned char hash[32]; unsigned short sw = BTCHIP_SW_OK; - cx_ecfp_private_key_t private_key; btchip_context_D.outLength = 0; if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, hash, @@ -267,11 +266,6 @@ unsigned short btchip_compute_hash() { goto discard; } - if (btchip_private_derive_keypair( - btchip_context_D.transactionSummary.keyPath, 0, - NULL, &private_key, NULL)) { - goto discard; - } size_t out_len = 100; btchip_sign_finalhash( btchip_context_D.transactionSummary.keyPath, From c3188578aa3c2496debd9e3b9ab171437f662991 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 26 Jul 2023 19:40:38 +0200 Subject: [PATCH 46/85] btchip_helpers: use function to parse serialized path --- src/btchip_helpers.c | 55 +++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index 24c87ce4..0829df7f 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -18,6 +18,7 @@ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #include "lib_standard_app/crypto_helpers.h" +#include "bip32_path.h" const unsigned char TRANSACTION_OUTPUT_SCRIPT_PRE[] = { 0x19, 0x76, 0xA9, @@ -296,39 +297,33 @@ Account < 100, change == 1 or 0, address index < 50000 Returns 1 if the path is unusual, or not compliant with BIP44*/ unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_path) { - unsigned char i, path_len; - unsigned int bip32PathInt[MAX_BIP32_PATH]; + unsigned char path_len; + bip32_path_t bip32PathInt; path_len = bip32Path[0]; - bip32Path++; - if (path_len > MAX_BIP32_PATH) { - THROW(INVALID_PARAMETER); - } - - for (i = 0; i < path_len; i++) { - bip32PathInt[i] = btchip_read_u32(bip32Path, 1, 0); - bip32Path += 4; + if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { + return 1; } // If the path length is not compliant with BIP44 or if the purpose don't match regular usage, return a warning if(path_len != BIP44_PATH_LEN || - ((bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) != 44 && - (bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) != 49 && - (bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) != 84)) { + ((bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 44 && + (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 49 && + (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 84)) { return 1; } // If the coin type doesn't match, return a warning if ((G_coin_config->bip44_coin_type != 0) && - (((bip32PathInt[BIP44_COIN_TYPE_OFFSET]^0x80000000) != G_coin_config->bip44_coin_type) && - ((bip32PathInt[BIP44_COIN_TYPE_OFFSET]^0x80000000) != G_coin_config->bip44_coin_type2))) { + (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != G_coin_config->bip44_coin_type) && + ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != G_coin_config->bip44_coin_type2))) { return 1; } // If the account or address index is very high or if the change isn't 1, return a warning - if((bip32PathInt[BIP44_ACCOUNT_OFFSET]^0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || - bip32PathInt[BIP44_CHANGE_OFFSET] != is_change_path?1:0 || - bip32PathInt[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { + if((bip32PathInt.path[BIP44_ACCOUNT_OFFSET]^0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || + bip32PathInt.path[BIP44_CHANGE_OFFSET] != is_change_path?1:0 || + bip32PathInt.path[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { return 1; } @@ -340,8 +335,7 @@ Only enforce the structure or coin type for consumed UTXOs or a public address Returns 0 if the path is non compliant, or 1 if compliant */ unsigned char enforce_bip44_coin_type(unsigned char *bip32Path, bool for_pubkey) { - unsigned char i, path_len; - unsigned int bip32PathInt[MAX_BIP32_PATH]; + bip32_path_t bip32PathInt; // No enforcement required if (G_coin_config->bip44_coin_type == 0) { return 1; @@ -351,26 +345,19 @@ unsigned char enforce_bip44_coin_type(unsigned char *bip32Path, bool for_pubkey) return for_pubkey; } - path_len = bip32Path[0]; - bip32Path++; - if (path_len > MAX_BIP32_PATH) { - THROW(INVALID_PARAMETER); - } - - for (i = 0; i < path_len; i++) { - bip32PathInt[i] = btchip_read_u32(bip32Path, 1, 0); - bip32Path += 4; + if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { + return 1; } // Path is not compliant with BIP 44 or derivatives - valid if not signing - if (!(((bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) == 44 || - (bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) == 49 || - (bip32PathInt[BIP44_PURPOSE_OFFSET]^0x80000000) == 84))) { + if (!(((bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 44 || + (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 49 || + (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 84))) { return for_pubkey; } - if (((bip32PathInt[BIP44_COIN_TYPE_OFFSET]^0x80000000) == G_coin_config->bip44_coin_type) || - ((bip32PathInt[BIP44_COIN_TYPE_OFFSET]^0x80000000) == G_coin_config->bip44_coin_type2)) { + if (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == G_coin_config->bip44_coin_type) || + ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == G_coin_config->bip44_coin_type2)) { // Valid BIP 44 path return 1; } From e818ad7cd90b50a5415a4aa12aa939821af8306d Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 4 Aug 2023 14:56:46 +0200 Subject: [PATCH 47/85] apdu_sign_message: cx_hash_sha256 fix return check --- src/btchip_apdu_sign_message.c | 2 +- src/btchip_helpers.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index cb40317a..00d596c0 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -262,7 +262,7 @@ unsigned short btchip_compute_hash() { goto discard; } - if (cx_hash_sha256(hash, sizeof(hash), hash, 32)) { + if (cx_hash_sha256(hash, sizeof(hash), hash, 32) == 0) { goto discard; } diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index 0829df7f..343ce74d 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -455,6 +455,11 @@ int btchip_sign_finalhash(unsigned char* path, size_t path_len, unsigned char *i return -1; } + // Store information about the parity of the 'y' coordinate + if (info & CX_ECCINFO_PARITY_ODD) { + out[0] |= 0x01; + } + io_seproxyhal_io_heartbeat(); return 0; } From b0d5fa00327578385255e5480c520fe861647ef0 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 4 Aug 2023 18:25:57 +0200 Subject: [PATCH 48/85] message signature: fix buffer --- src/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 7ca52aa4..4e0959d4 100644 --- a/src/main.c +++ b/src/main.c @@ -321,7 +321,8 @@ uint8_t prepare_message_signature() { return 0; } - format_hex((const uint8_t*) vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress), (char*) buffer, sizeof(buffer)); + format_hex((const uint8_t*) buffer, sizeof(buffer), vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress)); + return 1; } From 26914d5d6371090ecc5e5fcb23aca2743b8826c2 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 4 Aug 2023 18:28:01 +0200 Subject: [PATCH 49/85] tests: add sign message --- tests/automations/sign_message.json | 50 +++++++++++++++ tests/bitcoin_client/bitcoin_base_cmd.py | 40 ++++++++++++ tests/bitcoin_client/bitcoin_cmd_builder.py | 70 +++++++++++++++++++++ tests/test_sign_message.py | 13 ++++ 4 files changed, 173 insertions(+) create mode 100644 tests/automations/sign_message.json create mode 100644 tests/test_sign_message.py diff --git a/tests/automations/sign_message.json b/tests/automations/sign_message.json new file mode 100644 index 00000000..fa49d745 --- /dev/null +++ b/tests/automations/sign_message.json @@ -0,0 +1,50 @@ +{ + "version": 1, + "rules": [ + { + "regexp": "Tap to continue", + "actions": [ + ["finger", 55, 550, true], + ["finger", 55, 550, false] + ] + }, + { + "regexp": "Hold to sign", + "actions": [ + ["finger", 55, 550, true] + ] + }, + { + "regexp": "Message hash", + "actions": [ + ["button", 2, true], + ["button", 2, false] + ] + }, + { + "regexp": "[S]?ign", + "conditions": [ + [ "seen", false ] + ], + "actions": [ + ["setbool", "seen", true], + ["button", 2, true], + ["button", 2, false] + ] + }, + { + "regexp": "[S]?ign", + "conditions": [ + [ "seen", true ] + ], + "actions": [ + ["setbool", "seen", true], + [ "button", 1, true ], + [ "button", 2, true ], + [ "button", 2, false ], + [ "button", 1, false ] + + ] + } + ] +} diff --git a/tests/bitcoin_client/bitcoin_base_cmd.py b/tests/bitcoin_client/bitcoin_base_cmd.py index 5e71fde5..55605e2a 100644 --- a/tests/bitcoin_client/bitcoin_base_cmd.py +++ b/tests/bitcoin_client/bitcoin_base_cmd.py @@ -6,6 +6,7 @@ from bitcoin_client.hwi.serialization import CTransaction, hash256 from bitcoin_client.exception.device_exception import DeviceException from bitcoin_client.bitcoin_cmd_builder import AddrType, InsType, BitcoinCommandBuilder +import base64 class BitcoinBaseCommand: @@ -174,6 +175,45 @@ def get_public_key(self, return pub_key, addr, bip32_chain_code + def sign_message(self, + message: str, + bip32_path: str, + ) -> bytes: + """Sign message. + + Parameters + ---------- + bip32_path : str + BIP32 path to be used to sign. + message : str + Message to be signed + + Returns + ------- + bytes + Signature of the message + + """ + sw: int + response: bytes = b"" + + for chunk in self.builder.sign_message(bip32_path, message): + self.transport.send_raw(chunk) + sw, response = self.transport.recv() # type: int, bytes + + if sw != 0x9000: + raise DeviceException(error_code=sw, ins=InsType.SIGN_MESSAGE) + + sw, response = self.transport.exchange_raw( + self.builder.sign_message_sign() + ) + + if sw != 0x9000: + raise DeviceException(error_code=sw, ins=InsType.SIGN_MESSAGE) + + return base64.b64encode(response).decode('utf-8') + + def get_trusted_input(self, utxo: CTransaction, output_index: int) -> bytes: diff --git a/tests/bitcoin_client/bitcoin_cmd_builder.py b/tests/bitcoin_client/bitcoin_cmd_builder.py index baa95404..8279882d 100644 --- a/tests/bitcoin_client/bitcoin_cmd_builder.py +++ b/tests/bitcoin_client/bitcoin_cmd_builder.py @@ -19,6 +19,7 @@ class InsType(enum.IntEnum): UNTRUSTED_HASH_TRANSACTION_INPUT_START = 0x44 UNTRUSTED_HASH_TRANSACTION_INPUT_FINALIZE = 0x4A UNTRUSTED_HASH_SIGN = 0x48 + SIGN_MESSAGE = 0x4E class AddrType(enum.IntEnum): @@ -385,3 +386,72 @@ def untrusted_hash_sign(self, ]) return self.serialize(cla=self.CLA, ins=ins, p1=p1, p2=p2, cdata=cdata) + + + def sign_message(self, + sign_path: str, + message: str) -> Iterator[bytes]: + """Command builder for UNTRUSTED_HASH_SIGN. + + Parameters + ---------- + sign_path : str + BIP32 path to be used to sign. + lock_time : int + Block height or timestamp when transaction is final. + sig_hash : int + Either SIGHASH_ALL (0x01), SIGHASH_NONE (0x02) or SIGHASH_SINGLE (0x03). + Only SIGHASH_ALL (0x01) is supported. + + Yields + ------- + bytes + APDU command chunk for SIGN_MESSAGE. + + """ + ins: InsType = InsType.SIGN_MESSAGE + # P1: + # - 0x00, first transaction data chunk + # - 0x80, other transaction data chunk + p1: int + p2: int = 0x00 + + bip32_path: List[bytes] = bip32_path_from_string(sign_path) + cdata: bytes = b"".join([ + len(bip32_path).to_bytes(1, byteorder="big"), + *bip32_path, + len(message).to_bytes(1, byteorder="big"), # /!\ big instead of little + message.encode("utf-8") + ]) + + for i, (is_last, chunk) in enumerate(chunkify(cdata, MAX_APDU_LEN)): + p1 = 0x00 if i == 0 else 0x80 + if is_last: + yield self.serialize(cla=self.CLA, + ins=ins, + p1=p1, + p2=p2, + cdata=chunk) + return + yield self.serialize(cla=self.CLA, + ins=ins, + p1=p1, + p2=p2, + cdata=chunk) + + def sign_message_sign(self) -> bytes: + """Command builder for UNTRUSTED_HASH_SIGN. + + Parameters + ---------- + Returns + ------- + bytes + APDU command for SIGN_MESSAGE. + + """ + ins: InsType = InsType.SIGN_MESSAGE + p1: int = 0x80 + p2: int = 0x00 + + return self.serialize(cla=self.CLA, ins=ins, p1=p1, p2=p2, cdata=b"00") diff --git a/tests/test_sign_message.py b/tests/test_sign_message.py new file mode 100644 index 00000000..e4afd7d1 --- /dev/null +++ b/tests/test_sign_message.py @@ -0,0 +1,13 @@ +from bitcoin_client.bitcoin_base_cmd import AddrType +from utils import automation + + +@automation("automations/sign_message.json") +def test_sign_message(cmd): + result = cmd.sign_message( + message = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks.", + bip32_path = "m/44'/1'/0'/0/0" + ) + + assert result == "MUUCIQDkeGEVZZiRjMfh+z4ELx81gBdBwIK1IIEHkXZ6FiqcqQIgfaAberpvF+XbOCM5Cd/ljogNyU3w2OIL8eYCyZ6Ru2k=" + From 12c0035cce43a53e67b2940fe732ec556de02c46 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 4 Aug 2023 22:07:28 +0200 Subject: [PATCH 50/85] Makefile: Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 852c0a39..acb0cde0 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS) APPVERSION_M=2 APPVERSION_N=1 -APPVERSION_P=5 +APPVERSION_P=6 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APP_LOAD_FLAGS=--appFlags 0xa50 From 7e3a269e5305bc7fb35007549b265a0944784727 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 3 Aug 2023 10:37:18 +0200 Subject: [PATCH 51/85] QR code source path is now used explicitly --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index acb0cde0..523d94c8 100644 --- a/Makefile +++ b/Makefile @@ -242,6 +242,7 @@ endif ifeq ($(TARGET_NAME),TARGET_STAX) DEFINES += NBGL_QRCODE + SDK_SOURCE_PATH += qrcode else DEFINES += HAVE_BAGL HAVE_UX_FLOW ifneq ($(TARGET_NAME),TARGET_NANOS) From 7e2908c80821d597a9766c2567b8f7051b003a7a Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 26 Oct 2023 10:10:28 +0200 Subject: [PATCH 52/85] Makefile: remove COIN_COLOR_HDR and COIN_COLOR_DB --- Makefile | 60 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Makefile b/Makefile index 523d94c8..95d0c303 100644 --- a/Makefile +++ b/Makefile @@ -36,162 +36,162 @@ endif ifeq ($(COIN),bitcoin_testnet_legacy) # Bitcoin testnet -DEFINES += BIP44_COIN_TYPE=1 BIP44_COIN_TYPE_2=1 COIN_P2PKH_VERSION=111 COIN_P2SH_VERSION=196 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOIN\" COIN_COLOR_HDR=0xFCB653 COIN_COLOR_DB=0xFEDBA9 COIN_COINID_NAME=\"Bitcoin\" COIN_COINID_SHORT=\"TEST\" COIN_NATIVE_SEGWIT_PREFIX=\"tb\" COIN_KIND=COIN_KIND_BITCOIN_TESTNET COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +DEFINES += BIP44_COIN_TYPE=1 BIP44_COIN_TYPE_2=1 COIN_P2PKH_VERSION=111 COIN_P2SH_VERSION=196 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOIN\" COIN_COINID_NAME=\"Bitcoin\" COIN_COINID_SHORT=\"TEST\" COIN_NATIVE_SEGWIT_PREFIX=\"tb\" COIN_KIND=COIN_KIND_BITCOIN_TESTNET COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Bitcoin Test Legacy" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),bitcoin_legacy) # Bitcoin mainnet -DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=0 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOIN\" COIN_COLOR_HDR=0xFCB653 COIN_COLOR_DB=0xFEDBA9 COIN_COINID_NAME=\"Bitcoin\" COIN_COINID_SHORT=\"BTC\" COIN_NATIVE_SEGWIT_PREFIX=\"bc\" COIN_KIND=COIN_KIND_BITCOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=0 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOIN\" COIN_COINID_NAME=\"Bitcoin\" COIN_COINID_SHORT=\"BTC\" COIN_NATIVE_SEGWIT_PREFIX=\"bc\" COIN_KIND=COIN_KIND_BITCOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Bitcoin Legacy" APP_LOAD_PARAMS += --path $(APP_PATH) #LIB and global pin and else ifeq ($(COIN),bitcoin_cash) # Bitcoin cash # Initial fork from Bitcoin, public key access is authorized. Signature is different thanks to the forkId -DEFINES += BIP44_COIN_TYPE=145 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=0 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOINCASH\" COIN_COLOR_HDR=0x85bb65 COIN_COLOR_DB=0xc2ddb2 COIN_COINID_NAME=\"BitcoinCash\" COIN_COINID_SHORT=\"BCH\" COIN_KIND=COIN_KIND_BITCOIN_CASH COIN_FORKID=0 +DEFINES += BIP44_COIN_TYPE=145 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=0 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOINCASH\" COIN_COINID_NAME=\"BitcoinCash\" COIN_COINID_SHORT=\"BCH\" COIN_KIND=COIN_KIND_BITCOIN_CASH COIN_FORKID=0 APPNAME ="Bitcoin Cash" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),bitcoin_gold) # Bitcoin Gold # Initial fork from Bitcoin, public key access is authorized. Signature is different thanks to the forkId -DEFINES += BIP44_COIN_TYPE=156 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=23 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\\x20Gold\" COIN_COINID_HEADER=\"BITCOINGOLD\" COIN_COLOR_HDR=0x85bb65 COIN_COLOR_DB=0xc2ddb2 COIN_COINID_NAME=\"BitcoinGold\" COIN_COINID_SHORT=\"BTG\" COIN_KIND=COIN_KIND_BITCOIN_GOLD COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT COIN_FORKID=79 +DEFINES += BIP44_COIN_TYPE=156 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=23 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\\x20Gold\" COIN_COINID_HEADER=\"BITCOINGOLD\" COIN_COINID_NAME=\"BitcoinGold\" COIN_COINID_SHORT=\"BTG\" COIN_KIND=COIN_KIND_BITCOIN_GOLD COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT COIN_FORKID=79 APPNAME ="Bitcoin Gold" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),litecoin) # Litecoin -DEFINES += BIP44_COIN_TYPE=2 BIP44_COIN_TYPE_2=2 COIN_P2PKH_VERSION=48 COIN_P2SH_VERSION=50 COIN_FAMILY=1 COIN_COINID=\"Litecoin\" COIN_COINID_HEADER=\"LITECOIN\" COIN_COLOR_HDR=0xCCCCCC COIN_COLOR_DB=0xE6E6E6 COIN_COINID_NAME=\"Litecoin\" COIN_COINID_SHORT=\"LTC\" COIN_NATIVE_SEGWIT_PREFIX=\"ltc\" COIN_KIND=COIN_KIND_LITECOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +DEFINES += BIP44_COIN_TYPE=2 BIP44_COIN_TYPE_2=2 COIN_P2PKH_VERSION=48 COIN_P2SH_VERSION=50 COIN_FAMILY=1 COIN_COINID=\"Litecoin\" COIN_COINID_HEADER=\"LITECOIN\" COIN_COINID_NAME=\"Litecoin\" COIN_COINID_SHORT=\"LTC\" COIN_NATIVE_SEGWIT_PREFIX=\"ltc\" COIN_KIND=COIN_KIND_LITECOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Litecoin" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),dogecoin) # Doge -DEFINES += BIP44_COIN_TYPE=3 BIP44_COIN_TYPE_2=3 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=22 COIN_FAMILY=1 COIN_COINID=\"Dogecoin\" COIN_COINID_HEADER=\"DOGECOIN\" COIN_COLOR_HDR=0x65D196 COIN_COLOR_DB=0xB2E8CB COIN_COINID_NAME=\"Dogecoin\" COIN_COINID_SHORT=\"DOGE\" COIN_KIND=COIN_KIND_DOGE +DEFINES += BIP44_COIN_TYPE=3 BIP44_COIN_TYPE_2=3 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=22 COIN_FAMILY=1 COIN_COINID=\"Dogecoin\" COIN_COINID_HEADER=\"DOGECOIN\" COIN_COINID_NAME=\"Dogecoin\" COIN_COINID_SHORT=\"DOGE\" COIN_KIND=COIN_KIND_DOGE APPNAME ="Dogecoin" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),dash) # Dash -DEFINES += BIP44_COIN_TYPE=5 BIP44_COIN_TYPE_2=5 COIN_P2PKH_VERSION=76 COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"DarkCoin\" COIN_COINID_HEADER=\"DASH\" COIN_COLOR_HDR=0x0E76AA COIN_COLOR_DB=0x87BBD5 COIN_COINID_NAME=\"Dash\" COIN_COINID_SHORT=\"DASH\" COIN_KIND=COIN_KIND_DASH +DEFINES += BIP44_COIN_TYPE=5 BIP44_COIN_TYPE_2=5 COIN_P2PKH_VERSION=76 COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"DarkCoin\" COIN_COINID_HEADER=\"DASH\" COIN_COINID_NAME=\"Dash\" COIN_COINID_SHORT=\"DASH\" COIN_KIND=COIN_KIND_DASH APPNAME ="Dash" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),zcash) # Zcash (deprecated, code before the NU5 hard fork) $(error the zcash variant is deprecated and no longer functional since the NU5 hard fork) -DEFINES += BIP44_COIN_TYPE=133 BIP44_COIN_TYPE_2=133 COIN_P2PKH_VERSION=7352 COIN_P2SH_VERSION=7357 COIN_FAMILY=1 COIN_COINID=\"Zcash\" COIN_COINID_HEADER=\"ZCASH\" COIN_COLOR_HDR=0x3790CA COIN_COLOR_DB=0x9BC8E5 COIN_COINID_NAME=\"Zcash\" COIN_COINID_SHORT=\"ZEC\" COIN_KIND=COIN_KIND_ZCASH +DEFINES += BIP44_COIN_TYPE=133 BIP44_COIN_TYPE_2=133 COIN_P2PKH_VERSION=7352 COIN_P2SH_VERSION=7357 COIN_FAMILY=1 COIN_COINID=\"Zcash\" COIN_COINID_HEADER=\"ZCASH\" COIN_COINID_NAME=\"Zcash\" COIN_COINID_SHORT=\"ZEC\" COIN_KIND=COIN_KIND_ZCASH # Switch to Canopy over Heartwood DEFINES += COIN_CONSENSUS_BRANCH_ID=0xE9FF75A6 APPNAME ="Zcash" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),horizen) # Horizen -DEFINES += BIP44_COIN_TYPE=121 BIP44_COIN_TYPE_2=121 COIN_P2PKH_VERSION=8329 COIN_P2SH_VERSION=8342 COIN_FAMILY=4 COIN_COINID=\"Horizen\" COIN_COINID_HEADER=\"HORIZEN\" COIN_COLOR_HDR=0xFF4300 COIN_COLOR_DB=0xFF8356 COIN_COINID_NAME=\"Horizen\" COINID=$(COIN) COIN_COINID_SHORT=\"ZEN\" COIN_KIND=COIN_KIND_HORIZEN +DEFINES += BIP44_COIN_TYPE=121 BIP44_COIN_TYPE_2=121 COIN_P2PKH_VERSION=8329 COIN_P2SH_VERSION=8342 COIN_FAMILY=4 COIN_COINID=\"Horizen\" COIN_COINID_HEADER=\"HORIZEN\" COIN_COINID_NAME=\"Horizen\" COINID=$(COIN) COIN_COINID_SHORT=\"ZEN\" COIN_KIND=COIN_KIND_HORIZEN APPNAME ="Horizen" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),komodo) # Komodo -DEFINES += BIP44_COIN_TYPE=141 BIP44_COIN_TYPE_2=141 COIN_P2PKH_VERSION=60 COIN_P2SH_VERSION=85 COIN_FAMILY=1 COIN_COINID=\"Komodo\" COIN_COINID_HEADER=\"KOMODO\" COIN_COLOR_HDR=0x326464 COIN_COLOR_DB=0x99b2b2 COIN_COINID_NAME=\"Komodo\" COIN_COINID_SHORT=\"KMD\" COIN_KIND=COIN_KIND_KOMODO +DEFINES += BIP44_COIN_TYPE=141 BIP44_COIN_TYPE_2=141 COIN_P2PKH_VERSION=60 COIN_P2SH_VERSION=85 COIN_FAMILY=1 COIN_COINID=\"Komodo\" COIN_COINID_HEADER=\"KOMODO\" COIN_COINID_NAME=\"Komodo\" COIN_COINID_SHORT=\"KMD\" COIN_KIND=COIN_KIND_KOMODO APPNAME ="Komodo" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),stratis) # Stratis -DEFINES += BIP44_COIN_TYPE=105105 BIP44_COIN_TYPE_2=105105 COIN_P2PKH_VERSION=75 COIN_P2SH_VERSION=140 COIN_FAMILY=2 COIN_COINID=\"Stratis\" COIN_COINID_HEADER=\"STRATIS\" COIN_COLOR_HDR=0x3790CA COIN_COLOR_DB=0x9BC8E5 COIN_COINID_NAME=\"Stratis\" COIN_COINID_SHORT=\"STRAX\" COIN_KIND=COIN_KIND_STRATIS COIN_FLAGS=FLAG_PEERCOIN_SUPPORT +DEFINES += BIP44_COIN_TYPE=105105 BIP44_COIN_TYPE_2=105105 COIN_P2PKH_VERSION=75 COIN_P2SH_VERSION=140 COIN_FAMILY=2 COIN_COINID=\"Stratis\" COIN_COINID_HEADER=\"STRATIS\" COIN_COINID_NAME=\"Stratis\" COIN_COINID_SHORT=\"STRAX\" COIN_KIND=COIN_KIND_STRATIS COIN_FLAGS=FLAG_PEERCOIN_SUPPORT APPNAME ="Stratis" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),xrhodium) #Xrhodium -DEFINES += BIP44_COIN_TYPE=10291 BIP44_COIN_TYPE_2=10291 COIN_P2PKH_VERSION=61 COIN_P2SH_VERSION=123 COIN_FAMILY=1 COIN_COINID=\"xrhodium\" COIN_COINID_HEADER=\"XRHODIUM\" COIN_COLOR_HDR=0xFF9900 COIN_COLOR_DB=0xFEEBCE COIN_COINID_NAME=\"xRhodium\" COIN_COINID_SHORT=\"XRC\" COIN_KIND=COIN_KIND_XRHODIUM +DEFINES += BIP44_COIN_TYPE=10291 BIP44_COIN_TYPE_2=10291 COIN_P2PKH_VERSION=61 COIN_P2SH_VERSION=123 COIN_FAMILY=1 COIN_COINID=\"xrhodium\" COIN_COINID_HEADER=\"XRHODIUM\" COIN_COINID_NAME=\"xRhodium\" COIN_COINID_SHORT=\"XRC\" COIN_KIND=COIN_KIND_XRHODIUM APPNAME ="xRhodium" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),peercoin) # Peercoin -DEFINES += BIP44_COIN_TYPE=6 BIP44_COIN_TYPE_2=6 COIN_P2PKH_VERSION=55 COIN_P2SH_VERSION=117 COIN_FAMILY=2 COIN_COINID=\"PPCoin\" COIN_COINID_HEADER=\"PEERCOIN\" COIN_COLOR_HDR=0x3790CA COIN_COLOR_DB=0x9BC8E5 COIN_COINID_NAME=\"Peercoin\" COIN_COINID_SHORT=\"PPC\" COIN_KIND=COIN_KIND_PEERCOIN COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT +DEFINES += BIP44_COIN_TYPE=6 BIP44_COIN_TYPE_2=6 COIN_P2PKH_VERSION=55 COIN_P2SH_VERSION=117 COIN_FAMILY=2 COIN_COINID=\"PPCoin\" COIN_COINID_HEADER=\"PEERCOIN\" COIN_COINID_NAME=\"Peercoin\" COIN_COINID_SHORT=\"PPC\" COIN_KIND=COIN_KIND_PEERCOIN COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT APPNAME ="Peercoin" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),pivx) # PivX # 77 was used in the Chrome apps -DEFINES += BIP44_COIN_TYPE=119 BIP44_COIN_TYPE_2=77 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=13 COIN_FAMILY=1 COIN_COINID=\"DarkNet\" COIN_COINID_HEADER=\"PIVX\" COIN_COLOR_HDR=0x46385D COIN_COLOR_DB=0x9E96AA COIN_COINID_NAME=\"PivX\" COIN_COINID_SHORT=\"PIVX\" COIN_KIND=COIN_KIND_PIVX +DEFINES += BIP44_COIN_TYPE=119 BIP44_COIN_TYPE_2=77 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=13 COIN_FAMILY=1 COIN_COINID=\"DarkNet\" COIN_COINID_HEADER=\"PIVX\" COIN_COINID_NAME=\"PivX\" COIN_COINID_SHORT=\"PIVX\" COIN_KIND=COIN_KIND_PIVX APPNAME ="PivX" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),stealth) # Stealth -DEFINES += BIP44_COIN_TYPE=125 BIP44_COIN_TYPE_2=125 COIN_P2PKH_VERSION=62 COIN_P2SH_VERSION=85 COIN_FAMILY=4 COIN_COINID=\"Stealth\" COIN_COINID_HEADER=\"STEALTH\" COIN_COLOR_HDR=0x000000 COIN_COLOR_DB=0x808080 COIN_COINID_NAME=\"Stealth\" COIN_COINID_SHORT=\"XST\" COIN_KIND=COIN_KIND_STEALTH COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT +DEFINES += BIP44_COIN_TYPE=125 BIP44_COIN_TYPE_2=125 COIN_P2PKH_VERSION=62 COIN_P2SH_VERSION=85 COIN_FAMILY=4 COIN_COINID=\"Stealth\" COIN_COINID_HEADER=\"STEALTH\" COIN_COINID_NAME=\"Stealth\" COIN_COINID_SHORT=\"XST\" COIN_KIND=COIN_KIND_STEALTH COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT APPNAME ="Stealth" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),viacoin) # Viacoin -DEFINES += BIP44_COIN_TYPE=14 BIP44_COIN_TYPE_2=14 COIN_P2PKH_VERSION=71 COIN_P2SH_VERSION=33 COIN_FAMILY=1 COIN_COINID=\"Viacoin\" COIN_COINID_HEADER=\"VIACOIN\" COIN_COLOR_HDR=0x414141 COIN_COLOR_DB=0xA0A0A0 COIN_COINID_NAME=\"Viacoin\" COIN_COINID_SHORT=\"VIA\" COIN_KIND=COIN_KIND_VIACOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +DEFINES += BIP44_COIN_TYPE=14 BIP44_COIN_TYPE_2=14 COIN_P2PKH_VERSION=71 COIN_P2SH_VERSION=33 COIN_FAMILY=1 COIN_COINID=\"Viacoin\" COIN_COINID_HEADER=\"VIACOIN\" COIN_COINID_NAME=\"Viacoin\" COIN_COINID_SHORT=\"VIA\" COIN_KIND=COIN_KIND_VIACOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Viacoin" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),vertcoin) # Vertcoin # 128 was used in the Chrome apps -DEFINES += BIP44_COIN_TYPE=28 BIP44_COIN_TYPE_2=128 COIN_P2PKH_VERSION=71 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Vertcoin\" COIN_COINID_HEADER=\"VERTCOIN\" COIN_COLOR_HDR=0x1B5C2E COIN_COLOR_DB=0x8DAE97 COIN_COINID_NAME=\"Vertcoin\" COIN_COINID_SHORT=\"VTC\" COIN_NATIVE_SEGWIT_PREFIX=\"vtc\" COIN_KIND=COIN_KIND_VERTCOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +DEFINES += BIP44_COIN_TYPE=28 BIP44_COIN_TYPE_2=128 COIN_P2PKH_VERSION=71 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Vertcoin\" COIN_COINID_HEADER=\"VERTCOIN\" COIN_COINID_NAME=\"Vertcoin\" COIN_COINID_SHORT=\"VTC\" COIN_NATIVE_SEGWIT_PREFIX=\"vtc\" COIN_KIND=COIN_KIND_VERTCOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Vertcoin" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),digibyte) -DEFINES += BIP44_COIN_TYPE=20 BIP44_COIN_TYPE_2=20 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=63 COIN_FAMILY=1 COIN_COINID=\"DigiByte\" COIN_COINID_HEADER=\"DIGIBYTE\" COIN_COLOR_HDR=0x2864AE COIN_COLOR_DB=0x94B2D7 COIN_COINID_NAME=\"DigiByte\" COIN_COINID_SHORT=\"DGB\" COIN_NATIVE_SEGWIT_PREFIX=\"dgb\" COIN_KIND=COIN_KIND_DIGIBYTE COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +DEFINES += BIP44_COIN_TYPE=20 BIP44_COIN_TYPE_2=20 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=63 COIN_FAMILY=1 COIN_COINID=\"DigiByte\" COIN_COINID_HEADER=\"DIGIBYTE\" COIN_COINID_NAME=\"DigiByte\" COIN_COINID_SHORT=\"DGB\" COIN_NATIVE_SEGWIT_PREFIX=\"dgb\" COIN_KIND=COIN_KIND_DIGIBYTE COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Digibyte" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),qtum) # Qtum # Qtum can run significantly different code paths, thus is locked by the OS # using APP_LOAD_PARAMS instead of BIP44_COIN_TYPE -DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=58 COIN_P2SH_VERSION=50 COIN_FAMILY=3 COIN_COINID=\"Qtum\" COIN_COINID_HEADER=\"QTUM\" COIN_COLOR_HDR=0x2E9AD0 COIN_COLOR_DB=0x97CDE8 COIN_COINID_NAME=\"QTUM\" COIN_COINID_SHORT=\"QTUM\" COIN_NATIVE_SEGWIT_PREFIX=\"qc\" COIN_KIND=COIN_KIND_QTUM COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=58 COIN_P2SH_VERSION=50 COIN_FAMILY=3 COIN_COINID=\"Qtum\" COIN_COINID_HEADER=\"QTUM\" COIN_COINID_NAME=\"QTUM\" COIN_COINID_SHORT=\"QTUM\" COIN_NATIVE_SEGWIT_PREFIX=\"qc\" COIN_KIND=COIN_KIND_QTUM COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Qtum" APP_LOAD_PARAMS += --path "44'/88'" --path "49'/88'" --path "84'/88'" --path "0'/45342'" --path "20698'/3053'/12648430'" else ifeq ($(COIN),firo) -DEFINES += BIP44_COIN_TYPE=136 BIP44_COIN_TYPE_2=136 COIN_P2PKH_VERSION=82 COIN_P2SH_VERSION=7 COIN_FAMILY=1 COIN_COINID=\"Zcoin\" COIN_COINID_HEADER=\"FIRO\" COIN_COLOR_HDR=0x3EAD54 COIN_COLOR_DB=0xA3DCAE COIN_COINID_NAME=\"Firo\" COIN_COINID_SHORT=\"FIRO\" COIN_KIND=COIN_KIND_FIRO +DEFINES += BIP44_COIN_TYPE=136 BIP44_COIN_TYPE_2=136 COIN_P2PKH_VERSION=82 COIN_P2SH_VERSION=7 COIN_FAMILY=1 COIN_COINID=\"Zcoin\" COIN_COINID_HEADER=\"FIRO\" COIN_COINID_NAME=\"Firo\" COIN_COINID_SHORT=\"FIRO\" COIN_KIND=COIN_KIND_FIRO APPNAME ="Firo" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),bitcoin_private) # Bitcoin Private # Initial fork from Bitcoin, public key access is authorized. Signature is different thanks to the forkId # Note : might need a third lock on ZClassic -DEFINES += BIP44_COIN_TYPE=183 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=4901 COIN_P2SH_VERSION=5039 COIN_FAMILY=1 COIN_COINID=\"BPrivate\" COIN_COINID_HEADER=\"BITCOINPRIVATE\" COIN_COLOR_HDR=0x85bb65 COIN_COLOR_DB=0xc2ddb2 COIN_COINID_NAME=\"BPrivate\" COIN_COINID_SHORT=\"BTCP\" COIN_KIND=COIN_KIND_BITCOIN_PRIVATE COIN_FORKID=42 +DEFINES += BIP44_COIN_TYPE=183 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=4901 COIN_P2SH_VERSION=5039 COIN_FAMILY=1 COIN_COINID=\"BPrivate\" COIN_COINID_HEADER=\"BITCOINPRIVATE\" COIN_COINID_NAME=\"BPrivate\" COIN_COINID_SHORT=\"BTCP\" COIN_KIND=COIN_KIND_BITCOIN_PRIVATE COIN_FORKID=42 APPNAME ="Bitcoin Private" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),gamecredits) # GameCredits -DEFINES += BIP44_COIN_TYPE=101 BIP44_COIN_TYPE_2=101 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=62 COIN_FAMILY=1 COIN_COINID=\"GameCredits\" COIN_COINID_HEADER=\"GAMECREDITS\" COIN_COLOR_HDR=0x98C01F COIN_COLOR_DB=0xA1A2A7 COIN_COINID_NAME=\"GameCredits\" COIN_COINID_SHORT=\"GAME\" COIN_KIND=COIN_KIND_GAMECREDITS COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +DEFINES += BIP44_COIN_TYPE=101 BIP44_COIN_TYPE_2=101 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=62 COIN_FAMILY=1 COIN_COINID=\"GameCredits\" COIN_COINID_HEADER=\"GAMECREDITS\" COIN_COINID_NAME=\"GameCredits\" COIN_COINID_SHORT=\"GAME\" COIN_KIND=COIN_KIND_GAMECREDITS COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="GameCredits" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),zclassic) # ZClassic -DEFINES += BIP44_COIN_TYPE=147 BIP44_COIN_TYPE_2=147 COIN_P2PKH_VERSION=7352 COIN_P2SH_VERSION=7357 COIN_FAMILY=1 COIN_COINID=\"ZClassic\" COIN_COINID_HEADER=\"ZCLASSIC\" COIN_COLOR_HDR=0xc87035 COIN_COLOR_DB=0xc78457 COIN_COINID_NAME=\"ZClassic\" COIN_COINID_SHORT=\"ZCL\" COIN_KIND=COIN_KIND_ZCLASSIC +DEFINES += BIP44_COIN_TYPE=147 BIP44_COIN_TYPE_2=147 COIN_P2PKH_VERSION=7352 COIN_P2SH_VERSION=7357 COIN_FAMILY=1 COIN_COINID=\"ZClassic\" COIN_COINID_HEADER=\"ZCLASSIC\" COIN_COINID_NAME=\"ZClassic\" COIN_COINID_SHORT=\"ZCL\" COIN_KIND=COIN_KIND_ZCLASSIC APPNAME ="ZClassic" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),xsn) # XSN mainnet -DEFINES += BIP44_COIN_TYPE=384 BIP44_COIN_TYPE_2=384 COIN_P2PKH_VERSION=76 COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"XSN\" COIN_COINID_HEADER=\"XSN\" COIN_COLOR_HDR=0x2982D1 COIN_COLOR_DB=0x7FB6E6 COIN_COINID_NAME=\"XSN\" COIN_COINID_SHORT=\"XSN\" COIN_NATIVE_SEGWIT_PREFIX=\"xc\" COIN_KIND=COIN_KIND_XSN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +DEFINES += BIP44_COIN_TYPE=384 BIP44_COIN_TYPE_2=384 COIN_P2PKH_VERSION=76 COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"XSN\" COIN_COINID_HEADER=\"XSN\" COIN_COINID_NAME=\"XSN\" COIN_COINID_SHORT=\"XSN\" COIN_NATIVE_SEGWIT_PREFIX=\"xc\" COIN_KIND=COIN_KIND_XSN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="XSN" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),nix) # NIX -DEFINES += BIP44_COIN_TYPE=400 BIP44_COIN_TYPE_2=400 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=53 COIN_FAMILY=1 COIN_COINID=\"NIX\" COIN_COINID_HEADER=\"NIX\" COIN_COLOR_HDR=0x1685e8 COIN_COLOR_DB=0xffffff COIN_COINID_NAME=\"NIX\" COIN_COINID_SHORT=\"NIX\" COIN_NATIVE_SEGWIT_PREFIX=\"nix\" COIN_KIND=COIN_KIND_NIX COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +DEFINES += BIP44_COIN_TYPE=400 BIP44_COIN_TYPE_2=400 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=53 COIN_FAMILY=1 COIN_COINID=\"NIX\" COIN_COINID_HEADER=\"NIX\" COIN_COINID_NAME=\"NIX\" COIN_COINID_SHORT=\"NIX\" COIN_NATIVE_SEGWIT_PREFIX=\"nix\" COIN_KIND=COIN_KIND_NIX COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="NIX" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),lbry) # LBRY -DEFINES += BIP44_COIN_TYPE=140 BIP44_COIN_TYPE_2=140 COIN_P2PKH_VERSION=85 COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"LBRY\" COIN_COINID_HEADER=\"LBRY\" COIN_COLOR_HDR=0x38D9A9 COIN_COLOR_DB=0xFEDBA9 COIN_COINID_NAME=\"LBRY\" COIN_COINID_SHORT=\"LBC\" COIN_KIND=COIN_KIND_LBRY +DEFINES += BIP44_COIN_TYPE=140 BIP44_COIN_TYPE_2=140 COIN_P2PKH_VERSION=85 COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"LBRY\" COIN_COINID_HEADER=\"LBRY\" COIN_COINID_NAME=\"LBRY\" COIN_COINID_SHORT=\"LBC\" COIN_KIND=COIN_KIND_LBRY APPNAME ="LBRY" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),resistance) # Resistance -DEFINES += BIP44_COIN_TYPE=356 BIP44_COIN_TYPE_2=356 COIN_P2PKH_VERSION=7063 COIN_P2SH_VERSION=7068 COIN_FAMILY=1 COIN_COINID=\"Res\" COIN_COINID_HEADER=\"RES\" COIN_COLOR_HDR=0x3790CA COIN_COLOR_DB=0x9BC8E5 COIN_COINID_NAME=\"Res\" COIN_COINID_SHORT=\"RES\" COIN_KIND=COIN_KIND_RESISTANCE +DEFINES += BIP44_COIN_TYPE=356 BIP44_COIN_TYPE_2=356 COIN_P2PKH_VERSION=7063 COIN_P2SH_VERSION=7068 COIN_FAMILY=1 COIN_COINID=\"Res\" COIN_COINID_HEADER=\"RES\" COIN_COINID_NAME=\"Res\" COIN_COINID_SHORT=\"RES\" COIN_KIND=COIN_KIND_RESISTANCE APPNAME ="Resistance" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),ravencoin) # Ravencoin -DEFINES += BIP44_COIN_TYPE=175 BIP44_COIN_TYPE_2=175 COIN_P2PKH_VERSION=60 COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"Ravencoin\" COIN_COINID_HEADER=\"RAVENCOIN\" COIN_COLOR_HDR=0x2E4A80 COIN_COLOR_DB=0x74829E COIN_COINID_NAME=\"Ravencoin\" COIN_COINID_SHORT=\"RVN\" COIN_KIND=COIN_KIND_RAVENCOIN +DEFINES += BIP44_COIN_TYPE=175 BIP44_COIN_TYPE_2=175 COIN_P2PKH_VERSION=60 COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"Ravencoin\" COIN_COINID_HEADER=\"RAVENCOIN\" COIN_COINID_NAME=\"Ravencoin\" COIN_COINID_SHORT=\"RVN\" COIN_KIND=COIN_KIND_RAVENCOIN APPNAME ="Ravencoin" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),hydra_testnet) # Hydra testnet -DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=66 COIN_P2SH_VERSION=128 COIN_FAMILY=3 COIN_COINID=\"Hydra\" COIN_COINID_HEADER=\"HYDRA\" COIN_COLOR_HDR=0x2E9AD0 COIN_COLOR_DB=0x97CDE8 COIN_COINID_NAME=\"HYDRA\" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" COIN_KIND=COIN_KIND_HYDRA COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=66 COIN_P2SH_VERSION=128 COIN_FAMILY=3 COIN_COINID=\"Hydra\" COIN_COINID_HEADER=\"HYDRA\" COIN_COINID_NAME=\"HYDRA\" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" COIN_KIND=COIN_KIND_HYDRA COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Hydra Test" APP_LOAD_PARAMS += --path "44'/609'" else ifeq ($(COIN),hydra) # Hydra mainnet -DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=40 COIN_P2SH_VERSION=63 COIN_FAMILY=3 COIN_COINID=\"Hydra\" COIN_COINID_HEADER=\"HYDRA\" COIN_COLOR_HDR=0x2E9AD0 COIN_COLOR_DB=0x97CDE8 COIN_COINID_NAME=\"HYDRA\" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" COIN_KIND=COIN_KIND_HYDRA COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=40 COIN_P2SH_VERSION=63 COIN_FAMILY=3 COIN_COINID=\"Hydra\" COIN_COINID_HEADER=\"HYDRA\" COIN_COINID_NAME=\"HYDRA\" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" COIN_KIND=COIN_KIND_HYDRA COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Hydra" APP_LOAD_PARAMS += --path "44'/609'" else From 6ecc089b3e6094e948ebae32f00a26e2eecc5232 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 26 Oct 2023 11:28:07 +0200 Subject: [PATCH 53/85] clean: fix clang analyzer --- Makefile | 1 - src/main.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/Makefile b/Makefile index 95d0c303..1abeaf5f 100644 --- a/Makefile +++ b/Makefile @@ -230,7 +230,6 @@ DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERS #DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=$(shell echo -n $(WEBUSB_URL) | wc -c) WEBUSB_URL=$(shell echo -n $(WEBUSB_URL) | sed -e "s/./\\\'\0\\\',/g") DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL="" -DEFINES += UNUSED\(x\)=\(void\)x DEFINES += APPVERSION=\"$(APPVERSION)\" DEFINES += BLAKE_SDK diff --git a/src/main.c b/src/main.c index 4e0959d4..9f7ac4d6 100644 --- a/src/main.c +++ b/src/main.c @@ -605,7 +605,6 @@ struct libargs_s { }; static void library_main_helper(struct libargs_s *args) { - check_api_level(CX_COMPAT_APILEVEL); PRINTF("Inside a library \n"); switch (args->command) { case CHECK_ADDRESS: @@ -665,7 +664,6 @@ __attribute__((section(".boot"))) int main(int arg0) { btchip_altcoin_config_t coin_config; init_coin_config(&coin_config); PRINTF("Hello from litecoin\n"); - check_api_level(CX_COMPAT_APILEVEL); // delegate to bitcoin app/lib libcall_params[0] = "Bitcoin Legacy"; libcall_params[1] = 0x100; From 4e7b0307db28736da97fee3254d460975639064b Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 26 Oct 2023 12:00:09 +0200 Subject: [PATCH 54/85] Qtum: remove associated code and mark variant as deprecated --- Makefile | 13 ++++--------- include/btchip_context.h | 1 - include/btchip_filesystem.h | 1 - src/btchip_apdu_hash_input_finalize_full.c | 4 ++-- src/main.c | 4 ++-- 5 files changed, 8 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 1abeaf5f..0ac9f7b7 100644 --- a/Makefile +++ b/Makefile @@ -132,12 +132,7 @@ DEFINES += BIP44_COIN_TYPE=20 BIP44_COIN_TYPE_2=20 COIN_P2PKH_VERSION=30 COIN_ APPNAME ="Digibyte" APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),qtum) -# Qtum -# Qtum can run significantly different code paths, thus is locked by the OS -# using APP_LOAD_PARAMS instead of BIP44_COIN_TYPE -DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=58 COIN_P2SH_VERSION=50 COIN_FAMILY=3 COIN_COINID=\"Qtum\" COIN_COINID_HEADER=\"QTUM\" COIN_COINID_NAME=\"QTUM\" COIN_COINID_SHORT=\"QTUM\" COIN_NATIVE_SEGWIT_PREFIX=\"qc\" COIN_KIND=COIN_KIND_QTUM COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT -APPNAME ="Qtum" -APP_LOAD_PARAMS += --path "44'/88'" --path "49'/88'" --path "84'/88'" --path "0'/45342'" --path "20698'/3053'/12648430'" +$(error the qtum variant is deprecated and has been moved to its dedicated repo else ifeq ($(COIN),firo) DEFINES += BIP44_COIN_TYPE=136 BIP44_COIN_TYPE_2=136 COIN_P2PKH_VERSION=82 COIN_P2SH_VERSION=7 COIN_FAMILY=1 COIN_COINID=\"Zcoin\" COIN_COINID_HEADER=\"FIRO\" COIN_COINID_NAME=\"Firo\" COIN_COINID_SHORT=\"FIRO\" COIN_KIND=COIN_KIND_FIRO APPNAME ="Firo" @@ -196,7 +191,7 @@ APPNAME ="Hydra" APP_LOAD_PARAMS += --path "44'/609'" else ifeq ($(filter clean,$(MAKECMDGOALS)),) -$(error Unsupported COIN - use bitcoin_testnet, bitcoin, bitcoin_cash, bitcoin_gold, litecoin, dogecoin, dash, zcash, horizen, komodo, stratis, peercoin, pivx, viacoin, vertcoin, stealth, digibyte, qtum, bitcoin_private, firo, gamecredits, zclassic, xsn, nix, lbry, resistance, ravencoin, hydra, hydra_testnet, xrhodium) +$(error Unsupported COIN - use bitcoin_testnet, bitcoin, bitcoin_cash, bitcoin_gold, litecoin, dogecoin, dash, zcash, horizen, komodo, stratis, peercoin, pivx, viacoin, vertcoin, stealth, digibyte, bitcoin_private, firo, gamecredits, zclassic, xsn, nix, lbry, resistance, ravencoin, hydra, hydra_testnet, xrhodium) endif endif @@ -329,11 +324,11 @@ dep/%.d: %.c Makefile ifeq ($(TARGET_NAME),TARGET_NANOS) listvariants: - @echo VARIANTS COIN bitcoin_testnet_legacy bitcoin_legacy bitcoin_cash bitcoin_gold litecoin dogecoin dash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte qtum bitcoin_private firo gamecredits zclassic xsn nix lbry ravencoin resistance hydra hydra_testnet xrhodium + @echo VARIANTS COIN bitcoin_testnet_legacy bitcoin_legacy bitcoin_cash bitcoin_gold litecoin dogecoin dash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte bitcoin_private firo gamecredits zclassic xsn nix lbry ravencoin resistance hydra hydra_testnet xrhodium else listvariants: - @echo VARIANTS COIN bitcoin_testnet_legacy bitcoin_legacy bitcoin_cash bitcoin_gold litecoin dogecoin dash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte qtum bitcoin_private firo gamecredits zclassic xsn nix lbry ravencoin hydra hydra_testnet xrhodium + @echo VARIANTS COIN bitcoin_testnet_legacy bitcoin_legacy bitcoin_cash bitcoin_gold litecoin dogecoin dash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte bitcoin_private firo gamecredits zclassic xsn nix lbry ravencoin hydra hydra_testnet xrhodium endif diff --git a/include/btchip_context.h b/include/btchip_context.h index d199fea7..562fbd65 100644 --- a/include/btchip_context.h +++ b/include/btchip_context.h @@ -277,7 +277,6 @@ typedef enum btchip_coin_kind_e { COIN_KIND_VIACOIN, COIN_KIND_VERTCOIN, COIN_KIND_DIGIBYTE, - COIN_KIND_QTUM, COIN_KIND_BITCOIN_PRIVATE, COIN_KIND_XRHODIUM, COIN_KIND_HORIZEN, diff --git a/include/btchip_filesystem.h b/include/btchip_filesystem.h index 555953c8..3bbdc04d 100644 --- a/include/btchip_filesystem.h +++ b/include/btchip_filesystem.h @@ -34,7 +34,6 @@ enum btchip_supported_modes_e { enum btchip_family_e { BTCHIP_FAMILY_BITCOIN = 0x01, BTCHIP_FAMILY_PEERCOIN = 0x02, - BTCHIP_FAMILY_QTUM = 0x03, BTCHIP_FAMILY_STEALTH = 0x04 }; diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c index 8c12d49e..e023aa73 100644 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ b/src/btchip_apdu_hash_input_finalize_full.c @@ -70,10 +70,10 @@ static bool check_output_displayable() { isOpCall = btchip_output_script_is_op_call(btchip_context_D.currentOutput + 8, sizeof(btchip_context_D.currentOutput) - 8); - if (((G_coin_config->kind == COIN_KIND_QTUM || G_coin_config->kind == COIN_KIND_HYDRA) && + if (((G_coin_config->kind == COIN_KIND_HYDRA) && !btchip_output_script_is_regular(btchip_context_D.currentOutput + 8) && !isP2sh && !(nullAmount && isOpReturn) && !isOpCreate && !isOpCall) || - (!(G_coin_config->kind == COIN_KIND_QTUM || G_coin_config->kind == COIN_KIND_HYDRA) && + (!(G_coin_config->kind == COIN_KIND_HYDRA) && !btchip_output_script_is_regular(btchip_context_D.currentOutput + 8) && !isP2sh && !(nullAmount && isOpReturn))) { PRINTF("Error : Unrecognized output script"); diff --git a/src/main.c b/src/main.c index 9f7ac4d6..13c704f9 100644 --- a/src/main.c +++ b/src/main.c @@ -203,12 +203,12 @@ void get_address_from_output_script(unsigned char* script, int script_size, char strncpy(out, "OP_RETURN", out_size); return; } - if ((G_coin_config->kind == COIN_KIND_QTUM || G_coin_config->kind == COIN_KIND_HYDRA) && + if ((G_coin_config->kind == COIN_KIND_HYDRA) && btchip_output_script_is_op_create(script, script_size)) { strncpy(out, "OP_CREATE", out_size); return; } - if ((G_coin_config->kind == COIN_KIND_QTUM || G_coin_config->kind == COIN_KIND_HYDRA) && + if ((G_coin_config->kind == COIN_KIND_HYDRA) && btchip_output_script_is_op_call(script, script_size)) { strncpy(out, "OP_CALL", out_size); return; From bfe0af4164a9e2b843caf84a3be808c3e946f2ac Mon Sep 17 00:00:00 2001 From: tdejoigny-ledger <123755370+tdejoigny-ledger@users.noreply.github.com> Date: Thu, 26 Oct 2023 15:52:41 +0200 Subject: [PATCH 55/85] Update README.md --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f1fea8a5..9caaa6f2 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,12 @@ -# ledger-app-btc -Bitcoin wallet application for Ledger Nano S and Nano X, up to version 1.6.5. +# ledger-app-bitcoin -This is currently only used in order to support and maintain altcoins cloned from Bitcoin. The last stable version of the app as it was used for Bitcoin is kept in the branch [legacy-1.6.6](https://github.com/LedgerHQ/app-bitcoin/tree/legacy-1.6.6) for future reference. +Bitcoin wallet application for Ledger Nano S and Nano X, up to version 1.6.5. -Versions starting from 2.0.0 are at https://github.com/LedgerHQ/app-bitcoin-new. +> **Warning** +> This is currently only used in order to support and maintain altcoins cloned from Bitcoin. +> The last stable version of the app as it was used for Bitcoin is kept in the branch [legacy-1.6.6](https://github.com/LedgerHQ/app-bitcoin/tree/legacy-1.6.6) for future reference. +> +> Versions starting from 2.0.0 are at https://github.com/LedgerHQ/app-bitcoin-new. Ledger Blue is not maintained anymore, but the app can still be compiled for this target using the branch `blue-final-release`. From b983dfab0d0ca81017cb9fa6a903e4954ae49e47 Mon Sep 17 00:00:00 2001 From: Francois Beutin Date: Tue, 7 Nov 2023 16:02:13 +0100 Subject: [PATCH 56/85] Add cross CI for swap features --- .github/workflows/swap-ci-workflow.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/workflows/swap-ci-workflow.yml diff --git a/.github/workflows/swap-ci-workflow.yml b/.github/workflows/swap-ci-workflow.yml new file mode 100644 index 00000000..660a3132 --- /dev/null +++ b/.github/workflows/swap-ci-workflow.yml @@ -0,0 +1,16 @@ +name: Swap functional tests + +on: + workflow_dispatch: + push: + branches: + - master + - develop + pull_request: + +jobs: + job_functional_tests: + uses: LedgerHQ/app-exchange/.github/workflows/reusable_swap_functional_tests.yml@develop + with: + branch_for_bitcoin_legacy: ${{ github.ref }} + test_filter: '"ltc or litecoin or Litecoin"' From 2e14303125919de0f1a204a56cc40fc1f5ddffb5 Mon Sep 17 00:00:00 2001 From: Francois Beutin Date: Mon, 13 Nov 2023 17:07:40 +0100 Subject: [PATCH 57/85] Add a spinner on Stax when started via Exchange and return to Exchange after a sign request --- Makefile | 2 +- include/swap_lib_calls.h | 68 +++++++++++++++++++++--------- src/btchip.c | 4 +- src/handle_swap_sign_transaction.c | 17 ++++++++ src/handle_swap_sign_transaction.h | 4 +- src/main.c | 21 ++------- 6 files changed, 75 insertions(+), 41 deletions(-) diff --git a/Makefile b/Makefile index 0ac9f7b7..487261d6 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS) APPVERSION_M=2 APPVERSION_N=1 -APPVERSION_P=6 +APPVERSION_P=7 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APP_LOAD_FLAGS=--appFlags 0xa50 diff --git a/include/swap_lib_calls.h b/include/swap_lib_calls.h index 378b93c8..0f59a452 100644 --- a/include/swap_lib_calls.h +++ b/include/swap_lib_calls.h @@ -1,7 +1,14 @@ -#ifndef SWAP_LIB_CALLS -#define SWAP_LIB_CALLS +#pragma once + +/* This file is the shared API between Exchange and the apps started in Library mode for Exchange + * + * DO NOT MODIFY THIS FILE IN APPLICATIONS OTHER THAN EXCHANGE + * On modification in Exchange, forward the changes to all applications supporting Exchange + */ #include "stdbool.h" +#include "stdint.h" +#include "btchip_context.h" #define RUN_APPLICATION 1 @@ -11,15 +18,25 @@ #define GET_PRINTABLE_AMOUNT 4 +/* + * Amounts are stored as bytes, with a max size of 16 (see protobuf + * specifications). Max 16B integer is 340282366920938463463374607431768211455 + * in decimal, which is a 32-long char string. + * The printable amount also contains spaces, the ticker symbol (with variable + * size, up to 12 in Ethereum for instance) and a terminating null byte, so 50 + * bytes total should be a fair maximum. + */ +#define MAX_PRINTABLE_AMOUNT_SIZE 50 + // structure that should be send to specific coin application to get address typedef struct check_address_parameters_s { // IN - unsigned char* coin_configuration; - unsigned char coin_configuration_length; + uint8_t *coin_configuration; + uint8_t coin_configuration_length; // serialized path, segwit, version prefix, hash used, dictionary etc. - // fields and serialization format depends on spesific coin app - unsigned char* address_parameters; - unsigned char address_parameters_length; + // fields and serialization format depends on specific coin app + uint8_t *address_parameters; + uint8_t address_parameters_length; char *address_to_check; char *extra_id_to_check; // OUT @@ -29,25 +46,36 @@ typedef struct check_address_parameters_s { // structure that should be send to specific coin application to get printable amount typedef struct get_printable_amount_parameters_s { // IN - unsigned char* coin_configuration; - unsigned char coin_configuration_length; - unsigned char* amount; - unsigned char amount_length; + uint8_t *coin_configuration; + uint8_t coin_configuration_length; + uint8_t *amount; + uint8_t amount_length; bool is_fee; // OUT - char printable_amount[30]; - // int result; + char printable_amount[MAX_PRINTABLE_AMOUNT_SIZE]; } get_printable_amount_parameters_t; typedef struct create_transaction_parameters_s { - unsigned char* coin_configuration; - unsigned char coin_configuration_length; - unsigned char* amount; - unsigned char amount_length; - unsigned char* fee_amount; - unsigned char fee_amount_length; + // IN + uint8_t *coin_configuration; + uint8_t coin_configuration_length; + uint8_t *amount; + uint8_t amount_length; + uint8_t *fee_amount; + uint8_t fee_amount_length; char *destination_address; char *destination_address_extra_id; + // OUT + uint8_t result; } create_transaction_parameters_t; -#endif +typedef struct libargs_s { + unsigned int id; + unsigned int command; + btchip_altcoin_config_t *coin_config; + union { + check_address_parameters_t *check_address; + create_transaction_parameters_t *create_transaction; + get_printable_amount_parameters_t *get_printable_amount; + }; +} libargs_t; diff --git a/src/btchip.c b/src/btchip.c index 3b7eb229..a6b6430c 100644 --- a/src/btchip.c +++ b/src/btchip.c @@ -24,6 +24,8 @@ #include "btchip_apdu_constants.h" #include "btchip_display_variables.h" +#include "handle_swap_sign_transaction.h" + #define BTCHIP_TECHNICAL_NOT_IMPLEMENTED 0x99 #define COMMON_CLA 0xB0 @@ -114,7 +116,7 @@ void app_main(void) { btchip_context_D.outLength); if (btchip_context_D.called_from_swap && vars.swap_data.should_exit) { - os_sched_exit(0); + finalize_exchange_sign_transaction(btchip_context_D.sw == BTCHIP_SW_OK); } PRINTF("New APDU received:\n%.*H\n", btchip_context_D.inLength, G_io_apdu_buffer); diff --git a/src/handle_swap_sign_transaction.c b/src/handle_swap_sign_transaction.c index a332f8ae..1c2dc971 100644 --- a/src/handle_swap_sign_transaction.c +++ b/src/handle_swap_sign_transaction.c @@ -6,6 +6,12 @@ #include "usbd_core.h" #include "ux.h" +#ifdef HAVE_NBGL +#include "nbgl_use_case.h" +#endif + +// Save the BSS address where we will write the return value when finished +static uint8_t *G_swap_sign_return_value_address; bool copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params) { // first copy parameters to stack, and then to global data. @@ -26,6 +32,9 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti // Erase values inherited from Exchange app os_explicit_zero_BSS_segment(); + // Keep the address at which we'll reply the signing status + G_swap_sign_return_value_address = &sign_transaction_params->result; + // Copy from stack back to global data segment memcpy(&vars.swap_data, &stack_data, sizeof(stack_data)); return true; @@ -37,6 +46,9 @@ void handle_swap_sign_transaction(btchip_altcoin_config_t *config) { btchip_context_D.called_from_swap = 1; io_seproxyhal_init(); UX_INIT(); +#ifdef HAVE_NBGL + nbgl_useCaseSpinner("Signing"); +#endif // HAVE_BAGL USB_power(0); USB_power(1); //ui_idle(); @@ -51,3 +63,8 @@ void handle_swap_sign_transaction(btchip_altcoin_config_t *config) { #endif // HAVE_BLE app_main(); } + +void __attribute__((noreturn)) finalize_exchange_sign_transaction(bool is_success) { + *G_swap_sign_return_value_address = is_success; + os_lib_end(); +} diff --git a/src/handle_swap_sign_transaction.h b/src/handle_swap_sign_transaction.h index 46262601..85f5bd86 100644 --- a/src/handle_swap_sign_transaction.h +++ b/src/handle_swap_sign_transaction.h @@ -8,4 +8,6 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti void handle_swap_sign_transaction(btchip_altcoin_config_t *config); -#endif // _HANDLE_SWAP_SIGN_TRANSACTION_H_ \ No newline at end of file +void __attribute__((noreturn)) finalize_exchange_sign_transaction(bool is_success); + +#endif // _HANDLE_SWAP_SIGN_TRANSACTION_H_ diff --git a/src/main.c b/src/main.c index 13c704f9..fe9f1fc2 100644 --- a/src/main.c +++ b/src/main.c @@ -593,18 +593,7 @@ void coin_main(btchip_altcoin_config_t *coin_config) { app_exit(); } -struct libargs_s { - unsigned int id; - unsigned int command; - btchip_altcoin_config_t *coin_config; - union { - check_address_parameters_t *check_address; - create_transaction_parameters_t *create_transaction; - get_printable_amount_parameters_t *get_printable_amount; - }; -}; - -static void library_main_helper(struct libargs_s *args) { +static void library_main_helper(libargs_t *args) { PRINTF("Inside a library \n"); switch (args->command) { case CHECK_ADDRESS: @@ -620,10 +609,6 @@ static void library_main_helper(struct libargs_s *args) { } break; case GET_PRINTABLE_AMOUNT: - // ensure result is zero if an exception is thrown (compatibility breaking, disabled - // until LL is ready) - // args->get_printable_amount->result = 0; - // args->get_printable_amount->result = handle_get_printable_amount(args->get_printable_amount, args->coin_config); break; default: @@ -631,7 +616,7 @@ static void library_main_helper(struct libargs_s *args) { } } -void library_main(struct libargs_s *args) { +void library_main(libargs_t *args) { btchip_altcoin_config_t coin_config; if (args->coin_config == NULL) { init_coin_config(&coin_config); @@ -699,7 +684,7 @@ __attribute__((section(".boot"))) int main(int arg0) { coin_main(NULL); return 0; } - struct libargs_s *args = (struct libargs_s *) arg0; + libargs_t *args = (libargs_t *) arg0; if (args->id != 0x100) { app_exit(); return 0; From ac481eb34959a814e604be71a262e863af5b3099 Mon Sep 17 00:00:00 2001 From: Sarah Gliner <105934250+sgliner-ledger@users.noreply.github.com> Date: Wed, 29 Nov 2023 11:45:45 +0100 Subject: [PATCH 58/85] [auto]: add PR template --- .github/PULL_REQUEST_TEMPLATE.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..98b720fe --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,8 @@ +# Checklist + +- [ ] App update process has been followed +- [ ] Target branch is `develop` +- [ ] Application version has been bumped + + From bb60cde8d9502afac149066121dc8c4518a9b2e0 Mon Sep 17 00:00:00 2001 From: Lucas PASCAL Date: Fri, 1 Dec 2023 16:41:28 +0100 Subject: [PATCH 59/85] [add] ledger_app.toml manifest --- ledger_app.toml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 ledger_app.toml diff --git a/ledger_app.toml b/ledger_app.toml new file mode 100644 index 00000000..c264aa9d --- /dev/null +++ b/ledger_app.toml @@ -0,0 +1,7 @@ +[app] +build_directory = "./" +sdk = "C" +devices = ["nanos", "nanox", "nanos+", "stax"] + +[tests] +pytest_directory = "./tests/" From f58ec316eb33a109875d16672c6f46477a385315 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 5 Dec 2023 10:26:38 +0100 Subject: [PATCH 60/85] clean: add LEDGER_ASSERT to handle errors --- src/btchip_apdu_hash_sign.c | 7 ++++--- src/btchip_helpers.c | 3 ++- src/btchip_transaction.c | 11 ++++++----- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/btchip_apdu_hash_sign.c b/src/btchip_apdu_hash_sign.c index 8e006af9..286fd1b7 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/btchip_apdu_hash_sign.c @@ -20,6 +20,7 @@ #include "btchip_bagl_extensions.h" #include "btchip_display_variables.h" #include "ui.h" +#include "ledger_assert.h" #define SIGHASH_ALL 0x01 @@ -169,11 +170,11 @@ void btchip_bagl_user_action_signtx(unsigned char confirming, unsigned char dire if (confirming) { unsigned char hash[32]; if (btchip_context_D.usingOverwinter) { - cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, hash, 0, hash, 32); + LEDGER_ASSERT(cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, hash, 0, hash, 32) == CX_OK, "Hash Failed"); } else { - cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, - hash, 0, hash, 32); + LEDGER_ASSERT(cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, + hash, 0, hash, 32) == CX_OK, "Hash Failed"); PRINTF("Hash1\n%.*H\n", sizeof(hash), hash); // Rehash diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index 343ce74d..bbc020c8 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -19,6 +19,7 @@ #include "btchip_apdu_constants.h" #include "lib_standard_app/crypto_helpers.h" #include "bip32_path.h" +#include "ledger_assert.h" const unsigned char TRANSACTION_OUTPUT_SCRIPT_PRE[] = { 0x19, 0x76, 0xA9, @@ -215,7 +216,7 @@ void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, unsigned char buffer[32]; cx_hash_sha256(in, inlen, buffer, 32); cx_ripemd160_init(&riprip); - cx_hash_no_throw(&riprip.header, CX_LAST, buffer, 32, out, 20); + LEDGER_ASSERT(cx_hash_no_throw(&riprip.header, CX_LAST, buffer, 32, out, 20) == CX_OK, "hash160"); } void btchip_compute_checksum(unsigned char* in, unsigned short inlen, unsigned char * output) { diff --git a/src/btchip_transaction.c b/src/btchip_transaction.c index 9cd29e61..f15fe553 100644 --- a/src/btchip_transaction.c +++ b/src/btchip_transaction.c @@ -18,6 +18,7 @@ #include "btchip_internal.h" #include "btchip_apdu_constants.h" #include "btchip_display_variables.h" +#include "ledger_assert.h" #define CONSENSUS_BRANCH_ID_OVERWINTER 0x5ba81b19 #define CONSENSUS_BRANCH_ID_SAPLING 0x76b809bb @@ -87,18 +88,18 @@ void transaction_offset(unsigned char value) { if ((btchip_context_D.transactionHashOption & TRANSACTION_HASH_FULL) != 0) { PRINTF("--- ADD TO HASH FULL:\n%.*H\n", value, btchip_context_D.transactionBufferPointer); if (btchip_context_D.usingOverwinter) { - cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.transactionBufferPointer, value, NULL, 0); + LEDGER_ASSERT(cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); } else { - cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, - btchip_context_D.transactionBufferPointer, value, NULL, 0); + LEDGER_ASSERT(cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + btchip_context_D.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); } } if ((btchip_context_D.transactionHashOption & TRANSACTION_HASH_AUTHORIZATION) != 0) { PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", value, btchip_context_D.transactionBufferPointer); - cx_hash_no_throw(&btchip_context_D.transactionHashAuthorization.header, 0, - btchip_context_D.transactionBufferPointer, value, NULL, 0); + LEDGER_ASSERT(cx_hash_no_throw(&btchip_context_D.transactionHashAuthorization.header, 0, + btchip_context_D.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); } } From 1c117455eb07c126e8eb54d45ae7f5999eeb5174 Mon Sep 17 00:00:00 2001 From: Sarah Gliner <105934250+sgliner-ledger@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:24:31 +0100 Subject: [PATCH 61/85] [auto] Update screenshot --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 98b720fe..f2fb620f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,5 +4,5 @@ - [ ] Target branch is `develop` - [ ] Application version has been bumped - From f1c37d75415888e00996a5011da821174dd1ae06 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 4 Mar 2024 10:04:11 +0100 Subject: [PATCH 62/85] btchip_context: change bip44_coin_type type to prevent overflow --- include/btchip_context.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/btchip_context.h b/include/btchip_context.h index 562fbd65..db9656d3 100644 --- a/include/btchip_context.h +++ b/include/btchip_context.h @@ -292,8 +292,8 @@ typedef enum btchip_coin_kind_e { } btchip_coin_kind_t; typedef struct btchip_altcoin_config_s { - unsigned short bip44_coin_type; - unsigned short bip44_coin_type2; + unsigned int bip44_coin_type; + unsigned int bip44_coin_type2; unsigned short p2pkh_version; unsigned short p2sh_version; unsigned char family; From c6a80aef3c0a510e7540ac7a617716cffa9824a0 Mon Sep 17 00:00:00 2001 From: Paolo Tagliaferri Date: Wed, 7 Feb 2024 17:09:58 +0100 Subject: [PATCH 63/85] Fix Horizen transaction output checks This commit fixes the support for Horizen blockchain. The previous implementation was only taking into account outputs including the replay protection. That made sense as replay protection is mandatory, but it didn't take into account the release of Zendoo and the fact that sidechain certificates include Backward Transfers (outputs) without replay protection. --- src/btchip_helpers.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/btchip_helpers.c b/src/btchip_helpers.c index bbc020c8..b16fb540 100644 --- a/src/btchip_helpers.c +++ b/src/btchip_helpers.c @@ -70,6 +70,13 @@ unsigned char btchip_output_script_is_regular(unsigned char *buffer) { return 1; } } + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) && + (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, + TRANSACTION_OUTPUT_SCRIPT_POST, + sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { + return 1; + } if (G_coin_config->kind == COIN_KIND_HORIZEN) { if ((memcmp(buffer, ZEN_OUTPUT_SCRIPT_PRE, sizeof(ZEN_OUTPUT_SCRIPT_PRE)) == 0) && @@ -78,19 +85,19 @@ unsigned char btchip_output_script_is_regular(unsigned char *buffer) { sizeof(ZEN_OUTPUT_SCRIPT_POST)) == 0)) { return 1; } - } else { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) && - (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, - TRANSACTION_OUTPUT_SCRIPT_POST, - sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { - return 1; - } } + return 0; } unsigned char btchip_output_script_is_p2sh(unsigned char *buffer) { + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && + (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, + TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { + return 1; + } if (G_coin_config->kind == COIN_KIND_HORIZEN) { if ((memcmp(buffer, ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && @@ -99,14 +106,6 @@ unsigned char btchip_output_script_is_p2sh(unsigned char *buffer) { sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { return 1; } - } else { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && - (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, - TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { - return 1; - } } return 0; } From cc9e6fd2766a0f17f7edf4e1677ec6edc7f60ef5 Mon Sep 17 00:00:00 2001 From: Daniele Rogora Date: Tue, 20 Feb 2024 14:43:12 +0100 Subject: [PATCH 64/85] Fix signed message magic for Horizen This commit fixes message signing for Horizen coin. Differently from other coins, Horizen uses "Zcash" as a signed message header, instead of its own name. --- src/btchip_apdu_sign_message.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/btchip_apdu_sign_message.c b/src/btchip_apdu_sign_message.c index 00d596c0..b6717b8f 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/btchip_apdu_sign_message.c @@ -125,15 +125,18 @@ unsigned short btchip_apdu_sign_message_internal() { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } + // Horizen signed message magic header is "Zcash" + // See https://github.com/HorizenOfficial/zen/blob/v5.0.0/src/main.cpp#L122 + const char* magicHeader = (G_coin_config->kind != COIN_KIND_HORIZEN) ? G_coin_config->coinid : "Zcash"; chunkLength = - strlen(G_coin_config->coinid) + SIGNMAGIC_LENGTH; + strlen(magicHeader) + SIGNMAGIC_LENGTH; if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, &chunkLength, 1, NULL, 0)) { goto discard; } if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, - (uint8_t *)G_coin_config->coinid, - strlen(G_coin_config->coinid), NULL, 0)) { + (uint8_t *)magicHeader, + strlen(magicHeader), NULL, 0)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } From 8d29f5b3353a51b5e3d5ed38df536f0b1492cc3f Mon Sep 17 00:00:00 2001 From: Daniele Rogora Date: Tue, 20 Feb 2024 15:06:59 +0100 Subject: [PATCH 65/85] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 487261d6..068f14f8 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS) APPVERSION_M=2 APPVERSION_N=1 -APPVERSION_P=7 +APPVERSION_P=8 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APP_LOAD_FLAGS=--appFlags 0xa50 From 0a84516ba18930b7369fcbdbf13a3203b8afbc2b Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 29 Mar 2024 13:32:12 +0100 Subject: [PATCH 66/85] bump version --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 068f14f8..79c9be33 100644 --- a/Makefile +++ b/Makefile @@ -24,8 +24,8 @@ APP_PATH = "" APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS) APPVERSION_M=2 -APPVERSION_N=1 -APPVERSION_P=8 +APPVERSION_N=3 +APPVERSION_P=0 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APP_LOAD_FLAGS=--appFlags 0xa50 From 0eda743efa32e7503b5f4de14d796f63c49a4972 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 14 Mar 2024 20:03:01 +0100 Subject: [PATCH 67/85] Tests: Remove useless files --- tests/automations/accept.json | 51 -- tests/automations/accept_pubkey.json | 30 - tests/automations/reject.json | 35 -- tests/automations/sign_message.json | 50 -- tests/bitcoin_client/__init__.py | 0 tests/bitcoin_client/bitcoin_base_cmd.py | 385 ------------- tests/bitcoin_client/bitcoin_cmd.py | 244 -------- tests/bitcoin_client/bitcoin_cmd_builder.py | 457 --------------- tests/bitcoin_client/bitcoin_utils.py | 68 --- tests/bitcoin_client/exception/__init__.py | 64 --- .../exception/device_exception.py | 53 -- tests/bitcoin_client/exception/errors.py | 118 ---- tests/bitcoin_client/hwi/__init__.py | 0 tests/bitcoin_client/hwi/base58.py | 110 ---- tests/bitcoin_client/hwi/bech32.py | 123 ---- tests/bitcoin_client/hwi/serialization.py | 524 ------------------ tests/bitcoin_client/utils.py | 55 -- tests/clean_tests.sh | 4 - tests/data/many-to-many/p2pkh/apdu_debug.log | 446 --------------- tests/data/many-to-many/p2pkh/tx.json | 25 - .../many-to-many/p2sh-p2wpkh/apdu_debug.log | 359 ------------ tests/data/many-to-many/p2sh-p2wpkh/tx.json | 19 - tests/data/many-to-many/p2wpkh/apdu_debug.log | 415 -------------- tests/data/many-to-many/p2wpkh/tx.json | 19 - tests/data/one-to-many/p2pkh/apdu_debug.log | 168 ------ tests/data/one-to-many/p2pkh/tx.json | 19 - .../one-to-many/p2sh-p2wpkh/apdu_debug.log | 191 ------- tests/data/one-to-many/p2sh-p2wpkh/tx.json | 19 - tests/data/one-to-many/p2wpkh/apdu_debug.log | 207 ------- tests/data/one-to-many/p2wpkh/tx.json | 19 - tests/data/one-to-one/p2pkh/apdu_debug.log | 159 ------ tests/data/one-to-one/p2pkh/tx.json | 19 - .../one-to-one/p2sh-p2wpkh/apdu_debug.log | 199 ------- tests/data/one-to-one/p2sh-p2wpkh/tx.json | 19 - tests/data/one-to-one/p2wpkh/apdu_debug.log | 188 ------- tests/data/one-to-one/p2wpkh/tx.json | 19 - tests/prepare_tests.sh | 8 - tests/test_get_coin_version.py | 9 - tests/test_get_random.py | 15 - tests/test_get_trusted_inputs.py | 174 ------ tests/utils/__init__.py | 10 - 41 files changed, 5096 deletions(-) delete mode 100644 tests/automations/accept.json delete mode 100644 tests/automations/accept_pubkey.json delete mode 100644 tests/automations/reject.json delete mode 100644 tests/automations/sign_message.json delete mode 100644 tests/bitcoin_client/__init__.py delete mode 100644 tests/bitcoin_client/bitcoin_base_cmd.py delete mode 100644 tests/bitcoin_client/bitcoin_cmd.py delete mode 100644 tests/bitcoin_client/bitcoin_cmd_builder.py delete mode 100644 tests/bitcoin_client/bitcoin_utils.py delete mode 100644 tests/bitcoin_client/exception/__init__.py delete mode 100644 tests/bitcoin_client/exception/device_exception.py delete mode 100644 tests/bitcoin_client/exception/errors.py delete mode 100644 tests/bitcoin_client/hwi/__init__.py delete mode 100644 tests/bitcoin_client/hwi/base58.py delete mode 100644 tests/bitcoin_client/hwi/bech32.py delete mode 100644 tests/bitcoin_client/hwi/serialization.py delete mode 100644 tests/bitcoin_client/utils.py delete mode 100755 tests/clean_tests.sh delete mode 100644 tests/data/many-to-many/p2pkh/apdu_debug.log delete mode 100644 tests/data/many-to-many/p2pkh/tx.json delete mode 100644 tests/data/many-to-many/p2sh-p2wpkh/apdu_debug.log delete mode 100644 tests/data/many-to-many/p2sh-p2wpkh/tx.json delete mode 100644 tests/data/many-to-many/p2wpkh/apdu_debug.log delete mode 100644 tests/data/many-to-many/p2wpkh/tx.json delete mode 100644 tests/data/one-to-many/p2pkh/apdu_debug.log delete mode 100644 tests/data/one-to-many/p2pkh/tx.json delete mode 100644 tests/data/one-to-many/p2sh-p2wpkh/apdu_debug.log delete mode 100644 tests/data/one-to-many/p2sh-p2wpkh/tx.json delete mode 100644 tests/data/one-to-many/p2wpkh/apdu_debug.log delete mode 100644 tests/data/one-to-many/p2wpkh/tx.json delete mode 100644 tests/data/one-to-one/p2pkh/apdu_debug.log delete mode 100644 tests/data/one-to-one/p2pkh/tx.json delete mode 100644 tests/data/one-to-one/p2sh-p2wpkh/apdu_debug.log delete mode 100644 tests/data/one-to-one/p2sh-p2wpkh/tx.json delete mode 100644 tests/data/one-to-one/p2wpkh/apdu_debug.log delete mode 100644 tests/data/one-to-one/p2wpkh/tx.json delete mode 100755 tests/prepare_tests.sh delete mode 100644 tests/test_get_coin_version.py delete mode 100644 tests/test_get_random.py delete mode 100644 tests/test_get_trusted_inputs.py delete mode 100644 tests/utils/__init__.py diff --git a/tests/automations/accept.json b/tests/automations/accept.json deleted file mode 100644 index 15f42e09..00000000 --- a/tests/automations/accept.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "version": 1, - "rules": [ - { - "regexp": "Review|Amount|Address|Confirm|Fees", - "actions": [ - ["button", 2, true], - ["button", 2, false] - ] - }, - { - "regexp": "Tap to continue", - "actions": [ - ["finger", 55, 550, true], - ["finger", 55, 550, false] - ] - }, - { - "regexp": "Hold to sign", - "actions": [ - ["finger", 55, 550, true] - ] - }, - { - "regexp": "Processing|CONFIRMED", - "actions": [ - ["finger", 55, 550, false] - ] - }, - { - "text": "Accept", - "actions": [ - [ "button", 1, true ], - [ "button", 2, true ], - [ "button", 2, false ], - [ "button", 1, false ] - ] - }, - { - "regexp": "Approve", - "actions": [ - [ "button", 1, true ], - [ "button", 2, true ], - [ "button", 2, false ], - [ "button", 1, false ], - [ "finger", 55, 550, true], - [ "finger", 55, 550, false] - ] - } - ] -} diff --git a/tests/automations/accept_pubkey.json b/tests/automations/accept_pubkey.json deleted file mode 100644 index 89920983..00000000 --- a/tests/automations/accept_pubkey.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "version": 1, - "rules": [ - { - "regexp": "Review|Amount|Address|Confirm|Fees|public key", - "actions": [ - ["button", 2, true], - ["button", 2, false], - ["finger", 55, 550, true], - ["finger", 55, 550, false] - ] - }, - { - "regexp": "Tap to continue", - "actions": [ - ["finger", 55, 550, true], - ["finger", 55, 550, false] - ] - }, - { - "regexp": "Approve", - "actions": [ - [ "button", 1, true ], - [ "button", 2, true ], - [ "button", 2, false ], - [ "button", 1, false ] - ] - } - ] -} diff --git a/tests/automations/reject.json b/tests/automations/reject.json deleted file mode 100644 index 7de1fd2a..00000000 --- a/tests/automations/reject.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "version": 1, - "rules": [ - { - "regexp": "Review|Amount|Address|Confirm|Fees|Accept", - "actions": [ - ["button", 2, true], - ["button", 2, false] - ] - }, - { - "regexp": "Tap to continue", - "actions": [ - ["finger", 55, 550, true], - ["finger", 55, 550, false] - ] - }, - { - "text": "Reject", - "actions": [ - [ "button", 1, true ], - [ "button", 2, true ], - [ "button", 2, false ], - [ "button", 1, false ] - ] - }, - { - "regexp": "Cancel", - "actions": [ - ["finger", 55, 650, true], - ["finger", 55, 650, false] - ] - } - ] -} diff --git a/tests/automations/sign_message.json b/tests/automations/sign_message.json deleted file mode 100644 index fa49d745..00000000 --- a/tests/automations/sign_message.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "version": 1, - "rules": [ - { - "regexp": "Tap to continue", - "actions": [ - ["finger", 55, 550, true], - ["finger", 55, 550, false] - ] - }, - { - "regexp": "Hold to sign", - "actions": [ - ["finger", 55, 550, true] - ] - }, - { - "regexp": "Message hash", - "actions": [ - ["button", 2, true], - ["button", 2, false] - ] - }, - { - "regexp": "[S]?ign", - "conditions": [ - [ "seen", false ] - ], - "actions": [ - ["setbool", "seen", true], - ["button", 2, true], - ["button", 2, false] - ] - }, - { - "regexp": "[S]?ign", - "conditions": [ - [ "seen", true ] - ], - "actions": [ - ["setbool", "seen", true], - [ "button", 1, true ], - [ "button", 2, true ], - [ "button", 2, false ], - [ "button", 1, false ] - - ] - } - ] -} diff --git a/tests/bitcoin_client/__init__.py b/tests/bitcoin_client/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/bitcoin_client/bitcoin_base_cmd.py b/tests/bitcoin_client/bitcoin_base_cmd.py deleted file mode 100644 index 55605e2a..00000000 --- a/tests/bitcoin_client/bitcoin_base_cmd.py +++ /dev/null @@ -1,385 +0,0 @@ -import struct -from typing import Tuple, List, Optional - -from ledgercomm import Transport - -from bitcoin_client.hwi.serialization import CTransaction, hash256 -from bitcoin_client.exception.device_exception import DeviceException -from bitcoin_client.bitcoin_cmd_builder import AddrType, InsType, BitcoinCommandBuilder -import base64 - - -class BitcoinBaseCommand: - """Bitcoin Base Command. - - Send APDU command to device and get APDU response. - - Parameters - ---------- - transport : Transport - Transport interface to the device. - debug : bool - Whether you want to see logging or not. - - Attributes - ---------- - transport : Transport - Transport interface to send APDUs. - builder : BitcoinCommandBuilder - Command builder to construct APDUs. - - """ - - def __init__(self, transport: Transport, debug: bool = False) -> None: - """Init constructor.""" - self.transport = transport - self.builder = BitcoinCommandBuilder(debug=debug) - - def get_random(self, n: int = 5) -> bytes: - """Get `n` bytes random value. - - Parameters - ---------- - n : int - Number of bytes (5 <= n <= 248). - - Returns - ------- - bytes - Random bytes of length `n` from the device. - - """ - sw, response = self.transport.exchange_raw( - self.builder.get_random(n=n) - ) - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.GET_RANDOM) - - return response - - def get_firmware_version(self) -> Tuple[int, int, int]: - """Get the version of the application. - - Returns - ------- - Tuple[int, int, int] - (MAJOR, MINOR, PATCH) version of the application. - - """ - sw, response = self.transport.exchange_raw( - self.builder.get_firmware_version() - ) - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.GET_FIRMWARE_VERSION) - - # response = flag (1) [unused] || - # architecture id (1) [unused] || - # major version of the application (1) || - # minor version of the application (1) || - # patch version of the application (1) || - # loader id major version (1) [unused] || - # loader id minor version (1) [unused] || - # mode (1) [unused] - _, _, major, minor, patch, _, _, _ = struct.unpack( - "BBBBBBBB", - response - ) # type: int, int, int, int, int, int, int, int - - return major, minor, patch - - def get_coin_version(self) -> Tuple[int, int, int, str, str]: - """Get coin information depending on Bitcoin app fork. - - Returns - ------- - Tuple[int, int, int, str, str] - A tuple (p2pkh_pref, p2sh_prefix, coin_family, coin_name, coin_ticker). - - """ - sw, response = self.transport.exchange_raw( - self.builder.get_coin_version() - ) # type: int, bytes - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.GET_COIN_VERSION) - - # response = p2pkh_prefix (2) || p2sh_prefix (2) || coin_family (1) || - # len(coin_name) (1) || coin_name (var) || - # len(coin_ticker) (1) || coin_ticker (var) - offset: int = 0 - p2pkh_prefix: int = int.from_bytes(response[offset:offset + 2], byteorder="big") - offset += 2 - p2sh_prefix: int = int.from_bytes(response[offset:offset + 2], byteorder="big") - offset += 2 - coin_family: int = response[offset] - offset += 1 - coin_name_len: int = response[offset] - offset += 1 - coin_name: str = response[offset:offset + coin_name_len].decode("ascii") - offset += coin_name_len - coin_ticker_len: int = response[offset] - offset += 1 - coin_ticker: str = response[offset:offset + coin_ticker_len].decode("ascii") - offset += coin_ticker_len - - assert len(response) == offset - - return p2pkh_prefix, p2sh_prefix, coin_family, coin_name, coin_ticker - - def get_public_key(self, - addr_type: AddrType, - bip32_path: str, - display: bool = False) -> Tuple[bytes, str, bytes]: - """Get public key given address type and BIP32 path. - - Parameters - ---------- - addr_type : AddrType - Type of address. Could be AddrType.Legacy, AddrType.P2SH_P2WPKH, - AddrType.BECH32. - bip32_path : str - BIP32 path of the public key you want. - display : bool - Whether you want to display address and ask confirmation on the device. - - Returns - ------- - - """ - sw, response = self.transport.exchange_raw( - self.builder.get_public_key(addr_type=addr_type, - bip32_path=bip32_path, - display=display) - ) # type: int, bytes - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.GET_WALLET_PUBLIC_KEY) - - # response = len(pub_key) (1) || pub_key (var) || - # len(addr) (1) || addr (var) || bip32_chain_code (32) - offset: int = 0 - pub_key_len: int = response[offset] - offset += 1 - pub_key: bytes = response[offset:offset + pub_key_len] - offset += pub_key_len - addr_len: int = response[offset] - offset += 1 - addr: str = response[offset:offset + addr_len].decode("ascii") - offset += addr_len - bip32_chain_code: bytes = response[offset:offset + 32] - offset += 32 - - assert len(response) == offset - - return pub_key, addr, bip32_chain_code - - def sign_message(self, - message: str, - bip32_path: str, - ) -> bytes: - """Sign message. - - Parameters - ---------- - bip32_path : str - BIP32 path to be used to sign. - message : str - Message to be signed - - Returns - ------- - bytes - Signature of the message - - """ - sw: int - response: bytes = b"" - - for chunk in self.builder.sign_message(bip32_path, message): - self.transport.send_raw(chunk) - sw, response = self.transport.recv() # type: int, bytes - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.SIGN_MESSAGE) - - sw, response = self.transport.exchange_raw( - self.builder.sign_message_sign() - ) - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.SIGN_MESSAGE) - - return base64.b64encode(response).decode('utf-8') - - - def get_trusted_input(self, - utxo: CTransaction, - output_index: int) -> bytes: - """Get trusted input given UTXO and output index. - - Parameters - ---------- - utxo : CTransaction - Serialized Bitcoin transaction to extract UTXO. - output_index : int - Index of the UTXO to build the trusted input. - - Returns - ------- - bytes - Serialized trusted input. - - """ - sw: int - response: bytes = b"" - - for chunk in self.builder.get_trusted_input(utxo, output_index): - self.transport.send_raw(chunk) - sw, response = self.transport.recv() # type: int, bytes - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.GET_TRUSTED_INPUT) - - # response = 0x32 (1) || 0x00 (1) || random (2) || prev_txid (32) || - # output_index (4) || amount (8) || HMAC (8) - assert len(response) == 56 - - offset: int = 0 - magic_trusted_input: int = response[offset] - assert magic_trusted_input == 0x32 - offset += 1 - zero: int = response[offset] - assert zero == 0x00 - offset += 1 - _: bytes = response[offset:offset + 2] # random - offset += 2 - prev_txid: bytes = response[offset:offset + 32] - assert prev_txid == hash256(utxo.serialize_without_witness()) - offset += 32 - out_index: int = int.from_bytes(response[offset:offset + 4], - byteorder="little") - assert out_index == output_index - offset += 4 - amount: int = int.from_bytes(response[offset:offset + 8], - byteorder="little") - assert amount == utxo.vout[output_index].nValue - offset += 8 - _: bytes = response[offset:offset + 8] # HMAC - offset += 8 - - assert offset == len(response) - - return response - - def untrusted_hash_tx_input_start(self, - tx: CTransaction, - inputs: List[Tuple[CTransaction, bytes]], - input_index: int, - script: bytes, - is_new_transaction: bool) -> None: - """Send trusted inputs to build the new transaction. - - Parameters - ---------- - tx : CTransaction - Serialized Bitcoin transaction to sign. - inputs : List[Tuple[CTransaction, bytes]] - List of inputs with pair of UTXO and trusted input. - input_index : int - Index of the input to process. - script : bytes - The scriptSig to add at `input_index`. - is_new_transaction: bool - First time sending this input. - - Returns - ------- - None - - """ - sw: int - - for chunk in self.builder.untrusted_hash_tx_input_start(tx=tx, - inputs=inputs, - input_index=input_index, - script=script, - is_new_transaction=is_new_transaction): - self.transport.send_raw(chunk) - sw, _ = self.transport.recv() # type: int, bytes - - if sw != 0x9000: - raise DeviceException( - error_code=sw, - ins=InsType.UNTRUSTED_HASH_TRANSACTION_INPUT_START - ) - - def untrusted_hash_tx_input_finalize(self, - tx: CTransaction, - change_path: Optional[str]) -> bytes: - """Send transaction outputs to finalize the new transaciton. - - Parameters - ---------- - tx: CTransaction - Transaction to sign. - change_path: Optional[str] - BIP32 path for the change. - - Returns - ------- - bytes - Two bytes Reserved for Future Use (RFU) and transaction validation flag. - Unused, always 0x00 and 0x00. - - - """ - sw: int - response: bytes = b"" - - for chunk in self.builder.untrusted_hash_tx_input_finalize(tx=tx, - change_path=change_path): - self.transport.send_raw(chunk) - sw, response = self.transport.recv() - - if sw != 0x9000: - raise DeviceException( - error_code=sw, - ins=InsType.UNTRUSTED_HASH_TRANSACTION_INPUT_FINALIZE - ) - # response = RFU (1) || User validation flag (1) - return response - - def untrusted_hash_sign(self, - sign_path: str, - lock_time: int = 0, - sig_hash: int = 1) -> Tuple[int, bytes]: - """Sign input just sent using `sign_path`. - - Parameters - ---------- - sign_path : str - BIP32 path to be used to sign. - lock_time : int - Block height or timestamp when transaction is final. - sig_hash : int - Either SIGHASH_ALL (0x01), SIGHASH_NONE (0x02) or SIGHASH_SINGLE (0x03). - Only SIGHASH_ALL (0x01) is supported. - - Returns - ------- - Tuple[int, bytes] - A pair (v, der_sig) with: - - v: 0x01 if y-coordinate of R is odd, 0x00 otherwise. - - der_sig: DER encoded Bitcoin ECDSA signature (with SIGHASH). - - """ - sw, response = self.transport.exchange_raw( - self.builder.untrusted_hash_sign(sign_path, lock_time, sig_hash) - ) # type: int, bytes - - if sw != 0x9000: - raise DeviceException(error_code=sw, ins=InsType.UNTRUSTED_HASH_SIGN) - - return (1, b"\x30" + response[1:]) if response[0] & 0x01 else (0, response) diff --git a/tests/bitcoin_client/bitcoin_cmd.py b/tests/bitcoin_client/bitcoin_cmd.py deleted file mode 100644 index ec5818fd..00000000 --- a/tests/bitcoin_client/bitcoin_cmd.py +++ /dev/null @@ -1,244 +0,0 @@ -from typing import Tuple, List - -from ledgercomm import Transport - -from bitcoin_client.hwi.serialization import (CTransaction, CTxIn, CTxOut, COutPoint, - is_witness, is_p2wpkh, is_p2pkh, is_p2sh, hash160) -from bitcoin_client.hwi.bech32 import decode as bech32_decode -from bitcoin_client.hwi.base58 import decode as base58_decode -from bitcoin_client.utils import deser_trusted_input -from bitcoin_client.bitcoin_utils import bip143_digest, compress_pub_key -from bitcoin_client.bitcoin_cmd_builder import AddrType -from bitcoin_client.bitcoin_base_cmd import BitcoinBaseCommand - - -class BitcoinCommand(BitcoinBaseCommand): - """Bitcoin Command. - - Inherit from BitcoinBaseCommand and provide a high level - interface to sign Bitcoin transaction. - - Parameters - ---------- - transport : Transport - Transport interface to the device. - debug : bool - Whether you want to see logging or not. - - """ - - def __init__(self, transport: Transport, debug: bool = False) -> None: - """Init constructor.""" - super().__init__(transport, debug) - - def sign_new_tx(self, - address: str, - amount: int, - fees: int, - change_path: str, - sign_paths: List[str], - raw_utxos: List[Tuple[bytes, int]], - lock_time: int = 0) -> List[Tuple[bytes, bytes, Tuple[int, bytes]]]: - """Sign a new transaction with parameters.. - - Parameters - ---------- - address : str - Bitcoin address. - amount : int - Amount to send to address in satoshis. - fees : int - Fees of the new transaction. - change_path : str - BIP32 path for the change. - sign_paths : List[str] - BIP32 paths to sign inputs. - raw_utxos : List[Tuple[bytes, int]] - Pairs of raw hex transaction and output index to use as UTXOs. - lock_time : int - Block height or timestamp when transaction is final. - - Returns - ------- - List[Tuple[bytes, bytes, Tuple[int, bytes]]] - Tuples (tx_hash_digest, sign_pub_key, (v, der_sig)) - - """ - utxos: List[Tuple[CTransaction, int, int]] = [] - amount_available: int = 0 - for raw_tx, output_index in raw_utxos: - utxo = CTransaction.from_bytes(raw_tx) - value = utxo.vout[output_index].nValue - utxos.append((utxo, output_index, value)) - amount_available += value - - sign_pub_keys: List[bytes] = [] - for sign_path in sign_paths: - sign_pub_key, _, _ = self.get_public_key( - addr_type=AddrType.BECH32, - bip32_path=sign_path, - display=False - ) - sign_pub_keys.append(compress_pub_key(sign_pub_key)) - - inputs: List[Tuple[CTransaction, bytes]] = [ - (utxo, self.get_trusted_input(utxo=utxo, output_index=output_index)) - for utxo, output_index, _ in utxos - ] - - # new transaction - tx: CTransaction = CTransaction() - tx.nVersion = 2 - tx.nLockTime = lock_time - # prepare vin - for i, (utxo, trusted_input) in enumerate(inputs): - if utxo.sha256 is None: - utxo.calc_sha256(with_witness=False) - - _, _, _, prev_txid, output_index, _, _ = deser_trusted_input(trusted_input) - assert prev_txid != utxo.sha256 - - script_pub_key: bytes = utxo.vout[output_index].scriptPubKey - # P2WPKH - if is_p2wpkh(script_pub_key): - _, _, wit_prog = is_witness(script_pub_key) - script_pub_key = (b"\x76" + # OP_DUP - b"\xa9" + # OP_HASH160 - b"\x14" + # bytes to push (20) - wit_prog + # hash160(pubkey) - b"\x88" + # OP_EQUALVERIFY - b"\xac") # OP_CHECKSIG - # P2SH-P2WPKH or P2PKH - if (is_p2sh(script_pub_key) and not utxo.wit.is_null()) or is_p2pkh(script_pub_key): - script_pub_key = (b"\x76" + # OP_DUP - b"\xa9" + # OP_HASH160 - b"\x14" + # bytes to push (20) - hash160(sign_pub_keys[i]) + # hash160(pubkey) - b"\x88" + # OP_EQUALVERIFY - b"\xac") # OP_CHECKSIG - tx.vin.append(CTxIn(outpoint=COutPoint(h=utxo.sha256, n=output_index), - scriptSig=script_pub_key, - nSequence=0xfffffffd)) - - if amount_available - fees > amount: - change_pub_key, _, _ = self.get_public_key( - addr_type=AddrType.BECH32, - bip32_path=change_path, - display=False - ) - change_pubkey_hash = hash160(compress_pub_key(change_pub_key)) - change_script_pubkey: bytes - # Bech32 pubkey hash or script hash (mainnet and testnet) - if address.startswith("bc1") or address.startswith("tb1"): - change_script_pubkey = bytes([0, len(change_pubkey_hash)]) + change_pubkey_hash - # P2SH-P2WPKH (mainnet and testnet) - elif address.startswith("3") or address.startswith("2"): - change_script_pubkey = (b"\xa9" + # OP_HASH160 - b"\x14" + # bytes to push (20) - # hash160(redeem_script) - hash160(bytes([0, len(change_pubkey_hash)]) + change_pubkey_hash) + - b"\x87") # OP_EQUAL - # P2PKH address (mainnet and testnet) - elif address.startswith("1") or (address.startswith("m") or address.startswith("n")): - change_script_pubkey = (b"\x76" + # OP_DUP - b"\xa9" + # OP_HASH160 - b"\x14" + # bytes to push (20) - change_pubkey_hash + # hash160(pubkey) - b"\x88" + # OP_EQUALVERIFY - b"\xac") # OP_CHECKSIG - else: - raise Exception(f"Unsupported address: '{address}'") - tx.vout.append( - CTxOut(nValue=amount_available - fees - amount, - scriptPubKey=change_script_pubkey) - ) - - script_pub_key: bytes - # Bech32 pubkey hash or script hash (mainnet and testnet) - if address.startswith("bc1") or address.startswith("tb1"): - witness_version, witness_program = bech32_decode(address[0:2], address) - script_pub_key = bytes( - [witness_version + 0x50 if witness_version else 0, - len(witness_program)] + - witness_program - ) - # P2SH address (mainnet and testnet) - elif address.startswith("3") or address.startswith("2"): - script_pub_key = (b"\xa9" + # OP_HASH160 - b"\x14" + # bytes to push (20) - base58_decode(address)[1:-4] + # hash160(redeem_script) - b"\x87") # OP_EQUAL - # P2PKH address (mainnet and testnet) - elif address.startswith("1") or (address.startswith("m") or address.startswith("n")): - script_pub_key = (b"\x76" + # OP_DUP - b"\xa9" + # OP_HASH160 - b"\x14" + # bytes to push (20) - base58_decode(address)[1:-4] + # hash160(pubkey) - b"\x88" + # OP_EQUALVERIFY - b"\xac") # OP_CHECKSIG - else: - raise Exception(f"Unsupported address: '{address}'") - - tx.vout.append(CTxOut(nValue=amount, - scriptPubKey=script_pub_key)) - - for i in range(len(tx.vin)): - self.untrusted_hash_tx_input_start(tx=tx, - inputs=inputs, - input_index=i, - script=tx.vin[i].scriptSig, - is_new_transaction=(i == 0)) - - self.untrusted_hash_tx_input_finalize(tx=tx, - change_path=change_path) - - sigs: List[Tuple[bytes, bytes, Tuple[int, bytes]]] = [] - for i in range(len(tx.vin)): - self.untrusted_hash_tx_input_start(tx=tx, - inputs=[inputs[i]], - input_index=0, - script=tx.vin[i].scriptSig, - is_new_transaction=False) - _, _, amount = utxos[i] - sigs.append( - (bip143_digest(tx, amount, i), - sign_pub_keys[i], - self.untrusted_hash_sign(sign_path=sign_paths[i], - lock_time=tx.nLockTime, - sig_hash=1)) - ) - - return sigs - - def sign_tx(self, - tx: CTransaction, - change_path: str, - sign_paths: List[str], - utxos: List[Tuple[CTransaction, int, int]]) -> List[Tuple[int, bytes]]: - inputs: List[Tuple[CTransaction, bytes]] = [ - (utxo, self.get_trusted_input(utxo=utxo, output_index=output_index)) - for utxo, output_index, _ in utxos - ] - - for i in range(len(tx.vin)): - self.untrusted_hash_tx_input_start(tx=tx, - inputs=inputs, - input_index=i, - script=tx.vin[i].scriptSig, - is_new_transaction=(i == 0)) - - self.untrusted_hash_tx_input_finalize(tx=tx, - change_path=change_path) - - sigs = [] - for i in range(len(tx.vin)): - self.untrusted_hash_tx_input_start(tx=tx, - inputs=[inputs[i]], - input_index=0, - script=tx.vin[i].scriptSig, - is_new_transaction=False) - sigs.append(self.untrusted_hash_sign(sign_path=sign_paths[i], - lock_time=tx.nLockTime, - sig_hash=1)) - - return sigs diff --git a/tests/bitcoin_client/bitcoin_cmd_builder.py b/tests/bitcoin_client/bitcoin_cmd_builder.py deleted file mode 100644 index 8279882d..00000000 --- a/tests/bitcoin_client/bitcoin_cmd_builder.py +++ /dev/null @@ -1,457 +0,0 @@ -import enum -import logging -import struct -from typing import Optional, List, Tuple, Iterator, Union, cast - -from bitcoin_client.hwi.serialization import CTransaction, ser_compact_size -from bitcoin_client.utils import chunkify, MAX_APDU_LEN -from bitcoin_client.bitcoin_utils import bip32_path_from_string - - -class InsType(enum.IntEnum): - """Instruction commands supported.""" - - GET_RANDOM = 0xC0 - GET_FIRMWARE_VERSION = 0xC4 - GET_COIN_VERSION = 0x16 - GET_WALLET_PUBLIC_KEY = 0x40 - GET_TRUSTED_INPUT = 0x42 - UNTRUSTED_HASH_TRANSACTION_INPUT_START = 0x44 - UNTRUSTED_HASH_TRANSACTION_INPUT_FINALIZE = 0x4A - UNTRUSTED_HASH_SIGN = 0x48 - SIGN_MESSAGE = 0x4E - - -class AddrType(enum.IntEnum): - """Type of Bitcoin address.""" - - Legacy = 0x00 - P2SH_P2WPKH = 0x01 - BECH32 = 0x02 - - -class BitcoinCommandBuilder: - """APDU command builder for the Bitcoin application. - - Parameters - ---------- - debug : bool - Whether you want to see logging or not. - - Attributes - ---------- - debug : bool - Whether you want to see logging or not. - - """ - - CLA: int = 0xE0 - - def __init__(self, debug: bool = False): - """Init constructor.""" - self.debug = debug - - def serialize(self, - cla: int, - ins: Union[int, enum.IntEnum], - p1: int = 0, - p2: int = 0, - cdata: bytes = b"") -> bytes: - """Serialize the whole APDU command (header + cdata). - - Parameters - ---------- - cla : int - Instruction class: CLA (1 byte) - ins : Union[int, IntEnum] - Instruction code: INS (1 byte) - p1 : int - Instruction parameter 1: P1 (1 byte). - p2 : int - Instruction parameter 2: P2 (1 byte). - cdata : bytes - Bytes of command data. - - Returns - ------- - bytes - Bytes of a complete APDU command. - - """ - ins = cast(int, ins.value) if isinstance(ins, enum.IntEnum) else cast(int, ins) - - header: bytes = struct.pack("BBBBB", - cla, - ins, - p1, - p2, - len(cdata)) # add Lc to APDU header - - if self.debug: - logging.info("header: %s", header.hex()) - logging.info("cdata: %s", cdata.hex()) - - return header + cdata - - def get_random(self, n: int = 248) -> bytes: - """Command builder for GET_RANDOM. - - Parameters - ---------- - n : int - Number of bytes (1 <= n <= 248). - - Returns - ------- - bytes - APDU command for GET_RANDOM. - - """ - return self.serialize(cla=self.CLA, - ins=InsType.GET_RANDOM, - p1=0x00, - p2=0x00, - cdata=b"\x00" * n) - - def get_firmware_version(self) -> bytes: - """Command builder for GET_FIRMWARE_VERSION. - - Returns - ------- - bytes - APDU command for GET_FIMWARE_VERSION. - - """ - ins: InsType = InsType.GET_FIRMWARE_VERSION - p1: int = 0x00 - p2: int = 0x00 - - return self.serialize(cla=self.CLA, ins=ins, p1=p1, p2=p2, cdata=b"") - - def get_coin_version(self) -> bytes: - """Command builder for GET_COIN_VERSION. - - Returns - ------- - bytes - APDU command for GET_COIN_VERSION. - - """ - ins: InsType = InsType.GET_COIN_VERSION - p1: int = 0x00 - p2: int = 0x00 - - return self.serialize(cla=self.CLA, ins=ins, p1=p1, p2=p2, cdata=b"") - - def get_public_key(self, - addr_type: AddrType, - bip32_path: str, - display: bool = False) -> bytes: - """Command builder for GET_WALLET_PUBLIC_KEY. - - Parameters - ---------- - addr_type : AddrType - The type of address expected in the response. Could be Legacy (0x00), - P2SH-P2WPKH (0x01) or BECH32 encoded P2WPKH (0x02). - bip32_path : str - String representation of BIP32 path (e.g. "m/44'/0'/0'/0" or "44'/0'/0'/0"). - display : bool - Whether you want to display address and ask confirmation on the device. - - Returns - ------- - bytes - APDU command for GET_WALLET_PUBLIC_KEY. - - """ - ins: InsType = InsType.GET_WALLET_PUBLIC_KEY - # P1: - # - 0x00, do not display the address - # - 0x01, display the address - # - 0x02, display the validation token (unused here) - p1: int = 0x01 if display else 0x00 - # P2: type of Bitcoin address in the reponse - p2: int = addr_type.value - - path: List[bytes] = bip32_path_from_string(bip32_path) - - cdata: bytes = b"".join([ - len(path).to_bytes(1, byteorder="big"), - *path - ]) - - return self.serialize(cla=self.CLA, ins=ins, p1=p1, p2=p2, cdata=cdata) - - def get_trusted_input(self, - utxo: CTransaction, - output_index: int) -> Iterator[bytes]: - """Command builder for GET_TRUSTED_INPUT. - - Parameters - ---------- - utxo: CTransaction - Unspent Transaction Output (UTXO) serialized. - output_index: int - Output index owned in the UTXO. - - Yields - ------ - bytes - APDU command chunk for GET_TRUSTED_INPUT. - - """ - ins: InsType = InsType.GET_TRUSTED_INPUT - # P1: - # - 0x00, first transaction data chunk - # - 0x80, other transaction data chunk - p1: int - p2: int = 0x00 - - cdata: bytes = (output_index.to_bytes(4, byteorder="big") + - utxo.serialize_without_witness()) - - for i, (is_last, chunk) in enumerate(chunkify(cdata, MAX_APDU_LEN)): - p1 = 0x00 if i == 0 else 0x80 - if is_last: - yield self.serialize(cla=self.CLA, - ins=ins, - p1=p1, - p2=p2, - cdata=chunk) - return - yield self.serialize(cla=self.CLA, - ins=ins, - p1=p1, - p2=p2, - cdata=chunk) - - def untrusted_hash_tx_input_start(self, - tx: CTransaction, - inputs: List[Tuple[CTransaction, bytes]], - input_index: int, - script: bytes, - is_new_transaction: bool - ) -> Iterator[bytes]: - """Command builder for UNTRUSTED_HASH_TRANSACTION_INPUT_START. - - Parameters - ---------- - tx: CTransaction - Serialized Bitcoin transaction to sign. - inputs: List[Tuple[CTransaction, bytes]] - List of inputs with pair of UTXO and trusted input. - input_index: int - Index of the input to process. - script : bytes - The scriptSig to add at `input_index`. - is_new_transaction: bool - First time sending this input. - - Yields - ------- - bytes - APDU command chunk for UNTRUSTED_HASH_TRANSACTION_INPUT_START. - - """ - ins: InsType = InsType.UNTRUSTED_HASH_TRANSACTION_INPUT_START - # P1: - # - 0x00, first transaction data chunk - # - 0x80, other transaction data chunk - p1: int = 0x00 - # P2: - # - 0x80, new transaction - # - 0x02, new transaction with segwit input - p2: int = 0x02 if is_new_transaction else 0x80 - - cdata: bytes = (tx.nVersion.to_bytes(4, byteorder="little") + - ser_compact_size(len(inputs))) - - yield self.serialize(cla=self.CLA, - ins=ins, - p1=p1, - p2=p2, - cdata=cdata) - - p1 = 0x80 - for i, (_, trusted_input) in enumerate(inputs): - script_sig: bytes = script if i == input_index else b"" - cdata = b"".join([ - b"\x01", # 0x01 for trusted input, 0x02 for witness, 0x00 otherwise - len(trusted_input).to_bytes(1, byteorder="big"), - trusted_input, - ser_compact_size(len(script_sig)) - ]) - - yield self.serialize(cla=self.CLA, - ins=ins, - p1=p1, - p2=p2, - cdata=cdata) - - yield self.serialize(cla=self.CLA, - ins=ins, - p1=p1, - p2=p2, - cdata=(script_sig + - 0xfffffffd.to_bytes(4, byteorder="little"))) - - def untrusted_hash_tx_input_finalize(self, - tx: CTransaction, - change_path: Optional[str] - ) -> Iterator[bytes]: - """Command builder for UNTRUSTED_HASH_TRANSACTION_INPUT_FINALIZE. - - Parameters - ---------- - tx: CTransaction - Transaction to sign. - change_path: Optional[str] - BIP32 path for the change. - - Yields - ------- - bytes - APDU command chunk for UNTRUSTED_HASH_TRANSACTION_INPUT_FINALIZE. - - """ - ins: InsType = InsType.UNTRUSTED_HASH_TRANSACTION_INPUT_FINALIZE - # P1: - # - 0x00, more input chunk to be sent - # - 0x80, last chunk to be sent - # - 0xFF, BIP32 path for the change address - p1: int - p2: int = 0x00 - - p1 = 0xFF - if change_path: - bip32_change_path: List[bytes] = bip32_path_from_string(change_path) - cdata: bytes = b"".join([ - len(bip32_change_path).to_bytes(1, byteorder="big"), - *bip32_change_path - ]) - yield self.serialize(cla=self.CLA, ins=ins, p1=p1, p2=p2, cdata=cdata) - else: - yield self.serialize(cla=self.CLA, ins=ins, p1=p1, p2=p2, cdata=b"\x00") - - vout_num = len(tx.vout) - p1 = 0x00 - yield self.serialize(cla=self.CLA, - ins=ins, - p1=p1, - p2=p2, - cdata=ser_compact_size(vout_num)) - - for i, ctxout in enumerate(tx.vout): - p1 = 0x00 if i < vout_num - 1 else 0x80 - yield self.serialize(cla=self.CLA, - ins=ins, - p1=p1, - p2=p2, - cdata=ctxout.serialize()) - - def untrusted_hash_sign(self, - sign_path: str, - lock_time: int = 0, - sig_hash: int = 1) -> bytes: - """Command builder for UNTRUSTED_HASH_SIGN. - - Parameters - ---------- - sign_path : str - BIP32 path to be used to sign. - lock_time : int - Block height or timestamp when transaction is final. - sig_hash : int - Either SIGHASH_ALL (0x01), SIGHASH_NONE (0x02) or SIGHASH_SINGLE (0x03). - Only SIGHASH_ALL (0x01) is supported. - - Returns - ------- - bytes - APDU command for UNTRUSTED_HASH_SIGN. - - """ - ins: InsType = InsType.UNTRUSTED_HASH_SIGN - p1: int = 0x00 - p2: int = 0x00 - - bip32_path: List[bytes] = bip32_path_from_string(sign_path) - cdata: bytes = b"".join([ - len(bip32_path).to_bytes(1, byteorder="big"), - *bip32_path, - b"\00", # unused (Reserved for Future Use) - lock_time.to_bytes(4, byteorder="big"), # /!\ big instead of little - sig_hash.to_bytes(1, byteorder="big") - ]) - - return self.serialize(cla=self.CLA, ins=ins, p1=p1, p2=p2, cdata=cdata) - - - def sign_message(self, - sign_path: str, - message: str) -> Iterator[bytes]: - """Command builder for UNTRUSTED_HASH_SIGN. - - Parameters - ---------- - sign_path : str - BIP32 path to be used to sign. - lock_time : int - Block height or timestamp when transaction is final. - sig_hash : int - Either SIGHASH_ALL (0x01), SIGHASH_NONE (0x02) or SIGHASH_SINGLE (0x03). - Only SIGHASH_ALL (0x01) is supported. - - Yields - ------- - bytes - APDU command chunk for SIGN_MESSAGE. - - """ - ins: InsType = InsType.SIGN_MESSAGE - # P1: - # - 0x00, first transaction data chunk - # - 0x80, other transaction data chunk - p1: int - p2: int = 0x00 - - bip32_path: List[bytes] = bip32_path_from_string(sign_path) - cdata: bytes = b"".join([ - len(bip32_path).to_bytes(1, byteorder="big"), - *bip32_path, - len(message).to_bytes(1, byteorder="big"), # /!\ big instead of little - message.encode("utf-8") - ]) - - for i, (is_last, chunk) in enumerate(chunkify(cdata, MAX_APDU_LEN)): - p1 = 0x00 if i == 0 else 0x80 - if is_last: - yield self.serialize(cla=self.CLA, - ins=ins, - p1=p1, - p2=p2, - cdata=chunk) - return - yield self.serialize(cla=self.CLA, - ins=ins, - p1=p1, - p2=p2, - cdata=chunk) - - def sign_message_sign(self) -> bytes: - """Command builder for UNTRUSTED_HASH_SIGN. - - Parameters - ---------- - Returns - ------- - bytes - APDU command for SIGN_MESSAGE. - - """ - ins: InsType = InsType.SIGN_MESSAGE - p1: int = 0x80 - p2: int = 0x00 - - return self.serialize(cla=self.CLA, ins=ins, p1=p1, p2=p2, cdata=b"00") diff --git a/tests/bitcoin_client/bitcoin_utils.py b/tests/bitcoin_client/bitcoin_utils.py deleted file mode 100644 index 162d23db..00000000 --- a/tests/bitcoin_client/bitcoin_utils.py +++ /dev/null @@ -1,68 +0,0 @@ -import struct -from typing import List - -from bitcoin_client.hwi.serialization import CTransaction, hash256, ser_string - - -def bip143_digest(tx: CTransaction, - amount: int, - input_index: int, - sig_hash: int = 0x01) -> bytes: - hash_prev_outs: bytes = b"".join([ - txin.prevout.serialize() for txin in tx.vin - ]) - - hash_sequence: bytes = b"".join([ - struct.pack(" List[bytes]: - """Convert BIP32 path string to list of bytes.""" - splitted_path: List[str] = path.split("/") - - if "m" in splitted_path and splitted_path[0] == "m": - splitted_path = splitted_path[1:] - - return [int(p).to_bytes(4, byteorder="big") if "'" not in p - else (0x80000000 | int(p[:-1])).to_bytes(4, byteorder="big") - for p in splitted_path] - - -def compress_pub_key(pub_key: bytes) -> bytes: - """Convert uncompressed to compressed public key.""" - if pub_key[-1] & 1: - return b"\x03" + pub_key[1:33] - - return b"\x02" + pub_key[1:33] \ No newline at end of file diff --git a/tests/bitcoin_client/exception/__init__.py b/tests/bitcoin_client/exception/__init__.py deleted file mode 100644 index 4320abeb..00000000 --- a/tests/bitcoin_client/exception/__init__.py +++ /dev/null @@ -1,64 +0,0 @@ -from .device_exception import DeviceException -from .errors import (AccessConditionNotFullfilledError, - AlgorithmNotSupportedError, - ClaNotSupportedError, - CodeBlockedError, - CodeNotInitializedError, - CommandIncompatibleFileStructureError, - ConditionOfUseNotSatisfiedError, - ContradictionInvalidationError, - ContradictionSecretCodeStatusError, - FileAlreadyExistsError, - FileNotFoundError, - GPAuthFailedError, - HaltedError, - InconsistentFileError, - IncorrectDataError, - IncorrectLengthError, - IncorrectP1P2Error, - InsNotSupportedError, - InvalidKCVError, - InvalidOffsetError, - LicensingError, - MaxValueReachedError, - MemoryProblemError, - NoEFSelectedError, - NotEnoughMemorySpaceError, - ReferencedDataNotFoundError, - SecurityStatusNotSatisfiedError, - SwapWithoutTrustedInputsError, - TechnicalProblemError, - UnknownDeviceError) - -__all__ = [ - "AccessConditionNotFullfilledError", - "AlgorithmNotSupportedError", - "ClaNotSupportedError", - "CodeBlockedError", - "CodeNotInitializedError", - "CommandIncompatibleFileStructureError", - "ConditionOfUseNotSatisfiedError", - "ContradictionInvalidationError", - "ContradictionSecretCodeStatusError", - "FileAlreadyExistsError", - "FileNotFoundError", - "GPAuthFailedError", - "HaltedError", - "InconsistentFileError", - "IncorrectDataError", - "IncorrectLengthError", - "IncorrectP1P2Error", - "InsNotSupportedError", - "InvalidKCVError", - "InvalidOffsetError", - "LicensingError", - "MaxValueReachedError", - "MemoryProblemError", - "NoEFSelectedError", - "NotEnoughMemorySpaceError", - "ReferencedDataNotFoundError", - "SecurityStatusNotSatisfiedError", - "SwapWithoutTrustedInputsError", - "TechnicalProblemError", - "UnknownDeviceError" -] diff --git a/tests/bitcoin_client/exception/device_exception.py b/tests/bitcoin_client/exception/device_exception.py deleted file mode 100644 index ce00193f..00000000 --- a/tests/bitcoin_client/exception/device_exception.py +++ /dev/null @@ -1,53 +0,0 @@ -import enum -from typing import Dict, Any, Optional - -from .errors import * - - -class DeviceException(Exception): # pylint: disable=too-few-public-methods - exc: Dict[int, Any] = { - 0x6700: IncorrectLengthError, - 0x6981: CommandIncompatibleFileStructureError, - 0x6982: SecurityStatusNotSatisfiedError, - 0x6985: ConditionOfUseNotSatisfiedError, - 0x6A80: IncorrectDataError, - 0x6A84: NotEnoughMemorySpaceError, - 0x6A88: ReferencedDataNotFoundError, - 0x6A89: FileAlreadyExistsError, - 0x6A8A: SwapWithoutTrustedInputsError, - 0x6B00: IncorrectP1P2Error, - 0x6D00: InsNotSupportedError, - 0x6E00: ClaNotSupportedError, - 0x6F00: TechnicalProblemError, - 0x9240: MemoryProblemError, - 0x9400: NoEFSelectedError, - 0x9402: InvalidOffsetError, - 0x9404: FileNotFoundError, - 0x9408: InconsistentFileError, - 0x9484: AlgorithmNotSupportedError, - 0x9485: InvalidKCVError, - 0x9802: CodeNotInitializedError, - 0x9804: AccessConditionNotFullfilledError, - 0x9808: ContradictionSecretCodeStatusError, - 0x9810: ContradictionInvalidationError, - 0x9840: CodeBlockedError, - 0x9850: MaxValueReachedError, - 0x6300: GPAuthFailedError, - 0x6F42: LicensingError, - 0x6FAA: HaltedError - } - - def __new__(cls, - error_code: int, - ins: Optional[enum.IntEnum] = None, - message: str = "" - ) -> Any: - error_message: str = (f"Error in {ins!r} command" - if ins else "Error in command") - - if error_code in DeviceException.exc: - return DeviceException.exc[error_code](hex(error_code), - error_message, - message) - - return UnknownDeviceError(hex(error_code), error_message, message) diff --git a/tests/bitcoin_client/exception/errors.py b/tests/bitcoin_client/exception/errors.py deleted file mode 100644 index e19f4f73..00000000 --- a/tests/bitcoin_client/exception/errors.py +++ /dev/null @@ -1,118 +0,0 @@ -class UnknownDeviceError(Exception): - pass - - -class IncorrectLengthError(Exception): - pass - - -class CommandIncompatibleFileStructureError(Exception): - pass - - -class SecurityStatusNotSatisfiedError(Exception): - pass - - -class ConditionOfUseNotSatisfiedError(Exception): - pass - - -class IncorrectDataError(Exception): - pass - - -class NotEnoughMemorySpaceError(Exception): - pass - - -class ReferencedDataNotFoundError(Exception): - pass - - -class FileAlreadyExistsError(Exception): - pass - - -class SwapWithoutTrustedInputsError(Exception): - pass - - -class IncorrectP1P2Error(Exception): - pass - - -class InsNotSupportedError(Exception): - pass - - -class ClaNotSupportedError(Exception): - pass - - -class TechnicalProblemError(Exception): - pass - - -class MemoryProblemError(Exception): - pass - - -class NoEFSelectedError(Exception): - pass - - -class InvalidOffsetError(Exception): - pass - - -class FileNotFoundError(Exception): - pass - - -class InconsistentFileError(Exception): - pass - - -class AlgorithmNotSupportedError(Exception): - pass - - -class InvalidKCVError(Exception): - pass - - -class CodeNotInitializedError(Exception): - pass - - -class AccessConditionNotFullfilledError(Exception): - pass - - -class ContradictionSecretCodeStatusError(Exception): - pass - - -class ContradictionInvalidationError(Exception): - pass - - -class CodeBlockedError(Exception): - pass - - -class MaxValueReachedError(Exception): - pass - - -class GPAuthFailedError(Exception): - pass - - -class LicensingError(Exception): - pass - - -class HaltedError(Exception): - pass diff --git a/tests/bitcoin_client/hwi/__init__.py b/tests/bitcoin_client/hwi/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/bitcoin_client/hwi/base58.py b/tests/bitcoin_client/hwi/base58.py deleted file mode 100644 index e0df1152..00000000 --- a/tests/bitcoin_client/hwi/base58.py +++ /dev/null @@ -1,110 +0,0 @@ -"""base58 module. - -Original source: git://github.com/joric/brutus.git -which was forked from git://github.com/samrushing/caesure.git - -Distributed under the MIT/X11 software license, see the accompanying -file COPYING or http://www.opensource.org/licenses/mit-license.php. - -""" - -import hashlib -from binascii import hexlify, unhexlify -from typing import List - - -b58_digits: str = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' - - -def sha256(s: bytes) -> bytes: - return hashlib.new('sha256', s).digest() - - -def hash256(s: bytes) -> bytes: - return sha256(sha256(s)) - - -def encode(b: bytes) -> str: - """Encode bytes to a base58-encoded string""" - - # Convert big-endian bytes to integer - n: int = int('0x0' + hexlify(b).decode('utf8'), 16) - - # Divide that integer into base58 - temp: List[str] = [] - while n > 0: - n, r = divmod(n, 58) - temp.append(b58_digits[r]) - res: str = ''.join(temp[::-1]) - - # Encode leading zeros as base58 zeros - czero: int = 0 - pad: int = 0 - for c in b: - if c == czero: - pad += 1 - else: - break - return b58_digits[0] * pad + res - - -def decode(s: str) -> bytes: - """Decode a base58-encoding string, returning bytes""" - if not s: - return b'' - - # Convert the string to an integer - n: int = 0 - for c in s: - n *= 58 - if c not in b58_digits: - raise ValueError('Character %r is not a valid base58 character' % c) - digit = b58_digits.index(c) - n += digit - - # Convert the integer to bytes - h: str = '%x' % n - if len(h) % 2: - h = '0' + h - res = unhexlify(h.encode('utf8')) - - # Add padding back. - pad = 0 - for c in s[:-1]: - if c == b58_digits[0]: - pad += 1 - else: - break - return b'\x00' * pad + res - - -def get_xpub_fingerprint(s: str) -> bytes: - data = decode(s) - fingerprint = data[5:9] - return fingerprint - - -def get_xpub_fingerprint_hex(xpub: str) -> str: - data = decode(xpub) - fingerprint = data[5:9] - return hexlify(fingerprint).decode() - - -def to_address(b: bytes, version: bytes) -> str: - data = version + b - checksum = hash256(data)[0:4] - data += checksum - return encode(data) - - -def xpub_to_pub_hex(xpub: str) -> str: - data = decode(xpub) - pubkey = data[-37:-4] - return hexlify(pubkey).decode() - - -def xpub_main_2_test(xpub: str) -> str: - data = decode(xpub) - test_data = b'\x04\x35\x87\xCF' + data[4:-4] - checksum = hash256(test_data)[0:4] - return encode(test_data + checksum) diff --git a/tests/bitcoin_client/hwi/bech32.py b/tests/bitcoin_client/hwi/bech32.py deleted file mode 100644 index 68f24687..00000000 --- a/tests/bitcoin_client/hwi/bech32.py +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright (c) 2017 Pieter Wuille -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -"""Reference implementation for Bech32 and segwit addresses.""" - - -CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" - - -def bech32_polymod(values): - """Internal function that computes the Bech32 checksum.""" - generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3] - chk = 1 - for value in values: - top = chk >> 25 - chk = (chk & 0x1ffffff) << 5 ^ value - for i in range(5): - chk ^= generator[i] if ((top >> i) & 1) else 0 - return chk - - -def bech32_hrp_expand(hrp): - """Expand the HRP into values for checksum computation.""" - return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp] - - -def bech32_verify_checksum(hrp, data): - """Verify a checksum given HRP and converted data characters.""" - return bech32_polymod(bech32_hrp_expand(hrp) + data) == 1 - - -def bech32_create_checksum(hrp, data): - """Compute the checksum values given HRP and data.""" - values = bech32_hrp_expand(hrp) + data - polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ 1 - return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)] - - -def bech32_encode(hrp, data): - """Compute a Bech32 string given HRP and data values.""" - combined = data + bech32_create_checksum(hrp, data) - return hrp + '1' + ''.join([CHARSET[d] for d in combined]) - - -def bech32_decode(bech): - """Validate a Bech32 string, and determine HRP and data.""" - if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or - (bech.lower() != bech and bech.upper() != bech)): - return (None, None) - bech = bech.lower() - pos = bech.rfind('1') - if pos < 1 or pos + 7 > len(bech) or len(bech) > 90: - return (None, None) - if not all(x in CHARSET for x in bech[pos + 1:]): - return (None, None) - hrp = bech[:pos] - data = [CHARSET.find(x) for x in bech[pos + 1:]] - if not bech32_verify_checksum(hrp, data): - return (None, None) - return (hrp, data[:-6]) - - -def convertbits(data, frombits, tobits, pad=True): - """General power-of-2 base conversion.""" - acc = 0 - bits = 0 - ret = [] - maxv = (1 << tobits) - 1 - max_acc = (1 << (frombits + tobits - 1)) - 1 - for value in data: - if value < 0 or (value >> frombits): - return None - acc = ((acc << frombits) | value) & max_acc - bits += frombits - while bits >= tobits: - bits -= tobits - ret.append((acc >> bits) & maxv) - if pad: - if bits: - ret.append((acc << (tobits - bits)) & maxv) - elif bits >= frombits or ((acc << (tobits - bits)) & maxv): - return None - return ret - - -def decode(hrp, addr): - """Decode a segwit address.""" - hrpgot, data = bech32_decode(addr) - if hrpgot != hrp: - return (None, None) - decoded = convertbits(data[1:], 5, 8, False) - if decoded is None or len(decoded) < 2 or len(decoded) > 40: - return (None, None) - if data[0] > 16: - return (None, None) - if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32: - return (None, None) - return (data[0], decoded) - - -def encode(hrp, witver, witprog): - """Encode a segwit address.""" - ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5)) - if decode(hrp, ret) == (None, None): - return None - return ret diff --git a/tests/bitcoin_client/hwi/serialization.py b/tests/bitcoin_client/hwi/serialization.py deleted file mode 100644 index fc1cc643..00000000 --- a/tests/bitcoin_client/hwi/serialization.py +++ /dev/null @@ -1,524 +0,0 @@ -"""Bitcoin Object Python Serializations. - -Copyright (c) 2010 ArtForz -- public domain half-a-node -Copyright (c) 2012 Jeff Garzik -Copyright (c) 2010-2016 The Bitcoin Core developers - -Distributed under the MIT software license, see the accompanying -file COPYING or http://www.opensource.org/licenses/mit-license.php. - -Modified from the test/test_framework/mininode.py file from the -Bitcoin repository - -CTransaction,CTxIn, CTxOut, etc....: - data structures that should map to corresponding structures in - bitcoin/primitives for transactions only -ser_*, deser_*: functions that handle serialization/deserialization - -""" - -import struct -import binascii -import hashlib -import copy -import base64 -from io import BytesIO -from typing import ( - List, - Optional, - Sequence, - Tuple, - TypeVar, - Callable -) -from typing_extensions import Protocol - - -class Readable(Protocol): - def read(self, n: int = -1) -> bytes: - ... - - -class Deserializable(Protocol): - def deserialize(self, f: Readable) -> None: - ... - - -class Serializable(Protocol): - def serialize(self) -> bytes: - ... - - -def sha256(s: bytes) -> bytes: - return hashlib.new('sha256', s).digest() - - -def ripemd160(s: bytes) -> bytes: - return hashlib.new('ripemd160', s).digest() - - -def hash256(s: bytes) -> bytes: - return sha256(sha256(s)) - - -def hash160(s: bytes) -> bytes: - return ripemd160(sha256(s)) - - -# Serialization/deserialization tools -def ser_compact_size(size: int) -> bytes: - r: bytes - if size < 253: - r = struct.pack("B", size) - elif size < 0x10000: - r = struct.pack(" int: - nit: int = struct.unpack(" bytes: - nit = deser_compact_size(f) - return f.read(nit) - - -def ser_string(s: bytes) -> bytes: - return ser_compact_size(len(s)) + s - - -def deser_uint256(f: Readable) -> int: - r = 0 - for i in range(8): - t = struct.unpack(" bytes: - rs = b"" - for _ in range(8): - rs += struct.pack(">= 32 - return rs - - -def uint256_from_str(s: bytes) -> int: - r = 0 - t = struct.unpack(" List[D]: - nit = deser_compact_size(f) - r = [] - for _ in range(nit): - t = c() - t.deserialize(f) - r.append(t) - return r - - -def ser_vector(v: Sequence[Serializable]) -> bytes: - r = ser_compact_size(len(v)) - for i in v: - r += i.serialize() - return r - - -def deser_string_vector(f: Readable) -> List[bytes]: - nit = deser_compact_size(f) - r = [] - for _ in range(nit): - t = deser_string(f) - r.append(t) - return r - - -def ser_string_vector(v: List[bytes]) -> bytes: - r = ser_compact_size(len(v)) - for sv in v: - r += ser_string(sv) - return r - - -def hex_to_base64(s: str) -> bytes: - return base64.b64encode(binascii.unhexlify(s)) - - -def ser_sig_der(r: bytes, s: bytes) -> bytes: - sig = b"\x30" - - # Make r and s as short as possible - ri = 0 - for b in r: - if b == 0: - ri += 1 - else: - break - r = r[ri:] - si = 0 - for b in s: - if b == 0: - si += 1 - else: - break - s = s[si:] - - # Make positive of neg - first = r[0] - if first & (1 << 7) != 0: - r = b"\x00" + r - first = s[0] - if first & (1 << 7) != 0: - s = b"\x00" + s - - # Write total length - total_len = len(r) + len(s) + 4 - sig += struct.pack("B", total_len) - - # write r - sig += b"\x02" - sig += struct.pack("B", len(r)) - sig += r - - # write s - sig += b"\x02" - sig += struct.pack("B", len(s)) - sig += s - - sig += b"\x01" - return sig - - -def ser_sig_compact(r: bytes, s: bytes, recid: bytes) -> bytes: - rec = struct.unpack("B", recid)[0] - prefix = struct.pack("B", 27 + 4 + rec) - - sig = b"" - sig += prefix - sig += r + s - - return sig - -# Objects that map to bitcoind objects, which can be serialized/deserialized - - -MSG_WITNESS_FLAG = 1 << 30 - - -class COutPoint(object): - def __init__(self, h: int = 0, n: int = 0xffffffff): - self.hash = h - self.n = n - - def deserialize(self, f: Readable) -> None: - self.hash = deser_uint256(f) - self.n = struct.unpack(" bytes: - r = b"" - r += ser_uint256(self.hash) - r += struct.pack(" str: - return "COutPoint(hash=%064x n=%i)" % (self.hash, self.n) - - -class CTxIn(object): - def __init__( - self, - outpoint: Optional[COutPoint] = None, - scriptSig: bytes = b"", - nSequence: int = 0, - ): - if outpoint is None: - self.prevout = COutPoint() - else: - self.prevout = outpoint - self.scriptSig = scriptSig - self.nSequence = nSequence - - def deserialize(self, f: Readable) -> None: - self.prevout = COutPoint() - self.prevout.deserialize(f) - self.scriptSig = deser_string(f) - self.nSequence = struct.unpack(" bytes: - r = b"" - r += self.prevout.serialize() - r += ser_string(self.scriptSig) - r += struct.pack(" str: - return "CTxIn(prevout=%s scriptSig=%s nSequence=%i)" \ - % (repr(self.prevout), self.scriptSig.hex(), - self.nSequence) - - -def is_p2sh(script: bytes) -> bool: - return len(script) == 23 and script[0] == 0xa9 and script[1] == 0x14 and script[22] == 0x87 - - -def is_p2pkh(script: bytes) -> bool: - return (len(script) == 25 and - script[0] == 0x76 and - script[1] == 0xa9 and - script[2] == 0x14 and - script[23] == 0x88 and - script[24] == 0xac) - - -def is_p2pk(script: bytes) -> bool: - return ((len(script) == 35 or len(script) == 67) and - (script[0] == 0x21 or script[0] == 0x41) and - script[-1] == 0xac) - - -def is_witness(script: bytes) -> Tuple[bool, int, bytes]: - if len(script) < 4 or len(script) > 42: - return False, 0, b"" - - if script[0] != 0 and (script[0] < 81 or script[0] > 96): - return False, 0, b"" - - if script[1] + 2 == len(script): - return True, script[0] - 0x50 if script[0] else 0, script[2:] - - return False, 0, b"" - - -def is_p2wpkh(script: bytes) -> bool: - is_wit, wit_ver, wit_prog = is_witness(script) - if not is_wit: - return False - elif wit_ver != 0: - return False - return len(wit_prog) == 20 - - -def is_p2wsh(script: bytes) -> bool: - is_wit, wit_ver, wit_prog = is_witness(script) - if not is_wit: - return False - elif wit_ver != 0: - return False - return len(wit_prog) == 32 - - -class CTxOut(object): - def __init__(self, nValue: int = 0, scriptPubKey: bytes = b""): - self.nValue = nValue - self.scriptPubKey = scriptPubKey - - def deserialize(self, f: Readable) -> None: - self.nValue = struct.unpack(" bytes: - r = b"" - r += struct.pack(" bool: - return is_p2sh(self.scriptPubKey) - - def is_p2pkh(self) -> bool: - return is_p2pkh(self.scriptPubKey) - - def is_p2pk(self) -> bool: - return is_p2pk(self.scriptPubKey) - - def is_witness(self) -> Tuple[bool, int, bytes]: - return is_witness(self.scriptPubKey) - - def __repr__(self) -> str: - return "CTxOut(nValue=%i.%08i scriptPubKey=%s)" \ - % (self.nValue, self.nValue, self.scriptPubKey.hex()) - - -class CScriptWitness(object): - def __init__(self) -> None: - # stack is a vector of strings - self.stack: List[bytes] = [] - - def __repr__(self) -> str: - return "CScriptWitness(%s)" % \ - (",".join([x.hex() for x in self.stack])) - - def is_null(self) -> bool: - if self.stack: - return False - return True - - -class CTxInWitness(object): - def __init__(self) -> None: - self.scriptWitness = CScriptWitness() - - def deserialize(self, f: Readable) -> None: - self.scriptWitness.stack = deser_string_vector(f) - - def serialize(self) -> bytes: - return ser_string_vector(self.scriptWitness.stack) - - def __repr__(self) -> str: - return repr(self.scriptWitness) - - def is_null(self) -> bool: - return self.scriptWitness.is_null() - - -class CTxWitness(object): - def __init__(self) -> None: - self.vtxinwit: List[CTxInWitness] = [] - - def deserialize(self, f: Readable) -> None: - for i in range(len(self.vtxinwit)): - self.vtxinwit[i].deserialize(f) - - def serialize(self) -> bytes: - r = b"" - # This is different than the usual vector serialization -- - # we omit the length of the vector, which is required to be - # the same length as the transaction's vin vector. - for x in self.vtxinwit: - r += x.serialize() - return r - - def __repr__(self) -> str: - return "CTxWitness(%s)" % \ - (';'.join([repr(x) for x in self.vtxinwit])) - - def is_null(self) -> bool: - for x in self.vtxinwit: - if not x.is_null(): - return False - return True - - -class CTransaction(object): - def __init__(self, tx: Optional['CTransaction'] = None) -> None: - if tx is None: - self.nVersion = 1 - self.vin: List[CTxIn] = [] - self.vout: List[CTxOut] = [] - self.wit = CTxWitness() - self.nLockTime = 0 - self.sha256: Optional[int] = None - self.hash: Optional[str] = None - else: - self.nVersion = tx.nVersion - self.vin = copy.deepcopy(tx.vin) - self.vout = copy.deepcopy(tx.vout) - self.nLockTime = tx.nLockTime - self.sha256 = tx.sha256 - self.hash = tx.hash - self.wit = copy.deepcopy(tx.wit) - - def deserialize(self, f: Readable) -> None: - self.nVersion = struct.unpack(" bytes: - r = b"" - r += struct.pack(" bytes: - flags = 0 - if not self.wit.is_null(): - flags |= 1 - r = b"" - r += struct.pack(" bytes: - return self.serialize_without_witness() - - # Recalculate the txid (transaction hash without witness) - def rehash(self) -> None: - self.sha256 = None - self.calc_sha256() - - # We will only cache the serialization without witness in - # self.sha256 and self.hash -- those are expected to be the txid. - def calc_sha256(self, with_witness: bool = False) -> Optional[int]: - if with_witness: - # Don't cache the result, just return it - return uint256_from_str(hash256(self.serialize_with_witness())) - - if self.sha256 is None: - self.sha256 = uint256_from_str(hash256(self.serialize_without_witness())) - self.hash = hash256(self.serialize())[::-1].hex() - return None - - def is_null(self) -> bool: - return len(self.vin) == 0 and len(self.vout) == 0 - - @classmethod - def from_bytes(cls, b: bytes): - tx = cls() - tx.deserialize(BytesIO(b)) - - return tx - - def __repr__(self) -> str: - return "CTransaction(nVersion=%i vin=%s vout=%s wit=%s nLockTime=%i)" \ - % (self.nVersion, repr(self.vin), repr(self.vout), repr(self.wit), self.nLockTime) diff --git a/tests/bitcoin_client/utils.py b/tests/bitcoin_client/utils.py deleted file mode 100644 index 1027127d..00000000 --- a/tests/bitcoin_client/utils.py +++ /dev/null @@ -1,55 +0,0 @@ -from typing import Tuple, Iterator - - -MAX_APDU_LEN: int = 255 - - -def chunkify(data: bytes, chunk_len: int) -> Iterator[Tuple[bool, bytes]]: - """Split `data` into chunk of length `chunk_len`.`""" - size: int = len(data) - - if size <= chunk_len: - yield True, data - return - - chunk: int = size // chunk_len - remaining: int = size % chunk_len - offset: int = 0 - - for i in range(chunk): - yield False, data[offset:offset + chunk_len] - offset += chunk_len - - if remaining: - yield True, data[offset:] - - -def deser_trusted_input(trusted_input: bytes - ) -> Tuple[int, int, bytes, bytes, int, int, bytes]: - """Deserialize trusted input into 7 items.""" - assert len(trusted_input) == 56 - - offset: int = 0 - magic_trusted_input: int = trusted_input[offset] - assert magic_trusted_input == 0x32 - offset += 1 - zero: int = trusted_input[offset] - assert zero == 0x00 - offset += 1 - random: bytes = trusted_input[offset:offset + 2] - offset += 2 - prev_txid: bytes = trusted_input[offset:offset + 32] - offset += 32 - out_index: int = int.from_bytes(trusted_input[offset:offset + 4], - byteorder="little") - offset += 4 - amount: int = int.from_bytes(trusted_input[offset:offset + 8], - byteorder="little") - offset += 8 - hmac: bytes = trusted_input[offset:offset + 8] - offset += 8 - - assert offset == len(trusted_input) - - return (magic_trusted_input, zero, random, - prev_txid, out_index, amount, hmac) diff --git a/tests/clean_tests.sh b/tests/clean_tests.sh deleted file mode 100755 index 83b9187b..00000000 --- a/tests/clean_tests.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -rm -rf bitcoin-bin -rm -rf bitcoin-testnet-bin diff --git a/tests/data/many-to-many/p2pkh/apdu_debug.log b/tests/data/many-to-many/p2pkh/apdu_debug.log deleted file mode 100644 index ac5e51b0..00000000 --- a/tests/data/many-to-many/p2pkh/apdu_debug.log +++ /dev/null @@ -1,446 +0,0 @@ -New APDU received: -E0C4000000 -New APDU received: -F026000000 -New APDU received: -E0C4000000 -New APDU received: -E024000000 -New APDU received: -E02280000130 -New APDU received: -E04000000100 -pin ok -Using private component -34AC5D784EBB4DF4727BCDDF6A6743F5D5D46D83DD74AA825866390C694F2938 -To hash -0251EC84E33A3119486461A44240E906FF94BF40CF807B025B1CA43332B80DC9DB -Hash160 -F5ACC2FD5C60B7263C4A459541C1473BC29E58F4 -Checksum -A21FB2F3 -Length to encode 25 -To encode -6FF5ACC2FD5C60B7263C4A459541C1473BC29E58F4A21FB2F3 -Length encoded 34 -Encoded -6E3375786F6B3843337A566277476A72584476344E544E516A313865335A4D4A426B -Length 34 -New APDU received: -E0400000050180000000 -pin ok -Using private component -C71AE2E616FBCCC325A71600E9C82816505A6373EFCE4CAEDA60400667E0B75C -To hash -02E5646066C2C51CEAEA66F04EC85858D34E2BD285F4A60B1402BFC03CF462E767 -Hash160 -7D825341D36FC1297A41A9839A72975815B1FE61 -Checksum -E01B4FD2 -Length to encode 25 -To encode -6F7D825341D36FC1297A41A9839A72975815B1FE61E01B4FD2 -Length encoded 34 -Encoded -6D727861744272776D555959504E774E4879334A5461567350474750716A4A68674D -Length 34 -New APDU received: -E040000009028000002C80000001 -pin ok -Using private component -D0A20FEE4287C3C34ED5C30030FED4E87A6D4A86C87F8281091482BE76E266AD -To hash -03AC9DC20F0C2E9483FBDF9060E8154A19E38B1A886E0883B1E5E7C5582D56A638 -Hash160 -7CAC5506C90EF8E1F7D8928BDC0E3DC0DA4CD714 -Checksum -0EE9DF4F -Length to encode 25 -To encode -6F7CAC5506C90EF8E1F7D8928BDC0E3DC0DA4CD7140EE9DF4F -Length encoded 34 -Encoded -6D727441586771544634423463736770507972663639336455374C3256766A5A787A -Length 34 -New APDU received: -E04000000D038000002C8000000180000000 -pin ok -Using private component -F2D80B9A6B840D409622DB675EE45A2ED8051029D298F847AA8905BEC7967453 -To hash -03E84C7F4B7662FAED9F5EB2D812D9B7BCF0E0BF2A33B17AC45E38B8459669C321 -Hash160 -0812D36245DAC14478722DB30D66285EB115661A -Checksum -E53861E3 -Length to encode 25 -To encode -6F0812D36245DAC14478722DB30D66285EB115661AE53861E3 -Length encoded 34 -Encoded -6D6746654664344D42345A6B566257644647546156356956693369426668775A617A -Length 34 -New APDU received: -E0C4000000 -New APDU received: -E042000009000000000200000001 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -01 -Number of inputs : 1 -Process input -New APDU received: -E042800025F4C2B478DC9CEA2DF43C8BB94938FF43F3BED5AEB3AF9E36CDB7016104626BF2000000006B -Process input ---- ADD TO HASH FULL: -F4C2B478DC9CEA2DF43C8BB94938FF43F3BED5AEB3AF9E36CDB7016104626BF200000000 ---- ADD TO HASH FULL: -6B -Script to read 107 -Process input script, remaining 107 -New APDU received: -E04280006F483045022100B7B8244B3F83648397FA3C37349ED1827BF40BFCA22D4F87CC019D3FDED63E1D02205434CE222DE35E04AB98BE54AF57D2C8B464F0DA76A0275443B33C7B1DF79344012103462F1E48396CE2A4D7694D107FEF5123FE4D1E394394A370FA4901E744B4884EFDFFFFFF -Process input script, remaining 107 ---- ADD TO HASH FULL: -483045022100B7B8244B3F83648397FA3C37349ED1827BF40BFCA22D4F87CC019D3FDED63E1D02205434CE222DE35E04AB98BE54AF57D2C8B464F0DA76A0275443B33C7B1DF79344012103462F1E48396CE2A4D7694D107FEF5123FE4D1E394394A370FA4901E744B488 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -4E ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -New APDU received: -E04280000102 -Input hashing done ---- ADD TO HASH FULL: -02 -Number of outputs : 2 -New APDU received: -E042800009DCDB06000000000019 ---- ADD TO HASH FULL: -DCDB060000000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process output script, remaining 25 -New APDU received: -E04280001976A914B242BA04B8526B533B17B168D27EAF0DA7BACB8588AC -Process output script, remaining 25 ---- ADD TO HASH FULL: -76A914B242BA04B8526B533B17B168D27EAF0DA7BACB8588AC -Process output script, remaining 0 -New APDU received: -E042800009706408000000000019 -Process output script, remaining 0 ---- ADD TO HASH FULL: -7064080000000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process output script, remaining 25 -New APDU received: -E04280001976A91426C680EC6AC9C0ED760177F92096F1C5571B72EF88AC -Process output script, remaining 25 ---- ADD TO HASH FULL: -76A91426C680EC6AC9C0ED760177F92096F1C5571B72EF88AC -Process output script, remaining 0 -New APDU received: -E04280000420041D00 -Process output script, remaining 0 -Output hashing done ---- ADD TO HASH FULL: -20041D00 -Transaction parsed -New APDU received: -E042000009000000010200000001 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -01 -Number of inputs : 1 -Process input -New APDU received: -E0428000255DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E34010000006B -Process input ---- ADD TO HASH FULL: -5DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E3401000000 ---- ADD TO HASH FULL: -6B -Script to read 107 -Process input script, remaining 107 -New APDU received: -E04280006F483045022100C806957429935C5D61F548223C3536DC739FE351814BCE9EDC1694E5A5C25ABF022013E307B0B4885ACB64CCFFAF5F4794F205040325EBC36C258787C488B038C2BB0121038BA462D7DD65917ECE454142903BB362A0B412D1841D52087AD881646B6CDCCFFDFFFFFF -Process input script, remaining 107 ---- ADD TO HASH FULL: -483045022100C806957429935C5D61F548223C3536DC739FE351814BCE9EDC1694E5A5C25ABF022013E307B0B4885ACB64CCFFAF5F4794F205040325EBC36C258787C488B038C2BB0121038BA462D7DD65917ECE454142903BB362A0B412D1841D52087AD881646B6CDC -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -CF ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -New APDU received: -E04280000102 -Input hashing done ---- ADD TO HASH FULL: -02 -Number of outputs : 2 -New APDU received: -E042800009140C03000000000019 ---- ADD TO HASH FULL: -140C030000000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process output script, remaining 25 -New APDU received: -E04280001976A914B3E17C4DEF8A39148ED6FAD7DC6FEBE30DD324CB88AC -Process output script, remaining 25 ---- ADD TO HASH FULL: -76A914B3E17C4DEF8A39148ED6FAD7DC6FEBE30DD324CB88AC -Process output script, remaining 0 -New APDU received: -E042800009305705000000000019 -Process output script, remaining 0 ---- ADD TO HASH FULL: -3057050000000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process output script, remaining 25 -New APDU received: -E04280001976A914E0A89380635F18B7EE09546D963232BCB992412B88AC -Process output script, remaining 25 ---- ADD TO HASH FULL: -76A914E0A89380635F18B7EE09546D963232BCB992412B88AC -Process output script, remaining 0 -New APDU received: -E042800004FE041D00 -Process output script, remaining 0 -Output hashing done ---- ADD TO HASH FULL: -FE041D00 -Transaction parsed -New APDU received: -E02601000101 -New APDU received: -E0440000050200000002 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH AUTH: -02000000 ---- ADD TO HASH FULL: -02 ---- ADD TO HASH AUTH: -02 -Number of inputs : 2 -Process input -New APDU received: -E04480003B013832005E0D5DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E3400000000DCDB060000000000D9A1FF455D570FF519 -Process input -====> Input HMAC: D9A1FF455D570FF5 -====> Computed HMAC: D9A1FF455D570FF5 -Trusted input hash -5DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E3400000000 ---- ADD TO HASH FULL: -5DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E3400000000 ---- ADD TO HASH AUTH: -5DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E3400000000 -Adding amount -DCDB060000000000 -New amount -000000000006DBDC ---- ADD TO HASH FULL: -19 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A914B242BA04B8526B533B17B168D27EAF0DA7BACB8588ACFDFFFFFF -Process input script, remaining 25 ---- ADD TO HASH FULL: -76A914B242BA04B8526B533B17B168D27EAF0DA7BACB8588 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -AC ---- ADD TO HASH FULL: -FDFFFFFF ---- ADD TO HASH AUTH: -FDFFFFFF -Process input -New APDU received: -E04480003B01383200BA0857F891351E60E944718F1DF12B4F77B642CC63146184BEDC6C7BC64A0C0B39DE010000003057050000000000124EAC0C193C39F400 -Process input -====> Input HMAC: 124EAC0C193C39F4 -====> Computed HMAC: 124EAC0C193C39F4 -Trusted input hash -57F891351E60E944718F1DF12B4F77B642CC63146184BEDC6C7BC64A0C0B39DE01000000 ---- ADD TO HASH FULL: -57F891351E60E944718F1DF12B4F77B642CC63146184BEDC6C7BC64A0C0B39DE01000000 ---- ADD TO HASH AUTH: -57F891351E60E944718F1DF12B4F77B642CC63146184BEDC6C7BC64A0C0B39DE01000000 -Adding amount -3057050000000000 -New amount -00000000000C330C ---- ADD TO HASH FULL: -00 -Script to read 0 -Process input script, remaining 0 -New APDU received: -E044800004FDFFFFFF -Process input script, remaining 0 ---- ADD TO HASH FULL: -FDFFFFFF ---- ADD TO HASH AUTH: -FDFFFFFF -Process input -Input hashing done -Presign ready -New APDU received: -E04AFF0015058000002C80000001800000000000000100000002 -state=1 -Using private component -B35419B8D5EE1629A70718308955F5E8B736EC0C843FB2BEDB94940A29ADC18C -New APDU received: -E04A000032025C900400000000001976A914D8BB03D84A3AA993AE6DB1114488488DAB43D6DB88AC20A10700000000001976A914CBAE5B -state=1 ---- ADD TO HASH FULL: -025C900400000000001976A914D8BB03D84A3AA993AE6DB1114488488DAB43D6DB88AC20A10700000000001976A914CBAE5B ---- ADD TO HASH AUTH: -025C900400000000001976A914D8BB03D84A3AA993AE6DB1114488488DAB43D6DB88AC20A10700000000001976A914CBAE5B -New APDU received: -E04A80001350CF939E6F531B8A6B7ABD788FE14B029788AC -state=2 ---- ADD TO HASH FULL: -50CF939E6F531B8A6B7ABD788FE14B029788AC ---- ADD TO HASH AUTH: -50CF939E6F531B8A6B7ABD788FE14B029788AC -Checksum -21F8E07E -Length to encode 25 -To encode -6FCBAE5B50CF939E6F531B8A6B7ABD788FE14B029721F8E07E -Length encoded 34 -Encoded -6D7A35764C57644D3177485647536D58556B684B56765A624A32673465704D58536D -New APDU received: -E04800001B058000002C8000000180000000000000010000000000001D04D901 ---- ADD TO HASH FULL: -D9041D0001000000 -Using private component -AAEAB6598E3F057858A97DBDC8E9291F6EBECBB5D5D68BE0F83B623BA6EA3471 -Hash1 -B7DC3C28B80673141EFF6523DEFC02C054F7E6F8B7D977FB4490BBAEA2613E23 -Hash2 -C16F948104A1637627CD46DDB28D454C65A58B497D725A30081074BC632DD0A7 -New APDU received: -E0440080050200000002 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH AUTH: -02000000 ---- ADD TO HASH FULL: -02 ---- ADD TO HASH AUTH: -02 -Number of inputs : 2 -Process input -New APDU received: -E04480003B013832005E0D5DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E3400000000DCDB060000000000D9A1FF455D570FF500 -Process input -====> Input HMAC: D9A1FF455D570FF5 -====> Computed HMAC: D9A1FF455D570FF5 -Trusted input hash -5DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E3400000000 ---- ADD TO HASH FULL: -5DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E3400000000 ---- ADD TO HASH AUTH: -5DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E3400000000 -Adding amount -DCDB060000000000 -New amount -000000000006DBDC ---- ADD TO HASH FULL: -00 -Script to read 0 -Process input script, remaining 0 -New APDU received: -E044800004FDFFFFFF -Process input script, remaining 0 ---- ADD TO HASH FULL: -FDFFFFFF ---- ADD TO HASH AUTH: -FDFFFFFF -Process input -New APDU received: -E04480003B01383200BA0857F891351E60E944718F1DF12B4F77B642CC63146184BEDC6C7BC64A0C0B39DE010000003057050000000000124EAC0C193C39F419 -Process input -====> Input HMAC: 124EAC0C193C39F4 -====> Computed HMAC: 124EAC0C193C39F4 -Trusted input hash -57F891351E60E944718F1DF12B4F77B642CC63146184BEDC6C7BC64A0C0B39DE01000000 ---- ADD TO HASH FULL: -57F891351E60E944718F1DF12B4F77B642CC63146184BEDC6C7BC64A0C0B39DE01000000 ---- ADD TO HASH AUTH: -57F891351E60E944718F1DF12B4F77B642CC63146184BEDC6C7BC64A0C0B39DE01000000 -Adding amount -3057050000000000 -New amount -00000000000C330C ---- ADD TO HASH FULL: -19 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A914E0A89380635F18B7EE09546D963232BCB992412B88ACFDFFFFFF -Process input script, remaining 25 ---- ADD TO HASH FULL: -76A914E0A89380635F18B7EE09546D963232BCB992412B88 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -AC ---- ADD TO HASH FULL: -FDFFFFFF ---- ADD TO HASH AUTH: -FDFFFFFF -Process input -Input hashing done -Presign ready -New APDU received: -E04AFF0015058000002C80000001800000000000000100000002 -state=1 -New APDU received: -E04A000032025C900400000000001976A914D8BB03D84A3AA993AE6DB1114488488DAB43D6DB88AC20A10700000000001976A914CBAE5B -state=1 ---- ADD TO HASH FULL: -025C900400000000001976A914D8BB03D84A3AA993AE6DB1114488488DAB43D6DB88AC20A10700000000001976A914CBAE5B ---- ADD TO HASH AUTH: -025C900400000000001976A914D8BB03D84A3AA993AE6DB1114488488DAB43D6DB88AC20A10700000000001976A914CBAE5B -New APDU received: -E04A80001350CF939E6F531B8A6B7ABD788FE14B029788AC -state=1 ---- ADD TO HASH FULL: -50CF939E6F531B8A6B7ABD788FE14B029788AC ---- ADD TO HASH AUTH: -50CF939E6F531B8A6B7ABD788FE14B029788AC -New APDU received: -E04800001B058000002C8000000180000000000000000000000300001D04D901 ---- ADD TO HASH FULL: -D9041D0001000000 -Using private component -BC8CF06B27565698FBD1BEE909B761B17AF6D137D2CAA6ECEA6D45FC60C0DD5A -Hash1 -357754D0F6F0755BBAB62C6567F70A85A46AB5C4C7EE43CE52931B15E9837D69 -Hash2 -3C34D939F56D25E9636E1584D31C6D7E315F5BB28BD6071220978F3B10BD27B0 diff --git a/tests/data/many-to-many/p2pkh/tx.json b/tests/data/many-to-many/p2pkh/tx.json deleted file mode 100644 index ce38b5b4..00000000 --- a/tests/data/many-to-many/p2pkh/tx.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "txid": "6eb7ece9e847574ca460414b6c2db535cec29ba803cd79d2c0718bd66c289fba", - "raw": "02000000025df7b9e20c52d1da2701a244a49754215266f016f6bd77f640a5200cd1fb7e34000000006a4730440220186ec195f04cfedc62d6d383a855e4b0fec550efedd22c177d2031b293556c16022039f05b1b8cc40c48d07323fdf3cc0453909d54409551c7ddc259210b2862bc54012103ed3cf038f00b7ad1c3998e66cf22a688ab5dbaed8400784cbf962d54cd42c2bffdffffff57f891351e60e944718f1df12b4f77b642cc63146184bedc6c7bc64a0c0b39de010000006a47304402201592969826e01baba12c9833584e0e958c1562736192bd1264d079383e8f277902204d5aafb9566a6de419b9446536ccce62f750361530d2a8f9a3bbc5e47af685900121035879ca173a9c1b3f300ec587fb4cc6d54d618e30584e425c1b53b98828708f1dfdffffff025c900400000000001976a914d8bb03d84a3aa993ae6db1114488488dab43d6db88ac20a10700000000001976a914cbae5b50cf939e6f531b8a6b7abd788fe14b029788acd9041d00", - "amount": 500000, - "fees": 400, - "to": "mz5vLWdM1wHVGSmXUkhKVvZbJ2g4epMXSm", - "sign_paths": ["m/84'/1'/0'/1/0", "m/84'/1'/0'/0/3"], - "change_path": "m/84'/1'/0'/1/2", - "lock_time": 1901785, - "utxos": [ - { - "txid": "347efbd10c20a540f677bdf616f06652215497a444a20127dad1520ce2b9f75d", - "raw": "0200000001f4c2b478dc9cea2df43c8bb94938ff43f3bed5aeb3af9e36cdb7016104626bf2000000006b483045022100b7b8244b3f83648397fa3c37349ed1827bf40bfca22d4f87cc019d3fded63e1d02205434ce222de35e04ab98be54af57d2c8b464f0da76a0275443b33c7b1df79344012103462f1e48396ce2a4d7694d107fef5123fe4d1e394394a370fa4901e744b4884efdffffff02dcdb0600000000001976a914b242ba04b8526b533b17b168d27eaf0da7bacb8588ac70640800000000001976a91426c680ec6ac9c0ed760177f92096f1c5571b72ef88ac20041d00", - "output_indexes": [0], - "output_amounts": [449500] - }, - { - "txid": "de390b0c4ac67b6cdcbe84611463cc42b6774f2bf11d8f7144e9601e3591f857", - "raw": "02000000015df7b9e20c52d1da2701a244a49754215266f016f6bd77f640a5200cd1fb7e34010000006b483045022100c806957429935c5d61f548223c3536dc739fe351814bce9edc1694e5a5c25abf022013e307b0b4885acb64ccffaf5f4794f205040325ebc36c258787c488b038c2bb0121038ba462d7dd65917ece454142903bb362a0b412d1841d52087ad881646b6cdccffdffffff02140c0300000000001976a914b3e17c4def8a39148ed6fad7dc6febe30dd324cb88ac30570500000000001976a914e0a89380635f18b7ee09546d963232bcb992412b88acfe041d00", - "output_indexes": [1], - "output_amounts": [350000] - } - ] - -} diff --git a/tests/data/many-to-many/p2sh-p2wpkh/apdu_debug.log b/tests/data/many-to-many/p2sh-p2wpkh/apdu_debug.log deleted file mode 100644 index 053cd54d..00000000 --- a/tests/data/many-to-many/p2sh-p2wpkh/apdu_debug.log +++ /dev/null @@ -1,359 +0,0 @@ -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E042000009000000000200000001 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -01 -Number of inputs : 1 -Process input -New APDU received: -E042800025C3945B596FD88FD0D3031A2DF8963A68ADF9E9F0DFEF4F3C4DD72DF7D80777AE0000000017 -Process input ---- ADD TO HASH FULL: -C3945B596FD88FD0D3031A2DF8963A68ADF9E9F0DFEF4F3C4DD72DF7D80777AE00000000 ---- ADD TO HASH FULL: -17 -Script to read 23 -Process input script, remaining 23 -New APDU received: -E04280001B16001485D33A279D6AE91E59E0C43DE832FD4C3398252DFDFFFFFF -Process input script, remaining 23 ---- ADD TO HASH FULL: -16001485D33A279D6AE91E59E0C43DE832FD4C339825 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -2D ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -New APDU received: -E04280000102 -Input hashing done ---- ADD TO HASH FULL: -02 -Number of outputs : 2 -New APDU received: -E042800009909F07000000000017 ---- ADD TO HASH FULL: -909F070000000000 ---- ADD TO HASH FULL: -17 -Script to read 23 -Process output script, remaining 23 -New APDU received: -E042800017A914F0464D9FA0EA42D80E4D5F1457883982E23B8EEC87 -Process output script, remaining 23 ---- ADD TO HASH FULL: -A914F0464D9FA0EA42D80E4D5F1457883982E23B8EEC87 -Process output script, remaining 0 -New APDU received: -E04280000920A107000000000017 -Process output script, remaining 0 ---- ADD TO HASH FULL: -20A1070000000000 ---- ADD TO HASH FULL: -17 -Script to read 23 -Process output script, remaining 23 -New APDU received: -E042800017A91423E6F63C476F49E8ACF6AA583A0FDEC7B8ACA64587 -Process output script, remaining 23 ---- ADD TO HASH FULL: -A91423E6F63C476F49E8ACF6AA583A0FDEC7B8ACA64587 -Process output script, remaining 0 -New APDU received: -E04280000400041D00 -Process output script, remaining 0 -Output hashing done ---- ADD TO HASH FULL: -00041D00 -Transaction parsed -New APDU received: -E042000009000000010200000001 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -01 -Number of inputs : 1 -Process input -New APDU received: -E042800025C3945B596FD88FD0D3031A2DF8963A68ADF9E9F0DFEF4F3C4DD72DF7D80777AE0000000017 -Process input ---- ADD TO HASH FULL: -C3945B596FD88FD0D3031A2DF8963A68ADF9E9F0DFEF4F3C4DD72DF7D80777AE00000000 ---- ADD TO HASH FULL: -17 -Script to read 23 -Process input script, remaining 23 -New APDU received: -E04280001B16001485D33A279D6AE91E59E0C43DE832FD4C3398252DFDFFFFFF -Process input script, remaining 23 ---- ADD TO HASH FULL: -16001485D33A279D6AE91E59E0C43DE832FD4C339825 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -2D ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -New APDU received: -E04280000102 -Input hashing done ---- ADD TO HASH FULL: -02 -Number of outputs : 2 -New APDU received: -E042800009909F07000000000017 ---- ADD TO HASH FULL: -909F070000000000 ---- ADD TO HASH FULL: -17 -Script to read 23 -Process output script, remaining 23 -New APDU received: -E042800017A914F0464D9FA0EA42D80E4D5F1457883982E23B8EEC87 -Process output script, remaining 23 ---- ADD TO HASH FULL: -A914F0464D9FA0EA42D80E4D5F1457883982E23B8EEC87 -Process output script, remaining 0 -New APDU received: -E04280000920A107000000000017 -Process output script, remaining 0 ---- ADD TO HASH FULL: -20A1070000000000 ---- ADD TO HASH FULL: -17 -Script to read 23 -Process output script, remaining 23 -New APDU received: -E042800017A91423E6F63C476F49E8ACF6AA583A0FDEC7B8ACA64587 -Process output script, remaining 23 ---- ADD TO HASH FULL: -A91423E6F63C476F49E8ACF6AA583A0FDEC7B8ACA64587 -Process output script, remaining 0 -New APDU received: -E04280000400041D00 -Process output script, remaining 0 -Output hashing done ---- ADD TO HASH FULL: -00041D00 -Transaction parsed -New APDU received: -E02601000101 -New APDU received: -E0440002050200000002 -Init transaction parser -Number of inputs : 2 -Process input -New APDU received: -E04480003B01383200F97C53D3C0B27291BFFBF09D6EF5BD4F6051ED911914F55BEF0E3315B258BB13108900000000909F07000000000045E1BEBC7832647019 -Process input -Trusted input used in segwit mode -====> Input HMAC: 45E1BEBC78326470 -====> Computed HMAC: 45E1BEBC78326470 -Adding amount -909F070000000000 -New amount -0000000000079F90 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A914CB078087EFF485AAA2260E94A53D7D6D1C5DD15188ACFDFFFFFF -Process input script, remaining 25 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -FDFFFFFF -Process input -New APDU received: -E04480003B01383200F2B153D3C0B27291BFFBF09D6EF5BD4F6051ED911914F55BEF0E3315B258BB1310890100000020A10700000000005B710DFE9F3F308D00 -Process input -Trusted input used in segwit mode -====> Input HMAC: 5B710DFE9F3F308D -====> Computed HMAC: 5B710DFE9F3F308D -Adding amount -20A1070000000000 -New amount -00000000000F40B0 -Script to read 0 -Process input script, remaining 0 -New APDU received: -E044800004FDFFFFFF -Process input script, remaining 0 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done ---- ADD TO HASH FULL: -82D397CBBCFF87BC5D0C4C70E424F9B830EFBAD7BF0BE479DA5D1D1BAFDB9798 -hashPrevout -4E7FBD6CBE534923DBDC2E194612F7040271013133C736C5AE3DFC0CF1034370 -hashSequence -957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A098 -Presign ready -New APDU received: -E04AFF0015058000003180000001800000000000000100000001 -state=1 -Using private component -B2E6AA60D0137A93FF51ABE4FCA1512EF016222473B454CA9A4B4B9C8AB8402C -New APDU received: -E04A00003202840A03000000000017A914FFC91A30E33FC6D6ECFF42E4D9BD6C7E115D84988700350C000000000017A9142F5864A8ACD2 -state=1 ---- ADD TO HASH FULL: -840A03000000000017A914FFC91A30E33FC6D6ECFF42E4D9BD6C7E115D84988700350C000000000017A9142F5864A8ACD2 -New APDU received: -E04A80000F3FA85977D73E9AC30FD6B341B78C87 -state=2 ---- ADD TO HASH FULL: -3FA85977D73E9AC30FD6B341B78C87 -hashOutputs -B3B2A31981BCC4F256B0851EBE9D7A11BFBFA8559E7795190B4472D7E1E974C9 -Auth Hash: -E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -Checksum -CD4FBEC6 -Length to encode 25 -To encode -C42F5864A8ACD23FA85977D73E9AC30FD6B341B78CCD4FBEC6 -Length encoded 35 -Encoded -324D775A5A6479336243764568695073427963726543466971774468796B4163574E39 -Segwit parsed once -New APDU received: -E0440080050200000001 -Init transaction parser -Resume SegWit hash -SEGWIT Version -02000000 -SEGWIT HashedPrevouts -4E7FBD6CBE534923DBDC2E194612F7040271013133C736C5AE3DFC0CF1034370 -SEGWIT HashedSequence -957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A098 ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -4E7FBD6CBE534923DBDC2E194612F7040271013133C736C5AE3DFC0CF1034370 ---- ADD TO HASH FULL: -957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A098 ---- ADD TO HASH AUTH: -4E7FBD6CBE534923DBDC2E194612F7040271013133C736C5AE3DFC0CF1034370957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A098B3B2A31981BCC4F256B0851EBE9D7A11BFBFA8559E7795190B4472D7E1E974C9 -Number of inputs : 1 -Process input -New APDU received: -E04480003B01383200F97C53D3C0B27291BFFBF09D6EF5BD4F6051ED911914F55BEF0E3315B258BB13108900000000909F07000000000045E1BEBC7832647019 -Process input -Trusted input used in segwit mode -====> Input HMAC: 45E1BEBC78326470 -====> Computed HMAC: 45E1BEBC78326470 ---- ADD TO HASH FULL: -53D3C0B27291BFFBF09D6EF5BD4F6051ED911914F55BEF0E3315B258BB13108900000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A914CB078087EFF485AAA2260E94A53D7D6D1C5DD15188ACFDFFFFFF -Process input script, remaining 25 ---- ADD TO HASH FULL: -76A914CB078087EFF485AAA2260E94A53D7D6D1C5DD15188 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -AC -SEGWIT Add value -909F070000000000 ---- ADD TO HASH FULL: -909F070000000000 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -SEGWIT hashedOutputs -B3B2A31981BCC4F256B0851EBE9D7A11BFBFA8559E7795190B4472D7E1E974C9 -Sign ready -New APDU received: -E04800001B05800000318000000180000000000000010000000000001D03D001 ---- ADD TO HASH FULL: -D0031D0001000000 -Using private component -E8AE81F93160D032A7AA82BE9B719499A5DE635639D7237B7AB2572DE86F7E52 -Hash1 -01BB2AB227D2D0978E01A7212F1C7C5BC6FA848A8D46446A8242B3B00A7EF9BC -Hash2 -86B03281CD802D9764FFAB2E1F0E4B6825FA001899924C1DB1674C3A1D51054A -New APDU received: -E0440080050200000001 -Init transaction parser -Resume SegWit hash -SEGWIT Version -02000000 -SEGWIT HashedPrevouts -4E7FBD6CBE534923DBDC2E194612F7040271013133C736C5AE3DFC0CF1034370 -SEGWIT HashedSequence -957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A098 ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -4E7FBD6CBE534923DBDC2E194612F7040271013133C736C5AE3DFC0CF1034370 ---- ADD TO HASH FULL: -957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A098 ---- ADD TO HASH AUTH: -4E7FBD6CBE534923DBDC2E194612F7040271013133C736C5AE3DFC0CF1034370957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A098B3B2A31981BCC4F256B0851EBE9D7A11BFBFA8559E7795190B4472D7E1E974C9 -Number of inputs : 1 -Process input -New APDU received: -E04480003B01383200F2B153D3C0B27291BFFBF09D6EF5BD4F6051ED911914F55BEF0E3315B258BB1310890100000020A10700000000005B710DFE9F3F308D19 -Process input -Trusted input used in segwit mode -====> Input HMAC: 5B710DFE9F3F308D -====> Computed HMAC: 5B710DFE9F3F308D ---- ADD TO HASH FULL: -53D3C0B27291BFFBF09D6EF5BD4F6051ED911914F55BEF0E3315B258BB13108901000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A9143F8F2B556915A9306FD92EB5AE72217BE9DD593F88ACFDFFFFFF -Process input script, remaining 25 ---- ADD TO HASH FULL: -76A9143F8F2B556915A9306FD92EB5AE72217BE9DD593F88 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -AC -SEGWIT Add value -20A1070000000000 ---- ADD TO HASH FULL: -20A1070000000000 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -SEGWIT hashedOutputs -B3B2A31981BCC4F256B0851EBE9D7A11BFBFA8559E7795190B4472D7E1E974C9 -Sign ready -New APDU received: -E04800001B05800000318000000180000000000000000000000200001D03D001 ---- ADD TO HASH FULL: -D0031D0001000000 -Using private component -026553901CCECDDF76396E3B3BB2ACC48E68667FB793AAA239AC233AC99CE546 -Hash1 -FAA127DA08393CA5858E158219974145DB64C9C1F70ECB3E8582D6F562A56351 -Hash2 -D1D43A5549457E532745227067826A917150B060F55264615D077F2BA2AF530D diff --git a/tests/data/many-to-many/p2sh-p2wpkh/tx.json b/tests/data/many-to-many/p2sh-p2wpkh/tx.json deleted file mode 100644 index f62e5696..00000000 --- a/tests/data/many-to-many/p2sh-p2wpkh/tx.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "txid": "f5ff97147f8c7cca717536325eb157c696ef9630934271905b3f8c564b18e708", - "raw": "0200000000010253d3c0b27291bffbf09d6ef5bd4f6051ed911914f55bef0e3315b258bb1310890000000017160014cb078087eff485aaa2260e94a53d7d6d1c5dd151fdffffff53d3c0b27291bffbf09d6ef5bd4f6051ed911914f55bef0e3315b258bb13108901000000171600143f8f2b556915a9306fd92eb5ae72217be9dd593ffdffffff02840a03000000000017a914ffc91a30e33fc6d6ecff42e4d9bd6c7e115d84988700350c000000000017a9142f5864a8acd23fa85977d73e9ac30fd6b341b78c8702483045022100a0173bbd3dcdfe51c24386fee905b8197f36c2024f582b1a838e7bf09a1ec16902206bcd803041b13738f7d8896561e6a8ccec9a3f5d243be8645c403e83beb19b340121024ba3b77d933de9fa3f9583348c40f3caaf2effad5b6e244ece8abbfcc7244f6702483045022100ac5701f0cc3cb4b490269674d3463c4fab74f6ee9faf7c29b3d0dea22875dd0002206ba4f4195dce69ffd3e7d832ee5d67ee0d037bad03f4e00f841fbf84649375b5012103a1989dadf0bce57f4c96cfc4d9e6aa9abeba7ac0733e99176f69432e852666f1d0031d00", - "amount": 800000, - "fees": 300, - "to": "2MwZZdy3bCvEhiPsBycreCFiqwDhykAcWN9", - "sign_paths": ["m/49'/1'/0'/1/0", "m/49'/1'/0'/0/2"], - "change_path": "m/49'/1'/0'/1/1", - "lock_time": 1901520, - "utxos": [ - { - "txid": "891013bb58b215330eef5bf5141991ed51604fbdf56e9df0fbbf9172b2c0d353", - "raw": "02000000000101c3945b596fd88fd0d3031a2df8963a68adf9e9f0dfef4f3c4dd72df7d80777ae000000001716001485d33a279d6ae91e59e0c43de832fd4c3398252dfdffffff02909f07000000000017a914f0464d9fa0ea42d80e4d5f1457883982e23b8eec8720a107000000000017a91423e6f63c476f49e8acf6aa583a0fdec7b8aca6458702483045022100da88128e41ae9ea8d6c7fe54a32ab89bbd558993924acf7d86e7039675dd3e0002207228d510d4d8e16f77ef5b82af051a6e5bd5f0263e4464984db8be777dfc6387012102549c187d80a2c8d26760d1646b40e3dce3b9e6042579dcdb9fdeee85208ceb7c00041d00", - "output_indexes": [0, 1], - "output_amounts": [499600, 500000] - } - ] - -} diff --git a/tests/data/many-to-many/p2wpkh/apdu_debug.log b/tests/data/many-to-many/p2wpkh/apdu_debug.log deleted file mode 100644 index be6dcab4..00000000 --- a/tests/data/many-to-many/p2wpkh/apdu_debug.log +++ /dev/null @@ -1,415 +0,0 @@ -New APDU received: -E0C4000000 -New APDU received: -F026000000 -New APDU received: -E0C4000000 -New APDU received: -E024000000 -New APDU received: -E02280000130 -New APDU received: -E04000000100 -pin ok -Using private component -34AC5D784EBB4DF4727BCDDF6A6743F5D5D46D83DD74AA825866390C694F2938 -To hash -0251EC84E33A3119486461A44240E906FF94BF40CF807B025B1CA43332B80DC9DB -Hash160 -F5ACC2FD5C60B7263C4A459541C1473BC29E58F4 -Checksum -A21FB2F3 -Length to encode 25 -To encode -6FF5ACC2FD5C60B7263C4A459541C1473BC29E58F4A21FB2F3 -Length encoded 34 -Encoded -6E3375786F6B3843337A566277476A72584476344E544E516A313865335A4D4A426B -Length 34 -New APDU received: -E0400000050180000000 -pin ok -Using private component -C71AE2E616FBCCC325A71600E9C82816505A6373EFCE4CAEDA60400667E0B75C -To hash -02E5646066C2C51CEAEA66F04EC85858D34E2BD285F4A60B1402BFC03CF462E767 -Hash160 -7D825341D36FC1297A41A9839A72975815B1FE61 -Checksum -E01B4FD2 -Length to encode 25 -To encode -6F7D825341D36FC1297A41A9839A72975815B1FE61E01B4FD2 -Length encoded 34 -Encoded -6D727861744272776D555959504E774E4879334A5461567350474750716A4A68674D -Length 34 -New APDU received: -E040000009028000005480000001 -pin ok -Using private component -ADF229CD64E7ADC0915EA16BA3CD4A6923E65D2B6EA127D23DFE84E2D563D22A -To hash -0331B89176766FA4A6CA844A3A6B0DD301B55197DE3250EF47A9936019CF80CE31 -Hash160 -751B87653B01FC4A355D3E08D22995E02BEA88E4 -Checksum -57CDF1D9 -Length to encode 25 -To encode -6F751B87653B01FC4A355D3E08D22995E02BEA88E457CDF1D9 -Length encoded 34 -Encoded -6D7243414C456F71715961654368444C335233323975387578483651486145597243 -Length 34 -New APDU received: -E04000000D03800000548000000180000000 -pin ok -Using private component -08B5ED5B131552DA3B9CA9869E506420EDF4ABEC8C1BA5D468BE04CCC4EC4A48 -To hash -02668C624FDBF81D0E9D3601D5DA195E0D06E48E3F5021D9269774BD0A9E5F2CBE -Hash160 -DAAEB63EBF9E49ED7F25C491432B01D945E37A7C -Checksum -9B84A352 -Length to encode 25 -To encode -6FDAAEB63EBF9E49ED7F25C491432B01D945E37A7C9B84A352 -Length encoded 34 -Encoded -6E3154457534763756734C59696D575A5775333947553871736E7039694456676F6A -Length 34 -New APDU received: -E0C4000000 -New APDU received: -E042000009000000000200000001 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -01 -Number of inputs : 1 -Process input -New APDU received: -E0428000252C4CA2F29958ECF3E14DDBD449E7DFC716400D7BFEE8A9D7EEC1647C3A14A7100000000000 -Process input ---- ADD TO HASH FULL: -2C4CA2F29958ECF3E14DDBD449E7DFC716400D7BFEE8A9D7EEC1647C3A14A71000000000 ---- ADD TO HASH FULL: -00 -Script to read 0 -Process input script, remaining 0 -New APDU received: -E042800004FDFFFFFF -Process input script, remaining 0 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -New APDU received: -E04280000102 -Input hashing done ---- ADD TO HASH FULL: -02 -Number of outputs : 2 -New APDU received: -E042800009D02CF8000000000016 ---- ADD TO HASH FULL: -D02CF80000000000 ---- ADD TO HASH FULL: -16 -Script to read 22 -Process output script, remaining 22 -New APDU received: -E04280001600142318D66F84FEF5C4875F933B038DC63831F8DA13 -Process output script, remaining 22 ---- ADD TO HASH FULL: -00142318D66F84FEF5C4875F933B038DC63831F8DA13 -Process output script, remaining 0 -New APDU received: -E042800009008793030000000016 -Process output script, remaining 0 ---- ADD TO HASH FULL: -0087930300000000 ---- ADD TO HASH FULL: -16 -Script to read 22 -Process output script, remaining 22 -New APDU received: -E0428000160014EEE49309A5CE45D01F691AEC8E5CE206194F9A9F -Process output script, remaining 22 ---- ADD TO HASH FULL: -0014EEE49309A5CE45D01F691AEC8E5CE206194F9A9F -Process output script, remaining 0 -New APDU received: -E042800004F1F61C00 -Process output script, remaining 0 -Output hashing done ---- ADD TO HASH FULL: -F1F61C00 -Transaction parsed -New APDU received: -E042000009000000010200000001 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -01 -Number of inputs : 1 -Process input -New APDU received: -E0428000252C4CA2F29958ECF3E14DDBD449E7DFC716400D7BFEE8A9D7EEC1647C3A14A7100000000000 -Process input ---- ADD TO HASH FULL: -2C4CA2F29958ECF3E14DDBD449E7DFC716400D7BFEE8A9D7EEC1647C3A14A71000000000 ---- ADD TO HASH FULL: -00 -Script to read 0 -Process input script, remaining 0 -New APDU received: -E042800004FDFFFFFF -Process input script, remaining 0 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -New APDU received: -E04280000102 -Input hashing done ---- ADD TO HASH FULL: -02 -Number of outputs : 2 -New APDU received: -E042800009D02CF8000000000016 ---- ADD TO HASH FULL: -D02CF80000000000 ---- ADD TO HASH FULL: -16 -Script to read 22 -Process output script, remaining 22 -New APDU received: -E04280001600142318D66F84FEF5C4875F933B038DC63831F8DA13 -Process output script, remaining 22 ---- ADD TO HASH FULL: -00142318D66F84FEF5C4875F933B038DC63831F8DA13 -Process output script, remaining 0 -New APDU received: -E042800009008793030000000016 -Process output script, remaining 0 ---- ADD TO HASH FULL: -0087930300000000 ---- ADD TO HASH FULL: -16 -Script to read 22 -Process output script, remaining 22 -New APDU received: -E0428000160014EEE49309A5CE45D01F691AEC8E5CE206194F9A9F -Process output script, remaining 22 ---- ADD TO HASH FULL: -0014EEE49309A5CE45D01F691AEC8E5CE206194F9A9F -Process output script, remaining 0 -New APDU received: -E042800004F1F61C00 -Process output script, remaining 0 -Output hashing done ---- ADD TO HASH FULL: -F1F61C00 -Transaction parsed -New APDU received: -E02601000101 -New APDU received: -E0440002050200000002 -Init transaction parser -Number of inputs : 2 -Process input -New APDU received: -E04480003B0138320034B9AC4F7220317B689845CD25C42F608368B7B92A784169372D3C2CA2612EF1CD0D00000000D02CF800000000005B5ADD428D79EB3C19 -Process input -Trusted input used in segwit mode -====> Input HMAC: 5B5ADD428D79EB3C -====> Computed HMAC: 5B5ADD428D79EB3C -Adding amount -D02CF80000000000 -New amount -0000000000F82CD0 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A9142318D66F84FEF5C4875F933B038DC63831F8DA1388ACFDFFFFFF -Process input script, remaining 25 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -FDFFFFFF -Process input -New APDU received: -E04480003B013832006616AC4F7220317B689845CD25C42F608368B7B92A784169372D3C2CA2612EF1CD0D010000000087930300000000EAA238F5DA4E088C00 -Process input -Trusted input used in segwit mode -====> Input HMAC: EAA238F5DA4E088C -====> Computed HMAC: EAA238F5DA4E088C -Adding amount -0087930300000000 -New amount -00000000048BB3D0 -Script to read 0 -Process input script, remaining 0 -New APDU received: -E044800004FDFFFFFF -Process input script, remaining 0 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done ---- ADD TO HASH FULL: -82D397CBBCFF87BC5D0C4C70E424F9B830EFBAD7BF0BE479DA5D1D1BAFDB9798 -hashPrevout -B2790BC71EE0340E89998B4BEC430CFD8A6847CA49B6EA8185C1D6C368091185 -hashSequence -957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A098 -Presign ready -New APDU received: -E04AFF0015058000005480000001800000000000000100000005 -state=1 -Using private component -6938E6DBEDECC9FF7DF29A2C73BBB8250213D96F4B16B6E947AD5CA9F4160CC7 -New APDU received: -E04A00003202FE2BF80000000000160014C132F90DE4A19728E35D8AF8B3F9EC4E43CF194801879303000000001600143318E04FAE6C12 -state=1 ---- ADD TO HASH FULL: -FE2BF80000000000160014C132F90DE4A19728E35D8AF8B3F9EC4E43CF194801879303000000001600143318E04FAE6C12 -New APDU received: -E04A80000DAFCB009C69CD57E5B2504AE6B4 -state=2 ---- ADD TO HASH FULL: -AFCB009C69CD57E5B2504AE6B4 -hashOutputs -7AB7EB5CB887AE706482C5EF7A0218686D5EECDE5F8F6D6B3565433FB2EECFD6 -Auth Hash: -E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -Segwit parsed once -New APDU received: -E0440080050200000001 -Init transaction parser -Resume SegWit hash -SEGWIT Version -02000000 -SEGWIT HashedPrevouts -B2790BC71EE0340E89998B4BEC430CFD8A6847CA49B6EA8185C1D6C368091185 -SEGWIT HashedSequence -957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A098 ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -B2790BC71EE0340E89998B4BEC430CFD8A6847CA49B6EA8185C1D6C368091185 ---- ADD TO HASH FULL: -957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A098 ---- ADD TO HASH AUTH: -B2790BC71EE0340E89998B4BEC430CFD8A6847CA49B6EA8185C1D6C368091185957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A0987AB7EB5CB887AE706482C5EF7A0218686D5EECDE5F8F6D6B3565433FB2EECFD6 -Number of inputs : 1 -Process input -New APDU received: -E04480003B0138320034B9AC4F7220317B689845CD25C42F608368B7B92A784169372D3C2CA2612EF1CD0D00000000D02CF800000000005B5ADD428D79EB3C19 -Process input -Trusted input used in segwit mode -====> Input HMAC: 5B5ADD428D79EB3C -====> Computed HMAC: 5B5ADD428D79EB3C ---- ADD TO HASH FULL: -AC4F7220317B689845CD25C42F608368B7B92A784169372D3C2CA2612EF1CD0D00000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A9142318D66F84FEF5C4875F933B038DC63831F8DA1388ACFDFFFFFF -Process input script, remaining 25 ---- ADD TO HASH FULL: -76A9142318D66F84FEF5C4875F933B038DC63831F8DA1388 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -AC -SEGWIT Add value -D02CF80000000000 ---- ADD TO HASH FULL: -D02CF80000000000 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -SEGWIT hashedOutputs -7AB7EB5CB887AE706482C5EF7A0218686D5EECDE5F8F6D6B3565433FB2EECFD6 -Sign ready -New APDU received: -E04800001B05800000548000000180000000000000000000000100001D024301 ---- ADD TO HASH FULL: -43021D0001000000 -Using private component -21E9C06E0D5E169EE7E6C961D2F3F3286666EF74F2CE5EFF6F6108EB6D855DA5 -Hash1 -7F95C240698CB2D4E372B1EFDFB565D9447D4F0706249907AA8D90BF0AD615C0 -Hash2 -45EB814B30BA5E2E6C39A7326290F7DC1548484507CC230B11F84D56FE26800F -New APDU received: -E0440080050200000001 -Init transaction parser -Resume SegWit hash -SEGWIT Version -02000000 -SEGWIT HashedPrevouts -B2790BC71EE0340E89998B4BEC430CFD8A6847CA49B6EA8185C1D6C368091185 -SEGWIT HashedSequence -957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A098 ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -B2790BC71EE0340E89998B4BEC430CFD8A6847CA49B6EA8185C1D6C368091185 ---- ADD TO HASH FULL: -957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A098 ---- ADD TO HASH AUTH: -B2790BC71EE0340E89998B4BEC430CFD8A6847CA49B6EA8185C1D6C368091185957879FDCE4D8AB885E32FF307D54E75884DA52522CC53D3C4FDB60EDB69A0987AB7EB5CB887AE706482C5EF7A0218686D5EECDE5F8F6D6B3565433FB2EECFD6 -Number of inputs : 1 -Process input -New APDU received: -E04480003B013832006616AC4F7220317B689845CD25C42F608368B7B92A784169372D3C2CA2612EF1CD0D010000000087930300000000EAA238F5DA4E088C19 -Process input -Trusted input used in segwit mode -====> Input HMAC: EAA238F5DA4E088C -====> Computed HMAC: EAA238F5DA4E088C ---- ADD TO HASH FULL: -AC4F7220317B689845CD25C42F608368B7B92A784169372D3C2CA2612EF1CD0D01000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A914EEE49309A5CE45D01F691AEC8E5CE206194F9A9F88ACFDFFFFFF -Process input script, remaining 25 ---- ADD TO HASH FULL: -76A914EEE49309A5CE45D01F691AEC8E5CE206194F9A9F88 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -AC -SEGWIT Add value -0087930300000000 ---- ADD TO HASH FULL: -0087930300000000 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -SEGWIT hashedOutputs -7AB7EB5CB887AE706482C5EF7A0218686D5EECDE5F8F6D6B3565433FB2EECFD6 -Sign ready -New APDU received: -E04800001B05800000548000000180000000000000010000000400001D024301 ---- ADD TO HASH FULL: -43021D0001000000 -Using private component -EF8D5CCDB132BA01BAD92AA97B1DF75C7C6914809F2510E91AA1FCE703770625 -Hash1 -7A9AA279B55E743EEFE4B819CB5B6E197B32D2C19DF8A3B6DDF1E0520C3A2180 -Hash2 -94D3EBE11569A69F1A2B948C4275940854CD8ED914377B8ADEE0F2257C6AD925 diff --git a/tests/data/many-to-many/p2wpkh/tx.json b/tests/data/many-to-many/p2wpkh/tx.json deleted file mode 100644 index 1b3bdf2b..00000000 --- a/tests/data/many-to-many/p2wpkh/tx.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "txid": "5c09c82a4efa271adb692917aa35e92b1b360e333fade6cf081952bc7fd16a7a", - "raw": "02000000000102ac4f7220317b689845cd25c42f608368b7b92a784169372d3c2ca2612ef1cd0d0000000000fdffffffac4f7220317b689845cd25c42f608368b7b92a784169372d3c2ca2612ef1cd0d0100000000fdffffff02fe2bf80000000000160014c132f90de4a19728e35d8af8b3f9ec4e43cf194801879303000000001600143318e04fae6c12afcb009c69cd57e5b2504ae6b40247304402203aed260c81d21e36cfdd5a095ad289366103ae3a2690011b20e15001173e44d902206f17e60fc169db8bc21820dfefe51271446a6305284bcfb73738ca38a2715d9f012103455ee7cedc97b0ba435b80066fc92c963a34c600317981d135330c4ee43ac7a3024730440220223a3f37f85ed5e42d6ed463ca36932db28799ff12d0391b5e02bcfef829007302206c42e9cb5817bff184e8854848032867f129814df07a96afc49baa5542ede8a4012103affafaf410b74f019028055618695f89c23478aa5fca3ba531f44d382ad7791a43021d00", - "amount": 60000001, - "fees": 209, - "to": "tb1qxvvwqnawdsf2ljcqn35u64l9kfgy4e45v3uamu", - "sign_paths": ["m/84'/1'/0'/0/1", "m/84'/1'/0'/1/4"], - "change_path": "m/84'/1'/0'/1/5", - "lock_time": 1901123, - "utxos": [ - { - "txid": "0dcdf12e61a22c3c2d376941782ab9b76883602fc425cd4598687b3120724fac", - "raw": "020000000001012c4ca2f29958ecf3e14ddbd449e7dfc716400d7bfee8a9d7eec1647c3a14a7100000000000fdffffff02d02cf800000000001600142318d66f84fef5c4875f933b038dc63831f8da130087930300000000160014eee49309a5ce45d01f691aec8e5ce206194f9a9f02483045022100badae1c06849c8ba6616af3f306e5a2fccd433f23c1fa621e0dc7114f3c84a4002205ca637953d0b6fc2431f3cf6368fa00dbcb328d46c4778d8173cdb51b22a60760121027cb75d34b005c4eb9f62bbf2c457d7638e813e757efcec8fa68677d950b63662f1f61c00", - "output_indexes": [0, 1], - "output_amounts": [16264400, 60000000] - } - ] - -} \ No newline at end of file diff --git a/tests/data/one-to-many/p2pkh/apdu_debug.log b/tests/data/one-to-many/p2pkh/apdu_debug.log deleted file mode 100644 index 74689b25..00000000 --- a/tests/data/one-to-many/p2pkh/apdu_debug.log +++ /dev/null @@ -1,168 +0,0 @@ -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E042000009000000010200000001 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -01 -Number of inputs : 1 -Process input -New APDU received: -E042800025F4C2B478DC9CEA2DF43C8BB94938FF43F3BED5AEB3AF9E36CDB7016104626BF2000000006B -Process input ---- ADD TO HASH FULL: -F4C2B478DC9CEA2DF43C8BB94938FF43F3BED5AEB3AF9E36CDB7016104626BF200000000 ---- ADD TO HASH FULL: -6B -Script to read 107 -Process input script, remaining 107 -New APDU received: -E04280006F483045022100B7B8244B3F83648397FA3C37349ED1827BF40BFCA22D4F87CC019D3FDED63E1D02205434CE222DE35E04AB98BE54AF57D2C8B464F0DA76A0275443B33C7B1DF79344012103462F1E48396CE2A4D7694D107FEF5123FE4D1E394394A370FA4901E744B4884EFDFFFFFF -Process input script, remaining 107 ---- ADD TO HASH FULL: -483045022100B7B8244B3F83648397FA3C37349ED1827BF40BFCA22D4F87CC019D3FDED63E1D02205434CE222DE35E04AB98BE54AF57D2C8B464F0DA76A0275443B33C7B1DF79344012103462F1E48396CE2A4D7694D107FEF5123FE4D1E394394A370FA4901E744B488 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -4E ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -New APDU received: -E04280000102 -Input hashing done ---- ADD TO HASH FULL: -02 -Number of outputs : 2 -New APDU received: -E042800009DCDB06000000000019 ---- ADD TO HASH FULL: -DCDB060000000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process output script, remaining 25 -New APDU received: -E04280001976A914B242BA04B8526B533B17B168D27EAF0DA7BACB8588AC -Process output script, remaining 25 ---- ADD TO HASH FULL: -76A914B242BA04B8526B533B17B168D27EAF0DA7BACB8588AC -Process output script, remaining 0 -New APDU received: -E042800009706408000000000019 -Process output script, remaining 0 ---- ADD TO HASH FULL: -7064080000000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process output script, remaining 25 -New APDU received: -E04280001976A91426C680EC6AC9C0ED760177F92096F1C5571B72EF88AC -Process output script, remaining 25 ---- ADD TO HASH FULL: -76A91426C680EC6AC9C0ED760177F92096F1C5571B72EF88AC -Process output script, remaining 0 -New APDU received: -E04280000420041D00 -Process output script, remaining 0 -Output hashing done ---- ADD TO HASH FULL: -20041D00 -Transaction parsed -New APDU received: -E02601000101 -New APDU received: -E0440000050200000001 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH AUTH: -02000000 ---- ADD TO HASH FULL: -01 ---- ADD TO HASH AUTH: -01 -Number of inputs : 1 -Process input -New APDU received: -E04480003B0138320002AC5DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E3401000000706408000000000095CF3BF2ACF74FF919 -Process input -====> Input HMAC: 95CF3BF2ACF74FF9 -====> Computed HMAC: 95CF3BF2ACF74FF9 -Trusted input hash -5DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E3401000000 ---- ADD TO HASH FULL: -5DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E3401000000 ---- ADD TO HASH AUTH: -5DF7B9E20C52D1DA2701A244A49754215266F016F6BD77F640A5200CD1FB7E3401000000 -Adding amount -7064080000000000 -New amount -0000000000086470 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A91426C680EC6AC9C0ED760177F92096F1C5571B72EF88ACFDFFFFFF -Process input script, remaining 25 ---- ADD TO HASH FULL: -76A91426C680EC6AC9C0ED760177F92096F1C5571B72EF88 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -AC ---- ADD TO HASH FULL: -FDFFFFFF ---- ADD TO HASH AUTH: -FDFFFFFF -Process input -Input hashing done -Presign ready -New APDU received: -E04AFF0015058000002C80000001800000000000000100000001 -state=1 -Using private component -885E2F32C80E1D56DABC55AC271CC3983BF122F771AB45A1C890E0DEB740FAAB -New APDU received: -E04A00003202140C0300000000001976A914B3E17C4DEF8A39148ED6FAD7DC6FEBE30DD324CB88AC30570500000000001976A914E0A893 -state=1 ---- ADD TO HASH FULL: -02140C0300000000001976A914B3E17C4DEF8A39148ED6FAD7DC6FEBE30DD324CB88AC30570500000000001976A914E0A893 ---- ADD TO HASH AUTH: -02140C0300000000001976A914B3E17C4DEF8A39148ED6FAD7DC6FEBE30DD324CB88AC30570500000000001976A914E0A893 -New APDU received: -E04A80001380635F18B7EE09546D963232BCB992412B88AC -state=2 ---- ADD TO HASH FULL: -80635F18B7EE09546D963232BCB992412B88AC ---- ADD TO HASH AUTH: -80635F18B7EE09546D963232BCB992412B88AC -Checksum -62CF1861 -Length to encode 25 -To encode -6FE0A89380635F18B7EE09546D963232BCB992412B62CF1861 -Length encoded 34 -Encoded -6E317A71627548485461746D727359476A5042597953656F4637637250696A326A53 -New APDU received: -E04800001B058000002C8000000180000000000000000000000200001D04FE01 ---- ADD TO HASH FULL: -FE041D0001000000 -Using private component -E116F09653EDEBCCC7AC55622ECFA8DE2EE60C51A5006B6B6153B184B4DA914D -Hash1 -7E0EEB79AFE7BB94A68EB1CB0BCB591C380ADAB2120DB528F2D83EBB0BB9029B -Hash2 -971753A7B93CAB3510D9DAD6D08FB1805E580D8CBE292BF89A68C6CBE3BC8A72 diff --git a/tests/data/one-to-many/p2pkh/tx.json b/tests/data/one-to-many/p2pkh/tx.json deleted file mode 100644 index b68a6564..00000000 --- a/tests/data/one-to-many/p2pkh/tx.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "txid": "de390b0c4ac67b6cdcbe84611463cc42b6774f2bf11d8f7144e9601e3591f857", - "raw": "02000000015df7b9e20c52d1da2701a244a49754215266f016f6bd77f640a5200cd1fb7e34010000006b483045022100c806957429935c5d61f548223c3536dc739fe351814bce9edc1694e5a5c25abf022013e307b0b4885acb64ccffaf5f4794f205040325ebc36c258787c488b038c2bb0121038ba462d7dd65917ece454142903bb362a0b412d1841d52087ad881646b6cdccffdffffff02140c0300000000001976a914b3e17c4def8a39148ed6fad7dc6febe30dd324cb88ac30570500000000001976a914e0a89380635f18b7ee09546d963232bcb992412b88acfe041d00", - "amount": 350000, - "fees": 300, - "to": "n1zqbuHHTatmrsYGjPBYySeoF7crPij2jS", - "sign_paths": ["m/84'/1'/0'/0/2"], - "change_path": "m/84'/1'/0'/1/1", - "lock_time": 1901822, - "utxos": [ - { - "txid": "347efbd10c20a540f677bdf616f06652215497a444a20127dad1520ce2b9f75d", - "raw": "0200000001f4c2b478dc9cea2df43c8bb94938ff43f3bed5aeb3af9e36cdb7016104626bf2000000006b483045022100b7b8244b3f83648397fa3c37349ed1827bf40bfca22d4f87cc019d3fded63e1d02205434ce222de35e04ab98be54af57d2c8b464f0da76a0275443b33c7b1df79344012103462f1e48396ce2a4d7694d107fef5123fe4d1e394394a370fa4901e744b4884efdffffff02dcdb0600000000001976a914b242ba04b8526b533b17b168d27eaf0da7bacb8588ac70640800000000001976a91426c680ec6ac9c0ed760177f92096f1c5571b72ef88ac20041d00", - "output_indexes": [1], - "output_amounts": [550000] - } - ] - -} diff --git a/tests/data/one-to-many/p2sh-p2wpkh/apdu_debug.log b/tests/data/one-to-many/p2sh-p2wpkh/apdu_debug.log deleted file mode 100644 index 2116c1fa..00000000 --- a/tests/data/one-to-many/p2sh-p2wpkh/apdu_debug.log +++ /dev/null @@ -1,191 +0,0 @@ -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E042000009000000000200000001 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -01 -Number of inputs : 1 -Process input -New APDU received: -E042800025167FA3F3D4233D1660B4B3BB62E78FB35C9786B0A96E6B4D61697CA112D9BA4E0100000017 -Process input ---- ADD TO HASH FULL: -167FA3F3D4233D1660B4B3BB62E78FB35C9786B0A96E6B4D61697CA112D9BA4E01000000 ---- ADD TO HASH FULL: -17 -Script to read 23 -Process input script, remaining 23 -New APDU received: -E04280001B160014E310D044F88DAB1B42769E4A84CAF08363F9ECC1FDFFFFFF -Process input script, remaining 23 ---- ADD TO HASH FULL: -160014E310D044F88DAB1B42769E4A84CAF08363F9EC -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -C1 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -New APDU received: -E04280000101 -Input hashing done ---- ADD TO HASH FULL: -01 -Number of outputs : 1 -New APDU received: -E042800009AA410F000000000017 ---- ADD TO HASH FULL: -AA410F0000000000 ---- ADD TO HASH FULL: -17 -Script to read 23 -Process output script, remaining 23 -New APDU received: -E042800017A9144D7997B902D0F1A2441A0542C920413B957E8A2287 -Process output script, remaining 23 ---- ADD TO HASH FULL: -A9144D7997B902D0F1A2441A0542C920413B957E8A2287 -Process output script, remaining 0 -New APDU received: -E042800004FD031D00 -Process output script, remaining 0 -Output hashing done ---- ADD TO HASH FULL: -FD031D00 -Transaction parsed -New APDU received: -E02601000101 -New APDU received: -E0440002050200000001 -Init transaction parser -Number of inputs : 1 -Process input -New APDU received: -E04480003B013832006773C3945B596FD88FD0D3031A2DF8963A68ADF9E9F0DFEF4F3C4DD72DF7D80777AE00000000AA410F0000000000F438E5A7C4F7887819 -Process input -Trusted input used in segwit mode -====> Input HMAC: F438E5A7C4F78878 -====> Computed HMAC: F438E5A7C4F78878 -Adding amount -AA410F0000000000 -New amount -00000000000F41AA -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A91485D33A279D6AE91E59E0C43DE832FD4C3398252D88ACFDFFFFFF -Process input script, remaining 25 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done ---- ADD TO HASH FULL: -23E9829BFB4E23FBD3C4848BAA035AF15D73BCB83E510F7F097F90A21A4280D2 -hashPrevout -82C5F725DB8A39C6B9C7B3C0DAF5C67E85DDA91C1F0FE866598ECF64CAF01419 -hashSequence -CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52 -Presign ready -New APDU received: -E04AFF0015058000003180000001800000000000000100000000 -state=1 -Using private component -E8AE81F93160D032A7AA82BE9B719499A5DE635639D7237B7AB2572DE86F7E52 -New APDU received: -E04A00003202909F07000000000017A914F0464D9FA0EA42D80E4D5F1457883982E23B8EEC8720A107000000000017A91423E6F63C476F -state=1 ---- ADD TO HASH FULL: -909F07000000000017A914F0464D9FA0EA42D80E4D5F1457883982E23B8EEC8720A107000000000017A91423E6F63C476F -New APDU received: -E04A80000F49E8ACF6AA583A0FDEC7B8ACA64587 -state=2 ---- ADD TO HASH FULL: -49E8ACF6AA583A0FDEC7B8ACA64587 -hashOutputs -BBC96114CDDD96D506521DFD897A0F946AE5E59CFA4373A8A1AD62B8A5D38E14 -Auth Hash: -E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -Checksum -BF56514F -Length to encode 25 -To encode -C423E6F63C476F49E8ACF6AA583A0FDEC7B8ACA645BF56514F -Length encoded 35 -Encoded -324D7658344B5756424B344E717A4A766A67517952556841615538503775536B625141 -Segwit parsed once -New APDU received: -E0440080050200000001 -Init transaction parser -Resume SegWit hash -SEGWIT Version -02000000 -SEGWIT HashedPrevouts -82C5F725DB8A39C6B9C7B3C0DAF5C67E85DDA91C1F0FE866598ECF64CAF01419 -SEGWIT HashedSequence -CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52 ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -82C5F725DB8A39C6B9C7B3C0DAF5C67E85DDA91C1F0FE866598ECF64CAF01419 ---- ADD TO HASH FULL: -CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52 ---- ADD TO HASH AUTH: -82C5F725DB8A39C6B9C7B3C0DAF5C67E85DDA91C1F0FE866598ECF64CAF01419CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52BBC96114CDDD96D506521DFD897A0F946AE5E59CFA4373A8A1AD62B8A5D38E14 -Number of inputs : 1 -Process input -New APDU received: -E04480003B013832006773C3945B596FD88FD0D3031A2DF8963A68ADF9E9F0DFEF4F3C4DD72DF7D80777AE00000000AA410F0000000000F438E5A7C4F7887819 -Process input -Trusted input used in segwit mode -====> Input HMAC: F438E5A7C4F78878 -====> Computed HMAC: F438E5A7C4F78878 ---- ADD TO HASH FULL: -C3945B596FD88FD0D3031A2DF8963A68ADF9E9F0DFEF4F3C4DD72DF7D80777AE00000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A91485D33A279D6AE91E59E0C43DE832FD4C3398252D88ACFDFFFFFF -Process input script, remaining 25 ---- ADD TO HASH FULL: -76A91485D33A279D6AE91E59E0C43DE832FD4C3398252D88 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -AC -SEGWIT Add value -AA410F0000000000 ---- ADD TO HASH FULL: -AA410F0000000000 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -SEGWIT hashedOutputs -BBC96114CDDD96D506521DFD897A0F946AE5E59CFA4373A8A1AD62B8A5D38E14 -Sign ready -New APDU received: -E04800001B05800000318000000180000000000000000000000100001D040001 ---- ADD TO HASH FULL: -00041D0001000000 -Using private component -54D5FA61DC01FB1B00C7B2FD7DE49273A859AB47A572BD02E68DFB1F126867ED -Hash1 -AD7ADE5C5390D208BC4992C615545E0C1E379832D9801396C4AD20E8D670381B -Hash2 -97BC0CA93B0530F5EBC5AA69EB214948BF1A28D9637D7B0030F53FA5C951F4A5 diff --git a/tests/data/one-to-many/p2sh-p2wpkh/tx.json b/tests/data/one-to-many/p2sh-p2wpkh/tx.json deleted file mode 100644 index 23898ead..00000000 --- a/tests/data/one-to-many/p2sh-p2wpkh/tx.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "txid": "891013bb58b215330eef5bf5141991ed51604fbdf56e9df0fbbf9172b2c0d353", - "raw": "02000000000101c3945b596fd88fd0d3031a2df8963a68adf9e9f0dfef4f3c4dd72df7d80777ae000000001716001485d33a279d6ae91e59e0c43de832fd4c3398252dfdffffff02909f07000000000017a914f0464d9fa0ea42d80e4d5f1457883982e23b8eec8720a107000000000017a91423e6f63c476f49e8acf6aa583a0fdec7b8aca6458702483045022100da88128e41ae9ea8d6c7fe54a32ab89bbd558993924acf7d86e7039675dd3e0002207228d510d4d8e16f77ef5b82af051a6e5bd5f0263e4464984db8be777dfc6387012102549c187d80a2c8d26760d1646b40e3dce3b9e6042579dcdb9fdeee85208ceb7c00041d00", - "amount": 500000, - "fees": 250, - "to": "2MvX4KWVBK4NqzJvjgQyRUhAaU8P7uSkbQA", - "sign_paths": ["m/49'/1'/0'/0/1"], - "change_path": "m/49'/1'/0'/1/0", - "lock_time": 1901568, - "utxos": [ - { - "txid": "ae7707d8f72dd74d3c4fefdff0e9f9ad683a96f82d1a03d3d08fd86f595b94c3", - "raw": "02000000000101167fa3f3d4233d1660b4b3bb62e78fb35c9786b0a96e6b4d61697ca112d9ba4e0100000017160014e310d044f88dab1b42769e4a84caf08363f9ecc1fdffffff01aa410f000000000017a9144d7997b902d0f1a2441a0542c920413b957e8a228702483045022100b8ab2d40241c406b7e232e98fc99188ed46c062cc3f49ea39cfb77ae9f4918760220078763f7e0078be84ceb939bea8a87934e64ae3502d8636eb249c7ddd97036f7012102a80f007194d53d37f6f99539f635390588c4e1c328b098295f61af40d60cb28afd031d00", - "output_indexes": [0], - "output_amounts": [999850] - } - ] - -} diff --git a/tests/data/one-to-many/p2wpkh/apdu_debug.log b/tests/data/one-to-many/p2wpkh/apdu_debug.log deleted file mode 100644 index 86fa4185..00000000 --- a/tests/data/one-to-many/p2wpkh/apdu_debug.log +++ /dev/null @@ -1,207 +0,0 @@ -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E042000009000000010200000002 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -02 -Number of inputs : 2 -Process input -New APDU received: -E042800025AC4F7220317B689845CD25C42F608368B7B92A784169372D3C2CA2612EF1CD0D0000000000 -Process input ---- ADD TO HASH FULL: -AC4F7220317B689845CD25C42F608368B7B92A784169372D3C2CA2612EF1CD0D00000000 ---- ADD TO HASH FULL: -00 -Script to read 0 -Process input script, remaining 0 -New APDU received: -E042800004FDFFFFFF -Process input script, remaining 0 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -New APDU received: -E042800025AC4F7220317B689845CD25C42F608368B7B92A784169372D3C2CA2612EF1CD0D0100000000 -Process input ---- ADD TO HASH FULL: -AC4F7220317B689845CD25C42F608368B7B92A784169372D3C2CA2612EF1CD0D01000000 ---- ADD TO HASH FULL: -00 -Script to read 0 -Process input script, remaining 0 -New APDU received: -E042800004FDFFFFFF -Process input script, remaining 0 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -New APDU received: -E04280000102 -Input hashing done ---- ADD TO HASH FULL: -02 -Number of outputs : 2 -New APDU received: -E042800009FE2BF8000000000016 ---- ADD TO HASH FULL: -FE2BF80000000000 ---- ADD TO HASH FULL: -16 -Script to read 22 -Process output script, remaining 22 -New APDU received: -E0428000160014C132F90DE4A19728E35D8AF8B3F9EC4E43CF1948 -Process output script, remaining 22 ---- ADD TO HASH FULL: -0014C132F90DE4A19728E35D8AF8B3F9EC4E43CF1948 -Process output script, remaining 0 -New APDU received: -E042800009018793030000000016 -Process output script, remaining 0 ---- ADD TO HASH FULL: -0187930300000000 ---- ADD TO HASH FULL: -16 -Script to read 22 -Process output script, remaining 22 -New APDU received: -E04280001600143318E04FAE6C12AFCB009C69CD57E5B2504AE6B4 -Process output script, remaining 22 ---- ADD TO HASH FULL: -00143318E04FAE6C12AFCB009C69CD57E5B2504AE6B4 -Process output script, remaining 0 -New APDU received: -E04280000443021D00 -Process output script, remaining 0 -Output hashing done ---- ADD TO HASH FULL: -43021D00 -Transaction parsed -New APDU received: -E02601000101 -New APDU received: -E0440002050200000001 -Init transaction parser -Number of inputs : 1 -Process input -New APDU received: -E04480003B0138320001107A6AD17FBC521908CFE6AD3F330E361B2BE935AA172969DB1A27FA4E2AC8095C01000000018793030000000019D862B903E5346019 -Process input -Trusted input used in segwit mode -====> Input HMAC: 19D862B903E53460 -====> Computed HMAC: 19D862B903E53460 -Adding amount -0187930300000000 -New amount -0000000003938701 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A9143318E04FAE6C12AFCB009C69CD57E5B2504AE6B488ACFDFFFFFF -Process input script, remaining 25 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done ---- ADD TO HASH FULL: -23E9829BFB4E23FBD3C4848BAA035AF15D73BCB83E510F7F097F90A21A4280D2 -hashPrevout -0AD0C2779F8B2F0C994FD54CA86701607C7D162C622D8BCAA2DF8A195DE98C63 -hashSequence -CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52 -Presign ready -New APDU received: -E04AFF0015058000005480000001800000000000000100000006 -state=1 -Using private component -422277B0087551BAF831C6F099FADBD0E36048ABD1497E05DC9ECD0BFCF13243 -New APDU received: -E04A00003202B895980000000000160014AE4A9E12C72BAFA7C09DA2D0D924E0552FF68C2580F0FA02000000001600141347E82A037B5D -state=1 ---- ADD TO HASH FULL: -B895980000000000160014AE4A9E12C72BAFA7C09DA2D0D924E0552FF68C2580F0FA02000000001600141347E82A037B5D -New APDU received: -E04A80000DBB38CF8C4759F242B1F5C7E09A -state=2 ---- ADD TO HASH FULL: -BB38CF8C4759F242B1F5C7E09A -hashOutputs -D00F205254FBFFF03E8A8D31FE82421C83271E803EE12B4B0E2BF307E3E8D965 -Auth Hash: -E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -Segwit parsed once -New APDU received: -E0440080050200000001 -Init transaction parser -Resume SegWit hash -SEGWIT Version -02000000 -SEGWIT HashedPrevouts -0AD0C2779F8B2F0C994FD54CA86701607C7D162C622D8BCAA2DF8A195DE98C63 -SEGWIT HashedSequence -CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52 ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -0AD0C2779F8B2F0C994FD54CA86701607C7D162C622D8BCAA2DF8A195DE98C63 ---- ADD TO HASH FULL: -CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52 ---- ADD TO HASH AUTH: -0AD0C2779F8B2F0C994FD54CA86701607C7D162C622D8BCAA2DF8A195DE98C63CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52D00F205254FBFFF03E8A8D31FE82421C83271E803EE12B4B0E2BF307E3E8D965 -Number of inputs : 1 -Process input -New APDU received: -E04480003B0138320001107A6AD17FBC521908CFE6AD3F330E361B2BE935AA172969DB1A27FA4E2AC8095C01000000018793030000000019D862B903E5346019 -Process input -Trusted input used in segwit mode -====> Input HMAC: 19D862B903E53460 -====> Computed HMAC: 19D862B903E53460 ---- ADD TO HASH FULL: -7A6AD17FBC521908CFE6AD3F330E361B2BE935AA172969DB1A27FA4E2AC8095C01000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A9143318E04FAE6C12AFCB009C69CD57E5B2504AE6B488ACFDFFFFFF -Process input script, remaining 25 ---- ADD TO HASH FULL: -76A9143318E04FAE6C12AFCB009C69CD57E5B2504AE6B488 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -AC -SEGWIT Add value -0187930300000000 ---- ADD TO HASH FULL: -0187930300000000 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -SEGWIT hashedOutputs -D00F205254FBFFF03E8A8D31FE82421C83271E803EE12B4B0E2BF307E3E8D965 -Sign ready -New APDU received: -E04800001B05800000548000000180000000000000000000000300001D02A401 ---- ADD TO HASH FULL: -A4021D0001000000 -Using private component -BB2A3DBCB0FF5B3F483F58A916AC39D6B1D6D6F10CAF148FBB90BC8462214DB5 -Hash1 -D9463068D03E9557C2E47D7C8AC4B9C6651E535FD0F4B6FC955E9597832D07FE -Hash2 -D89635D546800B70DD465E2C89EE6764DD454091EA23D7F936408E8C2460D460 diff --git a/tests/data/one-to-many/p2wpkh/tx.json b/tests/data/one-to-many/p2wpkh/tx.json deleted file mode 100644 index 0c0b45f9..00000000 --- a/tests/data/one-to-many/p2wpkh/tx.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "txid": "2e06df6ac8282f8e93f49285a2dedb5d4d5821427cfd5cbcc8f98b24a925a09c", - "raw": "020000000001017a6ad17fbc521908cfe6ad3f330e361b2be935aa172969db1a27fa4e2ac8095c0100000000fdffffff02b895980000000000160014ae4a9e12c72bafa7c09da2d0d924e0552ff68c2580f0fa02000000001600141347e82a037b5dbb38cf8c4759f242b1f5c7e09a02483045022100f6e4c827b7c0ffc2cc781ea9b64ddacc9a6ac72ad50d08e84f5ae9ee26b6f88f02206441cd69a31563c6e80bd7fd21ba050d6720116330c461a4014ac6164d24e2a401210232804f473db3282d5baca4c53713463645729335b90d738e18e2286b603d3fc5a4021d00", - "amount": 50000000, - "fees": 201, - "to": "tb1qzdr7s2sr0dwmkwx033r4nujzk86u0cy6fmzfjk", - "sign_paths": ["m/84'/1'/0'/0/3"], - "change_path": "m/84'/1'/0'/1/6", - "lock_time": 1901220, - "utxos": [ - { - "txid": "5c09c82a4efa271adb692917aa35e92b1b360e333fade6cf081952bc7fd16a7a", - "raw": "02000000000102ac4f7220317b689845cd25c42f608368b7b92a784169372d3c2ca2612ef1cd0d0000000000fdffffffac4f7220317b689845cd25c42f608368b7b92a784169372d3c2ca2612ef1cd0d0100000000fdffffff02fe2bf80000000000160014c132f90de4a19728e35d8af8b3f9ec4e43cf194801879303000000001600143318e04fae6c12afcb009c69cd57e5b2504ae6b40247304402203aed260c81d21e36cfdd5a095ad289366103ae3a2690011b20e15001173e44d902206f17e60fc169db8bc21820dfefe51271446a6305284bcfb73738ca38a2715d9f012103455ee7cedc97b0ba435b80066fc92c963a34c600317981d135330c4ee43ac7a3024730440220223a3f37f85ed5e42d6ed463ca36932db28799ff12d0391b5e02bcfef829007302206c42e9cb5817bff184e8854848032867f129814df07a96afc49baa5542ede8a4012103affafaf410b74f019028055618695f89c23478aa5fca3ba531f44d382ad7791a43021d00", - "output_indexes": [1], - "output_amounts": [60000001] - } - ] - -} \ No newline at end of file diff --git a/tests/data/one-to-one/p2pkh/apdu_debug.log b/tests/data/one-to-one/p2pkh/apdu_debug.log deleted file mode 100644 index 36ff1307..00000000 --- a/tests/data/one-to-one/p2pkh/apdu_debug.log +++ /dev/null @@ -1,159 +0,0 @@ -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E042000009000000010200000001 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -01 -Number of inputs : 1 -Process input -New APDU received: -E042800025EC230E53095256052A2428270EEC0498944B10F6F1C578F431C23D0098B4AE5A0100000017 -Process input ---- ADD TO HASH FULL: -EC230E53095256052A2428270EEC0498944B10F6F1C578F431C23D0098B4AE5A01000000 ---- ADD TO HASH FULL: -17 -Script to read 23 -Process input script, remaining 23 -New APDU received: -E04280001B160014281539820E2DE973AE41BA6004B431C921C4D86DFEFFFFFF -Process input script, remaining 23 ---- ADD TO HASH FULL: -160014281539820E2DE973AE41BA6004B431C921C4D8 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -6D ---- ADD TO HASH FULL: -FEFFFFFF -Process input -Input hashing done -New APDU received: -E04280000102 -Input hashing done ---- ADD TO HASH FULL: -02 -Number of outputs : 2 -New APDU received: -E042800009727275000000000017 ---- ADD TO HASH FULL: -7272750000000000 ---- ADD TO HASH FULL: -17 -Script to read 23 -Process output script, remaining 23 -New APDU received: -E042800017A914C8B906AF298C70E603A28C3EFC2FAE19E6AB280F87 -Process output script, remaining 23 ---- ADD TO HASH FULL: -A914C8B906AF298C70E603A28C3EFC2FAE19E6AB280F87 -Process output script, remaining 0 -New APDU received: -E04280000940420F000000000019 -Process output script, remaining 0 ---- ADD TO HASH FULL: -40420F0000000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process output script, remaining 25 -New APDU received: -E04280001976A914CBAE5B50CF939E6F531B8A6B7ABD788FE14B029788AC -Process output script, remaining 25 ---- ADD TO HASH FULL: -76A914CBAE5B50CF939E6F531B8A6B7ABD788FE14B029788AC -Process output script, remaining 0 -New APDU received: -E04280000484F21C00 -Process output script, remaining 0 -Output hashing done ---- ADD TO HASH FULL: -84F21C00 -Transaction parsed -New APDU received: -E02601000101 -New APDU received: -E0440000050200000001 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH AUTH: -02000000 ---- ADD TO HASH FULL: -01 ---- ADD TO HASH AUTH: -01 -Number of inputs : 1 -Process input -New APDU received: -E04480003B013832007BB65122C2CDE6823E55754175B92C9C57A0A8E1AC83C38E1787FD3A1FF3348E95130100000040420F00000000009AC6444F05C5817019 -Process input -====> Input HMAC: 9AC6444F05C58170 -====> Computed HMAC: 9AC6444F05C58170 -Trusted input hash -5122C2CDE6823E55754175B92C9C57A0A8E1AC83C38E1787FD3A1FF3348E951301000000 ---- ADD TO HASH FULL: -5122C2CDE6823E55754175B92C9C57A0A8E1AC83C38E1787FD3A1FF3348E951301000000 ---- ADD TO HASH AUTH: -5122C2CDE6823E55754175B92C9C57A0A8E1AC83C38E1787FD3A1FF3348E951301000000 -Adding amount -40420F0000000000 -New amount -00000000000F4240 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A914CBAE5B50CF939E6F531B8A6B7ABD788FE14B029788ACFDFFFFFF -Process input script, remaining 25 ---- ADD TO HASH FULL: -76A914CBAE5B50CF939E6F531B8A6B7ABD788FE14B029788 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -AC ---- ADD TO HASH FULL: -FDFFFFFF ---- ADD TO HASH AUTH: -FDFFFFFF -Process input -Input hashing done -Presign ready -New APDU received: -E04AFF000100 -state=1 -New APDU received: -E04A8000230178410F00000000001976A91413D7D58166946C3EC022934066D8C0D111D1BB4188AC -state=1 ---- ADD TO HASH FULL: -0178410F00000000001976A91413D7D58166946C3EC022934066D8C0D111D1BB4188AC ---- ADD TO HASH AUTH: -0178410F00000000001976A91413D7D58166946C3EC022934066D8C0D111D1BB4188AC -Checksum -BA597C35 -Length to encode 25 -To encode -6F13D7D58166946C3EC022934066D8C0D111D1BB41BA597C35 -Length encoded 34 -Encoded -6D684B736837457A4A6F316753553176727079656A533171734A41754B7961575767 -New APDU received: -E04800001B058000002C8000000180000000000000000000000000001D041A01 ---- ADD TO HASH FULL: -1A041D0001000000 -Using private component -4FD5547026D24A120A268D246E90DD23568459A16BCFCB54FCEE86EBCD1834FA -Hash1 -9C12EA3D3E8644284EB010F24F97D5BC1FDA5A8F9B2E11B3D65FBC40BD7089BD -Hash2 -AB3C3430727A430B162A7CD73CE0BDC87A3DAEDDBAAA1A871E232CB0674F9129 diff --git a/tests/data/one-to-one/p2pkh/tx.json b/tests/data/one-to-one/p2pkh/tx.json deleted file mode 100644 index cce076fe..00000000 --- a/tests/data/one-to-one/p2pkh/tx.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "txid": "f26b62046101b7cd369eafb3aed5bef343ff3849b98b3cf42dea9cdc78b4c2f4", - "raw": "02000000015122c2cde6823e55754175b92c9c57a0a8e1ac83c38e1787fd3a1ff3348e9513010000006b483045022100e55b3ca788721aae8def2eadff710e524ffe8c9dec1764fdaa89584f9726e196022012a30fbcf9e1a24df31a1010356b794ab8de438b4250684757ed5772402540f4012102ee8608207e21028426f69e76447d7e3d5e077049f5e683c3136c2314762a4718fdffffff0178410f00000000001976a91413d7d58166946c3ec022934066d8c0d111d1bb4188ac1a041d00", - "amount": 999800, - "fees": 200, - "to": "mhKsh7EzJo1gSU1vrpyejS1qsJAuKyaWWg", - "sign_paths": ["m/84'/1'/0'/0/0"], - "change_path": null, - "lock_time": 1901594, - "utxos": [ - { - "txid": "13958e34f31f3afd87178ec383ace1a8a0579c2cb9754175553e82e6cdc22251", - "raw": "02000000000101ec230e53095256052a2428270eec0498944b10f6f1c578f431c23d0098b4ae5a0100000017160014281539820e2de973ae41ba6004b431c921c4d86dfeffffff02727275000000000017a914c8b906af298c70e603a28c3efc2fae19e6ab280f8740420f00000000001976a914cbae5b50cf939e6f531b8a6b7abd788fe14b029788ac02473044022037ecb4248361aafd4f8c11e705f0fa7a5fbdcd595172fcd5643f3b11beff5d400220020c6d326f6c37d63cecadaf4eb335faedf7c44e05f5ef1d2b68140b023bd13d012103dac82fc0acfcfc36348d4a48a46f01cea77f2b9ece3f8c3b4c99d0b0b2f995d284f21c00", - "output_indexes": [1], - "output_amounts": [999800] - } - ] - -} diff --git a/tests/data/one-to-one/p2sh-p2wpkh/apdu_debug.log b/tests/data/one-to-one/p2sh-p2wpkh/apdu_debug.log deleted file mode 100644 index 8fed7978..00000000 --- a/tests/data/one-to-one/p2sh-p2wpkh/apdu_debug.log +++ /dev/null @@ -1,199 +0,0 @@ -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E042000009000000010200000001 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -01 -Number of inputs : 1 -Process input -New APDU received: -E0428000251AF94AFBD37204AF7C23D6C7B8D41617831555831F72675C4181DB82B8A650410100000017 -Process input ---- ADD TO HASH FULL: -1AF94AFBD37204AF7C23D6C7B8D41617831555831F72675C4181DB82B8A6504101000000 ---- ADD TO HASH FULL: -17 -Script to read 23 -Process input script, remaining 23 -New APDU received: -E04280001B16001431C162CDDC618B8E80049620FFAF3F9210B10783FEFFFFFF -Process input script, remaining 23 ---- ADD TO HASH FULL: -16001431C162CDDC618B8E80049620FFAF3F9210B107 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -83 ---- ADD TO HASH FULL: -FEFFFFFF -Process input -Input hashing done -New APDU received: -E04280000102 -Input hashing done ---- ADD TO HASH FULL: -02 -Number of outputs : 2 -New APDU received: -E0428000090E19B7000000000017 ---- ADD TO HASH FULL: -0E19B70000000000 ---- ADD TO HASH FULL: -17 -Script to read 23 -Process output script, remaining 23 -New APDU received: -E042800017A914C9ED58BD29EF20ADC85156DA674A03E478799F1787 -Process output script, remaining 23 ---- ADD TO HASH FULL: -A914C9ED58BD29EF20ADC85156DA674A03E478799F1787 -Process output script, remaining 0 -New APDU received: -E04280000940420F000000000017 -Process output script, remaining 0 ---- ADD TO HASH FULL: -40420F0000000000 ---- ADD TO HASH FULL: -17 -Script to read 23 -Process output script, remaining 23 -New APDU received: -E042800017A914424B246398B68142926AEDC8D85628AC224A54DC87 -Process output script, remaining 23 ---- ADD TO HASH FULL: -A914424B246398B68142926AEDC8D85628AC224A54DC87 -Process output script, remaining 0 -New APDU received: -E04280000475F21C00 -Process output script, remaining 0 -Output hashing done ---- ADD TO HASH FULL: -75F21C00 -Transaction parsed -New APDU received: -E02601000101 -New APDU received: -E0440002050200000001 -Init transaction parser -Number of inputs : 1 -Process input -New APDU received: -E04480003B013832003BEF167FA3F3D4233D1660B4B3BB62E78FB35C9786B0A96E6B4D61697CA112D9BA4E0100000040420F000000000027708A585F4E617B19 -Process input -Trusted input used in segwit mode -====> Input HMAC: 27708A585F4E617B -====> Computed HMAC: 27708A585F4E617B -Adding amount -40420F0000000000 -New amount -00000000000F4240 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A914E310D044F88DAB1B42769E4A84CAF08363F9ECC188ACFDFFFFFF -Process input script, remaining 25 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done ---- ADD TO HASH FULL: -23E9829BFB4E23FBD3C4848BAA035AF15D73BCB83E510F7F097F90A21A4280D2 -hashPrevout -5878F55307FBC6A50458E9470B134440E1EB0AAF19172B45796FE925F031B18C -hashSequence -CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52 -Presign ready -New APDU received: -E04AFF000100 -state=1 -New APDU received: -E04A80002101AA410F000000000017A9144D7997B902D0F1A2441A0542C920413B957E8A2287 -state=1 ---- ADD TO HASH FULL: -AA410F000000000017A9144D7997B902D0F1A2441A0542C920413B957E8A2287 -hashOutputs -056D1137157786D3D8724535C9894AD074D7B1569A5E79B5221641CAB56D1900 -Auth Hash: -E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -Checksum -FF599171 -Length to encode 25 -To encode -C44D7997B902D0F1A2441A0542C920413B957E8A22FF599171 -Length encoded 35 -Encoded -324D7A4A736754696966747266426B636472766232394E34326273674B3177644A5938 -Segwit parsed once -New APDU received: -E0440080050200000001 -Init transaction parser -Resume SegWit hash -SEGWIT Version -02000000 -SEGWIT HashedPrevouts -5878F55307FBC6A50458E9470B134440E1EB0AAF19172B45796FE925F031B18C -SEGWIT HashedSequence -CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52 ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -5878F55307FBC6A50458E9470B134440E1EB0AAF19172B45796FE925F031B18C ---- ADD TO HASH FULL: -CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52 ---- ADD TO HASH AUTH: -5878F55307FBC6A50458E9470B134440E1EB0AAF19172B45796FE925F031B18CCAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52056D1137157786D3D8724535C9894AD074D7B1569A5E79B5221641CAB56D1900 -Number of inputs : 1 -Process input -New APDU received: -E04480003B013832003BEF167FA3F3D4233D1660B4B3BB62E78FB35C9786B0A96E6B4D61697CA112D9BA4E0100000040420F000000000027708A585F4E617B19 -Process input -Trusted input used in segwit mode -====> Input HMAC: 27708A585F4E617B -====> Computed HMAC: 27708A585F4E617B ---- ADD TO HASH FULL: -167FA3F3D4233D1660B4B3BB62E78FB35C9786B0A96E6B4D61697CA112D9BA4E01000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A914E310D044F88DAB1B42769E4A84CAF08363F9ECC188ACFDFFFFFF -Process input script, remaining 25 ---- ADD TO HASH FULL: -76A914E310D044F88DAB1B42769E4A84CAF08363F9ECC188 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -AC -SEGWIT Add value -40420F0000000000 ---- ADD TO HASH FULL: -40420F0000000000 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -SEGWIT hashedOutputs -056D1137157786D3D8724535C9894AD074D7B1569A5E79B5221641CAB56D1900 -Sign ready -New APDU received: -E04800001B05800000318000000180000000000000000000000000001D03FD01 ---- ADD TO HASH FULL: -FD031D0001000000 -Using private component -C16863B6D7B2B534AB6A7E049731E79907972F4689EBFC5A95398C537D683416 -Hash1 -746039019C2B7F0ACBF215F8DFB139CE369ECD7D463C18975EE588B9109FA971 -Hash2 -1398DE4932EC3444C1C18A8D3D9D5C8FEF5FAA838F45B91AD08D242405718092 diff --git a/tests/data/one-to-one/p2sh-p2wpkh/tx.json b/tests/data/one-to-one/p2sh-p2wpkh/tx.json deleted file mode 100644 index 33ce877b..00000000 --- a/tests/data/one-to-one/p2sh-p2wpkh/tx.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "txid": "ae7707d8f72dd74d3c4fefdff0e9f9ad683a96f82d1a03d3d08fd86f595b94c3", - "raw": "02000000000101167fa3f3d4233d1660b4b3bb62e78fb35c9786b0a96e6b4d61697ca112d9ba4e0100000017160014e310d044f88dab1b42769e4a84caf08363f9ecc1fdffffff01aa410f000000000017a9144d7997b902d0f1a2441a0542c920413b957e8a228702483045022100b8ab2d40241c406b7e232e98fc99188ed46c062cc3f49ea39cfb77ae9f4918760220078763f7e0078be84ceb939bea8a87934e64ae3502d8636eb249c7ddd97036f7012102a80f007194d53d37f6f99539f635390588c4e1c328b098295f61af40d60cb28afd031d00", - "amount": 999850, - "fees": 150, - "to": "2MzJsgTiiftrfBkcdrvb29N42bsgK1wdJY8", - "sign_paths": ["m/49'/1'/0'/0/0"], - "change_path": null, - "lock_time": 1901565, - "utxos": [ - { - "txid": "4ebad912a17c69614d6b6ea9b086975cb38fe762bbb3b460163d23d4f3a37f16", - "raw": "020000000001011af94afbd37204af7c23d6c7b8d41617831555831f72675c4181db82b8a65041010000001716001431c162cddc618b8e80049620ffaf3f9210b10783feffffff020e19b7000000000017a914c9ed58bd29ef20adc85156da674a03e478799f178740420f000000000017a914424b246398b68142926aedc8d85628ac224a54dc8702473044022072190b182ab580404974fc5f569d0497002d0018e2903a00f10d91994d257cd902207973fb20ba684a887c97914079ff6a8a4ea10f0b101e16ebbb2bc7d03b4da971012102193ba58ea7475219eb3eddd0d61ed86b664585bab55d01ef3afdc4b0c1a0dd4575f21c00", - "output_indexes": [1], - "output_amounts": [1000000] - } - ] - -} diff --git a/tests/data/one-to-one/p2wpkh/apdu_debug.log b/tests/data/one-to-one/p2wpkh/apdu_debug.log deleted file mode 100644 index e28db8ab..00000000 --- a/tests/data/one-to-one/p2wpkh/apdu_debug.log +++ /dev/null @@ -1,188 +0,0 @@ -New APDU received: -E04000000D03800000548000000180000000 -pin ok -Using private component -08B5ED5B131552DA3B9CA9869E506420EDF4ABEC8C1BA5D468BE04CCC4EC4A48 -To hash -02668C624FDBF81D0E9D3601D5DA195E0D06E48E3F5021D9269774BD0A9E5F2CBE -Hash160 -DAAEB63EBF9E49ED7F25C491432B01D945E37A7C -Checksum -9B84A352 -Length to encode 25 -To encode -6FDAAEB63EBF9E49ED7F25C491432B01D945E37A7C9B84A352 -Length encoded 34 -Encoded -6E3154457534763756734C59696D575A5775333947553871736E7039694456676F6A -Length 34 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E0C4000000 -New APDU received: -E042000009000000000200000001 -Init transaction parser ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -01 -Number of inputs : 1 -Process input -New APDU received: -E04280002534AB4E0084423B9DA3B7701023A4137C362F742328C5CB6F6D5086130A88B0940000000000 -Process input ---- ADD TO HASH FULL: -34AB4E0084423B9DA3B7701023A4137C362F742328C5CB6F6D5086130A88B09400000000 ---- ADD TO HASH FULL: -00 -Script to read 0 -Process input script, remaining 0 -New APDU received: -E042800004FDFFFFFF -Process input script, remaining 0 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -New APDU received: -E04280000101 -Input hashing done ---- ADD TO HASH FULL: -01 -Number of outputs : 1 -New APDU received: -E0428000095EB58B040000000016 ---- ADD TO HASH FULL: -5EB58B0400000000 ---- ADD TO HASH FULL: -16 -Script to read 22 -Process output script, remaining 22 -New APDU received: -E04280001600142318D66F84FEF5C4875F933B038DC63831F8DA13 -Process output script, remaining 22 ---- ADD TO HASH FULL: -00142318D66F84FEF5C4875F933B038DC63831F8DA13 -Process output script, remaining 0 -New APDU received: -E042800004FBF41C00 -Process output script, remaining 0 -Output hashing done ---- ADD TO HASH FULL: -FBF41C00 -Transaction parsed -New APDU received: -E02601000101 -New APDU received: -E0440002050200000001 -Init transaction parser -Number of inputs : 1 -Process input -New APDU received: -E04480003B013832002BD7F3DB0E87B75A0C4A113F30906230FFAD598BAA37F3AB27FC2C339DE849B9F385000000005EB58B0400000000F926369658DFFF5A19 -Process input -Trusted input used in segwit mode -====> Input HMAC: F926369658DFFF5A -====> Computed HMAC: F926369658DFFF5A -Adding amount -5EB58B0400000000 -New amount -00000000048BB55E -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A9142318D66F84FEF5C4875F933B038DC63831F8DA1388ACFDFFFFFF -Process input script, remaining 25 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done ---- ADD TO HASH FULL: -23E9829BFB4E23FBD3C4848BAA035AF15D73BCB83E510F7F097F90A21A4280D2 -hashPrevout -C7B413870810B6E08F118FBDFA1BF67FAB8F1048FC0F943E8EC91D60733CBCF4 -hashSequence -CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52 -Presign ready -New APDU received: -E04AFF000100 -state=1 -New APDU received: -E04A80002001F0B48B04000000001600141347E82A037B5DBB38CF8C4759F242B1F5C7E09A -state=1 ---- ADD TO HASH FULL: -F0B48B04000000001600141347E82A037B5DBB38CF8C4759F242B1F5C7E09A -hashOutputs -62BBD24C452AAF0705EF8A79E2E3BF9A20A75A587DBFF2753FEB7B99A0FE6DC6 -Auth Hash: -E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 -Segwit parsed once -New APDU received: -E0440080050200000001 -Init transaction parser -Resume SegWit hash -SEGWIT Version -02000000 -SEGWIT HashedPrevouts -C7B413870810B6E08F118FBDFA1BF67FAB8F1048FC0F943E8EC91D60733CBCF4 -SEGWIT HashedSequence -CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52 ---- ADD TO HASH FULL: -02000000 ---- ADD TO HASH FULL: -C7B413870810B6E08F118FBDFA1BF67FAB8F1048FC0F943E8EC91D60733CBCF4 ---- ADD TO HASH FULL: -CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC52 ---- ADD TO HASH AUTH: -C7B413870810B6E08F118FBDFA1BF67FAB8F1048FC0F943E8EC91D60733CBCF4CAF35E5224DE16EFA3CCAF41070F6E7B9432B6F79551E629FCA9D1C03B43BC5262BBD24C452AAF0705EF8A79E2E3BF9A20A75A587DBFF2753FEB7B99A0FE6DC6 -Number of inputs : 1 -Process input -New APDU received: -E04480003B013832002BD7F3DB0E87B75A0C4A113F30906230FFAD598BAA37F3AB27FC2C339DE849B9F385000000005EB58B0400000000F926369658DFFF5A19 -Process input -Trusted input used in segwit mode -====> Input HMAC: F926369658DFFF5A -====> Computed HMAC: F926369658DFFF5A ---- ADD TO HASH FULL: -F3DB0E87B75A0C4A113F30906230FFAD598BAA37F3AB27FC2C339DE849B9F38500000000 ---- ADD TO HASH FULL: -19 -Script to read 25 -Process input script, remaining 25 -New APDU received: -E04480001D76A9142318D66F84FEF5C4875F933B038DC63831F8DA1388ACFDFFFFFF -Process input script, remaining 25 ---- ADD TO HASH FULL: -76A9142318D66F84FEF5C4875F933B038DC63831F8DA1388 -Process input script, remaining 1 -Disabling P2SH consumption ---- ADD TO HASH FULL: -AC -SEGWIT Add value -5EB58B0400000000 ---- ADD TO HASH FULL: -5EB58B0400000000 ---- ADD TO HASH FULL: -FDFFFFFF -Process input -Input hashing done -SEGWIT hashedOutputs -62BBD24C452AAF0705EF8A79E2E3BF9A20A75A587DBFF2753FEB7B99A0FE6DC6 -Sign ready -New APDU received: -E04800001B05800000548000000180000000000000000000000100001CF59001 ---- ADD TO HASH FULL: -90F51C0001000000 -Using private component -21E9C06E0D5E169EE7E6C961D2F3F3286666EF74F2CE5EFF6F6108EB6D855DA5 -Hash1 -773DB7D1831DA4C933BD8DED5563DC5E03EF752CC9601A7423059368355CFE68 -Hash2 -824F6D8B43D99E86750D9F290E26BE16CEA93ACD1B8BC045E940B34704C61D60 diff --git a/tests/data/one-to-one/p2wpkh/tx.json b/tests/data/one-to-one/p2wpkh/tx.json deleted file mode 100644 index a69ba247..00000000 --- a/tests/data/one-to-one/p2wpkh/tx.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "txid": "10a7143a7c64c1eed7a9e8fe7b0d4016c7dfe749d4db4de1f3ec5899f2a24c2c", - "raw": "02000000000101f3db0e87b75a0c4a113f30906230ffad598baa37f3ab27fc2c339de849b9f3850000000000fdffffff01f0b48b04000000001600141347e82a037b5dbb38cf8c4759f242b1f5c7e09a0248304502210087dadcd43ba52983eb19786b20a4a8e6969e1f9330017d1ffc537effad0f7d9102200b293788f2956f6352afad08b6c9f48d213e9e96ff74ffd76a28cf448fb358a1012103455ee7cedc97b0ba435b80066fc92c963a34c600317981d135330c4ee43ac7a390f51c00", - "amount": 76264688, - "fees": 110, - "to": "tb1qzdr7s2sr0dwmkwx033r4nujzk86u0cy6fmzfjk", - "sign_paths": ["m/84'/1'/0'/0/1"], - "change_path": null, - "lock_time": 1897872, - "utxos": [ - { - "txid": "85f3b949e89d332cfc27abf337aa8b59adff306290303f114a0c5ab7870edbf3", - "raw": "0200000000010134ab4e0084423b9da3b7701023a4137c362f742328c5cb6f6d5086130a88b0940000000000fdffffff015eb58b04000000001600142318d66f84fef5c4875f933b038dc63831f8da130248304502210088e618e63f1a908022bb5fc6aaa19b454ac3eec104ffd78319acc0ccfe464378022003ce22f37a945eb2b9e70ebbc321a74c9594efd7c986a4004538b728d30ecb500121027cb75d34b005c4eb9f62bbf2c457d7638e813e757efcec8fa68677d950b63662fbf41c00", - "output_indexes": [0], - "output_amounts": [76264798] - } - ] - -} \ No newline at end of file diff --git a/tests/prepare_tests.sh b/tests/prepare_tests.sh deleted file mode 100755 index 617a4ad4..00000000 --- a/tests/prepare_tests.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -cd .. -make clean -make -j DEBUG=1 # compile optionally with PRINTF -mv bin/ tests/bitcoin-bin -make clean -make -j DEBUG=1 COIN=bitcoin_testnet_legacy -mv bin/ tests/bitcoin-testnet-bin diff --git a/tests/test_get_coin_version.py b/tests/test_get_coin_version.py deleted file mode 100644 index e475a9a5..00000000 --- a/tests/test_get_coin_version.py +++ /dev/null @@ -1,9 +0,0 @@ -def test_get_coin_version(cmd): - (p2pkh_prefix, p2sh_prefix, coin_family, coin_name, coin_ticker) = cmd.get_coin_version() - - # Bitcoin app: (0x00, 0x05, 0x01, "Bitcoin", "BTC") - assert (p2pkh_prefix, - p2sh_prefix, - coin_family, - coin_name, - coin_ticker) == (0x6F, 0xC4, 0x01, "Bitcoin", "TEST") diff --git a/tests/test_get_random.py b/tests/test_get_random.py deleted file mode 100644 index 91bb8f9f..00000000 --- a/tests/test_get_random.py +++ /dev/null @@ -1,15 +0,0 @@ -import pytest - -from bitcoin_client.exception import IncorrectLengthError - - -def test_random(cmd): - r: bytes = cmd.get_random(n=5) - assert len(r) == 5 - - r = cmd.get_random(n=32) - assert len(r) == 32 - - # max lenght is 248! - with pytest.raises(IncorrectLengthError): - cmd.get_random(n=249) diff --git a/tests/test_get_trusted_inputs.py b/tests/test_get_trusted_inputs.py deleted file mode 100644 index 7c2ff475..00000000 --- a/tests/test_get_trusted_inputs.py +++ /dev/null @@ -1,174 +0,0 @@ -from io import BytesIO - -from bitcoin_client.hwi.serialization import CTransaction -from bitcoin_client.utils import deser_trusted_input - - -def test_get_trusted_inputs(cmd): - raw_tx: bytes = bytes.fromhex( - # Version no (4 bytes little endian) - "02000000" - # In-counter (varint 1-9 bytes) - "02" - # [1] Previous Transaction hash (32 bytes) - "40d1ae8a596b34f48b303e853c56f8f6f54c483babc16978eb182e2154d5f2ab" - # [1] Previous Txout-index (4 bytes little endian) - "00000000" - # [1] Txin-script length (varint 1-9 bytes) - "6b" - # [1] scriptSig (0x6b = 107 bytes) - "48" - "3045" - "0221" - # r - "00ca145f0694ffaedd333d3724ce3f4e44aabc0ed5128113660d11f917b3c52053" - "0220" - # s - "7bec7c66328bace92bd525f385a9aa1261b83e0f92310ea1850488b40bd25a5d" - # sighash - "01" - "21" - # compressed public key - "032006c64cdd0485e068c1e22ba0fa267ca02ca0c2b34cdc6dd08cba23796b6ee7" - # [1] sequence_no (4 bytes little endian) - "fdffffff" - # [2] Previous Transaction hash (32 bytes) - "40d1ae8a596b34f48b303e853c56f8f6f54c483babc16978eb182e2154d5f2ab" - # [2] Previous Txout-index (4 bytes little endian) - "01000000" - # [2] Txin-script length (varint 1-9 bytes) - "6a" - # [2] scriptSig (0x6a = 106 bytes) - "47" - "3044" - "0220" - # r - "2a5d54a1635a7a0ae22cef76d8144ca2a1c3c035c87e7cd0280ab43d34510906" - "0220" - # s - "0c7e07e384b3620ccd2f97b5c08f5893357c653edc2b8570f099d9ff34a0285c" - "01" - "21" - # compressed public key - "02d82f3fa29d38297db8e1879010c27f27533439c868b1cc6af27dd3d33b243dec" - # [2] sequence_no (4 bytes little endian) - "fdffffff" - # Out-counter (varint 1-9 bytes) - "01" - # [1] Value (8 bytes little endian) - "d7ee7c0100000000" # 0.24964823 BTC - # [1] Txout-script length (varint 1-9 bytes) - "19" - # [1] scriptPubKey (0x19 = 25 bytes) - "76a914" - "0ea263ff8b0da6e8d187de76f6a362beadab7811" - "88ac" - # lock_time (4 bytes little endian) - "e3691900" - ) - - bip141_raw_tx: bytes = bytes.fromhex( - # Version no (4 bytes little endian) - "02000000" - # marker (1 byte) + flag (1 byte) - "0001" - # In-counter (varint 1-9 bytes) - "02" - # [1] Previous Transaction hash (32 bytes) - "e7576f53b5d92f9880b125d0622782fef40b0121eb4555c9d3a7be54e635cd6e" - # [1] Previous Txout-index (4 bytes little endian) - "00000000" - # [1] Txin-script length (varint 1-9 bytes) - "17" - # [1] scriptSig (0x17 = 23 bytes) - "160014" - "4c9fca3fd23ae5cc1f0dfe46b446da611219c020" # hash160(pubkey) - # [1] sequence_no (4 bytes little endian) - "fdffffff" - # [2] Previous Transaction hash (32 bytes) - "4ba91d8e1cedbfecdceda7f3432f618a2f0e122c66a63fe0c53a14de6305e5dc" - # [2] Previous Txout-index (4 bytes little endian) - "01000000" - # [2] Txin-script length (varint 1-9 bytes) - "17" - # [2] scriptSig (0x17 = 23 bytes) - "160014" - "92a9159a0ae40a748c18bd486ea13da85422450c" # hash160(pubkey) - # [2] sequence_no (4 bytes little endian) - "fdffffff" - # Out-counter (varint 1-9 bytes) - "02" - # [1] Value (8 bytes little endian) - "7f19060000000000" - # [1] Txout-script length (varint 1-9 bytes) - "17" - # [1] scriptPubKey (0x17 = 23 bytes) - "a9141a56dea1ff8a3f633916560fed5942400d17080b87" - # [2] Value (8 bytes little endian) - "60ae0a0000000000" - # [2] Txout-script length (varint 1-9 bytes) - "17" - # [2] scriptPubKey (0x17 = 23 bytes) - "a9147c28b075f506d829e2e2bacf897c1b5b0d309c1a87" - # Witnesses - "02" # number of items to push on the stack - "48" # length of 1st stack item - # 1st item - "3045" - "0221" - # r - "00c791ff9a5886903fbd3c1289f281e1d5a3e330f1558ea5df725bcd780b285677" - "0220" - # s - "2d76349a78585ea66df6eef5ab48a0348cc337994a1d6357a6e4e4328a343f6d" - "01" - # 2nd item - "21" # length of 2nd stack item - # compressed public key - "02623ed09f8c192938f7a638fbdd5dd7c297f86e41be8d7dff4f1c904f0685f227" - "02" # number of items to push on the stack - # 1st item - "48" # length of 1st stack item - "3045" - "0221" - # r - "008f2f017f5fa4fdd7dcfe41c83f4a71a726626cdb490d652edcb408b9a4638b7a" - "0220" - # s - "439c15a7f7a03f2876dec5392f2247437b57b227fea294f4019d06462f938b53" - "01" - # 2nd item - "21" # length of 2nd stack item - # compressed public key - "0347e9143aa6457c72a48d85b5065edc40d3a49f319d54fc4979dc3b95de949a41" - # lock_time (4 bytes little endian) - "d7681900" - ) - tx: CTransaction - bip141_tx: CTransaction - output_index: int - trusted_input: bytes - - tx = CTransaction() - tx.deserialize(BytesIO(raw_tx)) - tx.calc_sha256() - - output_index = 0 - trusted_input = cmd.get_trusted_input(utxo=tx, output_index=output_index) - - _, _, _, prev_txid, out_index, amount, _ = deser_trusted_input(trusted_input) - assert out_index == output_index - assert prev_txid == tx.sha256.to_bytes(32, byteorder="little") - assert amount == tx.vout[out_index].nValue - - bip141_tx = CTransaction() - bip141_tx.deserialize(BytesIO(bip141_raw_tx)) - bip141_tx.calc_sha256() - - output_index = 1 - trusted_input = cmd.get_trusted_input(utxo=bip141_tx, output_index=output_index) - - _, _, _, prev_txid, out_index, amount, _ = deser_trusted_input(trusted_input) - assert out_index == output_index - assert prev_txid == bip141_tx.sha256.to_bytes(32, byteorder="little") - assert amount == bip141_tx.vout[out_index].nValue diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py deleted file mode 100644 index 9991db72..00000000 --- a/tests/utils/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ - -def automation(filename): - """Decorator that adds the automation_file attribute to a test function. - - When present, this filename will be used as the --automation file when creating the speculos fixture. - """ - def decorator(func): - func.automation_file = filename - return func - return decorator \ No newline at end of file From 9d5e748ad7849e82fd6a4e18eb680162b2828029 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 12 Mar 2024 15:18:29 +0100 Subject: [PATCH 68/85] First import of ragger_bitcoin --- .gitignore | 1 + tests/README.md | 30 ++----- tests/ragger_bitcoin/README.md | 1 + tests/ragger_bitcoin/__init__.py | 5 ++ tests/ragger_bitcoin/ragger_adaptor.py | 81 +++++++++++++++++ tests/ragger_bitcoin/ragger_bitcoin.py | 78 ++++++++++++++++ tests/ragger_bitcoin/ragger_instructions.py | 98 +++++++++++++++++++++ tests/requirements.txt | 4 +- 8 files changed, 272 insertions(+), 26 deletions(-) create mode 100644 tests/ragger_bitcoin/README.md create mode 100644 tests/ragger_bitcoin/__init__.py create mode 100644 tests/ragger_bitcoin/ragger_adaptor.py create mode 100644 tests/ragger_bitcoin/ragger_bitcoin.py create mode 100644 tests/ragger_bitcoin/ragger_instructions.py diff --git a/.gitignore b/.gitignore index 02bb6dc8..4282af5b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ obj .idea .vscode build +tests/snapshots-tmp diff --git a/tests/README.md b/tests/README.md index 9e6f179f..54a2b9dc 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,8 +1,8 @@ # End-to-end tests using Bitcoin Testnet -These tests are implemented in Python and can be executed either using the [Speculos](https://github.com/LedgerHQ/speculos) emulator or a Ledger Nano S/X. +These tests are implemented in Python and can be executed either using the [Speculos](https://github.com/LedgerHQ/speculos) emulator or a Ledger device -All the commands in this folder are meant to be ran from the `tests` folder, not from the root. +All the commands in this folder are meant to be ran from the root. Python dependencies are listed in [requirements.txt](requirements.txt), install them using [pip](https://pypi.org/project/pip/) @@ -12,38 +12,20 @@ pip install -r requirements.txt ## Launch with Speculos -In order to create the necessary binaries for the Bitcoin Testnet application, you can use the convenience script `prepare_tests.sh`: - -``` -bash ./prepare_tests.sh -``` +In order to create the necessary binaries for the Bitcoin Testnet application, you can must first compile the binairies Then run all the tests using: ``` -pytest -``` - -You can delete the test binaries with - -``` -bash ./clean_tests.sh +pytest --device all ``` ## Launch with your Nano S/X Compile and install the app on your device as normal. -To run the tests on your Ledger Nano S/X you also need to install an optional dependency - -``` -pip install ledgercomm[hid] -``` - Be sure to have you device connected through USB (without any other software interacting with it) and run ``` -pytest --hid -``` - -Please note that tests that require an automation file are meant for speculos, and will currently hang the test suite. \ No newline at end of file +pytest --device `your_device` --backend ledgerblue +``` \ No newline at end of file diff --git a/tests/ragger_bitcoin/README.md b/tests/ragger_bitcoin/README.md new file mode 100644 index 00000000..ae9c2f4c --- /dev/null +++ b/tests/ragger_bitcoin/README.md @@ -0,0 +1 @@ +# Ragger wrapper for Ledger Bitcoin application client \ No newline at end of file diff --git a/tests/ragger_bitcoin/__init__.py b/tests/ragger_bitcoin/__init__.py new file mode 100644 index 00000000..516a775f --- /dev/null +++ b/tests/ragger_bitcoin/__init__.py @@ -0,0 +1,5 @@ +"""Ragger wrapper for Ledger Nano Bitcoin client""" + +from .ragger_bitcoin import createRaggerClient, RaggerClient +from .ragger_instructions import Instructions +__version__ = '0.0.1' diff --git a/tests/ragger_bitcoin/ragger_adaptor.py b/tests/ragger_bitcoin/ragger_adaptor.py new file mode 100644 index 00000000..1d1cb099 --- /dev/null +++ b/tests/ragger_bitcoin/ragger_adaptor.py @@ -0,0 +1,81 @@ +from typing import Tuple, Union +from pathlib import Path + +from ragger.navigator import Navigator +from ragger.utils import RAPDU +from ragger_bitcoin.ragger_instructions import Instructions + +# Interface with ledger_bitcoin library +class RaggerAdaptor: + def __init__(self, comm_client, screenshot_dir): + self.transport_client = comm_client + self.navigate = False + self.navigator = None + self.testname = "" + self.instructions = None + self.screenshot_dir = screenshot_dir + self.instructions_index = 0 + + def set_navigation(self, navigate, navigator, testname, instructions): + self.navigate = navigate + self.navigator = navigator + self.testname = testname + self.instructions = instructions + self.instructions_index = 0 + + def exchange(self, apdu: Union[bytes, bytearray]) -> bytearray: + if self.navigate: + sw, response, self.instructions_index = self.ragger_navigate( + self.navigator, apdu, self.instructions, self.testname, self.instructions_index) + else: + rapdu = self.transport_client.exchange_raw(apdu) + response = rapdu.data + return bytearray(response) + + + def last_async_response(self) -> RAPDU: + return self.transport_client.last_async_response + + + def ragger_navigate(self, navigator: Navigator, apdu: dict, instructions: Instructions, testname: str, index: int) -> Tuple[int, bytes, int]: + sub_index = 0 + + if instructions: + text = instructions.data['text'] + instruction_until_text = instructions.data['instruction_until_text'] + instruction_on_text = instructions.data['instruction_on_text'] + save_screenshot = instructions.data['save_screenshot'] + else: + text = [] + instruction_until_text = [] + instruction_on_text = [] + save_screenshot = [] + + try: + response = self.transport_client.exchange_raw(apdu, tick_timeout=2) + except TimeoutError: + with self.transport_client.exchange_async_raw(apdu): + for t, instr_approve, instr_next, compare in zip(text[index], + instruction_on_text[index], + instruction_until_text[index], + save_screenshot[index]): + if compare: + navigator.navigate_until_text_and_compare(instr_next, + [instr_approve], + t, + self.screenshot_dir, + Path( + f"{testname}_{index}_{sub_index}"), + screen_change_after_last_instruction=False, + screen_change_before_first_instruction=True) + else: + navigator.navigate_until_text(instr_next, + [instr_approve], + t, + screen_change_after_last_instruction=False, + screen_change_before_first_instruction=True) + sub_index += 1 + + response = self.last_async_response() + index += 1 + return response.status, response.data, index diff --git a/tests/ragger_bitcoin/ragger_bitcoin.py b/tests/ragger_bitcoin/ragger_bitcoin.py new file mode 100644 index 00000000..0f38565e --- /dev/null +++ b/tests/ragger_bitcoin/ragger_bitcoin.py @@ -0,0 +1,78 @@ +from typing import Tuple, List, Optional, Union +from pathlib import Path +import base64 + +from ledger_bitcoin.client_base import TransportClient, PartialSignature +from ledger_bitcoin.common import Chain +from ledger_bitcoin.wallet import WalletPolicy +from ledger_bitcoin.psbt import PSBT +from ledger_bitcoin.client_legacy import LegacyClient, check_keypath +from ledger_bitcoin.btchip.btchip import btchip + +from ragger.navigator import Navigator +from ragger_bitcoin.ragger_instructions import Instructions +from ragger_bitcoin.ragger_adaptor import RaggerAdaptor + + +TESTS_ROOT_DIR = Path(__file__).parent + +class RaggerClient(LegacyClient): + def __init__(self, comm_client: TransportClient, screenshot_dir: Path = TESTS_ROOT_DIR) -> None: + self.app = btchip(RaggerAdaptor(comm_client, screenshot_dir)) + self.chain = Chain.TEST + + def get_extended_pubkey(self, path: str, display: bool = False, navigator: Optional[Navigator] = None, + testname: str = "", + instructions: Instructions = None) -> str: + + if navigator: + self.app.dongle.set_navigation(True, navigator, testname, instructions) + + response = LegacyClient.get_extended_pubkey(self, path, display) + + self.app.dongle.set_navigation(False, navigator, testname, instructions) + + return response + + def sign_psbt(self, psbt: Union[PSBT, bytes, str], wallet: WalletPolicy, wallet_hmac: + Optional[bytes], navigator: Optional[Navigator] = None, + testname: str = "", instructions: Instructions = None) -> List[Tuple[int, PartialSignature]]: + + if navigator: + self.app.dongle.set_navigation(True, navigator, testname, instructions) + + result = LegacyClient.sign_psbt(self, psbt, wallet, wallet_hmac) + + self.app.dongle.set_navigation(False, navigator, testname, instructions) + + return result + + def sign_message(self, message: Union[str, bytes], bip32_path: str, navigator: + Optional[Navigator] = None, + instructions: Instructions = None, + testname: str = "" + ) -> str: + + if navigator: + self.app.dongle.set_navigation(True, navigator, testname, instructions) + + if not check_keypath(bip32_path): + raise ValueError("Invalid bip32_path") + if isinstance(message, str): + message = bytearray(message, 'utf-8') + else: + message = bytearray(message) + bip32_path = bip32_path[2:] + # First display on screen what address you're signing for + self.app.getWalletPublicKey(bip32_path, True) + self.app.signMessagePrepare(bip32_path, message) + signature = self.app.signMessageSign() + + self.app.dongle.set_navigation(False, navigator, testname, instructions) + + return base64.b64encode(signature).decode('utf-8') + + +def createRaggerClient(backend, screenshot_dir: Path = TESTS_ROOT_DIR) -> RaggerClient: + return RaggerClient(backend, screenshot_dir) + diff --git a/tests/ragger_bitcoin/ragger_instructions.py b/tests/ragger_bitcoin/ragger_instructions.py new file mode 100644 index 00000000..08e157d2 --- /dev/null +++ b/tests/ragger_bitcoin/ragger_instructions.py @@ -0,0 +1,98 @@ +from ragger.navigator import NavInsID + + +class Instructions: + def __init__(self, model): + self.data = { + 'text': [], + 'instruction_until_text': [], + 'instruction_on_text': [], + 'save_screenshot': [] + } + + if not model: + raise Exception("Model must be specified") + + self.model = model + + def __str__(self): + return "Data: {0}\n\t".format(self.data) + + def same_request(self, text, instruction_until_text=NavInsID.RIGHT_CLICK, + instruction_on_text=NavInsID.BOTH_CLICK, save_screenshot=True): + + self.data['text'][-1].append(text) + self.data['instruction_until_text'][-1].append(instruction_until_text) + self.data['instruction_on_text'][-1].append(instruction_on_text) + self.data['save_screenshot'][-1].append(save_screenshot) + + def new_request(self, text, instruction_until_text=NavInsID.RIGHT_CLICK, + instruction_on_text=NavInsID.BOTH_CLICK, save_screenshot=True): + + self.data['text'].append([text]) + self.data['instruction_until_text'].append([instruction_until_text]) + self.data['instruction_on_text'].append([instruction_on_text]) + self.data['save_screenshot'].append([save_screenshot]) + + def nano_skip_screen(self, text, save_screenshot=True): + self.new_request(text, NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, + save_screenshot=save_screenshot) + + def navigate_end_of_flow(self, save_screenshot=True): + self.new_request("Processing", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_TAP, + save_screenshot=save_screenshot) + + def confirm_transaction(self, save_screenshot=True): + self.new_request("Sign", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_CONFIRM, + save_screenshot=save_screenshot) + self.new_request("TRANSACTION", NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.USE_CASE_STATUS_DISMISS, + save_screenshot=save_screenshot) + + def same_request_confirm_transaction(self, save_screenshot=True): + self.same_request("Sign", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_CONFIRM, + save_screenshot=save_screenshot) + self.new_request("TRANSACTION", NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.USE_CASE_STATUS_DISMISS, + save_screenshot=save_screenshot) + + def confirm_message(self, save_screenshot=True): + self.new_request("Sign", NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.USE_CASE_REVIEW_CONFIRM, save_screenshot=save_screenshot) + self.new_request("MESSAGE", NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.USE_CASE_STATUS_DISMISS, save_screenshot=save_screenshot) + + def confirm_wallet(self, save_screenshot=True): + self.new_request("Approve", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_CONFIRM, + save_screenshot=save_screenshot) + self.same_request("WALLET", NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.USE_CASE_STATUS_DISMISS, save_screenshot=save_screenshot) + + def reject_message(self, save_screenshot=True): + self.new_request("Sign", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_REJECT, + save_screenshot=save_screenshot) + self.same_request("Reject", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_CHOICE_CONFIRM, + save_screenshot=save_screenshot) + self.new_request("MESSAGE", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_STATUS_DISMISS, + save_screenshot=save_screenshot) + + def warning_accept(self, save_screenshot=True): + self.new_request("Warning", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_CHOICE_CONFIRM, + save_screenshot=save_screenshot) + + def address_confirm(self, save_screenshot=True): + self.new_request("Confirm", NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CONFIRM, + save_screenshot=save_screenshot) + + def choice_confirm(self, save_screenshot=True): + self.new_request("Approve", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_CHOICE_CONFIRM, + save_screenshot=save_screenshot) + + def choice_reject(self, save_screenshot=True): + self.new_request("Approve", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_CHOICE_REJECT, + save_screenshot=save_screenshot) + + def footer_cancel(self, save_screenshot=True): + self.new_request("Approve", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.CANCEL_FOOTER_TAP, + save_screenshot=save_screenshot) diff --git a/tests/requirements.txt b/tests/requirements.txt index f8181210..dfb0a777 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,4 +1,4 @@ -typing-extensions>=3.7.4.3 pytest>=6.2.1 -ledgercomm>=1.1.0 ecdsa>=0.16.1,<0.17.0 +ragger[speculos]>=1.6.0 +ragger[ledgerwallet]>=1.6.0 From 4448fc65fb3b4896101a0dd1b3f6ccb743dc64c1 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 15 Mar 2024 13:46:12 +0100 Subject: [PATCH 69/85] tests: update with ragger --- tests/conftest.py | 98 ++------ tests/psbt/singlesig/pkh-1to1.psbt | 1 + tests/psbt/singlesig/sh-wpkh-1to2.psbt | 1 + tests/psbt/singlesig/sh-wpkh-1to2.rawtx | 1 + tests/psbt/singlesig/tr-1to2-sighash-all.psbt | 1 + .../singlesig/tr-1to2-sighash-default.psbt | 1 + .../singlesig/tr-1to2-sighash-omitted.psbt | 1 + tests/psbt/singlesig/wpkh-1to2.psbt | 1 + tests/psbt/singlesig/wpkh-1to2.rawtx | 2 + tests/psbt/singlesig/wpkh-2to2.psbt | 1 + tests/psbt/singlesig/wpkh-2to2.rawtx | 1 + tests/ragger_bitcoin/ragger_adaptor.py | 24 +- tests/ragger_bitcoin/ragger_bitcoin.py | 15 +- tests/ragger_bitcoin/ragger_instructions.py | 2 +- tests/requirements.txt | 1 + tests/test_get_pubkey.py | 129 +++++----- tests/test_sign.py | 229 ++++++++++++------ tests/test_sign_message.py | 36 ++- 18 files changed, 289 insertions(+), 256 deletions(-) create mode 100644 tests/psbt/singlesig/pkh-1to1.psbt create mode 100644 tests/psbt/singlesig/sh-wpkh-1to2.psbt create mode 100644 tests/psbt/singlesig/sh-wpkh-1to2.rawtx create mode 100644 tests/psbt/singlesig/tr-1to2-sighash-all.psbt create mode 100644 tests/psbt/singlesig/tr-1to2-sighash-default.psbt create mode 100644 tests/psbt/singlesig/tr-1to2-sighash-omitted.psbt create mode 100644 tests/psbt/singlesig/wpkh-1to2.psbt create mode 100644 tests/psbt/singlesig/wpkh-1to2.rawtx create mode 100644 tests/psbt/singlesig/wpkh-2to2.psbt create mode 100644 tests/psbt/singlesig/wpkh-2to2.rawtx diff --git a/tests/conftest.py b/tests/conftest.py index b774f370..84c0c98a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,89 +1,31 @@ -import subprocess -import os -import socket -import time -import logging import pytest +from pathlib import Path -from ledgercomm import Transport +from ragger.conftest import configuration +from ragger.backend.interface import BackendInterface +from ragger_bitcoin import createRaggerClient, RaggerClient -from bitcoin_client.bitcoin_cmd import BitcoinCommand +########################### +### CONFIGURATION START ### +########################### +# You can configure optional parameters by overriding the value of ragger.configuration.OPTIONAL_CONFIGURATION +# Please refer to ragger/conftest/configuration.py for their descriptions and accepted values -logging.basicConfig(level=logging.INFO) +MNEMONIC = "glory promote mansion idle axis finger extra february uncover one trip resource lawn turtle enact monster seven myth punch hobby comfort wild raise skin" +configuration.OPTIONAL.CUSTOM_SEED = MNEMONIC +configuration.OPTIONAL.BACKEND_SCOPE = "function" -def pytest_addoption(parser): - parser.addoption("--hid", - action="store_true") - parser.addoption("--model", action="store", default="nanos") +######################### +### CONFIGURATION END ### +######################### +TESTS_ROOT_DIR = Path(__file__).parent +# Pull all features from the base ragger conftest using the overridden configuration +pytest_plugins = ("ragger.conftest.base_conftest", ) -@pytest.fixture -def model(pytestconfig): - return pytestconfig.getoption("model") - - -@pytest.fixture -def hid(pytestconfig): - return pytestconfig.getoption("hid") - -@pytest.fixture -def device(request, hid, model): - # If running on real hardware, nothing to do here - if hid: - yield - return - - # Gets the speculos executable from the SPECULOS environment variable, - # or hopes that "speculos.py" is in the $PATH if not set - speculos_executable = os.environ.get("SPECULOS", "speculos.py") - - base_args = [ - speculos_executable, "./bitcoin-testnet-bin/app.elf", - "-l", "Bitcoin Legacy:./bitcoin-bin/app.elf", - "--display", "headless", - "--model", model - ] - - # Look for the automation_file attribute in the test function, if present - try: - automation_args = ["--automation", f"file:{request.function.automation_file}"] - except AttributeError: - automation_args = [] - - speculos_proc = subprocess.Popen([*base_args, *automation_args]) - - - # Attempts to connect to speculos to make sure that it's ready when the test starts - for _ in range(100): - try: - socket.create_connection(("127.0.0.1", 9999), timeout=1.0) - connected = True - break - except ConnectionRefusedError: - time.sleep(0.1) - connected = False - - if not connected: - raise RuntimeError("Unable to connect to speculos.") - - yield - - speculos_proc.terminate() - speculos_proc.wait() - - -@pytest.fixture -def transport(device, hid): - transport = (Transport(interface="hid", debug=True) - if hid else Transport(interface="tcp", - server="127.0.0.1", - port=9999, - debug=True)) - yield transport - transport.close() @pytest.fixture -def cmd(transport): - return BitcoinCommand(transport=transport, debug=False) +def client(backend: BackendInterface) -> RaggerClient: + return createRaggerClient(backend, screenshot_dir=TESTS_ROOT_DIR) diff --git a/tests/psbt/singlesig/pkh-1to1.psbt b/tests/psbt/singlesig/pkh-1to1.psbt new file mode 100644 index 00000000..a4c0898c --- /dev/null +++ b/tests/psbt/singlesig/pkh-1to1.psbt @@ -0,0 +1 @@ +cHNidP8BAFUCAAAAAVEiws3mgj5VdUF1uSycV6Co4ayDw44Xh/06H/M0jpUTAQAAAAD9////AXhBDwAAAAAAGXapFBPX1YFmlGw+wCKTQGbYwNER0btBiKwaBB0AAAEA+QIAAAAAAQHsIw5TCVJWBSokKCcO7ASYlEsQ9vHFePQxwj0AmLSuWgEAAAAXFgAUKBU5gg4t6XOuQbpgBLQxySHE2G3+////AnJydQAAAAAAF6kUyLkGrymMcOYDoow+/C+uGearKA+HQEIPAAAAAAAZdqkUy65bUM+Tnm9TG4prer14j+FLApeIrAJHMEQCIDfstCSDYar9T4wR5wXw+npfvc1ZUXL81WQ/OxG+/11AAiACDG0yb2w31jzsra9OszX67ffETgX17x0raBQLAjvRPQEhA9rIL8Cs/Pw2NI1KSKRvAc6nfyuezj+MO0yZ0LCy+ZXShPIcACIGAu6GCCB+IQKEJvaedkR9fj1eB3BJ9eaDwxNsIxR2KkcYGPWswv0sAACAAQAAgAAAAIAAAAAAAAAAAAAA diff --git a/tests/psbt/singlesig/sh-wpkh-1to2.psbt b/tests/psbt/singlesig/sh-wpkh-1to2.psbt new file mode 100644 index 00000000..dc54482a --- /dev/null +++ b/tests/psbt/singlesig/sh-wpkh-1to2.psbt @@ -0,0 +1 @@ +cHNidP8BAHICAAAAAXT0yaTajRSLu1boaayjaQ3aDOOsvPgWCcyUbRtvFkrOAQAAAAD9////AlDUEgAAAAAAFgAUMxjgT65sEq/LAJxpzVflslBK5rT1cQgAAAAAABepFG1IUtrzpUCfdyFtu46j1ZIxLX7phwAAAAAAAQCMAgAAAAHQ47WR3EhO23HqtmoOmUcxAH/rfQgqUMdC8CPqCQFNHgEAAAAXFgAU4xDQRPiNqxtCdp5KhMrwg2P57MH9////AmDqAAAAAAAAGXapFEWIHtDTWHVQ95SEe3yLn6A+3Qo8iKx/ZhsAAAAAABepFPBGTZ+g6kLYDk1fFFeIOYLiO47shwAAAAABASB/ZhsAAAAAABepFPBGTZ+g6kLYDk1fFFeIOYLiO47shwEEFgAUyweAh+/0haqiJg6UpT19bRxd0VEiBgJLo7d9kz3p+j+VgzSMQPPKry7/rVtuJE7Oirv8xyRPZxj1rML9MQAAgAEAAIAAAACAAQAAAAAAAAAAAAEAFgAUTLRHxTu3NSNPKxOQ1F2dhksVdtMiAgOKsR70a0i1XwDFPv3fOM3f+dYzW8r1L6n5k4R/LM0vVxj1rML9MQAAgAEAAIAAAACAAQAAAAIAAAAA diff --git a/tests/psbt/singlesig/sh-wpkh-1to2.rawtx b/tests/psbt/singlesig/sh-wpkh-1to2.rawtx new file mode 100644 index 00000000..7d5bdf80 --- /dev/null +++ b/tests/psbt/singlesig/sh-wpkh-1to2.rawtx @@ -0,0 +1 @@ +0200000000010174f4c9a4da8d148bbb56e869aca3690dda0ce3acbcf81609cc946d1b6f164ace0100000017160014cb078087eff485aaa2260e94a53d7d6d1c5dd151fdffffff0250d41200000000001600143318e04fae6c12afcb009c69cd57e5b2504ae6b4f57108000000000017a9146d4852daf3a5409f77216dbb8ea3d592312d7ee987024730440220720722b08489c2a50d10edea8e21880086c8e8f22889a16815e306daeea4665b02203fcf453fa490b76cf4f929714065fc90a519b7b97ab18914f9451b5a4b4524120121024ba3b77d933de9fa3f9583348c40f3caaf2effad5b6e244ece8abbfcc7244f6700000000 diff --git a/tests/psbt/singlesig/tr-1to2-sighash-all.psbt b/tests/psbt/singlesig/tr-1to2-sighash-all.psbt new file mode 100644 index 00000000..8cecafd2 --- /dev/null +++ b/tests/psbt/singlesig/tr-1to2-sighash-all.psbt @@ -0,0 +1 @@ +cHNidP8BAH0CAAAAAaG4I9IzbWlLSTTvm25bfeF6BVE9qKKdsCouy8eppv5tAQAAAAD9////AlX/pwAAAAAAIlEgC450hrwwagrvt6fACvBAVULbGs1z7syoJ3HM9f5etg+ghgEAAAAAABYAFBOZuKCYR6A5sDUvWNISwYC6sX93AAAAAAABASunhqkAAAAAACJRINj08dGJltthuxyvVCPeJdih7unJUNN+b/oCMBLV5i4NAQMEAQAAACEWIS6ihWpc8RDmaivp1zUxR5P9vLOIsrjxPytq3pguevUZAPWswv1WAACAAQAAgAAAAIABAAAAAAAAAAEXICEuooVqXPEQ5mor6dc1MUeT/byziLK48T8rat6YLnr1AAEFIAKQgezlYWqhy5kxn8SHTv7kfwjOul9gBGNsjENAml8KIQcCkIHs5WFqocuZMZ/Eh07+5H8IzrpfYARjbIxDQJpfChkA9azC/VYAAIABAACAAAAAgAEAAAACAAAAAAA= diff --git a/tests/psbt/singlesig/tr-1to2-sighash-default.psbt b/tests/psbt/singlesig/tr-1to2-sighash-default.psbt new file mode 100644 index 00000000..c62b238f --- /dev/null +++ b/tests/psbt/singlesig/tr-1to2-sighash-default.psbt @@ -0,0 +1 @@ +cHNidP8BAH0CAAAAAeFoYcDSl0n1LNLt3hDLzE9ZEhBxD2QOXY4UQM6F2W3GAQAAAAD9////Ao00lwAAAAAAIlEgC450hrwwagrvt6fACvBAVULbGs1z7syoJ3HM9f5etg+ghgEAAAAAABYAFBOZuKCYR6A5sDUvWNISwYC6sX93AAAAAAABASvfu5gAAAAAACJRIImQSmNI1/+aRNSduLaoB8Yi6Gg2TFR9pCbzC1piExhqAQMEAAAAACEW6cabCV7QS1Yq/I1BaRk2ulc+tvaJvCNmAL5Po5JvZBIZAPWswv1WAACAAQAAgAAAAIABAAAAAwAAAAEXIOnGmwle0EtWKvyNQWkZNrpXPrb2ibwjZgC+T6OSb2QSAAEFIAKQgezlYWqhy5kxn8SHTv7kfwjOul9gBGNsjENAml8KIQcCkIHs5WFqocuZMZ/Eh07+5H8IzrpfYARjbIxDQJpfChkA9azC/VYAAIABAACAAAAAgAEAAAACAAAAAAA= diff --git a/tests/psbt/singlesig/tr-1to2-sighash-omitted.psbt b/tests/psbt/singlesig/tr-1to2-sighash-omitted.psbt new file mode 100644 index 00000000..046f8896 --- /dev/null +++ b/tests/psbt/singlesig/tr-1to2-sighash-omitted.psbt @@ -0,0 +1 @@ +cHNidP8BAH0CAAAAAeFoYcDSl0n1LNLt3hDLzE9ZEhBxD2QOXY4UQM6F2W3GAQAAAAD9////Ao00lwAAAAAAIlEgC450hrwwagrvt6fACvBAVULbGs1z7syoJ3HM9f5etg+ghgEAAAAAABYAFBOZuKCYR6A5sDUvWNISwYC6sX93AAAAAAABASvfu5gAAAAAACJRIImQSmNI1/+aRNSduLaoB8Yi6Gg2TFR9pCbzC1piExhqIRbpxpsJXtBLVir8jUFpGTa6Vz629om8I2YAvk+jkm9kEhkA9azC/VYAAIABAACAAAAAgAEAAAADAAAAARcg6cabCV7QS1Yq/I1BaRk2ulc+tvaJvCNmAL5Po5JvZBIAAQUgApCB7OVhaqHLmTGfxIdO/uR/CM66X2AEY2yMQ0CaXwohBwKQgezlYWqhy5kxn8SHTv7kfwjOul9gBGNsjENAml8KGQD1rML9VgAAgAEAAIAAAACAAQAAAAIAAAAAAA== diff --git a/tests/psbt/singlesig/wpkh-1to2.psbt b/tests/psbt/singlesig/wpkh-1to2.psbt new file mode 100644 index 00000000..6e6b84ff --- /dev/null +++ b/tests/psbt/singlesig/wpkh-1to2.psbt @@ -0,0 +1 @@ +cHNidP8BAHQCAAAAAXoqmXlWwJ+Op/0oGcGph7sU4iv5rc2vIKiXY3Is7uJkAQAAAAD9////AqC7DQAAAAAAGXapFDRKD0jKFQ7CuQOBdmC5tosTpnAmiKx0OCMAAAAAABYAFOs4+puBKPgfJule2wxf+uqDaQ/kAAAAAAABAH0CAAAAAa+/rgZZD3Qf8a9ZtqxGESYzakxKgttVPfb++rc3rDPzAQAAAAD9////AnARAQAAAAAAIgAg/e5EHFblsG0N+CwSTHBwFKXKGWWL4LmFa8oW8e0yWfel9DAAAAAAABYAFDr4QprVlUql7oozyYP9ih6GeZJLAAAAAAEBH6X0MAAAAAAAFgAUOvhCmtWVSqXuijPJg/2KHoZ5kksiBgPuLD2Y6x+TwKGqjlpACbcOt7ROrRXxZm8TawEq1Y0waBj1rML9VAAAgAEAAIAAAACAAQAAAAgAAAAAACICAinsR3JxMe0liKIMRu2pq7fapvSf1Quv5wucWqaWHE7MGPWswv1UAACAAQAAgAAAAIABAAAACgAAAAA= diff --git a/tests/psbt/singlesig/wpkh-1to2.rawtx b/tests/psbt/singlesig/wpkh-1to2.rawtx new file mode 100644 index 00000000..a8dbde66 --- /dev/null +++ b/tests/psbt/singlesig/wpkh-1to2.rawtx @@ -0,0 +1,2 @@ +020000000001017a2a997956c09f8ea7fd2819c1a987bb14e22bf9adcdaf20a89763722ceee2640100000000fdffffff02a0bb0d00000000001976a914344a0f48ca150ec2b903817660b9b68b13a6702688ac7438230000000000160014eb38fa9b8128f81f26e95edb0c5ffaea83690fe402483045022100ab44f34dd7e87c9054591297a101e8500a0641d1d591878d0d23cf8096fa79e802205d12d1062d925e27b57bdcf994ecf332ad0a8e67b8fe407bab2101255da632aa012103ee2c3d98eb1f93c0a1aa8e5a4009b70eb7b44ead15f1666f136b012ad58d306800000000 + diff --git a/tests/psbt/singlesig/wpkh-2to2.psbt b/tests/psbt/singlesig/wpkh-2to2.psbt new file mode 100644 index 00000000..51588f88 --- /dev/null +++ b/tests/psbt/singlesig/wpkh-2to2.psbt @@ -0,0 +1 @@ +cHNidP8BAKYCAAAAAp4s/ifwrYe3iiN9XXQF1KMGZso2HVhaRnsN/kImK020AQAAAAD9////r7+uBlkPdB/xr1m2rEYRJjNqTEqC21U99v76tzesM/MAAAAAAP3///8CqDoGAAAAAAAWABTrOPqbgSj4HybpXtsMX/rqg2kP5OCTBAAAAAAAIgAgP6lmyd3Nwv2W5KXhvHZbn69s6LPrTxEEqta993Mk5b4AAAAAAAEAcQIAAAABk2qy4BBy95PP5Ml3VN4bYf4D59tlNsiy8h3QtXQsSEUBAAAAAP7///8C3uHHAAAAAAAWABTreNfEC/EGOw4/zinDVltonIVZqxAnAAAAAAAAFgAUIxjWb4T+9cSHX5M7A43GODH42hP5lx4AAQEfECcAAAAAAAAWABQjGNZvhP71xIdfkzsDjcY4MfjaEyIGA0Ve587cl7C6Q1uABm/JLJY6NMYAMXmB0TUzDE7kOsejGPWswv1UAACAAQAAgAAAAIAAAAAAAQAAAAABAHEBAAAAAQ5HHvTpLBrLUe/IZg+NP2mTbqnJsr/3L/m8gcUe/PRkAQAAAAAAAAAAAmCuCgAAAAAAFgAUNcbg3W08hLFrqIXcpzrIY9C1k+yvBjIAAAAAABYAFNwobgzS5r03zr6ew0n7XwiQVnL8AAAAAAEBH2CuCgAAAAAAFgAUNcbg3W08hLFrqIXcpzrIY9C1k+wiBgJxtbd5rYcIOFh3l7z28MeuxavnanCdck9I0uJs+HTwoBj1rML9VAAAgAEAAIAAAACAAQAAAAAAAAAAIgICKexHcnEx7SWIogxG7amrt9qm9J/VC6/nC5xappYcTswY9azC/VQAAIABAACAAAAAgAEAAAAKAAAAAAA= diff --git a/tests/psbt/singlesig/wpkh-2to2.rawtx b/tests/psbt/singlesig/wpkh-2to2.rawtx new file mode 100644 index 00000000..cb473f9c --- /dev/null +++ b/tests/psbt/singlesig/wpkh-2to2.rawtx @@ -0,0 +1 @@ +020000000001029e2cfe27f0ad87b78a237d5d7405d4a30666ca361d585a467b0dfe42262b4db40100000000fdffffffafbfae06590f741ff1af59b6ac461126336a4c4a82db553df6fefab737ac33f30000000000fdffffff02a83a060000000000160014eb38fa9b8128f81f26e95edb0c5ffaea83690fe4e0930400000000002200203fa966c9ddcdc2fd96e4a5e1bc765b9faf6ce8b3eb4f1104aad6bdf77324e5be0247304402206b3e877655f08c6e7b1b74d6d893a82cdf799f68a5ae7cecae63a71b0339e5ce022019b94aa3fb6635956e109f3d89c996b1bfbbaf3c619134b5a302badfaf52180e012103455ee7cedc97b0ba435b80066fc92c963a34c600317981d135330c4ee43ac7a302483045022100e2e98e4f8c70274f10145c89a5d86e216d0376bdf9f42f829e4315ea67d79d210220743589fd4f55e540540a976a5af58acd610fa5e188a5096dfe7d36baf3afb94001210271b5b779ad870838587797bcf6f0c7aec5abe76a709d724f48d2e26cf874f0a000000000 diff --git a/tests/ragger_bitcoin/ragger_adaptor.py b/tests/ragger_bitcoin/ragger_adaptor.py index 1d1cb099..8cf057ef 100644 --- a/tests/ragger_bitcoin/ragger_adaptor.py +++ b/tests/ragger_bitcoin/ragger_adaptor.py @@ -6,6 +6,8 @@ from ragger_bitcoin.ragger_instructions import Instructions # Interface with ledger_bitcoin library + + class RaggerAdaptor: def __init__(self, comm_client, screenshot_dir): self.transport_client = comm_client @@ -25,19 +27,18 @@ def set_navigation(self, navigate, navigator, testname, instructions): def exchange(self, apdu: Union[bytes, bytearray]) -> bytearray: if self.navigate: - sw, response, self.instructions_index = self.ragger_navigate( - self.navigator, apdu, self.instructions, self.testname, self.instructions_index) + _, response, self.instructions_index = self.ragger_navigate( + self.navigator, apdu, self.instructions, self.testname, self.instructions_index) else: rapdu = self.transport_client.exchange_raw(apdu) response = rapdu.data return bytearray(response) - def last_async_response(self) -> RAPDU: return self.transport_client.last_async_response - - def ragger_navigate(self, navigator: Navigator, apdu: dict, instructions: Instructions, testname: str, index: int) -> Tuple[int, bytes, int]: + def ragger_navigate(self, navigator: Navigator, apdu: dict, instructions: Instructions, + testname: str, index: int) -> Tuple[int, bytes, int]: sub_index = 0 if instructions: @@ -60,14 +61,11 @@ def ragger_navigate(self, navigator: Navigator, apdu: dict, instructions: Instru instruction_until_text[index], save_screenshot[index]): if compare: - navigator.navigate_until_text_and_compare(instr_next, - [instr_approve], - t, - self.screenshot_dir, - Path( - f"{testname}_{index}_{sub_index}"), - screen_change_after_last_instruction=False, - screen_change_before_first_instruction=True) + navigator.navigate_until_text_and_compare( + instr_next, [instr_approve], + t, self.screenshot_dir, Path(f"{testname}_{index}_{sub_index}"), + screen_change_after_last_instruction=False, + screen_change_before_first_instruction=True) else: navigator.navigate_until_text(instr_next, [instr_approve], diff --git a/tests/ragger_bitcoin/ragger_bitcoin.py b/tests/ragger_bitcoin/ragger_bitcoin.py index 0f38565e..ff6c2f10 100644 --- a/tests/ragger_bitcoin/ragger_bitcoin.py +++ b/tests/ragger_bitcoin/ragger_bitcoin.py @@ -16,14 +16,15 @@ TESTS_ROOT_DIR = Path(__file__).parent + class RaggerClient(LegacyClient): def __init__(self, comm_client: TransportClient, screenshot_dir: Path = TESTS_ROOT_DIR) -> None: self.app = btchip(RaggerAdaptor(comm_client, screenshot_dir)) self.chain = Chain.TEST - def get_extended_pubkey(self, path: str, display: bool = False, navigator: Optional[Navigator] = None, - testname: str = "", - instructions: Instructions = None) -> str: + def get_extended_pubkey( + self, path: str, display: bool = False, navigator: Optional[Navigator] = None, + testname: str = "", instructions: Instructions = None) -> str: if navigator: self.app.dongle.set_navigation(True, navigator, testname, instructions) @@ -34,9 +35,10 @@ def get_extended_pubkey(self, path: str, display: bool = False, navigator: Optio return response - def sign_psbt(self, psbt: Union[PSBT, bytes, str], wallet: WalletPolicy, wallet_hmac: - Optional[bytes], navigator: Optional[Navigator] = None, - testname: str = "", instructions: Instructions = None) -> List[Tuple[int, PartialSignature]]: + def sign_psbt(self, psbt: Union[PSBT, bytes, str], + wallet: WalletPolicy, wallet_hmac: Optional[bytes], + navigator: Optional[Navigator] = None, testname: str = "", + instructions: Instructions = None) -> List[Tuple[int, PartialSignature]]: if navigator: self.app.dongle.set_navigation(True, navigator, testname, instructions) @@ -75,4 +77,3 @@ def sign_message(self, message: Union[str, bytes], bip32_path: str, navigator: def createRaggerClient(backend, screenshot_dir: Path = TESTS_ROOT_DIR) -> RaggerClient: return RaggerClient(backend, screenshot_dir) - diff --git a/tests/ragger_bitcoin/ragger_instructions.py b/tests/ragger_bitcoin/ragger_instructions.py index 08e157d2..15af4509 100644 --- a/tests/ragger_bitcoin/ragger_instructions.py +++ b/tests/ragger_bitcoin/ragger_instructions.py @@ -60,7 +60,7 @@ def confirm_message(self, save_screenshot=True): self.new_request("Sign", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_CONFIRM, save_screenshot=save_screenshot) self.new_request("MESSAGE", NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_STATUS_DISMISS, save_screenshot=save_screenshot) + NavInsID.USE_CASE_STATUS_DISMISS, save_screenshot=save_screenshot) def confirm_wallet(self, save_screenshot=True): self.new_request("Approve", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_CONFIRM, diff --git a/tests/requirements.txt b/tests/requirements.txt index dfb0a777..030d75cb 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -2,3 +2,4 @@ pytest>=6.2.1 ecdsa>=0.16.1,<0.17.0 ragger[speculos]>=1.6.0 ragger[ledgerwallet]>=1.6.0 +ledger-bitcoin diff --git a/tests/test_get_pubkey.py b/tests/test_get_pubkey.py index dde1eb54..199e724e 100644 --- a/tests/test_get_pubkey.py +++ b/tests/test_get_pubkey.py @@ -1,82 +1,65 @@ -from bitcoin_client.bitcoin_base_cmd import AddrType -from utils import automation +from ragger.navigator import Navigator +from ragger.firmware import Firmware +from ragger_bitcoin import RaggerClient +from ragger_bitcoin.ragger_instructions import Instructions +from ragger.navigator import NavInsID -@automation("automations/accept_pubkey.json") -def test_get_public_key(cmd): - # legacy address - pub_key, addr, bip32_chain_code = cmd.get_public_key( - addr_type=AddrType.Legacy, - bip32_path="m/44'/1'/0'/0/0", - display=False - ) +def pubkey_instruction_approve(model: Firmware) -> Instructions: + instructions = Instructions(model) - assert pub_key == bytes.fromhex("04" - "ee8608207e21028426f69e76447d7e3d5e077049f5e683c3136c2314762a4718" - "b45f5224b05ebbad09f43594b7bd8dc0eff4519a07cbab37ecc66e0001ab959a") - assert addr == "mz5vLWdM1wHVGSmXUkhKVvZbJ2g4epMXSm" - assert bip32_chain_code == bytes.fromhex("0322c8f681e7274e767cee09b8e41770e6d2afd504fd5f85dfaab3e1ff6cdfcc") + if model.name.startswith("nano"): + instructions.new_request("Approve") + else: + instructions.address_confirm() + instructions.same_request("ADDRESS", NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.USE_CASE_STATUS_DISMISS) + return instructions - # P2SH-P2WPKH address - pub_key, addr, bip32_chain_code = cmd.get_public_key( - addr_type=AddrType.P2SH_P2WPKH, - bip32_path="m/49'/1'/0'/0/0", - display=False - ) - assert pub_key == bytes.fromhex("04" - "a80f007194d53d37f6f99539f635390588c4e1c328b098295f61af40d60cb28a" - "7b5649e8121c89148fbab7d693108654685b4e939d9c1bc55a71b43f389929fe") - assert addr == "2MyHkbusvLomaarGYMqyq7q9pSBYJRwWcsw" - assert bip32_chain_code == bytes.fromhex("dc699bc018541f456df1ebd4dea516a633a6260e0a701eba143449adc2ca63f3") +def pubkey_instruction_warning_approve(model: Firmware) -> Instructions: + instructions = Instructions(model) - # bech32 address - pub_key, addr, bip32_chain_code = cmd.get_public_key( - addr_type=AddrType.BECH32, - bip32_path="m/84'/1'/0'/0/0", - display=False - ) + if model.name.startswith("nano"): + instructions.new_request("Approve") + instructions.same_request("Approve") + else: + instructions.new_request("Unusual", NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.USE_CASE_CHOICE_CONFIRM) + instructions.same_request("Confirm", NavInsID.USE_CASE_ADDRESS_CONFIRMATION_TAP, + NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CONFIRM) + instructions.same_request("ADDRESS", NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.USE_CASE_STATUS_DISMISS) + return instructions - assert pub_key == bytes.fromhex("04" - "7cb75d34b005c4eb9f62bbf2c457d7638e813e757efcec8fa68677d950b63662" - "648e4f638cabc4e4383fa3fe8348456e46fa56742dcf500a5b50dc1d403492f0") - assert addr == "tb1qzdr7s2sr0dwmkwx033r4nujzk86u0cy6fmzfjk" - assert bip32_chain_code == bytes.fromhex("efd851020a3827ba0d3fd4375910f0ed55dbe8c5d740b37559e993b1d623a956") - # legacy address - pub_key, addr, bip32_chain_code = cmd.get_public_key( - addr_type=AddrType.Legacy, - bip32_path="m/44'/1'/0'/0/0", - display=True - ) - assert pub_key == bytes.fromhex("04" - "ee8608207e21028426f69e76447d7e3d5e077049f5e683c3136c2314762a4718" - "b45f5224b05ebbad09f43594b7bd8dc0eff4519a07cbab37ecc66e0001ab959a") - assert addr == "mz5vLWdM1wHVGSmXUkhKVvZbJ2g4epMXSm" - assert bip32_chain_code == bytes.fromhex("0322c8f681e7274e767cee09b8e41770e6d2afd504fd5f85dfaab3e1ff6cdfcc") +def test_get_public_key(navigator: Navigator, firmware: Firmware, + client: RaggerClient, test_name: str): + testcases = { + "m/84'/1'/2'/0/10": + "tpubDG9YpSUwScWJBBSrhnAT47NcT4NZGLcY18cpkaiWHnkUCi19EtCh8Heeox268NaFF6o56nVeSXuTyK6jpzTvV1h68Kr3edA8AZp27MiLUNt"} + for path, pubkey in testcases.items(): + assert pubkey == client.get_extended_pubkey( + path=path, + display=True, + navigator=navigator, + instructions=pubkey_instruction_approve(firmware), + testname=f"{test_name}_{path}" + ) + testcases = { + "m/44'/1'/0'": "tpubDCwYjpDhUdPGP5rS3wgNg13mTrrjBuG8V9VpWbyptX6TRPbNoZVXsoVUSkCjmQ8jJycjuDKBb9eataSymXakTTaGifxR6kmVsfFehH1ZgJT", + "m/44'/1'/10'": "tpubDCwYjpDhUdPGp21gSpVay2QPJVh6WNySWMXPhbcu1DsxH31dF7mY18oibbu5RxCLBc1Szerjscuc3D5HyvfYqfRvc9mesewnFqGmPjney4d", + "m/44'/1'/2'/1/42": "tpubDGF9YgHKv6qh777rcqVhpmDrbNzgophJM9ec7nHiSfrbss7fVBXoqhmZfohmJSvhNakDHAspPHjVVNL657tLbmTXvSeGev2vj5kzjMaeupT", + "m/48'/1'/4'/1'/0/7": "tpubDK8WPFx4WJo1R9mEL7Wq325wBiXvkAe8ipgb9Q1QBDTDUD2YeCfutWtzY88NPokZqJyRPKHLGwTNLT7jBG59aC6VH8q47LDGQitPB6tX2d7", + "m/49'/1'/1'/1/3": "tpubDGnetmJDCL18TyaaoyRAYbkSE9wbHktSdTS4mfsR6inC8c2r6TjdBt3wkqEQhHYPtXpa46xpxDaCXU2PRNUGVvDzAHPG6hHRavYbwAGfnFr", + "m/86'/1'/4'/1/12": "tpubDHTZ815MvTaRmo6Qg1rnU6TEU4ZkWyA56jA1UgpmMcBGomnSsyo34EZLoctzZY9MTJ6j7bhccceUeXZZLxZj5vgkVMYfcZ7DNPsyRdFpS3f", + } - # P2SH-P2WPKH address - pub_key, addr, bip32_chain_code = cmd.get_public_key( - addr_type=AddrType.P2SH_P2WPKH, - bip32_path="m/49'/1'/0'/0/0", - display=True - ) - - assert pub_key == bytes.fromhex("04" - "a80f007194d53d37f6f99539f635390588c4e1c328b098295f61af40d60cb28a" - "7b5649e8121c89148fbab7d693108654685b4e939d9c1bc55a71b43f389929fe") - assert addr == "2MyHkbusvLomaarGYMqyq7q9pSBYJRwWcsw" - assert bip32_chain_code == bytes.fromhex("dc699bc018541f456df1ebd4dea516a633a6260e0a701eba143449adc2ca63f3") - - # bech32 address - pub_key, addr, bip32_chain_code = cmd.get_public_key( - addr_type=AddrType.BECH32, - bip32_path="m/84'/1'/0'/0/0", - display=True - ) - - assert pub_key == bytes.fromhex("04" - "7cb75d34b005c4eb9f62bbf2c457d7638e813e757efcec8fa68677d950b63662" - "648e4f638cabc4e4383fa3fe8348456e46fa56742dcf500a5b50dc1d403492f0") - assert addr == "tb1qzdr7s2sr0dwmkwx033r4nujzk86u0cy6fmzfjk" - assert bip32_chain_code == bytes.fromhex("efd851020a3827ba0d3fd4375910f0ed55dbe8c5d740b37559e993b1d623a956") + for path, pubkey in testcases.items(): + assert pubkey == client.get_extended_pubkey( + path=path, + display=True, + navigator=navigator, + instructions=pubkey_instruction_warning_approve(firmware), + testname=f"{test_name}_{path}" + ) diff --git a/tests/test_sign.py b/tests/test_sign.py index 4fede15c..c9749c83 100644 --- a/tests/test_sign.py +++ b/tests/test_sign.py @@ -1,89 +1,168 @@ -from hashlib import sha256 -import json from pathlib import Path -from typing import Tuple, List, Dict, Any -import pytest - -from ecdsa.curves import SECP256k1 -from ecdsa.keys import VerifyingKey -from ecdsa.util import sigdecode_der - -from bitcoin_client.hwi.serialization import CTransaction -from bitcoin_client.exception import ConditionOfUseNotSatisfiedError -from utils import automation - - -def sign_from_json(cmd, filepath: Path): - tx_dct: Dict[str, Any] = json.load(open(filepath, "r")) - - raw_utxos: List[Tuple[bytes, int]] = [ - (bytes.fromhex(utxo_dct["raw"]), output_index) - for utxo_dct in tx_dct["utxos"] - for output_index in utxo_dct["output_indexes"] - ] - to_address: str = tx_dct["to"] - to_amount: int = tx_dct["amount"] - fees: int = tx_dct["fees"] - - sigs = cmd.sign_new_tx(address=to_address, - amount=to_amount, - fees=fees, - change_path=tx_dct["change_path"], - sign_paths=tx_dct["sign_paths"], - raw_utxos=raw_utxos, - lock_time=tx_dct["lock_time"]) - - expected_tx = CTransaction.from_bytes(bytes.fromhex(tx_dct["raw"])) - witnesses = expected_tx.wit.vtxinwit - for witness, (tx_hash_digest, sign_pub_key, (v, der_sig)) in zip(witnesses, sigs): - expected_der_sig, expected_pubkey = witness.scriptWitness.stack - assert expected_pubkey == sign_pub_key - assert expected_der_sig == der_sig - pk: VerifyingKey = VerifyingKey.from_string( - sign_pub_key, - curve=SECP256k1, - hashfunc=sha256 + +from ledger_bitcoin import WalletPolicy, PartialSignature + +from ledger_bitcoin.psbt import PSBT + +from ragger_bitcoin import RaggerClient +from ragger_bitcoin.ragger_instructions import Instructions +from ragger.navigator import Navigator +from ragger.firmware import Firmware +tests_root: Path = Path(__file__).parent + + +CURRENCY_TICKER = "TEST" + + +def sign_psbt_instruction_approve(model: Firmware) -> Instructions: + instructions = Instructions(model) + + if model.name.startswith("nano"): + instructions.new_request("Accept") + instructions.same_request("Accept") + else: + instructions.confirm_transaction() + return instructions + + +def sign_psbt_instruction_approve_2(model: Firmware) -> Instructions: + instructions = Instructions(model) + + if model.name.startswith("nano"): + instructions.new_request("Accept") + instructions.new_request("Accept") + else: + instructions.navigate_end_of_flow() + instructions.confirm_transaction() + return instructions + + +def open_psbt_from_file(filename: str) -> PSBT: + raw_psbt_base64 = open(filename, "r").read() + + psbt = PSBT() + psbt.deserialize(raw_psbt_base64) + return psbt + + +def test_sign_psbt_singlesig_pkh_1to1( + navigator: Navigator, firmware: Firmware, client: RaggerClient, test_name: str): + + # PSBT for a legacy 1-input 1-output spend (no change address) + psbt = open_psbt_from_file(f"{tests_root}/psbt/singlesig/pkh-1to1.psbt") + + wallet = WalletPolicy( + "", + "pkh(@0/**)", + ["[f5acc2fd/44'/1'/0']tpubDCwYjpDhUdPGP5rS3wgNg13mTrrjBuG8V9VpWbyptX6TRPbNoZVXsoVUSkCjmQ8jJycjuDKBb9eataSymXakTTaGifxR6kmVsfFehH1ZgJT"], + ) + + # expected sigs: + # #0: + # "pubkey" : "02ee8608207e21028426f69e76447d7e3d5e077049f5e683c3136c2314762a4718", + # "signature" : "3045022100e55b3ca788721aae8def2eadff710e524ffe8c9dec1764fdaa89584f9726e196022012a30fbcf9e1a24df31a1010356b794ab8de438b4250684757ed5772402540f401" + result = client.sign_psbt(psbt, wallet, None, navigator=navigator, + instructions=sign_psbt_instruction_approve(firmware), + testname=test_name) + + assert result == [(0, PartialSignature(pubkey=bytes.fromhex("02ee8608207e21028426f69e76447d7e3d5e077049f5e683c3136c2314762a4718"), signature=bytes.fromhex( + "3045022100e55b3ca788721aae8def2eadff710e524ffe8c9dec1764fdaa89584f9726e196022012a30fbcf9e1a24df31a1010356b794ab8de438b4250684757ed5772402540f401")))] + + +def test_sign_psbt_singlesig_sh_wpkh_1to2( + navigator: Navigator, firmware: Firmware, client: RaggerClient, test_name: str): + + # PSBT for a wrapped segwit 1-input 2-output spend (1 change address) + psbt = open_psbt_from_file(f"{tests_root}/psbt/singlesig/sh-wpkh-1to2.psbt") + + wallet = WalletPolicy( + "", + "sh(wpkh(@0/**))", + ["[f5acc2fd/49'/1'/0']tpubDC871vGLAiKPcwAw22EjhKVLk5L98UGXBEcGR8gpcigLQVDDfgcYW24QBEyTHTSFEjgJgbaHU8CdRi9vmG4cPm1kPLmZhJEP17FMBdNheh3"], + ) + + # expected sigs: + # #0: + # "pubkey" : "024ba3b77d933de9fa3f9583348c40f3caaf2effad5b6e244ece8abbfcc7244f67", + # "signature" : "30440220720722b08489c2a50d10edea8e21880086c8e8f22889a16815e306daeea4665b02203fcf453fa490b76cf4f929714065fc90a519b7b97ab18914f9451b5a4b45241201" + result = client.sign_psbt(psbt, wallet, None, navigator=navigator, + instructions=sign_psbt_instruction_approve_2(firmware), + testname=test_name) + + assert len(result) == 1 + + assert result == [( + 0, + PartialSignature( + pubkey=bytes.fromhex( + "024ba3b77d933de9fa3f9583348c40f3caaf2effad5b6e244ece8abbfcc7244f67"), + signature=bytes.fromhex( + "30440220720722b08489c2a50d10edea8e21880086c8e8f22889a16815e306daeea4665b02203fcf453fa490b76cf4f929714065fc90a519b7b97ab18914f9451b5a4b45241201" + ) ) - assert pk.verify_digest(signature=der_sig[:-1], # remove sighash - digest=tx_hash_digest, - sigdecode=sigdecode_der) is True + )] -def test_untrusted_hash_sign_fail_nonzero_p1_p2(cmd, transport): - # payloads do not matter, should check and fail before checking it (but non-empty is required) - sw, _ = transport.exchange(0xE0, 0x48, 0x01, 0x01, None, b"\x00") - assert sw == 0x6B00, "should fail with p1 and p2 both non-zero" - sw, _ = transport.exchange(0xE0, 0x48, 0x01, 0x00, None, b"\x00") - assert sw == 0x6B00, "should fail with non-zero p1" - sw, _ = transport.exchange(0xE0, 0x48, 0x00, 0x01, None, b"\x00") - assert sw == 0x6B00, "should fail with non-zero p2" +def test_sign_psbt_singlesig_wpkh_1to2( + navigator: Navigator, firmware: Firmware, client: RaggerClient, test_name: str): + # PSBT for a legacy 1-input 2-output spend (1 change address) + psbt = open_psbt_from_file(f"{tests_root}/psbt/singlesig/wpkh-1to2.psbt") -def test_untrusted_hash_sign_fail_short_payload(cmd, transport): - # should fail if the payload is less than 7 bytes - sw, _ = transport.exchange(0xE0, 0x48, 0x00, 0x00, None, b"\x01\x02\x03\x04\x05\x06") - assert sw == 0x6700 + wallet = WalletPolicy( + "", + "wpkh(@0/**)", + ["[f5acc2fd/84'/1'/0']tpubDCtKfsNyRhULjZ9XMS4VKKtVcPdVDi8MKUbcSD9MJDyjRu1A2ND5MiipozyyspBT9bg8upEp7a8EAgFxNxXn1d7QkdbL52Ty5jiSLcxPt1P"], + ) + result = client.sign_psbt(psbt, wallet, None, navigator=navigator, + instructions=sign_psbt_instruction_approve_2(firmware), + testname=test_name) + result = client.sign_psbt(psbt, wallet, None, navigator=navigator, + instructions=sign_psbt_instruction_approve_2(firmware), + testname=f"{test_name}_2") -@automation("automations/accept.json") -def test_sign_p2wpkh_accept(cmd): - for filepath in Path("data").rglob("p2wpkh/tx.json"): - sign_from_json(cmd, filepath) + # expected sigs + # #0: + # "pubkey" : "03ee2c3d98eb1f93c0a1aa8e5a4009b70eb7b44ead15f1666f136b012ad58d3068", + # "signature" : "3045022100ab44f34dd7e87c9054591297a101e8500a0641d1d591878d0d23cf8096fa79e802205d12d1062d925e27b57bdcf994ecf332ad0a8e67b8fe407bab2101255da632aa01" + assert result == [(0, PartialSignature(pubkey=bytes.fromhex("03ee2c3d98eb1f93c0a1aa8e5a4009b70eb7b44ead15f1666f136b012ad58d3068"), signature=bytes.fromhex( + "3045022100ab44f34dd7e87c9054591297a101e8500a0641d1d591878d0d23cf8096fa79e802205d12d1062d925e27b57bdcf994ecf332ad0a8e67b8fe407bab2101255da632aa01")))] -@automation("automations/accept.json") -def test_sign_p2sh_p2wpkh_accept(cmd): - for filepath in Path("data").rglob("p2sh-p2wpkh/tx.json"): - sign_from_json(cmd, filepath) +def test_sign_psbt_singlesig_wpkh_2to2( + navigator: Navigator, firmware: Firmware, client: RaggerClient, test_name: str): + # PSBT for a legacy 2-input 2-output spend (1 change address) -@automation("automations/accept.json") -def test_sign_p2pkh_accept(cmd): - for filepath in Path("data").rglob("p2pkh/tx.json"): - sign_from_json(cmd, filepath) + psbt = open_psbt_from_file(f"{tests_root}/psbt/singlesig/wpkh-2to2.psbt") + wallet = WalletPolicy( + "", + "wpkh(@0/**)", + ["[f5acc2fd/84'/1'/0']tpubDCtKfsNyRhULjZ9XMS4VKKtVcPdVDi8MKUbcSD9MJDyjRu1A2ND5MiipozyyspBT9bg8upEp7a8EAgFxNxXn1d7QkdbL52Ty5jiSLcxPt1P"], + ) -@automation("automations/reject.json") -def test_sign_fail_p2pkh_reject(cmd): - with pytest.raises(ConditionOfUseNotSatisfiedError): - sign_from_json(cmd, "./data/one-to-one/p2pkh/tx.json") \ No newline at end of file + result = client.sign_psbt(psbt, wallet, None, navigator=navigator, + instructions=sign_psbt_instruction_approve(firmware), + testname=test_name) + + assert result == [( + 0, + PartialSignature( + pubkey=bytes.fromhex( + "03455ee7cedc97b0ba435b80066fc92c963a34c600317981d135330c4ee43ac7a3"), + signature=bytes.fromhex( + "304402206b3e877655f08c6e7b1b74d6d893a82cdf799f68a5ae7cecae63a71b0339e5ce022019b94aa3fb6635956e109f3d89c996b1bfbbaf3c619134b5a302badfaf52180e01" + ) + ) + ), ( + 1, + PartialSignature( + pubkey=bytes.fromhex( + "0271b5b779ad870838587797bcf6f0c7aec5abe76a709d724f48d2e26cf874f0a0"), + signature=bytes.fromhex( + "3045022100e2e98e4f8c70274f10145c89a5d86e216d0376bdf9f42f829e4315ea67d79d210220743589fd4f55e540540a976a5af58acd610fa5e188a5096dfe7d36baf3afb94001" + ) + ) + )] diff --git a/tests/test_sign_message.py b/tests/test_sign_message.py index e4afd7d1..aed234a9 100644 --- a/tests/test_sign_message.py +++ b/tests/test_sign_message.py @@ -1,13 +1,31 @@ -from bitcoin_client.bitcoin_base_cmd import AddrType -from utils import automation +from ragger.navigator import Navigator +from ragger.firmware import Firmware +from ragger_bitcoin import RaggerClient +from ragger_bitcoin.ragger_instructions import Instructions +from ragger.navigator import NavInsID -@automation("automations/sign_message.json") -def test_sign_message(cmd): - result = cmd.sign_message( - message = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks.", - bip32_path = "m/44'/1'/0'/0/0" - ) - assert result == "MUUCIQDkeGEVZZiRjMfh+z4ELx81gBdBwIK1IIEHkXZ6FiqcqQIgfaAberpvF+XbOCM5Cd/ljogNyU3w2OIL8eYCyZ6Ru2k=" +def message_instruction_approve(model: Firmware) -> Instructions: + instructions = Instructions(model) + if model.name.startswith("nano"): + instructions.new_request("Approve") + instructions.nano_skip_screen("Message") + instructions.same_request("Sign") + else: + instructions.address_confirm() + instructions.same_request("ADDRESS", NavInsID.USE_CASE_REVIEW_TAP, + NavInsID.USE_CASE_STATUS_DISMISS) + instructions.confirm_message() + return instructions + +def test_sign_message(navigator: Navigator, firmware: Firmware, + client: RaggerClient, test_name: str): + message = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks." + bip32_path = "m/44'/1'/0'/0/0" + result = client.sign_message(message=message, bip32_path=bip32_path, navigator=navigator, + instructions=message_instruction_approve(firmware), + testname=test_name) + + assert result == "MUUCIQDkeGEVZZiRjMfh+z4ELx81gBdBwIK1IIEHkXZ6FiqcqQIgfaAberpvF+XbOCM5Cd/ljogNyU3w2OIL8eYCyZ6Ru2k=" From 61770ea5aa1f08aa27fd0e25d26703bef229417a Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 27 Mar 2024 23:57:35 +0100 Subject: [PATCH 70/85] Tests: add screenshots --- .../44'/1'/0'_0_0/00000.png | Bin 0 -> 431 bytes .../44'/1'/0'_0_0/00001.png | Bin 0 -> 363 bytes .../44'/1'/0'_0_0/00002.png | Bin 0 -> 427 bytes .../44'/1'/0'_0_0/00003.png | Bin 0 -> 394 bytes .../44'/1'/0'_0_1/00000.png | Bin 0 -> 493 bytes .../44'/1'/0'_0_1/00001.png | Bin 0 -> 495 bytes .../44'/1'/0'_0_1/00002.png | Bin 0 -> 293 bytes .../44'/1'/0'_0_1/00003.png | Bin 0 -> 341 bytes .../44'/1'/10'_0_0/00000.png | Bin 0 -> 431 bytes .../44'/1'/10'_0_0/00001.png | Bin 0 -> 358 bytes .../44'/1'/10'_0_0/00002.png | Bin 0 -> 427 bytes .../44'/1'/10'_0_0/00003.png | Bin 0 -> 394 bytes .../44'/1'/10'_0_1/00000.png | Bin 0 -> 485 bytes .../44'/1'/10'_0_1/00001.png | Bin 0 -> 476 bytes .../44'/1'/10'_0_1/00002.png | Bin 0 -> 320 bytes .../44'/1'/10'_0_1/00003.png | Bin 0 -> 341 bytes .../44'/1'/2'/1/42_0_0/00000.png | Bin 0 -> 431 bytes .../44'/1'/2'/1/42_0_0/00001.png | Bin 0 -> 403 bytes .../44'/1'/2'/1/42_0_0/00002.png | Bin 0 -> 427 bytes .../44'/1'/2'/1/42_0_0/00003.png | Bin 0 -> 394 bytes .../44'/1'/2'/1/42_0_1/00000.png | Bin 0 -> 480 bytes .../44'/1'/2'/1/42_0_1/00001.png | Bin 0 -> 521 bytes .../44'/1'/2'/1/42_0_1/00002.png | Bin 0 -> 341 bytes .../48'/1'/4'/1'/0/7_0_0/00000.png | Bin 0 -> 431 bytes .../48'/1'/4'/1'/0/7_0_0/00001.png | Bin 0 -> 399 bytes .../48'/1'/4'/1'/0/7_0_0/00002.png | Bin 0 -> 427 bytes .../48'/1'/4'/1'/0/7_0_0/00003.png | Bin 0 -> 394 bytes .../48'/1'/4'/1'/0/7_0_1/00000.png | Bin 0 -> 490 bytes .../48'/1'/4'/1'/0/7_0_1/00001.png | Bin 0 -> 503 bytes .../48'/1'/4'/1'/0/7_0_1/00002.png | Bin 0 -> 293 bytes .../48'/1'/4'/1'/0/7_0_1/00003.png | Bin 0 -> 341 bytes .../49'/1'/1'/1/3_0_0/00000.png | Bin 0 -> 431 bytes .../49'/1'/1'/1/3_0_0/00001.png | Bin 0 -> 369 bytes .../49'/1'/1'/1/3_0_0/00002.png | Bin 0 -> 427 bytes .../49'/1'/1'/1/3_0_0/00003.png | Bin 0 -> 394 bytes .../49'/1'/1'/1/3_0_1/00000.png | Bin 0 -> 475 bytes .../49'/1'/1'/1/3_0_1/00001.png | Bin 0 -> 501 bytes .../49'/1'/1'/1/3_0_1/00002.png | Bin 0 -> 293 bytes .../49'/1'/1'/1/3_0_1/00003.png | Bin 0 -> 341 bytes .../84'/1'/2'/0/10_0_0/00000.png | Bin 0 -> 493 bytes .../84'/1'/2'/0/10_0_0/00001.png | Bin 0 -> 498 bytes .../84'/1'/2'/0/10_0_0/00002.png | Bin 0 -> 354 bytes .../84'/1'/2'/0/10_0_0/00003.png | Bin 0 -> 341 bytes .../86'/1'/4'/1/12_0_0/00000.png | Bin 0 -> 431 bytes .../86'/1'/4'/1/12_0_0/00001.png | Bin 0 -> 401 bytes .../86'/1'/4'/1/12_0_0/00002.png | Bin 0 -> 427 bytes .../86'/1'/4'/1/12_0_0/00003.png | Bin 0 -> 394 bytes .../86'/1'/4'/1/12_0_1/00000.png | Bin 0 -> 491 bytes .../86'/1'/4'/1/12_0_1/00001.png | Bin 0 -> 519 bytes .../86'/1'/4'/1/12_0_1/00002.png | Bin 0 -> 341 bytes .../nanos/test_sign_message_0_0/00000.png | Bin 0 -> 466 bytes .../nanos/test_sign_message_0_0/00001.png | Bin 0 -> 532 bytes .../nanos/test_sign_message_0_0/00002.png | Bin 0 -> 345 bytes .../nanos/test_sign_message_0_0/00003.png | Bin 0 -> 341 bytes .../nanos/test_sign_message_1_0/00000.png | Bin 0 -> 368 bytes .../nanos/test_sign_message_1_0/00001.png | Bin 0 -> 527 bytes .../nanos/test_sign_message_1_1/00000.png | Bin 0 -> 516 bytes .../nanos/test_sign_message_1_1/00001.png | Bin 0 -> 528 bytes .../nanos/test_sign_message_1_1/00002.png | Bin 0 -> 487 bytes .../nanos/test_sign_message_1_1/00003.png | Bin 0 -> 407 bytes .../00000.png | Bin 0 -> 370 bytes .../00001.png | Bin 0 -> 333 bytes .../00002.png | Bin 0 -> 506 bytes .../00003.png | Bin 0 -> 509 bytes .../00004.png | Bin 0 -> 324 bytes .../00000.png | Bin 0 -> 362 bytes .../00001.png | Bin 0 -> 320 bytes .../00002.png | Bin 0 -> 414 bytes .../00000.png | Bin 0 -> 370 bytes .../00001.png | Bin 0 -> 351 bytes .../00002.png | Bin 0 -> 473 bytes .../00003.png | Bin 0 -> 515 bytes .../00004.png | Bin 0 -> 370 bytes .../00005.png | Bin 0 -> 324 bytes .../00000.png | Bin 0 -> 362 bytes .../00001.png | Bin 0 -> 334 bytes .../00002.png | Bin 0 -> 414 bytes .../00000.png | Bin 0 -> 370 bytes .../00001.png | Bin 0 -> 324 bytes .../00002.png | Bin 0 -> 493 bytes .../00003.png | Bin 0 -> 499 bytes .../00004.png | Bin 0 -> 324 bytes .../00000.png | Bin 0 -> 362 bytes .../00001.png | Bin 0 -> 340 bytes .../00002.png | Bin 0 -> 414 bytes .../00000.png | Bin 0 -> 370 bytes .../00001.png | Bin 0 -> 324 bytes .../00002.png | Bin 0 -> 493 bytes .../00003.png | Bin 0 -> 499 bytes .../00004.png | Bin 0 -> 324 bytes .../00000.png | Bin 0 -> 362 bytes .../00001.png | Bin 0 -> 340 bytes .../00002.png | Bin 0 -> 414 bytes .../00000.png | Bin 0 -> 384 bytes .../00001.png | Bin 0 -> 327 bytes .../00002.png | Bin 0 -> 487 bytes .../00003.png | Bin 0 -> 477 bytes .../00004.png | Bin 0 -> 508 bytes .../00005.png | Bin 0 -> 443 bytes .../00006.png | Bin 0 -> 324 bytes .../00000.png | Bin 0 -> 362 bytes .../00001.png | Bin 0 -> 333 bytes .../00002.png | Bin 0 -> 414 bytes .../44'/1'/0'_0_0/00000.png | Bin 0 -> 500 bytes .../44'/1'/0'_0_0/00001.png | Bin 0 -> 434 bytes .../44'/1'/0'_0_0/00002.png | Bin 0 -> 488 bytes .../44'/1'/0'_0_0/00003.png | Bin 0 -> 453 bytes .../44'/1'/0'_0_1/00000.png | Bin 0 -> 683 bytes .../44'/1'/0'_0_1/00001.png | Bin 0 -> 364 bytes .../44'/1'/10'_0_0/00000.png | Bin 0 -> 500 bytes .../44'/1'/10'_0_0/00001.png | Bin 0 -> 436 bytes .../44'/1'/10'_0_0/00002.png | Bin 0 -> 488 bytes .../44'/1'/10'_0_0/00003.png | Bin 0 -> 453 bytes .../44'/1'/10'_0_1/00000.png | Bin 0 -> 689 bytes .../44'/1'/10'_0_1/00001.png | Bin 0 -> 364 bytes .../44'/1'/2'/1/42_0_0/00000.png | Bin 0 -> 500 bytes .../44'/1'/2'/1/42_0_0/00001.png | Bin 0 -> 475 bytes .../44'/1'/2'/1/42_0_0/00002.png | Bin 0 -> 488 bytes .../44'/1'/2'/1/42_0_0/00003.png | Bin 0 -> 453 bytes .../44'/1'/2'/1/42_0_1/00000.png | Bin 0 -> 712 bytes .../44'/1'/2'/1/42_0_1/00001.png | Bin 0 -> 364 bytes .../48'/1'/4'/1'/0/7_0_0/00000.png | Bin 0 -> 500 bytes .../48'/1'/4'/1'/0/7_0_0/00001.png | Bin 0 -> 466 bytes .../48'/1'/4'/1'/0/7_0_0/00002.png | Bin 0 -> 488 bytes .../48'/1'/4'/1'/0/7_0_0/00003.png | Bin 0 -> 453 bytes .../48'/1'/4'/1'/0/7_0_1/00000.png | Bin 0 -> 704 bytes .../48'/1'/4'/1'/0/7_0_1/00001.png | Bin 0 -> 364 bytes .../49'/1'/1'/1/3_0_0/00000.png | Bin 0 -> 500 bytes .../49'/1'/1'/1/3_0_0/00001.png | Bin 0 -> 445 bytes .../49'/1'/1'/1/3_0_0/00002.png | Bin 0 -> 488 bytes .../49'/1'/1'/1/3_0_0/00003.png | Bin 0 -> 453 bytes .../49'/1'/1'/1/3_0_1/00000.png | Bin 0 -> 673 bytes .../49'/1'/1'/1/3_0_1/00001.png | Bin 0 -> 364 bytes .../84'/1'/2'/0/10_0_0/00000.png | Bin 0 -> 741 bytes .../84'/1'/2'/0/10_0_0/00001.png | Bin 0 -> 364 bytes .../86'/1'/4'/1/12_0_0/00000.png | Bin 0 -> 500 bytes .../86'/1'/4'/1/12_0_0/00001.png | Bin 0 -> 474 bytes .../86'/1'/4'/1/12_0_0/00002.png | Bin 0 -> 488 bytes .../86'/1'/4'/1/12_0_0/00003.png | Bin 0 -> 453 bytes .../86'/1'/4'/1/12_0_1/00000.png | Bin 0 -> 714 bytes .../86'/1'/4'/1/12_0_1/00001.png | Bin 0 -> 364 bytes .../nanosp/test_sign_message_0_0/00000.png | Bin 0 -> 758 bytes .../nanosp/test_sign_message_0_0/00001.png | Bin 0 -> 364 bytes .../nanosp/test_sign_message_1_0/00000.png | Bin 0 -> 415 bytes .../nanosp/test_sign_message_1_0/00001.png | Bin 0 -> 923 bytes .../nanosp/test_sign_message_1_1/00000.png | Bin 0 -> 554 bytes .../nanosp/test_sign_message_1_1/00001.png | Bin 0 -> 457 bytes .../00000.png | Bin 0 -> 418 bytes .../00001.png | Bin 0 -> 394 bytes .../00002.png | Bin 0 -> 724 bytes .../00003.png | Bin 0 -> 347 bytes .../00000.png | Bin 0 -> 403 bytes .../00001.png | Bin 0 -> 359 bytes .../00002.png | Bin 0 -> 472 bytes .../00000.png | Bin 0 -> 418 bytes .../00001.png | Bin 0 -> 410 bytes .../00002.png | Bin 0 -> 767 bytes .../00003.png | Bin 0 -> 347 bytes .../00000.png | Bin 0 -> 403 bytes .../00001.png | Bin 0 -> 385 bytes .../00002.png | Bin 0 -> 472 bytes .../00000.png | Bin 0 -> 418 bytes .../00001.png | Bin 0 -> 374 bytes .../00002.png | Bin 0 -> 701 bytes .../00003.png | Bin 0 -> 347 bytes .../00000.png | Bin 0 -> 403 bytes .../00001.png | Bin 0 -> 387 bytes .../00002.png | Bin 0 -> 472 bytes .../00000.png | Bin 0 -> 418 bytes .../00001.png | Bin 0 -> 374 bytes .../00002.png | Bin 0 -> 701 bytes .../00003.png | Bin 0 -> 347 bytes .../00000.png | Bin 0 -> 403 bytes .../00001.png | Bin 0 -> 387 bytes .../00002.png | Bin 0 -> 472 bytes .../00000.png | Bin 0 -> 426 bytes .../00001.png | Bin 0 -> 374 bytes .../00002.png | Bin 0 -> 917 bytes .../00003.png | Bin 0 -> 504 bytes .../00004.png | Bin 0 -> 347 bytes .../00000.png | Bin 0 -> 403 bytes .../00001.png | Bin 0 -> 384 bytes .../00002.png | Bin 0 -> 472 bytes .../44'/1'/0'_0_0/00000.png | Bin 0 -> 500 bytes .../44'/1'/0'_0_0/00001.png | Bin 0 -> 434 bytes .../44'/1'/0'_0_0/00002.png | Bin 0 -> 488 bytes .../44'/1'/0'_0_0/00003.png | Bin 0 -> 453 bytes .../44'/1'/0'_0_1/00000.png | Bin 0 -> 683 bytes .../44'/1'/0'_0_1/00001.png | Bin 0 -> 364 bytes .../44'/1'/10'_0_0/00000.png | Bin 0 -> 500 bytes .../44'/1'/10'_0_0/00001.png | Bin 0 -> 436 bytes .../44'/1'/10'_0_0/00002.png | Bin 0 -> 488 bytes .../44'/1'/10'_0_0/00003.png | Bin 0 -> 453 bytes .../44'/1'/10'_0_1/00000.png | Bin 0 -> 689 bytes .../44'/1'/10'_0_1/00001.png | Bin 0 -> 364 bytes .../44'/1'/2'/1/42_0_0/00000.png | Bin 0 -> 500 bytes .../44'/1'/2'/1/42_0_0/00001.png | Bin 0 -> 475 bytes .../44'/1'/2'/1/42_0_0/00002.png | Bin 0 -> 488 bytes .../44'/1'/2'/1/42_0_0/00003.png | Bin 0 -> 453 bytes .../44'/1'/2'/1/42_0_1/00000.png | Bin 0 -> 712 bytes .../44'/1'/2'/1/42_0_1/00001.png | Bin 0 -> 364 bytes .../48'/1'/4'/1'/0/7_0_0/00000.png | Bin 0 -> 500 bytes .../48'/1'/4'/1'/0/7_0_0/00001.png | Bin 0 -> 466 bytes .../48'/1'/4'/1'/0/7_0_0/00002.png | Bin 0 -> 488 bytes .../48'/1'/4'/1'/0/7_0_0/00003.png | Bin 0 -> 453 bytes .../48'/1'/4'/1'/0/7_0_1/00000.png | Bin 0 -> 704 bytes .../48'/1'/4'/1'/0/7_0_1/00001.png | Bin 0 -> 364 bytes .../49'/1'/1'/1/3_0_0/00000.png | Bin 0 -> 500 bytes .../49'/1'/1'/1/3_0_0/00001.png | Bin 0 -> 445 bytes .../49'/1'/1'/1/3_0_0/00002.png | Bin 0 -> 488 bytes .../49'/1'/1'/1/3_0_0/00003.png | Bin 0 -> 453 bytes .../49'/1'/1'/1/3_0_1/00000.png | Bin 0 -> 673 bytes .../49'/1'/1'/1/3_0_1/00001.png | Bin 0 -> 364 bytes .../84'/1'/2'/0/10_0_0/00000.png | Bin 0 -> 741 bytes .../84'/1'/2'/0/10_0_0/00001.png | Bin 0 -> 364 bytes .../86'/1'/4'/1/12_0_0/00000.png | Bin 0 -> 500 bytes .../86'/1'/4'/1/12_0_0/00001.png | Bin 0 -> 474 bytes .../86'/1'/4'/1/12_0_0/00002.png | Bin 0 -> 488 bytes .../86'/1'/4'/1/12_0_0/00003.png | Bin 0 -> 453 bytes .../86'/1'/4'/1/12_0_1/00000.png | Bin 0 -> 714 bytes .../86'/1'/4'/1/12_0_1/00001.png | Bin 0 -> 364 bytes .../nanox/test_sign_message_0_0/00000.png | Bin 0 -> 758 bytes .../nanox/test_sign_message_0_0/00001.png | Bin 0 -> 364 bytes .../nanox/test_sign_message_1_0/00000.png | Bin 0 -> 415 bytes .../nanox/test_sign_message_1_0/00001.png | Bin 0 -> 923 bytes .../nanox/test_sign_message_1_1/00000.png | Bin 0 -> 554 bytes .../nanox/test_sign_message_1_1/00001.png | Bin 0 -> 457 bytes .../00000.png | Bin 0 -> 418 bytes .../00001.png | Bin 0 -> 394 bytes .../00002.png | Bin 0 -> 724 bytes .../00003.png | Bin 0 -> 347 bytes .../00000.png | Bin 0 -> 403 bytes .../00001.png | Bin 0 -> 359 bytes .../00002.png | Bin 0 -> 472 bytes .../00000.png | Bin 0 -> 418 bytes .../00001.png | Bin 0 -> 410 bytes .../00002.png | Bin 0 -> 767 bytes .../00003.png | Bin 0 -> 347 bytes .../00000.png | Bin 0 -> 403 bytes .../00001.png | Bin 0 -> 385 bytes .../00002.png | Bin 0 -> 472 bytes .../00000.png | Bin 0 -> 418 bytes .../00001.png | Bin 0 -> 374 bytes .../00002.png | Bin 0 -> 701 bytes .../00003.png | Bin 0 -> 347 bytes .../00000.png | Bin 0 -> 403 bytes .../00001.png | Bin 0 -> 387 bytes .../00002.png | Bin 0 -> 472 bytes .../00000.png | Bin 0 -> 418 bytes .../00001.png | Bin 0 -> 374 bytes .../00002.png | Bin 0 -> 701 bytes .../00003.png | Bin 0 -> 347 bytes .../00000.png | Bin 0 -> 403 bytes .../00001.png | Bin 0 -> 387 bytes .../00002.png | Bin 0 -> 472 bytes .../00000.png | Bin 0 -> 426 bytes .../00001.png | Bin 0 -> 374 bytes .../00002.png | Bin 0 -> 917 bytes .../00003.png | Bin 0 -> 504 bytes .../00004.png | Bin 0 -> 347 bytes .../00000.png | Bin 0 -> 403 bytes .../00001.png | Bin 0 -> 384 bytes .../00002.png | Bin 0 -> 472 bytes .../44'/1'/0'_0_0/00000.png | Bin 0 -> 9271 bytes .../44'/1'/0'_0_0/00001.png | Bin 0 -> 8810 bytes .../44'/1'/0'_0_1/00000.png | Bin 0 -> 13161 bytes .../44'/1'/0'_0_1/00001.png | Bin 0 -> 7127 bytes .../44'/1'/0'_0_2/00000.png | Bin 0 -> 5035 bytes .../44'/1'/10'_0_0/00000.png | Bin 0 -> 9271 bytes .../44'/1'/10'_0_0/00001.png | Bin 0 -> 8810 bytes .../44'/1'/10'_0_1/00000.png | Bin 0 -> 13088 bytes .../44'/1'/10'_0_1/00001.png | Bin 0 -> 7123 bytes .../44'/1'/10'_0_2/00000.png | Bin 0 -> 5035 bytes .../44'/1'/2'/1/42_0_0/00000.png | Bin 0 -> 9271 bytes .../44'/1'/2'/1/42_0_0/00001.png | Bin 0 -> 8810 bytes .../44'/1'/2'/1/42_0_1/00000.png | Bin 0 -> 13928 bytes .../44'/1'/2'/1/42_0_1/00001.png | Bin 0 -> 7393 bytes .../44'/1'/2'/1/42_0_2/00000.png | Bin 0 -> 5035 bytes .../48'/1'/4'/1'/0/7_0_0/00000.png | Bin 0 -> 9271 bytes .../48'/1'/4'/1'/0/7_0_0/00001.png | Bin 0 -> 8810 bytes .../48'/1'/4'/1'/0/7_0_1/00000.png | Bin 0 -> 13385 bytes .../48'/1'/4'/1'/0/7_0_1/00001.png | Bin 0 -> 7845 bytes .../48'/1'/4'/1'/0/7_0_2/00000.png | Bin 0 -> 5035 bytes .../49'/1'/1'/1/3_0_0/00000.png | Bin 0 -> 9271 bytes .../49'/1'/1'/1/3_0_0/00001.png | Bin 0 -> 8810 bytes .../49'/1'/1'/1/3_0_1/00000.png | Bin 0 -> 13335 bytes .../49'/1'/1'/1/3_0_1/00001.png | Bin 0 -> 7548 bytes .../49'/1'/1'/1/3_0_2/00000.png | Bin 0 -> 5035 bytes .../84'/1'/2'/0/10_0_0/00000.png | Bin 0 -> 9271 bytes .../84'/1'/2'/0/10_0_0/00001.png | Bin 0 -> 13624 bytes .../84'/1'/2'/0/10_0_1/00000.png | Bin 0 -> 5035 bytes .../86'/1'/4'/1/12_0_0/00000.png | Bin 0 -> 9271 bytes .../86'/1'/4'/1/12_0_0/00001.png | Bin 0 -> 8810 bytes .../86'/1'/4'/1/12_0_1/00000.png | Bin 0 -> 13570 bytes .../86'/1'/4'/1/12_0_1/00001.png | Bin 0 -> 7795 bytes .../86'/1'/4'/1/12_0_2/00000.png | Bin 0 -> 5035 bytes .../stax/test_sign_message_0_0/00000.png | Bin 0 -> 9271 bytes .../stax/test_sign_message_0_0/00001.png | Bin 0 -> 14119 bytes .../stax/test_sign_message_0_1/00000.png | Bin 0 -> 5035 bytes .../stax/test_sign_message_1_0/00000.png | Bin 0 -> 8620 bytes .../stax/test_sign_message_1_0/00001.png | Bin 0 -> 15024 bytes .../stax/test_sign_message_1_0/00002.png | Bin 0 -> 9017 bytes .../00000.png | Bin 0 -> 10255 bytes .../00001.png | Bin 0 -> 14666 bytes .../00002.png | Bin 0 -> 7060 bytes .../00003.png | Bin 0 -> 11704 bytes .../00000.png | Bin 0 -> 10255 bytes .../00001.png | Bin 0 -> 15753 bytes .../00002.png | Bin 0 -> 3660 bytes .../00000.png | Bin 0 -> 7650 bytes .../00001.png | Bin 0 -> 11704 bytes .../00000.png | Bin 0 -> 10255 bytes .../00001.png | Bin 0 -> 13920 bytes .../00002.png | Bin 0 -> 3660 bytes .../00000.png | Bin 0 -> 7399 bytes .../00001.png | Bin 0 -> 11704 bytes .../00000.png | Bin 0 -> 10255 bytes .../00001.png | Bin 0 -> 13920 bytes .../00002.png | Bin 0 -> 3660 bytes .../00000.png | Bin 0 -> 7399 bytes .../00001.png | Bin 0 -> 11704 bytes .../00000.png | Bin 0 -> 10255 bytes .../00001.png | Bin 0 -> 19470 bytes .../00002.png | Bin 0 -> 7691 bytes .../00003.png | Bin 0 -> 11704 bytes 325 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_0/00000.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_0/00001.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_0/00002.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_0/00003.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_1/00000.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_1/00001.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_1/00002.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_1/00003.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_0/00000.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_0/00001.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_0/00002.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_0/00003.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_1/00000.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_1/00001.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_1/00002.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_1/00003.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_0/00000.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_0/00001.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_0/00002.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_0/00003.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_1/00000.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_1/00001.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_1/00002.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00000.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00001.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00002.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00003.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00000.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00001.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00002.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00003.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_0/00000.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_0/00001.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_0/00002.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_0/00003.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_1/00000.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_1/00001.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_1/00002.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_1/00003.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/84'/1'/2'/0/10_0_0/00000.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/84'/1'/2'/0/10_0_0/00001.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/84'/1'/2'/0/10_0_0/00002.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/84'/1'/2'/0/10_0_0/00003.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_0/00000.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_0/00001.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_0/00002.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_0/00003.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_1/00000.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_1/00001.png create mode 100644 tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_1/00002.png create mode 100644 tests/snapshots/nanos/test_sign_message_0_0/00000.png create mode 100644 tests/snapshots/nanos/test_sign_message_0_0/00001.png create mode 100644 tests/snapshots/nanos/test_sign_message_0_0/00002.png create mode 100644 tests/snapshots/nanos/test_sign_message_0_0/00003.png create mode 100644 tests/snapshots/nanos/test_sign_message_1_0/00000.png create mode 100644 tests/snapshots/nanos/test_sign_message_1_0/00001.png create mode 100644 tests/snapshots/nanos/test_sign_message_1_1/00000.png create mode 100644 tests/snapshots/nanos/test_sign_message_1_1/00001.png create mode 100644 tests/snapshots/nanos/test_sign_message_1_1/00002.png create mode 100644 tests/snapshots/nanos/test_sign_message_1_1/00003.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_0/00000.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_0/00001.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_0/00002.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_0/00003.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_0/00004.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_1/00000.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_1/00001.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_1/00002.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00000.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00001.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00002.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00003.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00004.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00005.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00000.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00001.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00002.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_0_0/00000.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_0_0/00001.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_0_0/00002.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_0_0/00003.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_0_0/00004.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_1_0/00000.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_1_0/00001.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_1_0/00002.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00000.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00001.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00002.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00003.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00004.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00000.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00001.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00002.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00000.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00001.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00002.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00003.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00004.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00005.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00006.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_1/00000.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_1/00001.png create mode 100644 tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_1/00002.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/0'_0_0/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/0'_0_0/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/0'_0_0/00002.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/0'_0_0/00003.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/0'_0_1/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/0'_0_1/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/10'_0_0/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/10'_0_0/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/10'_0_0/00002.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/10'_0_0/00003.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/10'_0_1/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/10'_0_1/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/2'/1/42_0_0/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/2'/1/42_0_0/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/2'/1/42_0_0/00002.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/2'/1/42_0_0/00003.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/2'/1/42_0_1/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/44'/1'/2'/1/42_0_1/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00002.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00003.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/49'/1'/1'/1/3_0_0/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/49'/1'/1'/1/3_0_0/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/49'/1'/1'/1/3_0_0/00002.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/49'/1'/1'/1/3_0_0/00003.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/49'/1'/1'/1/3_0_1/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/49'/1'/1'/1/3_0_1/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/84'/1'/2'/0/10_0_0/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/84'/1'/2'/0/10_0_0/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/86'/1'/4'/1/12_0_0/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/86'/1'/4'/1/12_0_0/00001.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/86'/1'/4'/1/12_0_0/00002.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/86'/1'/4'/1/12_0_0/00003.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/86'/1'/4'/1/12_0_1/00000.png create mode 100644 tests/snapshots/nanosp/test_get_public_key_m/86'/1'/4'/1/12_0_1/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_message_0_0/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_message_0_0/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_message_1_0/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_message_1_0/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_message_1_1/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_message_1_1/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_0/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_0/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_0/00002.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_0/00003.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_1/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_1/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_1/00002.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00002.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00003.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00002.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_0_0/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_0_0/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_0_0/00002.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_0_0/00003.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_1_0/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_1_0/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_1_0/00002.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00002.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00003.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00002.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_0/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_0/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_0/00002.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_0/00003.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_0/00004.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_1/00000.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_1/00001.png create mode 100644 tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_1/00002.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/0'_0_0/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/0'_0_0/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/0'_0_0/00002.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/0'_0_0/00003.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/0'_0_1/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/0'_0_1/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/10'_0_0/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/10'_0_0/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/10'_0_0/00002.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/10'_0_0/00003.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/10'_0_1/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/10'_0_1/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/2'/1/42_0_0/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/2'/1/42_0_0/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/2'/1/42_0_0/00002.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/2'/1/42_0_0/00003.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/2'/1/42_0_1/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/44'/1'/2'/1/42_0_1/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00002.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00003.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/49'/1'/1'/1/3_0_0/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/49'/1'/1'/1/3_0_0/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/49'/1'/1'/1/3_0_0/00002.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/49'/1'/1'/1/3_0_0/00003.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/49'/1'/1'/1/3_0_1/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/49'/1'/1'/1/3_0_1/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/84'/1'/2'/0/10_0_0/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/84'/1'/2'/0/10_0_0/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/86'/1'/4'/1/12_0_0/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/86'/1'/4'/1/12_0_0/00001.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/86'/1'/4'/1/12_0_0/00002.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/86'/1'/4'/1/12_0_0/00003.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/86'/1'/4'/1/12_0_1/00000.png create mode 100644 tests/snapshots/nanox/test_get_public_key_m/86'/1'/4'/1/12_0_1/00001.png create mode 100644 tests/snapshots/nanox/test_sign_message_0_0/00000.png create mode 100644 tests/snapshots/nanox/test_sign_message_0_0/00001.png create mode 100644 tests/snapshots/nanox/test_sign_message_1_0/00000.png create mode 100644 tests/snapshots/nanox/test_sign_message_1_0/00001.png create mode 100644 tests/snapshots/nanox/test_sign_message_1_1/00000.png create mode 100644 tests/snapshots/nanox/test_sign_message_1_1/00001.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_0/00000.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_0/00001.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_0/00002.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_0/00003.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_1/00000.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_1/00001.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_1/00002.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00000.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00001.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00002.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00003.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00000.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00001.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00002.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_0_0/00000.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_0_0/00001.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_0_0/00002.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_0_0/00003.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_1_0/00000.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_1_0/00001.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_1_0/00002.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00000.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00001.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00002.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00003.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00000.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00001.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00002.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_0/00000.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_0/00001.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_0/00002.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_0/00003.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_0/00004.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_1/00000.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_1/00001.png create mode 100644 tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_1/00002.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_0/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_0/00001.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_1/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_1/00001.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_2/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_0/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_0/00001.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_1/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_1/00001.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_2/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_0/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_0/00001.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_1/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_1/00001.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_2/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00001.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00001.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_2/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_0/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_0/00001.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_1/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_1/00001.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_2/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/84'/1'/2'/0/10_0_0/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/84'/1'/2'/0/10_0_0/00001.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/84'/1'/2'/0/10_0_1/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_0/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_0/00001.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_1/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_1/00001.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_2/00000.png create mode 100644 tests/snapshots/stax/test_sign_message_0_0/00000.png create mode 100644 tests/snapshots/stax/test_sign_message_0_0/00001.png create mode 100644 tests/snapshots/stax/test_sign_message_0_1/00000.png create mode 100644 tests/snapshots/stax/test_sign_message_1_0/00000.png create mode 100644 tests/snapshots/stax/test_sign_message_1_0/00001.png create mode 100644 tests/snapshots/stax/test_sign_message_1_0/00002.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_0/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_0/00001.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_0/00002.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_0/00003.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00001.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00002.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00001.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_0_0/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_0_0/00001.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_0_0/00002.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_1_0/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_1_0/00001.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00001.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00002.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00001.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_0/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_0/00001.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_0/00002.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_0/00003.png diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_0/00000.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..547b31a7656e18b1283fb57d8a41508e072e8b31 GIT binary patch literal 431 zcmV;g0Z{&lP)?RaprLBmq%#i2nu!+9B3M_ zssRQ}*ZlIPwd8iXuADP^+_h|{0y8sg&-d=NM} zi~Wn_&VyKoqc4fb<^4IJU3y8%xd%m1u<{IWI=FhkFo6E;;}Aq1cm&KKy0EPM5(Ibp z6+Rh>2w1nFJ5GCVGY97Hid_a27b(6A^@4W`KDkl^e{8O%2hh$ll?gPr1xaxr4 zC1mT>GISXr`z^x@08Ze#adMBC^Q_dYkxhP+GMKCdNo6pl>PS(xW&T#Lq5OmWR1iOn zDrKwZZ`A-PG(6zQB3BHgAo|}&&{7{3t^Z%rB7|&HML@e|+>Fg@`#}CZ1)0YUa2&^Z ZE+1Q*^F;27?cV?Z002ovPDHLkV1kx^y^sI^ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_0/00001.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..fcc7b0171d23e4d7421c2a1ea1ee466819c6c0f3 GIT binary patch literal 363 zcmV-x0hIoUP)`p27|uFLm*KYlY->go1QT*&;TP+w_14HqKEs^mi20gZ$1r$dfi zBWoFzV_jx(-vJI@(?nExuLMl*S+e)7ahCH-fQDLjlU7(0&Q1V(bKBoeM}sRB=>0r% z^Rq4*Ia~hVY4;4GF0-S1ljxVwD;1^h6a5l>v5fkyqMrfeAQDueNdDtKEG?tk8z7C? z(J|H}32z6fn=J*794H%2jnS+(iUylkHa*UBcVUMlO;eO{i~2H0TXC)lQ@5w z5>P8RDdm#=5+v(}R`%an$qo$BJcdfcx?_g^GXMYp0000C_yB{~{ukYqLJt4{002ov JPDHLkV1gW*n~VSe literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_0/00002.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..81fc3c1f92e9a459d0abdd2a72ab4bf33d32ff9e GIT binary patch literal 427 zcmV;c0aX5pP)(JnGERun-|N$0=m!itJPL1o(j004kBeBRfu+OktoqSO%E(Wa8v z#e7Vybc9Bhr{Od#37@pTu9~<^rL=pHhVDmwNlO1#r*V|CjcH$xWIccucxl%9B}Jv( zs@2Zxt*Se5-~rj4GCz!%Bb#K?0#Fy0ODT!N#+7^*=g21cXji~{x|R^2S8+@rISj_r z;o-w-bb9g0e6jn)fQ(~xWw{u4Ol+c3Gm3$OFdOz@8tDjum=8@spPcg-!L z^Fm0Z-LGO>_=|@dWc>-NYZ9_l>QY_J-Y3r`fSA)Nkx<{QKigcwHZxS-ZDu!4SB{FktpkdE$wMjl}oH{9O?HV2v14qSQwpN8b~ul!21Cn*5{0001hC0~BB VDq+7FunGVG002ovPDHLkV1k3NxnBSP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_0/00003.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..72c21b30f0ef246cc94290480218449f0f4a695a GIT binary patch literal 394 zcmV;50d@X~P)=};%SUm_YzAdh6R-~%PdQ*9;ED)r{Q}$J|z}}o#V53t@1LcPL^450wCZ0 zSb}5s^RdTwR_-eV8btV>0Ji?bp!XK+z834Xbm!n_47;C=Uxan%fNj>}Pp?B-3U8e9 zRoLh8vDZVYB6;zdZh|7xsV#r&IV>H#3!;p_t#X#@Ax*IBB=XX00H&b>2}=L34tnM| o77sF$+_OM}8iN1;0KmL_0H7M(5GF1@4*&oF07*qoM6N<$f;>&FbpQYW literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_1/00000.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..c6dfcb230e707557b61b5ca00fc28f9f8601e16d GIT binary patch literal 493 zcmV?qyb}jG_rD_z=88 ztpfn;+yA~>)(JP$4Ul&Vbg!_ibNn=ONeY^HKTQt7%!6wTB&Od@{0V^1wu%c%vuCf} z!h-~#0D8cSgpE-*aJ7Q{A&irD-J`>Q>M(sVrw_#RlSB+&l7bTCr_$qd$u+p2T!TBw z=-h^nTV^Apl5Taa!X8GVt4`QBawP(kw}*74MpQJ zXo`(#Sgcuw7a+99i3~=>YwFw@G^1=rCY=CKzXG~+#&MalJWHjzvpX;r=_!|Z$ZqJ( jjJ*km7BfkbBuOxDX1->oeQkDz00000NkvXXu0mjfv}5F= literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_1/00001.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..7e85ce5e06a8fcfcfecdb380d71ace29f2ed26fb GIT binary patch literal 495 zcmV>X&0ZvE^YF*BBI+h^e5)dg-B9TZW60um9wk5!SWcPL1J}QG; z9jnG=VDrGLhj>r{ivm{T1Mm~QfeEMInKI4IKNA~d2B_B^#3Eq+WCF@~WRAltR5}sS zx@_lhng)jwS_AW$C!jqr80LaQ1KZ+?_(8bc5!CG z5x$xCiD-%yFAZi&;WAz=h=qi{hp@FN7Ov_aj)!!DF8_3Q@wvf zD6UTLpNx#bmB=b|CH77hZK&FKscjsI=C4Yu?)68pno+=SwV_yZrhDGtRQ;vE>McEe zEtn4Cq^YJw9fz%Ib=UzgYkP002ovPDHLkV1mDy-cJAk literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_1/00002.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/0'_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..14f8d90a5fdd58936c25f0db62cd3e3edb0445af GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0vp^4M42G!2~2j9iA5fsW+Z3jv*Cu-cEHCYBu0-^;~}M z{{g*{vlre&5>>P|#2#;0jb(6ZtH8-I?FvoAf`Ism6Eg%{~31O-}#uTEjS< zg!7X={xW~?c5cFSue(=;mL2ZjAXv|M^0%_wxG+Yry2qARt#sf<#$}=)VJ~ zBlvESR-Jq3=$jydfC?r!$iuAw9oGJ!U-M%YMJ+y&Ch%TCM^JUq5BGkf8O_{y`#mQ} nq4{V^xv44i3V1v$0C_ea3_go|-rj`700000NkvXXu0mjfd&QW1 literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_0/00000.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..547b31a7656e18b1283fb57d8a41508e072e8b31 GIT binary patch literal 431 zcmV;g0Z{&lP)?RaprLBmq%#i2nu!+9B3M_ zssRQ}*ZlIPwd8iXuADP^+_h|{0y8sg&-d=NM} zi~Wn_&VyKoqc4fb<^4IJU3y8%xd%m1u<{IWI=FhkFo6E;;}Aq1cm&KKy0EPM5(Ibp z6+Rh>2w1nFJ5GCVGY97Hid_a27b(6A^@4W`KDkl^e{8O%2hh$ll?gPr1xaxr4 zC1mT>GISXr`z^x@08Ze#adMBC^Q_dYkxhP+GMKCdNo6pl>PS(xW&T#Lq5OmWR1iOn zDrKwZZ`A-PG(6zQB3BHgAo|}&&{7{3t^Z%rB7|&HML@e|+>Fg@`#}CZ1)0YUa2&^Z ZE+1Q*^F;27?cV?Z002ovPDHLkV1kx^y^sI^ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_0/00001.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..010681b12ef35d1e5fd48222b91739841bb46791 GIT binary patch literal 358 zcmV-s0h#`ZP)<{9=)k)Cz1qFha+Vm&X&^%! zF=EG{kCFb2=#(Lk{`IAg>+-uE+waCqe%!Cbh4h~i^_9j`a3ON6N-U%mP`IhSd&#kC zWGz?aSQjnkE5N`@jYpNYN`QLJlC?h?V>!D7w2;eg&(JnGERun-|N$0=m!itJPL1o(j004kBeBRfu+OktoqSO%E(Wa8v z#e7Vybc9Bhr{Od#37@pTu9~<^rL=pHhVDmwNlO1#r*V|CjcH$xWIccucxl%9B}Jv( zs@2Zxt*Se5-~rj4GCz!%Bb#K?0#Fy0ODT!N#+7^*=g21cXji~{x|R^2S8+@rISj_r z;o-w-bb9g0e6jn)fQ(~xWw{u4Ol+c3Gm3$OFdOz@8tDjum=8@spPcg-!L z^Fm0Z-LGO>_=|@dWc>-NYZ9_l>QY_J-Y3r`fSA)Nkx<{QKigcwHZxS-ZDu!4SB{FktpkdE$wMjl}oH{9O?HV2v14qSQwpN8b~ul!21Cn*5{0001hC0~BB VDq+7FunGVG002ovPDHLkV1k3NxnBSP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_0/00003.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..72c21b30f0ef246cc94290480218449f0f4a695a GIT binary patch literal 394 zcmV;50d@X~P)=};%SUm_YzAdh6R-~%PdQ*9;ED)r{Q}$J|z}}o#V53t@1LcPL^450wCZ0 zSb}5s^RdTwR_-eV8btV>0Ji?bp!XK+z834Xbm!n_47;C=Uxan%fNj>}Pp?B-3U8e9 zRoLh8vDZVYB6;zdZh|7xsV#r&IV>H#3!;p_t#X#@Ax*IBB=XX00H&b>2}=L34tnM| o77sF$+_OM}8iN1;0KmL_0H7M(5GF1@4*&oF07*qoM6N<$f;>&FbpQYW literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_1/00000.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/10'_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..406ba3f9936cc5b3de996be4972daba0141c8866 GIT binary patch literal 485 zcmV;0u`JD zKcTY|5$)S6?v~ZzWts-Mx&*6tu&h3M!VD=vj_*^{5UxDzV-hy~Y~nM3{=+KHC`HVU z4dI&vXMjxbL!#QKX}I$M{3FbZHr11le^oMlFx?5^o=IZDAtfkbzN$Pvm-NAW(g!n1 z>(Auf`peK&i_PLo1x$F}8p>gEv)Jql@vvfmI=@t-k2(8Vq(#%$9Wv&>f7e#S3E&`B zJ7mfO4*x91(0c|%fW-S*+h!yp0~l!pHK8@Ild#mA4SJTy3o;L)1z^!2%{o)guBusB zh&85SS`mGDsv1#xrSNW3lMa6v9|mvl#yG%HOZ5{?*pbr9`qcGCScu$q02?AS@$ovw z46a4e2-xZY86bO>AYkFL_f*a9rad9}*XAWXv!6NwW2gW&2Eh+P)H3o|*H)f^;<$nTjZYw{x$(~iV z@MO^ku=tAS4yP6pveZi&iG;eBa89W%T(sYvhunPssdlP+GztPA8GX#O0GiCFMt?$t zP)GC!6KilMk%jK$KgjGFTD+O1M)B?lb|ZxC`^b(cN4(UEbNMjtvTi4LUz~2ybpfRg zGq|$YQa#O8mh2_yih7hPaBMYH|I$%Dm-sBwqUh3x{c2GTR`uB}ZF$22kQ0|8Qp{9b zz5OH>SB1;rHZ&f5adU|7H(*!*lEL`{?)`Q@G3w3jmE0lV)9tS`!x+zE+eN762AP9mWcp@K`|5DJY Se!AQM00009Re)*>QMPWiuh;abx(HI4`X006MXpU+f@=WD$CGhERJw6<*+ z!{GE1+8kkJ09TTP*1iF6YX_HP)}1Bpc>EIt^a+UG7YIeea+<1FkZ_S>vmGx}>qJEU z4D;xY2FctO=+=ch{vzSJs1hL z&`36U5A#2ls|5UIt!T4YJf$vQ!eCn#AAiCL02Qo1{)7`S95es`000004B!K}CBU5R S@Z{nE0000_wxG+Yry2qARt#sf<#$}=)VJ~ zBlvESR-Jq3=$jydfC?r!$iuAw9oGJ!U-M%YMJ+y&Ch%TCM^JUq5BGkf8O_{y`#mQ} nq4{V^xv44i3V1v$0C_ea3_go|-rj`700000NkvXXu0mjfd&QW1 literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_0/00000.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..547b31a7656e18b1283fb57d8a41508e072e8b31 GIT binary patch literal 431 zcmV;g0Z{&lP)?RaprLBmq%#i2nu!+9B3M_ zssRQ}*ZlIPwd8iXuADP^+_h|{0y8sg&-d=NM} zi~Wn_&VyKoqc4fb<^4IJU3y8%xd%m1u<{IWI=FhkFo6E;;}Aq1cm&KKy0EPM5(Ibp z6+Rh>2w1nFJ5GCVGY97Hid_a27b(6A^@4W`KDkl^e{8O%2hh$ll?gPr1xaxr4 zC1mT>GISXr`z^x@08Ze#adMBC^Q_dYkxhP+GMKCdNo6pl>PS(xW&T#Lq5OmWR1iOn zDrKwZZ`A-PG(6zQB3BHgAo|}&&{7{3t^Z%rB7|&HML@e|+>Fg@`#}CZ1)0YUa2&^Z ZE+1Q*^F;27?cV?Z002ovPDHLkV1kx^y^sI^ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_0/00001.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..0af77d032232b5fdb0d882771e278da5ba3e09a1 GIT binary patch literal 403 zcmV;E0c`$>P)wcb+)A(*Q!W zh&V9mHm+Y5MiFZCk2k#Cx9_#>e+Vn}_P7ESV80ZoOT{x#0q#&QYeB7mL1X%@NO3Ae zB~o{&iWc`3;Gm@@qRM+sfO^e>wQr5HJHH9wP|NP371o5SCji~t+U-=DT&h5~c69bp z6^=Vw{@`u*3ZjNN@q3f(m(Y=tuJ4om5nFS0yzhfWEF}eav!FQPk-@)&3y)loZ?1u9Mho)$(Cz+vY=-go0jdURS;oMyO8 z06+V&M8xB@0;F(q(f8p*gCrOedNs=Vz_yDI&LzV(JnGERun-|N$0=m!itJPL1o(j004kBeBRfu+OktoqSO%E(Wa8v z#e7Vybc9Bhr{Od#37@pTu9~<^rL=pHhVDmwNlO1#r*V|CjcH$xWIccucxl%9B}Jv( zs@2Zxt*Se5-~rj4GCz!%Bb#K?0#Fy0ODT!N#+7^*=g21cXji~{x|R^2S8+@rISj_r z;o-w-bb9g0e6jn)fQ(~xWw{u4Ol+c3Gm3$OFdOz@8tDjum=8@spPcg-!L z^Fm0Z-LGO>_=|@dWc>-NYZ9_l>QY_J-Y3r`fSA)Nkx<{QKigcwHZxS-ZDu!4SB{FktpkdE$wMjl}oH{9O?HV2v14qSQwpN8b~ul!21Cn*5{0001hC0~BB VDq+7FunGVG002ovPDHLkV1k3NxnBSP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_0/00003.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..72c21b30f0ef246cc94290480218449f0f4a695a GIT binary patch literal 394 zcmV;50d@X~P)=};%SUm_YzAdh6R-~%PdQ*9;ED)r{Q}$J|z}}o#V53t@1LcPL^450wCZ0 zSb}5s^RdTwR_-eV8btV>0Ji?bp!XK+z834Xbm!n_47;C=Uxan%fNj>}Pp?B-3U8e9 zRoLh8vDZVYB6;zdZh|7xsV#r&IV>H#3!;p_t#X#@Ax*IBB=XX00H&b>2}=L34tnM| o77sF$+_OM}8iN1;0KmL_0H7M(5GF1@4*&oF07*qoM6N<$f;>&FbpQYW literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_1/00000.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..2314a10afd3491dae90443dda03de8b4367da2ea GIT binary patch literal 480 zcmV<60U!Q}P)OzYRO2Zlpx1Vgj|y=PmVFzJUG|;Fe3v1VB4?HIQwOc zZ>QRH@5As6Kub!lNx`Un)O1{_pnnMGL7USf4gTqK+n3ul(ESNq8Jtprf{e?XNMI#m zu%3v)O2YdqS>t`O2TAJ4ni>W2Qq!eSy2jE~T;~0*;k#BS>x>9M7cHBugBW+hLD33>1cxK_G6C@=|h2u@mnKp+qZ1blHGbzQ>v9`EOIU&R5m zckDElAuUhnwKR54fNK$Y{R8mp?SO@m_tdiO)sKN2Gy{tF4UH&Z_GB_<0Qd88_;Ixk z0B|1ne%$r}i=ijDB?jD-&^_1Ui77|Wz)ggxNheQ=F=!0-^g6&l0{~##@5|4A9%CWZ z9>zWZY`*4&1V@ymUet&zw7rBmr<`%l`wYC~pYJ!C7d4y>#o#O1hbIL}d#a&e6Ms|=oET+b`LVMlZELvm~yL&XVtrc<$xl1rthnk?}QKu?lVc8ue> z7}$->g{Fqmsb2w~qf+IYi|*gzDOBWolpK3`9P(k~12F><*Xhv?#2xVL41ubH=CjI4 zL=i1cxN6};{tj4uEVS?h7bCFlqr4v)w(Y+`L#@l%2?PRxz-s&fp)Z^FyCw9Y00000 LNkvXXu0mjf9xUsB literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_1/00002.png b/tests/snapshots/nanos/test_get_public_key_m/44'/1'/2'/1/42_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..66c411c2ebc833c701039f213ad4ff68cc881146 GIT binary patch literal 341 zcmV-b0jmCqP)_wxG+Yry2qARt#sf<#$}=)VJ~ zBlvESR-Jq3=$jydfC?r!$iuAw9oGJ!U-M%YMJ+y&Ch%TCM^JUq5BGkf8O_{y`#mQ} nq4{V^xv44i3V1v$0C_ea3_go|-rj`700000NkvXXu0mjfd&QW1 literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00000.png b/tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..547b31a7656e18b1283fb57d8a41508e072e8b31 GIT binary patch literal 431 zcmV;g0Z{&lP)?RaprLBmq%#i2nu!+9B3M_ zssRQ}*ZlIPwd8iXuADP^+_h|{0y8sg&-d=NM} zi~Wn_&VyKoqc4fb<^4IJU3y8%xd%m1u<{IWI=FhkFo6E;;}Aq1cm&KKy0EPM5(Ibp z6+Rh>2w1nFJ5GCVGY97Hid_a27b(6A^@4W`KDkl^e{8O%2hh$ll?gPr1xaxr4 zC1mT>GISXr`z^x@08Ze#adMBC^Q_dYkxhP+GMKCdNo6pl>PS(xW&T#Lq5OmWR1iOn zDrKwZZ`A-PG(6zQB3BHgAo|}&&{7{3t^Z%rB7|&HML@e|+>Fg@`#}CZ1)0YUa2&^Z ZE+1Q*^F;27?cV?Z002ovPDHLkV1kx^y^sI^ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00001.png b/tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..ccad08401f5c4b96ae7547b568e881a08ae51cd1 GIT binary patch literal 399 zcmV;A0dW3_P)FpUB1`4|JGP2kJ}ZAApHPXmK)EG2r@@nITzdt*tzMx9TMy| zk}ad=NRe6GSAc`mG!a?eD*)4L7Oj12oXzVoxno?4Aib|x za*#w<5d(AfE1+eY1}gW1Y(JnGERun-|N$0=m!itJPL1o(j004kBeBRfu+OktoqSO%E(Wa8v z#e7Vybc9Bhr{Od#37@pTu9~<^rL=pHhVDmwNlO1#r*V|CjcH$xWIccucxl%9B}Jv( zs@2Zxt*Se5-~rj4GCz!%Bb#K?0#Fy0ODT!N#+7^*=g21cXji~{x|R^2S8+@rISj_r z;o-w-bb9g0e6jn)fQ(~xWw{u4Ol+c3Gm3$OFdOz@8tDjum=8@spPcg-!L z^Fm0Z-LGO>_=|@dWc>-NYZ9_l>QY_J-Y3r`fSA)Nkx<{QKigcwHZxS-ZDu!4SB{FktpkdE$wMjl}oH{9O?HV2v14qSQwpN8b~ul!21Cn*5{0001hC0~BB VDq+7FunGVG002ovPDHLkV1k3NxnBSP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00003.png b/tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..72c21b30f0ef246cc94290480218449f0f4a695a GIT binary patch literal 394 zcmV;50d@X~P)=};%SUm_YzAdh6R-~%PdQ*9;ED)r{Q}$J|z}}o#V53t@1LcPL^450wCZ0 zSb}5s^RdTwR_-eV8btV>0Ji?bp!XK+z834Xbm!n_47;C=Uxan%fNj>}Pp?B-3U8e9 zRoLh8vDZVYB6;zdZh|7xsV#r&IV>H#3!;p_t#X#@Ax*IBB=XX00H&b>2}=L34tnM| o77sF$+_OM}8iN1;0KmL_0H7M(5GF1@4*&oF07*qoM6N<$f;>&FbpQYW literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00000.png b/tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..5c305f72e4b7b3f3b87134ae654ac49a21d2d866 GIT binary patch literal 490 zcmVgeDD`bqCfhz^{e}utk(>?t7ql)Rq3>SoXB_V}NuAl&T)b;pY;tZ}Q&frQS z`d8u@eXc1b2apBFK~ic%@QObwm2LS!k57Ax;L|tDIkgq7%k#VKa#3F5apXmNJu_CvLp)dYMB) zlWanBJbvZ(fHCIdMb@rtv3!uznH?+L!$(dreE?O>TIDilOVBxQk#yeqI+{KJ6aO@q z?@Q-mMir3IbuZ5#L1x(2m^^vXoS2*qK>4{zR%=Z2-(k&Dwm$e7awDdp7c+4M;qOo@ gc}Ri>K@i-TFRG1hX1(J{YybcN07*qoM6N<$f<-Rg5C8xG literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00001.png b/tests/snapshots/nanos/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..2bc09cc9e7f54abee5aabea848d23eb59047d3e0 GIT binary patch literal 503 zcmVB_C7Kr^kV2TS62m}IwfG^IYY)V<*qWwJXhh0Et z`_dSOWS%l>8EhmVjVQDJ0r>M)Aj0VPG_vi*UjsMj4q!i545EP9H5SEnc!dd?ASmc-QFRG2|?v0GVCA|+b1wfOzs`n=Z zja+TN`q5MAUziq!X+M1Z^HJhWG|oSbtEb)*=W@ZcO}ZisL>Ehxfg^wR&}6PO7;RQ zz59HNU99*b`>ql6w%j$|g}tDZ>6AxB6Om@t^~}?*X(V&`L=`gb4;h-CrKX}o)gyAK zU*w>%YXB-X0quyf0@(#pWk51@6-5k7YmuQ0$^nqPX>?f@Y1#V)hn_?BlgTc#C#Jff tO+}^|vlre&5>>P|#2#;0jb(6ZtH8-I?FvoAf`Ism6Eg%{~31O-}#uTEjS< zg!7X={xW~?c5cFSue(=;mL2ZjAXv|M^0%_wxG+Yry2qARt#sf<#$}=)VJ~ zBlvESR-Jq3=$jydfC?r!$iuAw9oGJ!U-M%YMJ+y&Ch%TCM^JUq5BGkf8O_{y`#mQ} nq4{V^xv44i3V1v$0C_ea3_go|-rj`700000NkvXXu0mjfd&QW1 literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_0/00000.png b/tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..547b31a7656e18b1283fb57d8a41508e072e8b31 GIT binary patch literal 431 zcmV;g0Z{&lP)?RaprLBmq%#i2nu!+9B3M_ zssRQ}*ZlIPwd8iXuADP^+_h|{0y8sg&-d=NM} zi~Wn_&VyKoqc4fb<^4IJU3y8%xd%m1u<{IWI=FhkFo6E;;}Aq1cm&KKy0EPM5(Ibp z6+Rh>2w1nFJ5GCVGY97Hid_a27b(6A^@4W`KDkl^e{8O%2hh$ll?gPr1xaxr4 zC1mT>GISXr`z^x@08Ze#adMBC^Q_dYkxhP+GMKCdNo6pl>PS(xW&T#Lq5OmWR1iOn zDrKwZZ`A-PG(6zQB3BHgAo|}&&{7{3t^Z%rB7|&HML@e|+>Fg@`#}CZ1)0YUa2&^Z ZE+1Q*^F;27?cV?Z002ovPDHLkV1kx^y^sI^ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_0/00001.png b/tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..efab9718814e96a3117d418218ecb68e8ce48a83 GIT binary patch literal 369 zcmV-%0gnEOP)!^NcbjpxNe|ys6zP+zy`=c_Gi^r9Skp5GmveI}?M2I?8ODv=naB|apIwaVv zWNSv%u_CjWuK)w7X*{C5l>?^NELr>77^|~$Ko2?W292;PT(JnGERun-|N$0=m!itJPL1o(j004kBeBRfu+OktoqSO%E(Wa8v z#e7Vybc9Bhr{Od#37@pTu9~<^rL=pHhVDmwNlO1#r*V|CjcH$xWIccucxl%9B}Jv( zs@2Zxt*Se5-~rj4GCz!%Bb#K?0#Fy0ODT!N#+7^*=g21cXji~{x|R^2S8+@rISj_r z;o-w-bb9g0e6jn)fQ(~xWw{u4Ol+c3Gm3$OFdOz@8tDjum=8@spPcg-!L z^Fm0Z-LGO>_=|@dWc>-NYZ9_l>QY_J-Y3r`fSA)Nkx<{QKigcwHZxS-ZDu!4SB{FktpkdE$wMjl}oH{9O?HV2v14qSQwpN8b~ul!21Cn*5{0001hC0~BB VDq+7FunGVG002ovPDHLkV1k3NxnBSP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_0/00003.png b/tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..72c21b30f0ef246cc94290480218449f0f4a695a GIT binary patch literal 394 zcmV;50d@X~P)=};%SUm_YzAdh6R-~%PdQ*9;ED)r{Q}$J|z}}o#V53t@1LcPL^450wCZ0 zSb}5s^RdTwR_-eV8btV>0Ji?bp!XK+z834Xbm!n_47;C=Uxan%fNj>}Pp?B-3U8e9 zRoLh8vDZVYB6;zdZh|7xsV#r&IV>H#3!;p_t#X#@Ax*IBB=XX00H&b>2}=L34tnM| o77sF$+_OM}8iN1;0KmL_0H7M(5GF1@4*&oF07*qoM6N<$f;>&FbpQYW literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_1/00000.png b/tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..3f243a2545a47fcb44cf631b09c0d492a23b7486 GIT binary patch literal 475 zcmV<10VMv3P)q_iY9bRtAz=W5AP9oMm-DE*C5$&}KM!K^OLE=H z2CqPRJ>jlKXf%McgjEZkD_~LjJxR8``Vzy*7YFY<@^^!0XV=f3F)Jve?S{%aAf%f2!bG3nm>}KKGhg3 R_=H2*pml|AAfDMJ;1_2_YENad^{(l7xRSp+t#9B9TbMVqN-%l=(-bugmr;PQcNz zYFq|3PZ_lk4=PZjD5LQKct;DU!svIVOmp{ZVgv4g;`SOP@Q>E|8P9y`!{ zA0szAz1e40WHnn)2dr+jBJiezS!qP=(nLMYOJ4@@?g>ThT1T3JY5;I&i6VfzRrii) zd!eF&4|}aQ%$6)M>TC=-PAeJ+7}Sh&RKTKIxVATQ?O!0AaAb=pjSUs2G~>R&PH$+3 z?u&KzUn8kbDRvCIDjw#F!NC3<;3x~Y{Im|2`-|lk*C|B}z&@nSLa7srtd#SH&r@B? rjh)oms@hEDtei+B5{X12k@(>QNkL@B-!$TF00000NkvXXu0mjfa7^AL literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_1/00002.png b/tests/snapshots/nanos/test_get_public_key_m/49'/1'/1'/1/3_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..14f8d90a5fdd58936c25f0db62cd3e3edb0445af GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0vp^4M42G!2~2j9iA5fsW+Z3jv*Cu-cEHCYBu0-^;~}M z{{g*{vlre&5>>P|#2#;0jb(6ZtH8-I?FvoAf`Ism6Eg%{~31O-}#uTEjS< zg!7X={xW~?c5cFSue(=;mL2ZjAXv|M^0%_wxG+Yry2qARt#sf<#$}=)VJ~ zBlvESR-Jq3=$jydfC?r!$iuAw9oGJ!U-M%YMJ+y&Ch%TCM^JUq5BGkf8O_{y`#mQ} nq4{V^xv44i3V1v$0C_ea3_go|-rj`700000NkvXXu0mjfd&QW1 literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/84'/1'/2'/0/10_0_0/00000.png b/tests/snapshots/nanos/test_get_public_key_m/84'/1'/2'/0/10_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..f1ca3208a92c5dfa0560c0e302ef5522b29453e7 GIT binary patch literal 493 zcmVfr;=2a zHGTrPJf+rB*eQS{iL@WX#o+k!oPL!H{&1+>vHu$ii?+-bD!pica(053 z>*xRg=kafM+dg11MFrJPf#M~$eT&apWMjqT_AUeG_{vH4yv+`3)X0vlm zxD#g&pbnl&SREA=cWq!lgmKcMc(nUZIn#}4c8KAgL@JvM*Upg$-k;UaskvyWX#Vt72eUM4G9!hL%k%DKZB&~h>HsHD# zKjUgf`7Wl2n$=142_+7{{y?Q3vI^cXNVxw$(t?|Fyuo5yaFT=i9{mN7VA>hWsJWv`?~BuaRBeF zt424Vc}B0N@uC7+i_zOY0PoflsBronTc)}AHL-(dfcP9}Bmwg$lc9`9W<9)`N(TT~ zmwi1>a|L5g9psq;RU*#-FwJ%JbmNv1RM8$%Td?wAjDh)-D>G7oYM%k{T~_VPCTrGM z!h?Aq0H(I$xxv^%T!y`*kw}Pb!rG*^a8du}c*x237h$8Sd*ejlBfSqJ1;CQ|RPPT6 z!PV*gn~^c-iL63B@#|!E3=Q03v;!qS`GK3I*}mduMB@mn2_Yl>ja-^|x)tx$nj5d4 zYXf9Uj9L*X2bLc25vsC3C^KLi~B8PTo{{S z+Ri^z)T1P}8Gy~md-?H!P-=e2QRRDpSU~NnT77%uC^G)ada|nx*|)H<13D(nU*&6q of5e>ocH*)4s|-ja5{ZuZ00kXfo*jZOQUCw|07*qoM6N<$f=RCA7ytkO literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/84'/1'/2'/0/10_0_0/00002.png b/tests/snapshots/nanos/test_get_public_key_m/84'/1'/2'/0/10_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..3435379786ed905b32db8992cc7ac62c8d01737f GIT binary patch literal 354 zcmV-o0iFJdP)%dtOmC9ZE-{n)RMcmenJ zO=B8LD22Lvi`yRm1Q+}c5WiO#gMyV5m5-ociISN8_^3uF zB0Bb~AKlhrGg*PMOStWpiBC`T>N8{nb=*%dTm0nlH72I%+UVZ_^lK|UQG%Ww+ro`F z-SE5_y(N&$djn$-q3%zZFIo~@%wHWlz4L(TO?6iz6Y!Pl(@F(M#eA#!3nEAj^#_9* z%mh2)0VZQ@1c~F`;KPqi-Y7Ii&}2{m008)3PNPr8*JPL9K>z>%07*qoM6N<$f=Gv$ A`~Uy| literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/84'/1'/2'/0/10_0_0/00003.png b/tests/snapshots/nanos/test_get_public_key_m/84'/1'/2'/0/10_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..66c411c2ebc833c701039f213ad4ff68cc881146 GIT binary patch literal 341 zcmV-b0jmCqP)_wxG+Yry2qARt#sf<#$}=)VJ~ zBlvESR-Jq3=$jydfC?r!$iuAw9oGJ!U-M%YMJ+y&Ch%TCM^JUq5BGkf8O_{y`#mQ} nq4{V^xv44i3V1v$0C_ea3_go|-rj`700000NkvXXu0mjfd&QW1 literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_0/00000.png b/tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..547b31a7656e18b1283fb57d8a41508e072e8b31 GIT binary patch literal 431 zcmV;g0Z{&lP)?RaprLBmq%#i2nu!+9B3M_ zssRQ}*ZlIPwd8iXuADP^+_h|{0y8sg&-d=NM} zi~Wn_&VyKoqc4fb<^4IJU3y8%xd%m1u<{IWI=FhkFo6E;;}Aq1cm&KKy0EPM5(Ibp z6+Rh>2w1nFJ5GCVGY97Hid_a27b(6A^@4W`KDkl^e{8O%2hh$ll?gPr1xaxr4 zC1mT>GISXr`z^x@08Ze#adMBC^Q_dYkxhP+GMKCdNo6pl>PS(xW&T#Lq5OmWR1iOn zDrKwZZ`A-PG(6zQB3BHgAo|}&&{7{3t^Z%rB7|&HML@e|+>Fg@`#}CZ1)0YUa2&^Z ZE+1Q*^F;27?cV?Z002ovPDHLkV1kx^y^sI^ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_0/00001.png b/tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..d583d89b733e1fd20be6f5f0953c75ccbe7940af GIT binary patch literal 401 zcmV;C0dD?@P)Y_`@@(>r^k`Gu>Og-Z)rRg7Zy&8vKFNkQ2Ell+U3|Z zik9ARqKlR3D`0|`nTRSsYXZz`maTnnCWo6h0UA=-U9`fwFnR*S&F#FM_9nMfpwIo- z`WIa^;e7dlr`-`m-DV^1MY2z!cUla6o$OQe%?i;kmHidK97KXD6iL`VoJ*ukH!Ud& zdOe`oQj}>cvASek4PifVo8WVn!!+(1iK#AFi3#$|+TE|~Zt|BMjpcxesa?LBt8Prx zg7R0&QR;4l#Sm*WE0rJ{sdiV2_&1$9udS8TP#gLGXruVI%2s*| vWfsw~*+$>8Qm-g0P##aB000000D$NPOPNDjTz!ws00000NkvXXu0mjf0GGIm literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_0/00002.png b/tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..81fc3c1f92e9a459d0abdd2a72ab4bf33d32ff9e GIT binary patch literal 427 zcmV;c0aX5pP)(JnGERun-|N$0=m!itJPL1o(j004kBeBRfu+OktoqSO%E(Wa8v z#e7Vybc9Bhr{Od#37@pTu9~<^rL=pHhVDmwNlO1#r*V|CjcH$xWIccucxl%9B}Jv( zs@2Zxt*Se5-~rj4GCz!%Bb#K?0#Fy0ODT!N#+7^*=g21cXji~{x|R^2S8+@rISj_r z;o-w-bb9g0e6jn)fQ(~xWw{u4Ol+c3Gm3$OFdOz@8tDjum=8@spPcg-!L z^Fm0Z-LGO>_=|@dWc>-NYZ9_l>QY_J-Y3r`fSA)Nkx<{QKigcwHZxS-ZDu!4SB{FktpkdE$wMjl}oH{9O?HV2v14qSQwpN8b~ul!21Cn*5{0001hC0~BB VDq+7FunGVG002ovPDHLkV1k3NxnBSP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_0/00003.png b/tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..72c21b30f0ef246cc94290480218449f0f4a695a GIT binary patch literal 394 zcmV;50d@X~P)=};%SUm_YzAdh6R-~%PdQ*9;ED)r{Q}$J|z}}o#V53t@1LcPL^450wCZ0 zSb}5s^RdTwR_-eV8btV>0Ji?bp!XK+z834Xbm!n_47;C=Uxan%fNj>}Pp?B-3U8e9 zRoLh8vDZVYB6;zdZh|7xsV#r&IV>H#3!;p_t#X#@Ax*IBB=XX00H&b>2}=L34tnM| o77sF$+_OM}8iN1;0KmL_0H7M(5GF1@4*&oF07*qoM6N<$f;>&FbpQYW literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_1/00000.png b/tests/snapshots/nanos/test_get_public_key_m/86'/1'/4'/1/12_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..f1e9d3fcc86ea0822142bc6194dc4d12e6e337b4 GIT binary patch literal 491 zcmV>m>scp|bEUy4`Nl$8?#h^Jd6W5>MzX>;|W_YZ@e|q1}Wx5BZ-+_t2EiI^Mr2G;o zqSP9^Pp!e5RQBIwVfLM-sp4p=6cKmSH7kfxgZ*jjM9B!67>s!Uk98>^Q|C!RSH+d& znmUzfU%>hqidLTetmreW4lHdzWPv^+u{rW+e5Oa_&L1cB>pwJX+AJ$2BhI;?{$Zlq zr0=XdrIXB60BxsA3nGN22)cKu3;?PSPeWA1gE$eLj#{8`B2mO5`$>58Nl()0wmmVT zZlgG5Lk-6nTL5;S_A%YE^k(9p)mO}D^|ZA1g7%^~IRY&RZJD{!)~B=T>5wB+K+VO| ha*LuUilQhAfIs10vjA-`Es+2K002ovPDHLkV1lsP*z#8 z`*ysK%Q|2&atF7>Kr@Mb*Cd`y*@6bXM9ej5=SeZ9ng_46I^drHM6|5O$8Y>R#vs)m z=6xbse1``K&RmvSnUIap_am%LstvBqK7*H>e9v?*YPdHl1HRJx^rQfwG2iO_2U2i# zcz-exgFA^`=uXZ~7ROL<@M7VSXUC#q^=N3PRYe-i?!a_jg}hJL4Zw<)5h^s*GOImt zeH5s7+eo1#?@)Cm zsHR!K(bB4QdB(`Ab(bYwwIEiKlyx5YdgkwSM}1UN$=CdCnpQk0Izbj|YjkA*cAT*! ziIGV&?Sy6wVX;qp$=$6SElXXj^^0b%R0R6~d&C}OhG9GXF$X}4ZIWxJQu)aCdTkfh zI_wxG+Yry2qARt#sf<#$}=)VJ~ zBlvESR-Jq3=$jydfC?r!$iuAw9oGJ!U-M%YMJ+y&Ch%TCM^JUq5BGkf8O_{y`#mQ} nq4{V^xv44i3V1v$0C_ea3_go|-rj`700000NkvXXu0mjfd&QW1 literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_message_0_0/00000.png b/tests/snapshots/nanos/test_sign_message_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..931a29c148d1d904f004d16ca16f4180ee44c2d8 GIT binary patch literal 466 zcmV;@0WJQCP)iq2taMm>Hj~thxUVKGmc!nP}#7a$`lZRij;yN2!gCd92|G#b;qC@%jBT23KuBnB>1>W zPbsDI_>a47pRgI#L9Hslyv(-GvD3^YC1~P)su}{72hKPlpFSJ^3`oDQ@^eZRv)6|3 zAkGU;3Xv}0G29`?OPwId-`Sq0aERZZ5S z$@~Fu|CV@%suR0?+Um+m3+c)cdn^ck>ldVUAIaR5*Cv$pVgLXD literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_message_0_0/00001.png b/tests/snapshots/nanos/test_sign_message_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..b57f67c8718393ad52667eea58c32e87acce504d GIT binary patch literal 532 zcmV+v0_**WP)Bc1~C~!U`w_xVM7z5*!JM*LjmA?bvZ&~F{o2*%5 z2|tW|09bO>^9iGbP=>8UNHokH!kSTAx#)j7Uh?MqAJdZxXQQL=mF&Zl0$}NUEBgz+SM*ms8#5US9nsb>{j=*+NXwz^(WrU4X(ya_-ikt z0qE9+hP>*UcB+jH061Ljlp^p->A#GSG7IX_`gE0Wo%YqK>s||@R$E@i&C!N~z|c~J zSlA*H^V}`lA$EV!L|1uRIMPh~3VG>?oAY}sAua$;+ng+vjP8tB$Ham8ZzX05YD*~2 zW$TZ@C@E3wlbk@##0000hCpghJAo~4*P!z1BsConm7bP~^@n>qC zi0IhQehgcK!((=gEG#T8%HjI00000NkvXXu0mjfjkJ_v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_message_0_0/00003.png b/tests/snapshots/nanos/test_sign_message_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..66c411c2ebc833c701039f213ad4ff68cc881146 GIT binary patch literal 341 zcmV-b0jmCqP)_wxG+Yry2qARt#sf<#$}=)VJ~ zBlvESR-Jq3=$jydfC?r!$iuAw9oGJ!U-M%YMJ+y&Ch%TCM^JUq5BGkf8O_{y`#mQ} nq4{V^xv44i3V1v$0C_ea3_go|-rj`700000NkvXXu0mjfd&QW1 literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_message_1_0/00000.png b/tests/snapshots/nanos/test_sign_message_1_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..ab16f62bfcfb15701d788a6a84fe55001d152730 GIT binary patch literal 368 zcmV-$0gwKPP)m1gYoarBO3LH$euV2HeiC{**okfHIi+m$sv2p+{O|Q}I5aNh^Ys5dP#v zj%1qABdJ+S6K!y2Hbl8uvs5Q~cSHZe-9%(GG&6lVhU>>5GXsQK^2D%BBCpwrIq!n_ zbF$#pv0JKROAs&1vS|{M6`m6<_23d_XsOOAL5k@8zo4r@s|o-B(!2ofEx#wWs1tqw O0000jI`K3qN!QBa)?HuQ9&^x4u`|xaIkov@;)myE6Ggnm41b$ z*)@%newteUFT77VUiHec#rHeX86y%3M9CtoDfKec*)nw-EimhABh1Ir01%W#m9Pk3 zU{TleqNL{g42LQ`rY~tD!kr$F)}*T`Es|WDmKbad<4G%~2)Uwn0;1n(LRn1=0^ubq z3W_{ha;w>;a5r)IwCi^XU$qHmfzpnf$7}jRt1Io079VL}B7c}2f>I-yO<2sZ8*O9u zOeg^gG!S&bX5<L1nL(v|k|82_2)bdDaa>@9!M$rgA|#(1v+D%_rhT!s z&xFsxPCPvdeK)Rye1Ol{0kL#mtX|#dORFp&)*Z8Y=6XjfD(M>MqqUO^r6U>4GQH9} zc>`lhtIA>Sgwsz|syrV?b(LY6Z8;Nu)OnOAv+E?iC=+hYNV~y|Ba8!UMxPu9qFLhv zKvS#XFTIJII7UrwF~Ub12+cGYmbJ{d3xe05!UjQrzDX)wPmc4s)2nXy9{|z%10Vx4 zC8b{uckt2Z_3Yj~fN28{Ua8mHN6D;l#IyLMZK@0%4u`|xa5x-Sd;rMHjFX{t RU-fF&&Q<#kb{-`l;4UM z;w`u1u2OIBBRL@Hwc1<9C^2&fl$LU#RXf_})7qFz2kuSLpJBWcK>Lm-R9Q#_@QY=+`JrpJXAud>*n@8eWCS(a`fLcCrPP#6Fysl%0VJ8;na|< zvJLmyr6tPU?m3qDt_Iims7$T;q8FntNoFu8c*ywYRX?7w_X9$c!L@6jp!4TV@|l4! zv-o^qWAcCfx!bR`K;tfN%NxzOt;fYb#67|G+!o#9^1^!yu*9-vL=J zx?0v1?rN2h3h|EIqRYLWgSCtbCV;qggbsor2!bH^8h!yYgpSE8gX4Dq0000FWJoY_HG3vD3$;rGp7Kpa{xBji+P_H%f3P+r)jaK^OUcEKLB}SskbNlsq6$ zal74A(qiADL6%46TbF%}nGsO8)DIen=r)_)&Ny{gC;n^XB#%{-Ehj8?2RIYJZoEPC@k~Eid6D=I$~#?>m!A z%Ifg!t0#bZ(ich}m0P>E8-7zef?q&UW- z^9Bgzc+T+*aCx#W_JP755QB5E`tBk7kdTE)(%?y7EojZJq^i9XWVPCPpMFs z%s6(#RsR%rtha}u19RV9lc%{-T?C7)M5?7Ur`x1D)F8FLJ?u?m>bOyxX^pW(_77X6 za@O zEL`NFmS;OGg}W&`baP7qP}i~W-T^Fi!umm1e05!4q7R6EL#l}ASh!9=e-|Kz(78#IoGAjA~d;_;-k69GHG zBS+}q02LyivDjldvM&J>;E^NraX=q9L@mBAOVZH|=Fal%xOv002ovPDHLkV1f;c+XVms literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_message_1_1/00003.png b/tests/snapshots/nanos/test_sign_message_1_1/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..f5c2d6774a86d59f5cad0974eb03748765433d08 GIT binary patch literal 407 zcmV;I0cie-P)H|@ zz8wshkB{~MB4`H0-uM*3M1j}m%A!300N{kCpu~9KJs1LQ1E{7`qHO>OJQ#XfRy9Bv z^==(ieYk597RD@{OEdS6GT+Lmuf_h$vek1^KVM4p7nbmHWt7bot=9>X{;(33tDmYc z&D9U$Wf)T#sV`+WTVz^Qo=ISYs`0?ozXTD=g%{*$&h`n6Q%*!K%L9vjA?<}S_3O~y z51_40w#ON-)XL64x@JligSXK^F9>U5TpZCDR;l1-dd45KJ?)^knt8<|^tT^?&`+$? zRq8>0Bcb3GkI=CJNF3=@I3K*Rlqo0JRixhcTL&d5MMji-{W*PXyu+hM-x=UTI}_BI zGx^;Gypw%}(Vkv=s~wl1InZ7QJjtlNRl_ihQog8p&yJp0VZ8tV002ovPDHLkV1iJ- Bw$=au literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_0/00000.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..cd4545e54ed1befa2ce759e3477a0524a508f7f1 GIT binary patch literal 370 zcmV-&0ge8NP)TBt?T(>7BpbpDHJFn0002+N>sMLt!FtdeGR+ngEFZD z(y|*~+8ZCEfOESayUShxjhwhn(T@$S9 z+4viO$GRaOf~cYP%EhuhCPo1LW5<*E{uq~XT$-PGCp5f}%xZjSEXg4hTsCJ6w~?>sz_4Xw%jtf@GaLuwh_Xin^n zGaIokLxQdN4APBgp9h4}?jh@y*_1_Z8(UF}{7YPLnO)!?cD15*Yn%BS!7@}Ce-6lw zZnRf!{v2?G__&+}RkY6oYPn1%$()@ZbhV<^!3f%MLlA!<$QW<{008)92lxrBqKLy;Ql8-o~lf-L08R^*~gUq6{O zfgJZ_dKS{oh=a4EoSJ9(n_J{P@vygNO}1N4H-TF~P!IX%l{Py?KCtpR6unM}v>OHQ3q7xSkdv`nr6 f0000006AF!M!CfxU6qFE00000NkvXXu0mjf#R-Zl literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_0/00002.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..2a3a9cfe70b8fa9ff273b1c05338f9887ee523b8 GIT binary patch literal 506 zcmV9lJ{&m&gP#OoPBfPc}ITlFjnU>Y1FR(&Ziyz zT)hJT+}CH`9jC!y@D8r2f$XqY7TDs6DO-@?Br2%MJ5R1Lj4?QueVDNV0N^-3A3y)k z8h0Fk613Mht@s7b}Z994;XHqal!IcPOK(&6lqZ1T_d8{LC4XQSe9OZMTH3LyF1 zmHi(CL3OY{8Bv3kh+SwU%+BHJy}wm`E5t}_>Bv^@&c)?IRJ~PUImP7ybhFl^L~2|q z!*Lc_NgalG5#z3x`EJ6gkH!5(-%*(i*%A8`+O$T;jqw-@iVF66pjRS`eM9iWbtE5= zTaaEfRgR)b-Rs~4J9)rCiXgB4eRq0t3fpP}PYq+m+X5dk4lh8BKsHBsNmHIwRad}G z4aJO)zYj2}kfAP{Ml_a{ry82~qK+ds0iS7{D}5ABKqXyuyX=CVVaAY+B`4IpB%X(aS{8t+bq4qHC z1Hh6?F9bMJ*|~})5rgj~%n9YlIq7%cC11Y(a6eSIHadi_)IL1P021e0wf{g6sxIx{ zjIzN@R2G_v^!ISvdPJ4ILxiu~HSH(wG7YW#=@7cUBUDNfcSjRB5XVNY+M#Ymv^5J? z`v}DgIZu{9!hZQ|+&Q@=vL18;St7WIlih*bX6i%=4kbr`Ub;pE;&%*5eg?zMI6>0Y zovpsWh0*@sTa{@wduD%k3>%=USw|OI?!%balyptTzVgC@<+dij|pv z$}5qZQs=``2S85|8O{}``fOWktXVLMz&?mgb+dqA*R_k+c)nb#&~!a@IBbn z2d)x8w7;ybbqqrlK&!*h+BdQQ0$B#k_Khrns5nX|w{K>PcLC#+U5M7cRh|I+vqYww z%l?U8eESi?BmbLb*`)WwNJX{m{~2ZAiMo&{*V%^|kzR2I@A>j0z(x_}jNunQffVr5 zyMR7YW#QF#bR{fi0Ry~6Bh7+ZL!MIB@k+cdFRGt)1*`>`*|Jv5rW~vsw-=<&6Txdi zGn!!j*Zsge0qJBvo%@$gdseDI#sjkl^tAQB%qE0000|)v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_1/00000.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..50d6e47abce1fc3745b9d6d63add67123a0ebc08 GIT binary patch literal 362 zcmV-w0hRuVP)Ky%N^A_N=A(>VYD09NtZAK=`vf1mx+}P2UrIOpv=2h zKxYo)tfwv=2f*EEoDo(Mq9O^5mO^D~7L-(w8LhR$%)KuL5Jf}pMMzrQ2&ta(KLIDw z53(Q)2H1gg&2jx}7-j)dAqp~F<8VhWNK*GIp;)E<7{6)oInAEu$3`=sjjDD-GkwaM z-lt=gM}AIB*g}#ciTXpNwk03D)zmDuOK(Yj(r&tYK@U;?pOY7P9VV^={8qO8Fo(E{ zr98&O2T;$L`d)_#T#(d5t+EC2ui literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_1/00001.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_pkh_1to1_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..7ba086f8f1e63e98bc4b1a2cb9c5b2c39fdf45f6 GIT binary patch literal 320 zcmV-G0l)rx`GR1H#13c?>2g zL+ebk>`&PDdYPUt@OOS;uDMhZz&>`I;JHNc|X4(Gss`_L- ztZxmmj4fwXn{%S(|LyC|oad+MP~Rv?COxd)3A;x(0LT70a?7*PoraS1m*;)w0|T+# z?H~m?mp;h;IUNMRIl^^|j~f|{k#}B z4)Di%0(GQh%XXzDG$sKK-Q2JkKR-`QsiPFD-4d_!i{fwH;J|_aEL%ZYNu#B0FJ7G| z;=_VQWOA9;dQ4Y9)LpKCV=ri`X({49JagUwO3&5UdSK)wEJxPN%9wG}45n;lzK(aC zKtbL$y*-#9uSql`7 zENOEh^0jsFWbV&<+yj5)WEX_aERLO-`${sQhD#B5ZCio#Fr4qHlr^7X|9DL69eFa= z#kf#}$Pcl(QEE=tNl8Pt$o;~Fk*8r@j8mpwSGW8d!1&11FbzPh@^gWj=oh7f%f7G)4s^6#xJL07*qo IM6N<$g02I(Gynhq literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00000.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..cd4545e54ed1befa2ce759e3477a0524a508f7f1 GIT binary patch literal 370 zcmV-&0ge8NP)TBt?T(>7BpbpDHJFn0002+N>sMLt!FtdeGR+ngEFZD z(y|*~+8ZCEfOESayUShxjhwhn(T@$S9 z+4viO$GRaOf~cYP%EhuhCPo1LW5<*E{uq~XT$-PGCp5f}%xZjSEXg4hTsCJ6w~?>sz_4Xw%jtf@GaLuwh_Xin^n zGaIokLxQdN4APBgp9h4}?jh@y*_1_Z8(UF}{7YPLnO)!?cD15*Yn%BS!7@}Ce-6lw zZnRf!{v2?G__&+}RkY6oYPn1%$()@ZbhV<^!3f%MLlA!<$QW<{008)92lxr%zV6W7K1RsetR2m zPU)kx{2tT750nzQW_sut?0kN9EZgm+DZZZl00002+x9o+>xj4xni?{#)002ovPDHLkV1l1jnhF2_ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00002.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..67cc27f5cc81b2c10c3e506e1c026250eba8a97b GIT binary patch literal 473 zcmV;~0Ve*5P)W+)WWy8o*h?%|~-HD4xALU`h15mmFvIR}3fL92|G#b%9WgWl|_Sg%_yKN$}{Z z9RT3I-f?%F4F;n+D7Oo5p5r*%*qO|bC8*(eqBX>?JbsP=`E+giX8?S{s-IJ$m>nC! zm2}PkoZwDE`bc$L*dToq_MNKc;m0Q=)9=Ji2E~JF?hQrZmfnYzCP31;tM?a#aJ6}V zFg6D>u~ld$<@>NuP1|zjWLJdc5TS-zTi8%*vvQ^Lr^zbchVmS5hzGIIx!g&IJK%Vt z@_@S_Pe6hsY#*w^y+jf$Bvo;0BMtr}hz;hbJ<1hiR$~1!{Q`fgyGxp0}B#D P00000NkvXXu0mjfxUAOP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00003.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..54a169e0b44738a8ed9026979e566d298840b542 GIT binary patch literal 515 zcmV+e0{s1nP)9! z+p%igMlsKL>nZ$D0jF|->$4UXP`h2SQ z7esJ%dVew*gFDGp=uT$r!(v)d%S2Y&in>=KoRlH044j(OG^E7>;&*w%AQsk|fClegGpNmG$>K{gMCx002ovPDHLk FV1g9C>Tdu5 literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00004.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..34ac2789dabe22dae9d5e568dc5f92fa9765031c GIT binary patch literal 370 zcmV-&0ge8NP)2t{$#-2cE?q?^=I!2=%fkp8DEQi!nqv588E00000TduRrm3Y2o^y|E@-~-az zcN)|1%S(7Q#>NT6ED5iD0^ZgGL{aMQE$%4(32x*G2;Ns1S;90)l_iJ`p^4d#muYk& zqU*f(qdPh*CM!^O2zUI<#7{5iwP#2P>bM?OTYTm5IVPd$+Ss1}`fe*bQP`dxyM-HZ zw&CSw^cE(W_c9}kQ1=p+gKB~Y=WotFd#8ZvMRivr6Y!Dh(@F_Q#eAyz3lfkT>JJ7v zmC%FZ9aR}I03$YxwDjYtdRgou&>$W>+$|o3jhEB0N??900YPZ7yJLl QyZ`_I07*qoM6N<$g8lHM!2kdN literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00005.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..1e284f082ac82ce25a1a8f68870b8152aa91a8ec GIT binary patch literal 324 zcmV-K0lWT*P)ktXVLMz&?mgb+dqA*R_k+c)nb#&~!a@IBbn z2d)x8w7;ybbqqrlK&!*h+BdQQ0$B#k_Khrns5nX|w{K>PcLC#+U5M7cRh|I+vqYww z%l?U8eESi?BmbLb*`)WwNJX{m{~2ZAiMo&{*V%^|kzR2I@A>j0z(x_}jNunQffVr5 zyMR7YW#QF#bR{fi0Ry~6Bh7+ZL!MIB@k+cdFRGt)1*`>`*|Jv5rW~vsw-=<&6Txdi zGn!!j*Zsge0qJBvo%@$gdseDI#sjkl^tAQB%qE0000|)v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00000.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..50d6e47abce1fc3745b9d6d63add67123a0ebc08 GIT binary patch literal 362 zcmV-w0hRuVP)Ky%N^A_N=A(>VYD09NtZAK=`vf1mx+}P2UrIOpv=2h zKxYo)tfwv=2f*EEoDo(Mq9O^5mO^D~7L-(w8LhR$%)KuL5Jf}pMMzrQ2&ta(KLIDw z53(Q)2H1gg&2jx}7-j)dAqp~F<8VhWNK*GIp;)E<7{6)oInAEu$3`=sjjDD-GkwaM z-lt=gM}AIB*g}#ciTXpNwk03D)zmDuOK(Yj(r&tYK@U;?pOY7P9VV^={8qO8Fo(E{ zr98&O2T;$L`d)_#T#(d5t+EC2ui literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00001.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..8c60935064b07220419a4b51b6363a585c0f8055 GIT binary patch literal 334 zcmV-U0kQsxP)oUP%c-R`?5`6P^KSrRBmmi)28qCJAuyowS1Rzko)q8^3kN!`gt!#KXA{7AZsd zPO|MG>^okT=ZCydUxA{?P+tu}YN)Rad|(N7Axq98vods~dlbi(^(IzqYfD9^Xc&KV z$x5ZnEm_inMsrTo9Pe5yz4CBOfcGaM!iACM23Ej1d1Bki# zzVE~hDIiE>j~f|{k#}B z4)Di%0(GQh%XXzDG$sKK-Q2JkKR-`QsiPFD-4d_!i{fwH;J|_aEL%ZYNu#B0FJ7G| z;=_VQWOA9;dQ4Y9)LpKCV=ri`X({49JagUwO3&5UdSK)wEJxPN%9wG}45n;lzK(aC zKtbL$y*-#9uSql`7 zENOEh^0jsFWbV&<+yj5)WEX_aERLO-`${sQhD#B5ZCio#Fr4qHlr^7X|9DL69eFa= z#kf#}$Pcl(QEE=tNl8Pt$o;~Fk*8r@j8mpwSGW8d!1&11FbzPh@^gWj=oh7f%f7G)4s^6#xJL07*qo IM6N<$g02I(Gynhq literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_0_0/00000.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..cd4545e54ed1befa2ce759e3477a0524a508f7f1 GIT binary patch literal 370 zcmV-&0ge8NP)TBt?T(>7BpbpDHJFn0002+N>sMLt!FtdeGR+ngEFZD z(y|*~+8ZCEfOESayUShxjhwhn(T@$S9 z+4viO$GRaOf~cYP%EhuhCPo1LW5<*E{uq~XT$-PGCp5f}%xZjSEXg4hTsCJ6w~?>sz_4Xw%jtf@GaLuwh_Xin^n zGaIokLxQdN4APBgp9h4}?jh@y*_1_Z8(UF}{7YPLnO)!?cD15*Yn%BS!7@}Ce-6lw zZnRf!{v2?G__&+}RkY6oYPn1%$()@ZbhV<^!3f%MLlA!<$QW<{008)92lxr1c->OR=(165GDmB)BPZf0W!1a zAbv79)u;+UX=Fp?pfszE z%AANe-%&eKU&KnUmothdnJwO)78@GaqLYfZB_En$R%h)u;W#s0KxRYKi@RbjNwg&z z)sfn&-4@&jYRxc=p|2Fdd6nc1kG0a^!*q?}4o1=?n@E=PvD#4|s=feJnG_E(Qv!s% zEkmnPq0M;!-PO<`RsJ4;>MKRSSMk#S0l@9_^dckqMUAK|G9zgY)?7j7H%IO5y&Oya jka3jZ0dP1Rj{l1fuT69qz%l=w00000NkvXXu0mjfvI*pD literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_0_0/00003.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..9f3ae167e403ba80cf7a815b469b9c724f522fbf GIT binary patch literal 499 zcmV_)fK~!(;}_sJx&sxX-b=}{cK=Ndqy<#(2MXDO*^S9)0a|lEenO=a z5$)TtAD7i(GSY)v)<7E)yVpu0xy1!JZX%|d;(5v%Q%i$aY6FP303uq}?Mw_N_oPlV00%O9U zc@GLf+8HzlBeW+?d!}i76PEdOoGi2Tt#)z##d3B%zdyFo{PER9tx zSN>vf>ewPg^Dw>IcTu;*riX{V2S~*gZwtI9Yx^L6uKbo{oD0Tu9y9!=C#;^I?CiCl zvHf^hz}eP}{zq~SkU;aM{4h-g(Z2v)uAmym*@a-IktXVLMz&?mgb+dqA*R_k+c)nb#&~!a@IBbn z2d)x8w7;ybbqqrlK&!*h+BdQQ0$B#k_Khrns5nX|w{K>PcLC#+U5M7cRh|I+vqYww z%l?U8eESi?BmbLb*`)WwNJX{m{~2ZAiMo&{*V%^|kzR2I@A>j0z(x_}jNunQffVr5 zyMR7YW#QF#bR{fi0Ry~6Bh7+ZL!MIB@k+cdFRGt)1*`>`*|Jv5rW~vsw-=<&6Txdi zGn!!j*Zsge0qJBvo%@$gdseDI#sjkl^tAQB%qE0000|)v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_1_0/00000.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_1_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..50d6e47abce1fc3745b9d6d63add67123a0ebc08 GIT binary patch literal 362 zcmV-w0hRuVP)Ky%N^A_N=A(>VYD09NtZAK=`vf1mx+}P2UrIOpv=2h zKxYo)tfwv=2f*EEoDo(Mq9O^5mO^D~7L-(w8LhR$%)KuL5Jf}pMMzrQ2&ta(KLIDw z53(Q)2H1gg&2jx}7-j)dAqp~F<8VhWNK*GIp;)E<7{6)oInAEu$3`=sjjDD-GkwaM z-lt=gM}AIB*g}#ciTXpNwk03D)zmDuOK(Yj(r&tYK@U;?pOY7P9VV^={8qO8Fo(E{ zr98&O2T;$L`d)_#T#(d5t+EC2ui literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_1_0/00001.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_1_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..8bcd6e61d204f185a73e2ad53562f97cef589393 GIT binary patch literal 340 zcmV-a0jvIrP)UTWgoFS90N|}`)(%u~9@)=rH}d1PkN`Z3 zueAfc#Hhp#K`i_Q&&pKw#>d(LWww3s7&y6x z@{{DTMR@IeanB!lq5cGlB18RY2vS4+$sh)n;1seX7nxl{Tf0YbRC(RFimhzvqA5DV zm-H;@62J16UM`{4oD((gcd8d7ou)xh$Ajq7d1Ur+N5#`S;U-GCsX0?p8^(#9sj~f|{k#}B z4)Di%0(GQh%XXzDG$sKK-Q2JkKR-`QsiPFD-4d_!i{fwH;J|_aEL%ZYNu#B0FJ7G| z;=_VQWOA9;dQ4Y9)LpKCV=ri`X({49JagUwO3&5UdSK)wEJxPN%9wG}45n;lzK(aC zKtbL$y*-#9uSql`7 zENOEh^0jsFWbV&<+yj5)WEX_aERLO-`${sQhD#B5ZCio#Fr4qHlr^7X|9DL69eFa= z#kf#}$Pcl(QEE=tNl8Pt$o;~Fk*8r@j8mpwSGW8d!1&11FbzPh@^gWj=oh7f%f7G)4s^6#xJL07*qo IM6N<$g02I(Gynhq literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00000.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..cd4545e54ed1befa2ce759e3477a0524a508f7f1 GIT binary patch literal 370 zcmV-&0ge8NP)TBt?T(>7BpbpDHJFn0002+N>sMLt!FtdeGR+ngEFZD z(y|*~+8ZCEfOESayUShxjhwhn(T@$S9 z+4viO$GRaOf~cYP%EhuhCPo1LW5<*E{uq~XT$-PGCp5f}%xZjSEXg4hTsCJ6w~?>sz_4Xw%jtf@GaLuwh_Xin^n zGaIokLxQdN4APBgp9h4}?jh@y*_1_Z8(UF}{7YPLnO)!?cD15*Yn%BS!7@}Ce-6lw zZnRf!{v2?G__&+}RkY6oYPn1%$()@ZbhV<^!3f%MLlA!<$QW<{008)92lxr1c->OR=(165GDmB)BPZf0W!1a zAbv79)u;+UX=Fp?pfszE z%AANe-%&eKU&KnUmothdnJwO)78@GaqLYfZB_En$R%h)u;W#s0KxRYKi@RbjNwg&z z)sfn&-4@&jYRxc=p|2Fdd6nc1kG0a^!*q?}4o1=?n@E=PvD#4|s=feJnG_E(Qv!s% zEkmnPq0M;!-PO<`RsJ4;>MKRSSMk#S0l@9_^dckqMUAK|G9zgY)?7j7H%IO5y&Oya jka3jZ0dP1Rj{l1fuT69qz%l=w00000NkvXXu0mjfvI*pD literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00003.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..9f3ae167e403ba80cf7a815b469b9c724f522fbf GIT binary patch literal 499 zcmV_)fK~!(;}_sJx&sxX-b=}{cK=Ndqy<#(2MXDO*^S9)0a|lEenO=a z5$)TtAD7i(GSY)v)<7E)yVpu0xy1!JZX%|d;(5v%Q%i$aY6FP303uq}?Mw_N_oPlV00%O9U zc@GLf+8HzlBeW+?d!}i76PEdOoGi2Tt#)z##d3B%zdyFo{PER9tx zSN>vf>ewPg^Dw>IcTu;*riX{V2S~*gZwtI9Yx^L6uKbo{oD0Tu9y9!=C#;^I?CiCl zvHf^hz}eP}{zq~SkU;aM{4h-g(Z2v)uAmym*@a-IktXVLMz&?mgb+dqA*R_k+c)nb#&~!a@IBbn z2d)x8w7;ybbqqrlK&!*h+BdQQ0$B#k_Khrns5nX|w{K>PcLC#+U5M7cRh|I+vqYww z%l?U8eESi?BmbLb*`)WwNJX{m{~2ZAiMo&{*V%^|kzR2I@A>j0z(x_}jNunQffVr5 zyMR7YW#QF#bR{fi0Ry~6Bh7+ZL!MIB@k+cdFRGt)1*`>`*|Jv5rW~vsw-=<&6Txdi zGn!!j*Zsge0qJBvo%@$gdseDI#sjkl^tAQB%qE0000|)v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00000.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..50d6e47abce1fc3745b9d6d63add67123a0ebc08 GIT binary patch literal 362 zcmV-w0hRuVP)Ky%N^A_N=A(>VYD09NtZAK=`vf1mx+}P2UrIOpv=2h zKxYo)tfwv=2f*EEoDo(Mq9O^5mO^D~7L-(w8LhR$%)KuL5Jf}pMMzrQ2&ta(KLIDw z53(Q)2H1gg&2jx}7-j)dAqp~F<8VhWNK*GIp;)E<7{6)oInAEu$3`=sjjDD-GkwaM z-lt=gM}AIB*g}#ciTXpNwk03D)zmDuOK(Yj(r&tYK@U;?pOY7P9VV^={8qO8Fo(E{ zr98&O2T;$L`d)_#T#(d5t+EC2ui literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00001.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..8bcd6e61d204f185a73e2ad53562f97cef589393 GIT binary patch literal 340 zcmV-a0jvIrP)UTWgoFS90N|}`)(%u~9@)=rH}d1PkN`Z3 zueAfc#Hhp#K`i_Q&&pKw#>d(LWww3s7&y6x z@{{DTMR@IeanB!lq5cGlB18RY2vS4+$sh)n;1seX7nxl{Tf0YbRC(RFimhzvqA5DV zm-H;@62J16UM`{4oD((gcd8d7ou)xh$Ajq7d1Ur+N5#`S;U-GCsX0?p8^(#9sj~f|{k#}B z4)Di%0(GQh%XXzDG$sKK-Q2JkKR-`QsiPFD-4d_!i{fwH;J|_aEL%ZYNu#B0FJ7G| z;=_VQWOA9;dQ4Y9)LpKCV=ri`X({49JagUwO3&5UdSK)wEJxPN%9wG}45n;lzK(aC zKtbL$y*-#9uSql`7 zENOEh^0jsFWbV&<+yj5)WEX_aERLO-`${sQhD#B5ZCio#Fr4qHlr^7X|9DL69eFa= z#kf#}$Pcl(QEE=tNl8Pt$o;~Fk*8r@j8mpwSGW8d!1&11FbzPh@^gWj=oh7f%f7G)4s^6#xJL07*qo IM6N<$g02I(Gynhq literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00000.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..a63982497a50522fb324ee699f3bab9c6e6ec3b8 GIT binary patch literal 384 zcmV-`0e}99P)U=!o2}_X^@Bil+;5WmPXaZt)o7|6mz< zWVrj=GeB~6lf=#NMo literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00001.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..6c697ed854bb624735dc48e9923c0dc4b469ca9e GIT binary patch literal 327 zcmV-N0l5B&P)VSQ-kD4?!c1QPCfvTCfoSHVgI0002Q^L|CopfacWZXTpD`x!lf zK3t=1|2}TJ?7(YuS&Tzhvs?e_=pA5|b>aWYP#)0}AR@L}`AV-rnh;b>_eL56bY!nV z0t0yFq)!x@=0-Cu(;fekCgEZW(3^?8P~U;B$WY%6Lu#n+3_OSgQ7DqD$eYo;^kgPH z9$(k=YREc14vv+&Nz|Ap+7+yp_g93Pdgt}_;Jqn_5C+Zwvqc002ovPDHLkV1jERj+Foa literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00002.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..cf122072779d8507c6610702b59cf151b621edec GIT binary patch literal 487 zcmVKWKMzK@+~PZ# zhTl->008F!KY!6`49rArTszgz%EA6I20peF8x7sI^xDaYHwhOviZZ=Ljn@|%iJ3;7 zY893TmNrS-%u;5nEzZyOrCzk!>+f)hl#{78*9ms3oA8tTOXIdiqw?5tXigccChA>GvKtO>P>Y464^ST!lx zg}1NtR;N%{Rg0rD?{cjAAAs>Fob1_%bF2giDRdv3e#jIo#=Trz>q&!v3^_skFUfg^ z{w357^L1Vfh7}-h!Yy*K)3S+;3b#YvwQrT|*N3XnewJm}(19X_KOqIZnys6#3%fsK dk|ar<%NH)2eU_1180Y{1002ovPDHLkV1hA{+sOa` literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00003.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..a0201ce2a0f95f2f3d261628dcbe7a7ced9704fa GIT binary patch literal 477 zcmV<30V4j1P)_UGgE>rRJD z)(W$MYXPlgL>hoCVQT{o@asBy6Q$lu$?ZP;Xcp{t|NLE#sXc)GZzv>c(mT_TFs(rr z@#8l%z4Uo{UJ>3f!ipx937^<>IDD*rdQ>UuMVU);c zLk;UkH;oh#iw$APHkpKFiQ zN>#a4@kjVniRd!TCe$CqWYi$U2IeGAXTuIeEM?hs;c3v5MS6Q;m4g=yKz6NmC{;dS z1{~KfFp{E*kpH+!SXKcUfCMra>~U8h?%ps85-&-KviZSAN=ipGvDF-a*AvsZC1sHa z#)dTSxav0Xne;`hfa!KT5!dmy4r^GziZ5yoz_*Fz^)shaa$l&nIgw4Ll!aLYLSbrM y_%DQ?J{tnc8-J2?XjpFzcm{gaI)}sIu*3(7+LgztX+>uM0000=H2taA4-v7WZ>>^WY2_YXLVJvUasfr=trxJi52!bH6;@JBx3G!On^ON!!-6{R@ zv>O@#;Mn1@nJ%Ck*4B@$B4fsDnx-$kQJJjMbttH=286?)87D2Hl+O5n;3P3ni&I*h}I;z$V#@zXk+XET!2vur`$p< zh#4%lOL9_N0FXE{L{UvVR lf>bz%IjLPySb`u3GTtY}E=pTg41WLs002ovPDHLkV1l&7$*uqZ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00006.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_0/00006.png new file mode 100644 index 0000000000000000000000000000000000000000..1e284f082ac82ce25a1a8f68870b8152aa91a8ec GIT binary patch literal 324 zcmV-K0lWT*P)ktXVLMz&?mgb+dqA*R_k+c)nb#&~!a@IBbn z2d)x8w7;ybbqqrlK&!*h+BdQQ0$B#k_Khrns5nX|w{K>PcLC#+U5M7cRh|I+vqYww z%l?U8eESi?BmbLb*`)WwNJX{m{~2ZAiMo&{*V%^|kzR2I@A>j0z(x_}jNunQffVr5 zyMR7YW#QF#bR{fi0Ry~6Bh7+ZL!MIB@k+cdFRGt)1*`>`*|Jv5rW~vsw-=<&6Txdi zGn!!j*Zsge0qJBvo%@$gdseDI#sjkl^tAQB%qE0000|)v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_1/00000.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..50d6e47abce1fc3745b9d6d63add67123a0ebc08 GIT binary patch literal 362 zcmV-w0hRuVP)Ky%N^A_N=A(>VYD09NtZAK=`vf1mx+}P2UrIOpv=2h zKxYo)tfwv=2f*EEoDo(Mq9O^5mO^D~7L-(w8LhR$%)KuL5Jf}pMMzrQ2&ta(KLIDw z53(Q)2H1gg&2jx}7-j)dAqp~F<8VhWNK*GIp;)E<7{6)oInAEu$3`=sjjDD-GkwaM z-lt=gM}AIB*g}#ciTXpNwk03D)zmDuOK(Yj(r&tYK@U;?pOY7P9VV^={8qO8Fo(E{ zr98&O2T;$L`d)_#T#(d5t+EC2ui literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_1/00001.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..82d0ff39557aa059acb5a7d10f3060bdb741535d GIT binary patch literal 333 zcmV-T0kZyyP)EBk~1Mh+F|Ql5%02NmjsJO%~wlJ2ZmuuRx;KiQgLIGunX0xYM`~CMiSZ zPO@wgwjD3i6Ok9{cfcz$)bEBOHPr76d@vI1LL+&KEXvS=?omCh4EL^TH|wi4ReR*4 zDkIX!!(Z|i6u1qWbEf9|W;JlClXVspy-*Fv`uhu3?}Wn`=+Rmp#;GgUz?|bSJK03& zc%#N#S~`H)ci;D?a09_I7P+TJJaylK>`UKwneLqf4A3zL}00000NkvXXu0mjf;kuD# literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_1/00002.png b/tests/snapshots/nanos/test_sign_psbt_singlesig_wpkh_2to2_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..1c9156c31edf73cb072eaebf2db3fbe1ba5c612b GIT binary patch literal 414 zcmV;P0b%}$P)j~f|{k#}B z4)Di%0(GQh%XXzDG$sKK-Q2JkKR-`QsiPFD-4d_!i{fwH;J|_aEL%ZYNu#B0FJ7G| z;=_VQWOA9;dQ4Y9)LpKCV=ri`X({49JagUwO3&5UdSK)wEJxPN%9wG}45n;lzK(aC zKtbL$y*-#9uSql`7 zENOEh^0jsFWbV&<+yj5)WEX_aERLO-`${sQhD#B5ZCio#Fr4qHlr^7X|9DL69eFa= z#kf#}$Pcl(QEE=tNl8Pt$o;~Fk*8r@j8mpwSGW8d!1&11FbzPh@^gWj=oh7f%f7G)4s^6#xJL07*qo IM6N<$g02I(Gynhq literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_m/44'/1'/0'_0_0/00000.png b/tests/snapshots/nanosp/test_get_public_key_m/44'/1'/0'_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..6ebf2582dda066ab28d4095a45b5b1a1a814312e GIT binary patch literal 500 zcmV#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000@8YPShSld0g(AHT7BV#D}ma`>I{;_j&rP-*Tuqt^l

kTU{x)#Y{tgqjqg%;ED%WhS{hbb3 zU(OdHv)gT-jeBr6aSzGP)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_m/44'/1'/0'_0_1/00000.png b/tests/snapshots/nanosp/test_get_public_key_m/44'/1'/0'_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..adbbfe3edf9ab1aa9381c4f94bb87b8cdc1a5f7a GIT binary patch literal 683 zcmV;c0#yBpP)3`I#QH{t$A@?ElU6-6|B#9-sJ|66rqA!Gp($SDy*2qA|*l{5Dpc)LAb_j6iSMW>1fecx7^Po zc7SkJaP5z2s6Fn@=$-7(0qKIInk!Pv>3eg}&Iu@QUWbA+rfcEIIt4P%j6W%*uZ?5l zm|*5fFP(ZT`uRzi5JCtc&b|g5?dnL2AG`y zof5T`krq#Ly`Z#TCRLd}z0TJrvlDQgq4+d%sj9I#5WRv**6e`f&xB6hSZ1CsRgqlk zojaQy&Eb|USue{GjBwN=zKFdFvE8R`!u+f;%$<3jNEohnLhtWHdq0!|>YGd5-rMM@ z6)j$ovRRwdM?-9RX$SW*zMBuWy&8CGG@xdS{3$9J^;Gvr^ES-5JCtcgb+dqA%qY@2qAFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000VvAL$Qu(t4d^7YRwj} zU`yOuxCWo*mIu;6izlGSI`Ry|&z7BeDlZ0Af%Z8#7_IuRJ?@Y#X#5pmN%y6G+A5#s zz1WGm@*K?Cg0{W|Qd`cm`Nti<1vTWoc)fQ9Z61cR0TYlO3FKax%G=hF?7>pLbRm;eC48fwoZ>eE7goPR7kt#jPU%|bU}OZHW{{LFW?&R*jG?Lk>( z0%}Rj%PlXxZ7;@8eG~3y&;I)?F#!!MbMuJ#yMF@GF9Gr=frIjwnfN){NG?*jW^3gy zckeP)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_m/44'/1'/10'_0_1/00000.png b/tests/snapshots/nanosp/test_get_public_key_m/44'/1'/10'_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..4d77a5f3faf093264e4e06ab55ed875ae948c923 GIT binary patch literal 689 zcmV;i0#5yjP)|M%2-j6qO93=seT00000?_}GyZQJ5MIsI?P z?`#36s`4>9-Nk3N04AzE)ZI`@`L>r*Sf6;yEGF*&rckyUm}=BUHc0KGDw;hjTdrq` z9l(?oT>E1qv>LZ8dL{E?0G$w2O9Sk7U;U3QMFQ>V|G{)dQuCcfME z32L0Q!l|{Q*AKz~00000@8qI1)XFd8jcTGlX6#uwk`4x((Kfo zQn#}lFs|7|RJGJb$33>3QVkv3r>YXARjdkxCCPw2oWPK7-BS#ZD5V;r>Ay3y$kILy z%_z7;jv9d7Mx8|5k5w-AMN$dDx99Hw7O3M71|63=c(AdXkI5t=Ci@OKZ<)xhkCUqU z|1NPO_9|HPnt37f44m%=zNkJ2zGx=z`~qqfp#7Oh?RR2;lipdmopTSK;`RL6C%L(! zbwB+i~i#+Y*$$K3=ozT1AdymF*(0Q&AU3dg-Na0H@lVHPsY?@3q!S zu-v3hzuVd2#FOxvXN^+IHBtqq|I$)~TFs7>xYOylAl0!tF<^l7?C8h>FXGOXjVY(k z%oYia000000N}1SV#&2eFwEWWH(q)Y207e)`4e^k80P`YpRfa_0|Nj600000@IL+k XsQGqe(aN%h00000NkvXXu0mjfa|%iO literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_m/44'/1'/10'_0_1/00001.png b/tests/snapshots/nanosp/test_get_public_key_m/44'/1'/10'_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..53ae65195fbea5b281a1bc1a80351dbf1cd79ff8 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-%ba4!+nDh2#AYZeBfa}G~ z%X2sUSKTFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000GGQ1YY$0Aw=AJK?8id8e#329x007(lj8sl3m4C(rIqPOC|_PA5Fp!qAnlJ2f{d^g|b zU2R0HybV@uL1Aoyw5IcF`{T~vf*g5Q*ZW{lcQ-bhFaY^TQ0|qv+&7QP7A)mqU=-E2 zu01aNo{-Qbry$rd004k3T1O7?<)FTAW7dnae@JXZ>00000000000000000013<{#8}-5GuO RPXPb`002ovPDHLkV1n|P-ERN@ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_m/44'/1'/2'/1/42_0_0/00002.png b/tests/snapshots/nanosp/test_get_public_key_m/44'/1'/2'/1/42_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..2b51f30cfe212df5691953efe741325df2f02f56 GIT binary patch literal 488 zcmVP)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_m/44'/1'/2'/1/42_0_1/00000.png b/tests/snapshots/nanosp/test_get_public_key_m/44'/1'/2'/1/42_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..9f852fe5188e19490cb6ca4b7e759cd54a1558a9 GIT binary patch literal 712 zcmV;(0yq7MP)o|abf6?5W@1fJ{C1_AFoU|bT000000Ps#yN+~7(SBm}P z_})E$kVE+~F>T^!_W-Jh^C9kr7~|C*Vlt_3i{r&XXgauJ1*W z^_(D{leOctwxZ8JgaH5m006*RJk?ezFl`hA@uR1}_7r7`aO*d|n^wuQ=_YlX=@Za| z>Co1KNX=4~ue^iHz$|OITk=)Sd6OT-Shv(~fqa`CitQ8NTBGxq4m0s1xvG|eYAfA2 zFtMHg?Cz+>eQKyb`6w$c_=L{~F<}BcqONmqDk;l!{?M72Fab-&tiCB3r_AXjzt3gb z4hZTpcbj6aGjd`XqNZb0Swi!=1_CZIa86cq8^I$o?38 zA@iy?8~#MO(>FcfzA@p8=jM?-6Yj|N7rrX^5yq4vxQ8Z*M(nrA#u*K}5Yv?z{WRBWG*MIZ4BFY(bPuVJ zX=gpdG*`l9U2aC73uop`cuM73@2#n?yo!%jthxzGW$qlzS~Ya!#P3+q`e8sM9WLSV z!k)~H7;Y{+H0_eL6ELz*TQyGQww+G4R7SQG!AF11`8~B9d9EN!*qMdmKZAq0x>K~a z4vZa;W1T)-bS&E^(Nvo0 ue#V^u000000000000000000004(AsZMcQP}X3Pcv0000FSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000HnV66l}Jnln?*_004KNmC7k4`7y>gT6d_5 zQIHqqZL}lLfxPy~=&8uNu^GQxqSR#ju9cEfiZSN3Q(wr6`F;_hS*EC4+>xP*HQRiG zHF_9=5kv)w6Le=wpznQd1bj`s{Ym0C7dAGcR_CEod;U0=JSNL(< zn?Z^v&w1H_FFadc>Am5ew{@gl}5j6M1!Ynp_ zb@h2M?;8fxWETWICIA3ntk`VSXIu5Prp)8FL(!U>qI^cOva3F<*ZIeb`&y&%N88ZL zb<@)c=DQ%xnT+OtY%fS1e7U>TB54gHfpF3*0ryqj#Xg;%R zI05qKD;T^zt>f3}Eat=MINGB1*746UT1WTW&|Y3m8GXseGO|@h`=5s(uiWImO?QwP zeK(DvX7rsg2Pg3sI*H%mlNeqA000000000000000006+uA155vDx5CVkN^Mx07*qo IM6N<$f~*$ZhyVZp literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00002.png b/tests/snapshots/nanosp/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..2b51f30cfe212df5691953efe741325df2f02f56 GIT binary patch literal 488 zcmVP)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00000.png b/tests/snapshots/nanosp/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..7ff89fe67ebae7c5feed15f3d273201d88a44593 GIT binary patch literal 704 zcmV;x0zdtUP)k`f_=5JCtc-$~9n=ZwD!$^?`zuS>yM)3q=%PXn1f>rYDQXQA!5 zCYbxAx1D-3djCzB5JCtcgbd*|71GsvmKc>^XcM^t(P=i6%%7&_;7jW#xL4CKI|0|s zmv0EHbiFd)dg;Uky2MPPUXZx0)E8H6;JjFhYf&A?;7%m2QQ#fbyEB_sJej(Ax1=@H zXvXOdK{JA4xPB{i)-r*rCSt7F+Yrr<5p$qR!WqpL-B6stkeO?@X|W#bsm-syC5o8Y zKG6&%Ko^|xi5!~?>dBx*&-uG6(oh0sIfvBWyUWEYCai#@YJFT@kwrZ|Pz#%B_QYZn zdLz`MOmC-6qvlx{95~U3o2*Pn__oDAVqZmlpih@ekkImQb>4Y`BRp^dCK2yGf!-TN zeQ4?2J2X2AAg+@TYFG2JFJKfyGOyWwfL1+VjmyWXWa7K^Rd&&>>(PXfuN#pXaw z;~0u3R-B8>;X+kYGx8-594B;qL5oN(8|`SYqZEMjQ-iTN>@NkehzH_ib-$gP@9v9O znd#aUa}mVo$#t^H8F|o?Ga#{&mF;LfL%Y7V%!BfCdfLQ|=?;sN6L4V>#Mi>0QR-EO zuFhbWd%d*?DT7f0yl8?UYf{7(b~1XmC0yrZZa?0_?BmH4-svw%uNHj;A2#m@A%qY@ m2qAFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000V~o9dyRvL5 z49JW*UX@^`QF&F2EK1E;a|O55 zTdQusV>su9+)(oc6q!c8VSEe4o9B45QdQAw3@%!$p0?M!WD8oq0$RGetDLdKxBYGw zqE?=RU0YC?n;^C6yqkZ$>$jkRemB?qWTnH+aJFCo@{vI9l{tQF9?23~;={x!n%}zZ z^=WkN$rrSVEuHH1|M>A%JGpC@Ii<*`n zx2s|f+ISaKGjL7jZ01s=*MR}3F_(PHXw9clPvsvN*Tv5B9ssrf=9eu0<@gca10d(r z=kG-a_+P%~aC!KvZAxp?n5W@Q{cuz4uPy&0s+~;lyD_?&-gm|roWw4465qoo(Y*iw n0000000000000000Khg+?VzO^2+iqh00000NkvXXu0mjf`ftxg literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_m/49'/1'/1'/1/3_0_0/00002.png b/tests/snapshots/nanosp/test_get_public_key_m/49'/1'/1'/1/3_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..2b51f30cfe212df5691953efe741325df2f02f56 GIT binary patch literal 488 zcmVP)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_m/49'/1'/1'/1/3_0_1/00000.png b/tests/snapshots/nanosp/test_get_public_key_m/49'/1'/1'/1/3_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..bcb6eaba9c09b069c77350ebd7f39ae9702b9bcb GIT binary patch literal 673 zcmV;S0$%-zP)Ty z-EBa*T=_LVP4U@nfQlFoaW~Xj&+=L;sS_{R#pWGA97=WragA6=I=SkIjwWq+$$B2K z1BkPNYrn6D*5g`4SF-;MC=(9V+E6^F?>&2V2H=``n+ndH&MQaOsZr;d`KOffvvF)Y zCy3{ycARP}`uT@200000z&n|84JA(-Q9MXp{z&~`bK@c_UR%XJ#j)B#(xE%|=|mou z*~ce&Dt9z@f4FV!4zMn-zTq?ac(Cv4 zaB^SIWBfba^cZ}10Hy-h?F8Q63B11(?)@9oQ0;A*y>D@0hby3(-aranT{9w-+Mn`^ z@^W7Mj3~scxXNhv6YMQs?&_(=Sg!UtGV7=sDz58PvcjuA<##ZTzq1g!w@okfy> z_MX%rvJ5wr^rNYAw#}rz7PFwu!I1N6LFxA%H8hw3T}4`y$xFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y?HO`vxM7Ol$FH$A~I^McdZUzUj8m2^UBD--ZHdN|38Y!la7y%p z0QeR22i>rpt}zq~^57XMZ0VcuJ}_A zd*mD%{F%vQXB)C_wZd?BaaPkHmu3F@0OzI+Udyvq0000alKB&*Da6!PFpZc7xeiPG zPT0u}7rOg-QUJ<4A$A=e761{ay16DxtD#>20Z8UyDaaOL!L_{7(MUnbAOHXW06-G| XY?FSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000Ar-C6KkUw$D9Bas*F%x^NfG ze_elE%zHvYm&}6T#|;1gtk+IC)I3$KADF#*+vC0C6~jTSCrp!Kv{@b}LT>a@*>)cv z*^YL&w-+nWgJwaVui4%gR=e_Z_S^Wb#r=hAK~lSPoPw5f)6}}#zcVO7y_(=}@su^Q zWg=F%2bG{XwRR7R_?5v|zgwG1&^oH71?KCX%C_!}>rF!sqkE3=A33O3sVPw5Gtq;g z{>Ys7*}6$4``Z|)Ci|Ol5AH-2x)cAycOtz2000000000000000006);KL>2jcgl{F Q2LJ#707*qoM6N<$f-N`P)c^nh literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_m/86'/1'/4'/1/12_0_0/00002.png b/tests/snapshots/nanosp/test_get_public_key_m/86'/1'/4'/1/12_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..2b51f30cfe212df5691953efe741325df2f02f56 GIT binary patch literal 488 zcmVP)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_get_public_key_m/86'/1'/4'/1/12_0_1/00000.png b/tests/snapshots/nanosp/test_get_public_key_m/86'/1'/4'/1/12_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..596276aa98c524ec030a587743c547a2db457a1e GIT binary patch literal 714 zcmV;*0yX`KP)DK0Ypu2XCD8xv z_}y(lIbHcNJ{{t3w*et;Jlt%kwI1!YR@EopvWv|bpd6~QLAl0lRD+y-Tt_Qe+wwdw zkpaqC$+*Yu! z6DmBjy3xhzz)CWg0qT+(zZ-z7)lfTky}oM<(Z|GAQ*%FFa|rJ_jf|?@5Fk4;755SY=0B@)uN}K*h#Yw4&&C|C@1h6G2Kvspj^V zQs+_Y-Z_YaaZ%R|0kEdn)y6hjR28p4S9V|I>e>ucsFlhtwo=@c$}>|7QsrD*qO#M| z7KqA76(tgp_k3J>?5yuPK{aNW$pGxQ%sSAu(k9JgPjAT(g5uSXx>avSZk({ ziGGT}9#n>nR!?sy8-OUbw*H5!kLqrt`&WCi6>)W~z`gN@i>!|lJvDwRFY*6?Z)WG~ w=@IxiN(do@5JCtcgb+dqA%qY@2zev^0hk^orB-ja6951J07*qoM6N<$f@z~!FSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=YLCyMefdy-1W~8P?HcY<=Z< zw%7s0S;n>R(@=U`is+N9uL0qPqIwmCmebePo|OT}cV4D~l+$Zr%Q{tL_RK#agntX? z)^h?|C#7;Kt?2!WFaQ7m008h43ltgYBN@mxd{{|#tnpyQ+S8o6zRl*1>r87!^gd0e z4jS9oaX*-sjX590s{FfT)rhqTF#zPKQl47L9X6flwzAiib@PrrV2^uELGhbkk<{d3 zx2H5j+TBEemDgqT7Q2H!`&od*`p^}X0 zt+5-ffX{JOnS3XR!FmvbmB9Nef%jKp^}f<_uw0jBl9~h-6ZM_}Yf{}OP;e|vwhz(l zj&x|R2hR$Cq|;)kF#x?f=LVo@XGT1TS&p)-O?6*LX;LWd}Bhe|XE%$3I zMhDL91=Xj=1X<%P5I$p4jFan}u&}v+s*?jIfCHsvT#Gf6$o1V9Hv>%Gc8$W+Zuj zD2D(5zQjp2pzA>pOy-%!!1EmZ7%DZzus?2rZNAsPAGcAC*#Tu={!MHAuy;e>FSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y5YKJ%(KU&1ONcAAJx@!`E?Y1^<~WN}zCyXs#X zo?o6k@9c|LZskJhD8km*o@uZbHa}-B?&(7HD5C%IYmwHRbJ)2) z`V`bZme<8JnX>F>hL3vOBL0b~>J+pM|9!ySI57nP0000WkROv_^0k3i)wKWs002ov JPDHLkV1lAe!YTj& literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_message_1_0/00001.png b/tests/snapshots/nanosp/test_sign_message_1_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..4ea64dab2914fd437ebb5d5ff135dd16925a83ba GIT binary patch literal 923 zcmV;M17!S(P)btwu-twuaN$>@Ad7!YlNF|;T5x{@SGk|arz?||+vp(a%QXQj=4Hxi&#l%j@f3#9_S zM3oCFs~X7Qau!>WEn$o*hS@uyj=Xy1ovgN`{BViOYwO@HWD_R1tPHNpYQ+EqSJ*p1 zrG^F*#9c9Gx^P=Ds$!^d0>P;}ppB?TFAbNS^jgwQ>JIfXx-I}#aCO;PNG#^S5@apV zDtP_DbSo9Fa47PUXk;N^Y6*J!t26r2mKRWBO_?s5+66C3h8+rmpZT&xF0*Ur&_=qf zff0H|&!z}@4lr3VbKM}$N%%0U?iU*TwO9K5NQU%66wJxtfGLZH^%hJMrzgcoBSopuxMbnGO|A4ex) z@~Ex@XR=S`fvGk&0P3Z>%U`YhobOlVXy~?>(IYRAG<2DnG3y0gA`$Aq44vs?gVZhS zZI&nXY`v=%3;=_*sUTs7q}$Tq`jdJj;XAt@033*sE1l8qbwVv6?McfGjV;8h^t5$c zg{>H*_Feb!OE8n1**}Jo>dgLOatz)iSD`m?lAL3(6`5ZDjTq@f0_zm-(5>AYurpof za#E)oN8JIF85l$L`MNIE53)}Ej8CK>Ch#@gt}OwvI998`VcUNx|53K+B>S%AkQ>@U z+E}BeraWgdt*k=+v^*LoEVAQ}7j)SkWVfoe#sE0et48CHqW~Cs?PYaA+D*X$h)w_4 z7Hhe2*0Inb58yuo7G8GwVO7BY0Ot;{d_J`rs9<@Jma}+y>$tioS^HNYjJcNBqb1OF zk|arzB+2&>{B3B=Tm%i(YL@G%Hot5~K?cOeDr3GfCh^pneA2mW>oBe)s77`-hv^w5_bWByNm2@%P zXOCJ(rTdD>#*`g>Cfy`q4NTVd-OVTdn<|-_$x%FPwXT|T{vT{&ZdKm7?8=vHL)8}# xrTODJ*w?gPT7WvPS}Q+Ek|arzBuVlS`~@8mJE*@$*MI;3002ovPDHLkV1mXpx5xkh literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_message_1_1/00000.png b/tests/snapshots/nanosp/test_sign_message_1_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..1285e85e98c1394a44d0affe0f70b994a6fff8b1 GIT binary patch literal 554 zcmV+_0@eMAP)>Qn#HMdqql1x?cej0kEYgYYV}4veBNTl8aSIV zB*lA?%%1i>8U{Ax?ha_vZe}iG>Miw;qUzrJ#6##uGUD1f$ji+I2^ms5pqDeHYe(^m-YjBK3(OqE5CNXJ*>>_|9=RYp(Sp1N zZ4&pN7}2Tn5l$&zRtWwLj2^dI&^cIJ(Zy;nfyG-dLd_f^ACi`x5)tvY?G@_k zzgCJ*wSVmCJ!1L~?+ue~W-br1>NRxFdfBrim*#T!By2JpasIfNKMy~}=XIXqG>!W$ zC?k~|F(25q>)1Tc?*P$T_pczYt(*78vD=1Ro}U1b!2bQK-zcGXIzI*%lPjHJ&^|xV^n(A+cId~Jg(3=d3%p5F*@&W(= s00000000000000000000001oG7s@gS!EywZ$N&HU07*qoM6N<$f)L;RkpKVy literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_message_1_1/00001.png b/tests/snapshots/nanosp/test_sign_message_1_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..e7ffedd90f5279e10fd67907e6122c12c1bbafd7 GIT binary patch literal 457 zcmV;)0XF`LP)Bo7fQz-)#Q&A!PMpz3O%n|+fjfT!4#E}eZd``R7A6>%04 z&A!Rq0acf7-Rx_VTk-<{0APxR-Amm`Z_ezOhUqW=r@`mED)n>^wO4fWLn<5k8hwp+ z*c7VQlDSFeL7Ml1+K3Zc$L1++d!-5U?%MEvn{hd75c|*Sy20_M8!B3Zc2Y_%-kP`W z6B3uv5sEp6+7}?3cGS-jo%#RmC+k+Iq6=2ZCt{yO@|m#fhCEXc001~`+bXE-Sq__* zaSL|sh|S-mJG0AswVnF_Z;Zqai5F&=srY7G+YlXo%RjEI;O00000NkvXXu0mjf&CAl) literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_0/00000.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..73cd118fdd24fc9be59f2356f1e8ca08df127b43 GIT binary patch literal 418 zcmV;T0bTxyP)d9^P)FJrgx2V?00000003YXFYf@(Q`N04 zB94)KBIN+s)LR*cA>ROO*|+I#ZcO3FJAjjlM5oJpR;p^(pZ?nvvd#dw**ncMp8iYT z8BpXpW9nD={sk@k4GrQuF2n!;0D#*?zhG2jwBt=7T`qK}MQPJ9l3UqB%TWum)1p}g zs*BRi?alV{L?r0x)y&Z)jr!G*4dB-?j;8({$DvP%NmcEkg&Tl1xFU%|wYJEGxgz`F z^p~Jw&!L^0?FhonfSUcuIy`-bb_M_d03H?RfyU^?xO1u5>s4=ezch7wE~vg-vbk8> z#gjkH2Z0WI)!*3vkSQEi5&9d4dez_CoCjkEaGmH&(AS$~0E$~QaY}Nt48Xd?i^$gS zj_99HHFU3L*(oL$_X*zVwU^~M*-s|Ux^badmY}d000000008iyKWtAmNzx`H{Qv*} M07*qoM6N<$f{cj6jsO4v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_0/00001.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..05ccaac79741aac66e30b935ffdee643ba8e1b43 GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|Jr`_=;_!R_^H9`=wn<4ooIqU_I)Z`|U##Z%AYRL;xirLie-7Wb zneWTLu$FXsoZH#5(#&i3ybCsqs%I9S3HY@|S0JDtB$JLl%jxcqAO;r(;iUPwLN|*i;g<@5<7jB47D? zn&0)uRswC`7-!68T5TO~@ZxImEZM&&&c-gQ&%QVDenG&Km$H_Xe-c)(_EzV9bbfPk z+O?)xtWVBP-=>*&Kkp^WjQ0frelwo|c`PoJ!|=Tm%Vwy85}Sb4q9e07_i0YybcN literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_0/00002.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..9d8efd1df120d50b84cd15a7884717514b7c131c GIT binary patch literal 724 zcmV;_0xSKAP)j{ZUbD*c$mB4IF76RI1Vu;-m;6$J3u&8>;~Z)vr!1iV@yYjcXiAC zJYok3X9d@OpM=umUPSL?{~3@L9I8h_syTh{*|ReMdFEv*xN^E499gGe%ro;(O6g~# zZk!X$bJ9Cby%qiZLzoak2qA>DQN6E%0;k!S@meBsw9LpD?+PuZv*OCOsubbfr#!%y z{)hqCWpN`T()vIF5WXlcu3~_$nwdAF>Wgt>yx!b}Yj#bl^tnUNUh}qNPs`mcO?qx}+GV_h2M}&ULP*LTmZV zaRy47jYG0n0a(h{0!4VD(+qJnYE54 zYw_ti9U$NBdXe`#?nKWCfZh8d?|0*U*Dli4Jm4E*@DM&B3%!?$lNp1h+~HocoFH1d z1?tC$4IPTG+4?c4;#Rz(&`1D+63qHcldjUmxQI09{f1i5X_Wv=3-Y6P*D%}l#i!}w zR;u$X^txux&b8v@Yr6jRJVYA2dAfNU6JN zy9Xrbj_K=bqU%@3a{8@;5JCtcgb+dqA%qY@2qA=!&)^>!)Ke!g;}B literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_0/00003.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..0a22ed9c048e1c509e4db8bb538a09179382d08c GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|>}8ba4!+nDh2#Am1Sc0oRKc zcL;ymuk!5?JEvmnwkuibaeJSyRt)^uD?4EpBTyF!;K^XIuI0vnmuluBIu;=7LF=pwdVFK5RvW*sptdHLn+n}@cI{$FA}Oll|ZX6|ym zv+E^4$J-}Qw*A>Az5dSkz%5cnFXPh$Okc+LNL4K2u1u2s=CbF;;vKu~m9N=9{MYha zTwZY10sZ%!KAFne?ELQTryeXiAb8GzN%q)U*^OTlbNjEn{+IM4Dt=?sgqcgH{7Q+I zR=)jKHRSoqLt7UZ8y@``d%nAfeardKTg&xoml-QN8=e+U<(-lF`shs89kuD*QImdm oYP)0002s-}zlITITZM$M#37_F*2YcQcLS@s@`23cFYdn^|)y zTYqM$SHI1Y;;$HEvD@|!IK5lmqnF*Rx2J{Eod*XllV4Xg8>*}5`!v8(^~mF;0pupq zYwB_TwWS_~G%FSpqlc*y0002EQBg=pY|?CdV17JiSwW zp_v-jf+&o`Fn15WNBWKaWTf}v!C`Uh70u(!%G94SG0k;)k9E< xUEOWZ#B@A)hE@W#z8pzb00000007{j{s6i#4}-hd;qCwc002ovPDHLkV1jp(v}6DP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_1/00001.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..cc9e51b573b9d37c00067cae1a9752839985bd45 GIT binary patch literal 359 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|`hqba4!+nDh3Ax6mO4o`%Gd zJ)ZCCm)tq(>dscF$0GFV|Jtk)tC+gvs8tc{?$+lo4MxmCclI?(@OjK zA{u;tMI70x*?e`r<(Dmf2|l68rt7%{Jy*x@#wA@?%lxh3)%`vGE`F6v=dv9i?q0C* zLgduTrU9YbvkM%!yH>fr3AtAPpEG^y0+WiJ2i15O7(UFOCgZ$1_{_hL8~^yOkdu+m!bz04_Bb=W!AUOZ%QZ|Bu7-HBoLRxf>jOxvc{P`6~_TuzHEr4r%iPCIR1 z`+H;Fob>xmbEezr$Su32-%z~U{ig8jqDrn)-x`X%C7xZl>2xaEw{uG7|D*!pZAW-# zxi0&4JH*TPt9df7&c#-pjr`Gz_5i(%3=SCOUo_*oGs|$R4@lV4)z4*}Q$iB}A#;`! literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_1/00002.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_pkh_1to1_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000d9^P)FJrgx2V?00000003YXFYf@(Q`N04 zB94)KBIN+s)LR*cA>ROO*|+I#ZcO3FJAjjlM5oJpR;p^(pZ?nvvd#dw**ncMp8iYT z8BpXpW9nD={sk@k4GrQuF2n!;0D#*?zhG2jwBt=7T`qK}MQPJ9l3UqB%TWum)1p}g zs*BRi?alV{L?r0x)y&Z)jr!G*4dB-?j;8({$DvP%NmcEkg&Tl1xFU%|wYJEGxgz`F z^p~Jw&!L^0?FhonfSUcuIy`-bb_M_d03H?RfyU^?xO1u5>s4=ezch7wE~vg-vbk8> z#gjkH2Z0WI)!*3vkSQEi5&9d4dez_CoCjkEaGmH&(AS$~0E$~QaY}Nt48Xd?i^$gS zj_99HHFU3L*(oL$_X*zVwU^~M*-s|Ux^badmY}d000000008iyKWtAmNzx`H{Qv*} M07*qoM6N<$f{cj6jsO4v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00001.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..760425304657bf273b8136e3420d3c5248b7561d GIT binary patch literal 410 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|>x2ba4!+nDh2#w9p|19*2uB zb_jplzvRu){&NOC6;q--3-&zc{_Vh{n!A_-sOiJ@kkHV@?t%{_Z5ae7%2aK)ypg^y z{vz{>psQ0Z2`;;1aqDNpvuU4nF89A&WuxQuhsz*5>F39e*qa9JPxmg551cpew&v0s zFHZ9b7wiz}wt6)C$z=XFlbY(xo6K3)HyD{-Ke=~#oc6<+Pm-gTEHKiHw^~{$zBXT? z`SSm=r;H2?N2=DmzGd_9YHD*_=<>>>yTzX)H{VO$cIL_ypZ5K~Cn*}~eEqV`Cr`d4 zRqE`zG`B||7Hv4%eZ#6;FK&Le{Q|KoK1>@=@0q!yrcK0v@mV`>7uRbO?kkGd59(>2 z_&j|+o7H_ww(S%0Z!VR2o3<~+y#9}D8I#Pk#P9^K2 z=S}F`H`{GR=RV_S3PO<@mpmuTY+lNt4-6z^u;Gk!umflBpK!TUkg%t#pUXO@geCxp Cz_pVA literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00002.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..fda030d56c962bf18cefd5b175cf5f284825a115 GIT binary patch literal 767 zcmVJK#dKP) zNf80eSi!kJrh!`A^5~uH-vi2mP4yrY&**#io}CUjM^2Z5*P1ScBlEN&lXLwkrF?B{ zyS*l;`=qsA)7pfM;q}+ zMfPx(T2*s=L>9}lp)6T{CsUS3D>oGvXpF_U8ate-@GKfWC^R4d>@!ni@X10msPj!BV7o=UmFm)0mo^3D%`wS=k%bmi23` zv5hUhBdR%{;dUp`n-^>!*Lssn5w(#n#XH~5K}B#<5tU$-1nKJQ*r|+V+0;JEp0kdr z!KBs-Mz;E~V?6BHvZI_1(sQadIXt(D`p|H2FnX>RT0?GFe_Ad`CVbqsS;cr;Qg|$4 zhMQA~51EqU$GH?Xouy?X_brxMS3qr-)pC2-MLGwt+p+lA+CGq8WG;!f+a>8bzU6>; z-tiP`-@{351J^aG=0&xNNN28SBE-lho&$G7-pj*p#PXAF510;HNH^Y50{}oacK(Z! zWbH`~#7S~Syn*bepsHO7uv3jJVUeUNNkTdYM9zrqI}p`RX-Ve*IcFtrVc8(>`X+qw xN1u6kR|h}8ba4!+nDh2#Am1Sc0oRKc zcL;ymuk!5?JEvmnwkuibaeJSyRt)^uD?4EpBTyF!;K^XIuI0vnmuluBIu;=7LF=pwdVFK5RvW*sptdHLn+n}@cI{$FA}Oll|ZX6|ym zv+E^4$J-}Qw*A>Az5dSkz%5cnFXPh$Okc+LNL4K2u1u2s=CbF;;vKu~m9N=9{MYha zTwZY10sZ%!KAFne?ELQTryeXiAb8GzN%q)U*^OTlbNjEn{+IM4Dt=?sgqcgH{7Q+I zR=)jKHRSoqLt7UZ8y@``d%nAfeardKTg&xoml-QN8=e+U<(-lF`shs89kuD*QImdm oYP)0002s-}zlITITZM$M#37_F*2YcQcLS@s@`23cFYdn^|)y zTYqM$SHI1Y;;$HEvD@|!IK5lmqnF*Rx2J{Eod*XllV4Xg8>*}5`!v8(^~mF;0pupq zYwB_TwWS_~G%FSpqlc*y0002EQBg=pY|?CdV17JiSwW zp_v-jf+&o`Fn15WNBWKaWTf}v!C`Uh70u(!%G94SG0k;)k9E< xUEOWZ#B@A)hE@W#z8pzb00000007{j{s6i#4}-hd;qCwc002ovPDHLkV1jp(v}6DP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00001.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..0a11ccdf7184c11729310cd4da5a2c8d124bcdb2 GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|{s{ba4!+nDh3AC*NTO9*4lF zuWI}LPpp})rxYo|Q^FDa>%P{)z-FHUnRcKa2A=ZSwvAGuz5cE#*L;3eo|)%xTlI0C zSww@&9^IVWPmbR=vEEJhU*H?6JL`C3$C1D?c7C%RYk2Q5zDtf%SK9ri;crkt1@8)0 ztInc5Y^!#?k;<9S)FXYwE9Lrm`^5DkBK&fCAB5N#7=HMtPg|Jxc~hL}v+FGDvr1lH zyyU;U=gIx@+gG-FntcA}xN`9Yne~6JzGQ!Y=dXx$Eoc0tj<^ZC=T5(M^qR%0^Q*3u z|2o>idg6AH4k$cMefVqz6veXyv&Ciu@lvQ_4 zzxPb%uGM{Eu5^z2HA4b;d<()=I&YYYVgwaf1Q_ c36y+hS@ib*hrM_1&IO5jy85}Sb4q9e0LUPxasU7T literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00002.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000d9^P)FJrgx2V?00000003YXFYf@(Q`N04 zB94)KBIN+s)LR*cA>ROO*|+I#ZcO3FJAjjlM5oJpR;p^(pZ?nvvd#dw**ncMp8iYT z8BpXpW9nD={sk@k4GrQuF2n!;0D#*?zhG2jwBt=7T`qK}MQPJ9l3UqB%TWum)1p}g zs*BRi?alV{L?r0x)y&Z)jr!G*4dB-?j;8({$DvP%NmcEkg&Tl1xFU%|wYJEGxgz`F z^p~Jw&!L^0?FhonfSUcuIy`-bb_M_d03H?RfyU^?xO1u5>s4=ezch7wE~vg-vbk8> z#gjkH2Z0WI)!*3vkSQEi5&9d4dez_CoCjkEaGmH&(AS$~0E$~QaY}Nt48Xd?i^$gS zj_99HHFU3L*(oL$_X*zVwU^~M*-s|Ux^badmY}d000000008iyKWtAmNzx`H{Qv*} M07*qoM6N<$f{cj6jsO4v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_0_0/00001.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..073b4ff597eccfee869a2e673a20fdc9a26808d2 GIT binary patch literal 374 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|_WMba4!+nDh2V^g1R*o`yu5 zLiIQGo_9}I&hU`p>RG&T?WcPGj>D?1r#v))nhtDpadBCcF8DydifQSTOHS{%u~lCC zEoa-PDY$a0Tw+%1;yZE@*ItCh+Q)|f+Nkl-dckkiSN-m9N)}eHsjaqZ$-8%I>$Mv% zrt@$Y>=5CW{;2Zv32S7~h3{@3d=FYXEKi$#C;d$v=Xn)t?iGJu&72j#ZO8waS8XEqzjzgN(6`Gz$@=sr zhEEH!nVvsZJDnOcy++)eS6*oAy~wfy6K+q8kgsXG9Hf7sucmBKE%&Q)4Am-g{PGK1 zZmfHA*v@>hx^qs^yQ8z%X1>@h*)r>ebuzEg#8#z3K6j-(K>s6y1IPa`?+y7|aM8si P5+v^F>gTe~DWM4f6K$a+ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_0_0/00002.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..dcf25e82e2e4c493e6cad0d5895a85127de65a18 GIT binary patch literal 701 zcmV;u0z&>p;!qt(b2aLJCUeI8%*+yU!`Z>cwG@W-Y0jD%|5 zsEa{w(Rf|nZFZbzboah5lDL)UWj}2>0Cq!<%zoN+0PMD&ItCl^T~%l|f+TYcZbhdz zekecv!&Ivja}UHrdow~ukTAo*qjiKPC!Pi1;;4Ubs5P2`C9V?t>Zad{`LCg##wX#{ zT}3x=Mv@f{>!*5pj~Klf_TCnS0Vm) z{3#MKHULAVKuo1kDbz1YmkZ17fQ2J1y3p%sih6-YCccmh`HVf_!JuzN5JCtcgb+dq jA%qY@2qA}8ba4!+nDh2#Am1Sc0oRKc zcL;ymuk!5?JEvmnwkuibaeJSyRt)^uD?4EpBTyF!;K^XIuI0vnmuluBIu;=7LF=pwdVFK5RvW*sptdHLn+n}@cI{$FA}Oll|ZX6|ym zv+E^4$J-}Qw*A>Az5dSkz%5cnFXPh$Okc+LNL4K2u1u2s=CbF;;vKu~m9N=9{MYha zTwZY10sZ%!KAFne?ELQTryeXiAb8GzN%q)U*^OTlbNjEn{+IM4Dt=?sgqcgH{7Q+I zR=)jKHRSoqLt7UZ8y@``d%nAfeardKTg&xoml-QN8=e+U<(-lF`shs89kuD*QImdm oYP)0002s-}zlITITZM$M#37_F*2YcQcLS@s@`23cFYdn^|)y zTYqM$SHI1Y;;$HEvD@|!IK5lmqnF*Rx2J{Eod*XllV4Xg8>*}5`!v8(^~mF;0pupq zYwB_TwWS_~G%FSpqlc*y0002EQBg=pY|?CdV17JiSwW zp_v-jf+&o`Fn15WNBWKaWTf}v!C`Uh70u(!%G94SG0k;)k9E< xUEOWZ#B@A)hE@W#z8pzb00000007{j{s6i#4}-hd;qCwc002ovPDHLkV1jp(v}6DP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_1_0/00001.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_1_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..1806981156ba178e3ddb67d1e79d2272e5292d32 GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|{s}ba4!+nDh2V^rk}!JPnC9 zkNr0NS54J_zR;M*$z$s&)nE1gQ?Je9)IG9<1*prXJX*HFJ@j z_u`v76AHf^diQlfoM{%*t!oiQ;Wr}mOfssM={Y_OnqSVEUR@DzgoC6Hw8qS>Nj;+7=4E~|rCv(;YD&G)vjo+!g;Q^|hb!#` d1_m-XVDMkmSZis~zQsl$VNX{-mvv4FO#rpbr#1ip literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_1_0/00002.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_1_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000d9^P)FJrgx2V?00000003YXFYf@(Q`N04 zB94)KBIN+s)LR*cA>ROO*|+I#ZcO3FJAjjlM5oJpR;p^(pZ?nvvd#dw**ncMp8iYT z8BpXpW9nD={sk@k4GrQuF2n!;0D#*?zhG2jwBt=7T`qK}MQPJ9l3UqB%TWum)1p}g zs*BRi?alV{L?r0x)y&Z)jr!G*4dB-?j;8({$DvP%NmcEkg&Tl1xFU%|wYJEGxgz`F z^p~Jw&!L^0?FhonfSUcuIy`-bb_M_d03H?RfyU^?xO1u5>s4=ezch7wE~vg-vbk8> z#gjkH2Z0WI)!*3vkSQEi5&9d4dez_CoCjkEaGmH&(AS$~0E$~QaY}Nt48Xd?i^$gS zj_99HHFU3L*(oL$_X*zVwU^~M*-s|Ux^badmY}d000000008iyKWtAmNzx`H{Qv*} M07*qoM6N<$f{cj6jsO4v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00001.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..073b4ff597eccfee869a2e673a20fdc9a26808d2 GIT binary patch literal 374 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|_WMba4!+nDh2V^g1R*o`yu5 zLiIQGo_9}I&hU`p>RG&T?WcPGj>D?1r#v))nhtDpadBCcF8DydifQSTOHS{%u~lCC zEoa-PDY$a0Tw+%1;yZE@*ItCh+Q)|f+Nkl-dckkiSN-m9N)}eHsjaqZ$-8%I>$Mv% zrt@$Y>=5CW{;2Zv32S7~h3{@3d=FYXEKi$#C;d$v=Xn)t?iGJu&72j#ZO8waS8XEqzjzgN(6`Gz$@=sr zhEEH!nVvsZJDnOcy++)eS6*oAy~wfy6K+q8kgsXG9Hf7sucmBKE%&Q)4Am-g{PGK1 zZmfHA*v@>hx^qs^yQ8z%X1>@h*)r>ebuzEg#8#z3K6j-(K>s6y1IPa`?+y7|aM8si P5+v^F>gTe~DWM4f6K$a+ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00002.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..dcf25e82e2e4c493e6cad0d5895a85127de65a18 GIT binary patch literal 701 zcmV;u0z&>p;!qt(b2aLJCUeI8%*+yU!`Z>cwG@W-Y0jD%|5 zsEa{w(Rf|nZFZbzboah5lDL)UWj}2>0Cq!<%zoN+0PMD&ItCl^T~%l|f+TYcZbhdz zekecv!&Ivja}UHrdow~ukTAo*qjiKPC!Pi1;;4Ubs5P2`C9V?t>Zad{`LCg##wX#{ zT}3x=Mv@f{>!*5pj~Klf_TCnS0Vm) z{3#MKHULAVKuo1kDbz1YmkZ17fQ2J1y3p%sih6-YCccmh`HVf_!JuzN5JCtcgb+dq jA%qY@2qA}8ba4!+nDh2#Am1Sc0oRKc zcL;ymuk!5?JEvmnwkuibaeJSyRt)^uD?4EpBTyF!;K^XIuI0vnmuluBIu;=7LF=pwdVFK5RvW*sptdHLn+n}@cI{$FA}Oll|ZX6|ym zv+E^4$J-}Qw*A>Az5dSkz%5cnFXPh$Okc+LNL4K2u1u2s=CbF;;vKu~m9N=9{MYha zTwZY10sZ%!KAFne?ELQTryeXiAb8GzN%q)U*^OTlbNjEn{+IM4Dt=?sgqcgH{7Q+I zR=)jKHRSoqLt7UZ8y@``d%nAfeardKTg&xoml-QN8=e+U<(-lF`shs89kuD*QImdm oYP)0002s-}zlITITZM$M#37_F*2YcQcLS@s@`23cFYdn^|)y zTYqM$SHI1Y;;$HEvD@|!IK5lmqnF*Rx2J{Eod*XllV4Xg8>*}5`!v8(^~mF;0pupq zYwB_TwWS_~G%FSpqlc*y0002EQBg=pY|?CdV17JiSwW zp_v-jf+&o`Fn15WNBWKaWTf}v!C`Uh70u(!%G94SG0k;)k9E< xUEOWZ#B@A)hE@W#z8pzb00000007{j{s6i#4}-hd;qCwc002ovPDHLkV1jp(v}6DP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00001.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..1806981156ba178e3ddb67d1e79d2272e5292d32 GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|{s}ba4!+nDh2V^rk}!JPnC9 zkNr0NS54J_zR;M*$z$s&)nE1gQ?Je9)IG9<1*prXJX*HFJ@j z_u`v76AHf^diQlfoM{%*t!oiQ;Wr}mOfssM={Y_OnqSVEUR@DzgoC6Hw8qS>Nj;+7=4E~|rCv(;YD&G)vjo+!g;Q^|hb!#` d1_m-XVDMkmSZis~zQsl$VNX{-mvv4FO#rpbr#1ip literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00002.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000P@)+k+{o#AVrq>NXZ&(m-qQmF&b8C0u4@%0{{R30002H__6N5eL3f| zoKiCE$$x|#02z8I;xNP;fHV3s+|9}meyuxjlL~aWxJQ+9mg~>>&k&-{0GR2W<`GZ- zBkl}Pv5pw}BHmTd!DXlu-?0$`0000U=Y7MNh1rG=b?M_=cU7e}4SVt^`PE|Ng5@R=p%*t)sXDK%dj6!<2#O1|G}r6v;1oA2B36K1#v3Z<~cE^ zqVLXl2~tN+9o#H?;BE%g0w98*SV!vk2qLsaEypUZyKnig7>SX@;l&E(4%$(WrT2xcKZc z042mJrL$1#&6j?gY-lfMIar<5eS&vd^&+e4$)3LJE3ejfS%TbR00000006*3e@pj9 U47?QzQ~&?~07*qoM6N<$f_Fp8NB{r; literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_0/00001.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..700453f77358dbd81ba0271da35c7fdc921d320c GIT binary patch literal 374 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|_WMba4!+nDh2VF5e*qo`yt| zdo91^SC)Td=Ty|);A)qBl#ov1C zx;8K#T^eztgZ-qse8;4wI`gLZqJ7M_uH;Pq-LW_Pj`7LkPD>V;X~w_0RNHln{n(P< z+sfsDPG5ig(a$T{^KHE)WWSbJ-oPtEZ@ytVtRVb1)oP*IukMZP^G-O;tKh3v+5-#$WN;w&-u?YQ#ZINg QaD#+BUHx3vIVCg!033IwcK`qY literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_0/00002.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..6c57d4dd591edcb595d432c52143dba70d3e23c6 GIT binary patch literal 917 zcmV;G18V$>=D9~t?h z{IRQ}DfJ(%;!*spFnSPom&O!F##+r*O1YlW-*%}PeurDMQQM%-hEhr^5O~U%4@TK= zmdt?GaH9cbPi33s&?}{=fo5f83adh9K#*03uy6)2kHN7&W`PE@)uRTkkrB(n4hSDC za-`F~ImdNWrQ5cy_$BCaozC<#Kr%BjzKlG``U5iT-XyC|L3F`oiEMBoYwMM#by8F_ zfK{kR09pl2+_^u0iup^%>TAmPneTuoPm&}_lEjZo-Rx$o1S19U=a&1|rgKqO4m=aP zt{A~W9(8>S0XG=c_Z=yM2A5rD)T@^Cua&_Iy-Tb8bm|c5-MbQPmANFFW2D$^VcDde zL0U6_MFGjC&e`swgcw)zx29&RRM+@qS(Sb71Fj)i8@kZZ7<5K{uLEG>PIkYLVIaX} zYs(C-_cnW2CC0^q>&&#b0()*9deXx|l@UnFl zw9?WQmNHWX=&-l>!~XF4ym7Q;pC>cl0eDLXr3iL0VTUN=OeJqL($tk%y(rNXDJoFK z$*_Z~5ynleY65NiVbUx6(I3W)ZjCa~c$AZ%1F~$_KDY!yGhl4#Fywn_e{A5~wWdjj zr6=IWy!{Tq<2XiFqXvtII0L#NWxnB+Crk}JeVU2mTej$vD2MwqV0e203%cyv+v#0M zug0{}S)LG!C-~sv9WP`)Ow23E8>U;sha^do1m{;b$Nc&(HIsP>1+nARosNn7;3~Wd zC}?C-C`IhJst9T3817S$sv~w22aF#Ly>kP#_l;@mDRmo^hx@LyejM-sWWS~Q=(PjR z0I9{Q3T0RFWb!BI5;&_IQp9AQ#H$q^ r#Q9W1Z{~4(z&Ch;Je(v+l02P19Wsnw&}-*700000NkvXXu0mjf-*>yw literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_0/00003.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..562b8c3a7d73de03a021e86dd7b6a40d2558ecef GIT binary patch literal 504 zcmVO-XHi(D?sxm170001wQA#PL_zxNNXZ1&1 z%kD#4C#ZYxh(_z%h-m+;HjX*xq;;<@Z|g+d&foMF4eAZ3Gco7fi-NyI)jQ-oeY*K8 zKm=5*261m{Vd~6THPGVRwxoB7vwDl>M^P(4bk{leueDGI*BNe6?bPI$D{26y&y;qi z*JE=`eCI_y)s{WICa0ipzw1O^C)#b^@}9GFGcJPXdupin zsklJMcC^9X-R*7o_@}43IES^?@btPAZOz4qMi7i|4c`*+w*s9gr&S`x6w z=0a2J7sTom)Z^dF^gA-o=DRn$3_uDP1F<<;=NyrLZX{FCf^MCPvOOwx;`XO?bx$>t`F?6Bp*+#>Hie;far@KWQ^ZuZl^ziwpypp)(tgdu)rY5 uj6o>E3jhEB000000000000000g!uq`W2>+d#rh`z0000hKx> literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_0/00004.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_0/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..0a22ed9c048e1c509e4db8bb538a09179382d08c GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|>}8ba4!+nDh2#Am1Sc0oRKc zcL;ymuk!5?JEvmnwkuibaeJSyRt)^uD?4EpBTyF!;K^XIuI0vnmuluBIu;=7LF=pwdVFK5RvW*sptdHLn+n}@cI{$FA}Oll|ZX6|ym zv+E^4$J-}Qw*A>Az5dSkz%5cnFXPh$Okc+LNL4K2u1u2s=CbF;;vKu~m9N=9{MYha zTwZY10sZ%!KAFne?ELQTryeXiAb8GzN%q)U*^OTlbNjEn{+IM4Dt=?sgqcgH{7Q+I zR=)jKHRSoqLt7UZ8y@``d%nAfeardKTg&xoml-QN8=e+U<(-lF`shs89kuD*QImdm oYP)0002s-}zlITITZM$M#37_F*2YcQcLS@s@`23cFYdn^|)y zTYqM$SHI1Y;;$HEvD@|!IK5lmqnF*Rx2J{Eod*XllV4Xg8>*}5`!v8(^~mF;0pupq zYwB_TwWS_~G%FSpqlc*y0002EQBg=pY|?CdV17JiSwW zp_v-jf+&o`Fn15WNBWKaWTf}v!C`Uh70u(!%G94SG0k;)k9E< xUEOWZ#B@A)hE@W#z8pzb00000007{j{s6i#4}-hd;qCwc002ovPDHLkV1jp(v}6DP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_1/00001.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..53d797266cb3ed3c2a86d4d076d29d4f3c5e0b67 GIT binary patch literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|@9jba4!+nDh2V?xbb~o`%G- z<>n{<_8*D;)^03m=CVQ8DdYb0>Aq`^Dafm;0(B+qntzpZ%ab{$`;|6nP5x~Yrhei3 z#L{qSlZL=D?%df{FXo9|c>jv!SJAnsvyUBIPHF8v*vxkLRsvr^{AV-4n@ic>n6oVX z&wABqw$}9A3B`Q3*`#?KPw6Ht-t_VK{4Li7LfH7_4LF$@7;2U?o(?EKziDs8n)9Cb zk}k%!&8sz4DN=n~mUMbX*0tMg>C&8cD;@_q^W9;Yx9hic*)MgQn3nJ#$M!00f9_WC zOmFh?N`bqnQlE6p%^dbxPfO~XXPb8H(lg0Vc4y_99!;++GXML^Qen~b^lw$7OMIUE zl0EzL*^RxAHw&77E|W^XzH`y%)rzmRw#*fq`O5$Clv%I*-K5tX(byvN`GeOKabQRw bgB@q(m)ug6ywthW8YJxL>gTe~DWM4fBlD&g literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_1/00002.png b/tests/snapshots/nanosp/test_sign_psbt_singlesig_wpkh_2to2_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000@8YPShSld0g(AHT7BV#D}ma`>I{;_j&rP-*Tuqt^l

kTU{x)#Y{tgqjqg%;ED%WhS{hbb3 zU(OdHv)gT-jeBr6aSzGP)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_public_key_m/44'/1'/0'_0_1/00000.png b/tests/snapshots/nanox/test_get_public_key_m/44'/1'/0'_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..adbbfe3edf9ab1aa9381c4f94bb87b8cdc1a5f7a GIT binary patch literal 683 zcmV;c0#yBpP)3`I#QH{t$A@?ElU6-6|B#9-sJ|66rqA!Gp($SDy*2qA|*l{5Dpc)LAb_j6iSMW>1fecx7^Po zc7SkJaP5z2s6Fn@=$-7(0qKIInk!Pv>3eg}&Iu@QUWbA+rfcEIIt4P%j6W%*uZ?5l zm|*5fFP(ZT`uRzi5JCtc&b|g5?dnL2AG`y zof5T`krq#Ly`Z#TCRLd}z0TJrvlDQgq4+d%sj9I#5WRv**6e`f&xB6hSZ1CsRgqlk zojaQy&Eb|USue{GjBwN=zKFdFvE8R`!u+f;%$<3jNEohnLhtWHdq0!|>YGd5-rMM@ z6)j$ovRRwdM?-9RX$SW*zMBuWy&8CGG@xdS{3$9J^;Gvr^ES-5JCtcgb+dqA%qY@2qAFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000VvAL$Qu(t4d^7YRwj} zU`yOuxCWo*mIu;6izlGSI`Ry|&z7BeDlZ0Af%Z8#7_IuRJ?@Y#X#5pmN%y6G+A5#s zz1WGm@*K?Cg0{W|Qd`cm`Nti<1vTWoc)fQ9Z61cR0TYlO3FKax%G=hF?7>pLbRm;eC48fwoZ>eE7goPR7kt#jPU%|bU}OZHW{{LFW?&R*jG?Lk>( z0%}Rj%PlXxZ7;@8eG~3y&;I)?F#!!MbMuJ#yMF@GF9Gr=frIjwnfN){NG?*jW^3gy zckeP)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_public_key_m/44'/1'/10'_0_1/00000.png b/tests/snapshots/nanox/test_get_public_key_m/44'/1'/10'_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..4d77a5f3faf093264e4e06ab55ed875ae948c923 GIT binary patch literal 689 zcmV;i0#5yjP)|M%2-j6qO93=seT00000?_}GyZQJ5MIsI?P z?`#36s`4>9-Nk3N04AzE)ZI`@`L>r*Sf6;yEGF*&rckyUm}=BUHc0KGDw;hjTdrq` z9l(?oT>E1qv>LZ8dL{E?0G$w2O9Sk7U;U3QMFQ>V|G{)dQuCcfME z32L0Q!l|{Q*AKz~00000@8qI1)XFd8jcTGlX6#uwk`4x((Kfo zQn#}lFs|7|RJGJb$33>3QVkv3r>YXARjdkxCCPw2oWPK7-BS#ZD5V;r>Ay3y$kILy z%_z7;jv9d7Mx8|5k5w-AMN$dDx99Hw7O3M71|63=c(AdXkI5t=Ci@OKZ<)xhkCUqU z|1NPO_9|HPnt37f44m%=zNkJ2zGx=z`~qqfp#7Oh?RR2;lipdmopTSK;`RL6C%L(! zbwB+i~i#+Y*$$K3=ozT1AdymF*(0Q&AU3dg-Na0H@lVHPsY?@3q!S zu-v3hzuVd2#FOxvXN^+IHBtqq|I$)~TFs7>xYOylAl0!tF<^l7?C8h>FXGOXjVY(k z%oYia000000N}1SV#&2eFwEWWH(q)Y207e)`4e^k80P`YpRfa_0|Nj600000@IL+k XsQGqe(aN%h00000NkvXXu0mjfa|%iO literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_public_key_m/44'/1'/10'_0_1/00001.png b/tests/snapshots/nanox/test_get_public_key_m/44'/1'/10'_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..53ae65195fbea5b281a1bc1a80351dbf1cd79ff8 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|=-%ba4!+nDh2#AYZeBfa}G~ z%X2sUSKTFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000GGQ1YY$0Aw=AJK?8id8e#329x007(lj8sl3m4C(rIqPOC|_PA5Fp!qAnlJ2f{d^g|b zU2R0HybV@uL1Aoyw5IcF`{T~vf*g5Q*ZW{lcQ-bhFaY^TQ0|qv+&7QP7A)mqU=-E2 zu01aNo{-Qbry$rd004k3T1O7?<)FTAW7dnae@JXZ>00000000000000000013<{#8}-5GuO RPXPb`002ovPDHLkV1n|P-ERN@ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_public_key_m/44'/1'/2'/1/42_0_0/00002.png b/tests/snapshots/nanox/test_get_public_key_m/44'/1'/2'/1/42_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..2b51f30cfe212df5691953efe741325df2f02f56 GIT binary patch literal 488 zcmVP)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_public_key_m/44'/1'/2'/1/42_0_1/00000.png b/tests/snapshots/nanox/test_get_public_key_m/44'/1'/2'/1/42_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..9f852fe5188e19490cb6ca4b7e759cd54a1558a9 GIT binary patch literal 712 zcmV;(0yq7MP)o|abf6?5W@1fJ{C1_AFoU|bT000000Ps#yN+~7(SBm}P z_})E$kVE+~F>T^!_W-Jh^C9kr7~|C*Vlt_3i{r&XXgauJ1*W z^_(D{leOctwxZ8JgaH5m006*RJk?ezFl`hA@uR1}_7r7`aO*d|n^wuQ=_YlX=@Za| z>Co1KNX=4~ue^iHz$|OITk=)Sd6OT-Shv(~fqa`CitQ8NTBGxq4m0s1xvG|eYAfA2 zFtMHg?Cz+>eQKyb`6w$c_=L{~F<}BcqONmqDk;l!{?M72Fab-&tiCB3r_AXjzt3gb z4hZTpcbj6aGjd`XqNZb0Swi!=1_CZIa86cq8^I$o?38 zA@iy?8~#MO(>FcfzA@p8=jM?-6Yj|N7rrX^5yq4vxQ8Z*M(nrA#u*K}5Yv?z{WRBWG*MIZ4BFY(bPuVJ zX=gpdG*`l9U2aC73uop`cuM73@2#n?yo!%jthxzGW$qlzS~Ya!#P3+q`e8sM9WLSV z!k)~H7;Y{+H0_eL6ELz*TQyGQww+G4R7SQG!AF11`8~B9d9EN!*qMdmKZAq0x>K~a z4vZa;W1T)-bS&E^(Nvo0 ue#V^u000000000000000000004(AsZMcQP}X3Pcv0000FSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000HnV66l}Jnln?*_004KNmC7k4`7y>gT6d_5 zQIHqqZL}lLfxPy~=&8uNu^GQxqSR#ju9cEfiZSN3Q(wr6`F;_hS*EC4+>xP*HQRiG zHF_9=5kv)w6Le=wpznQd1bj`s{Ym0C7dAGcR_CEod;U0=JSNL(< zn?Z^v&w1H_FFadc>Am5ew{@gl}5j6M1!Ynp_ zb@h2M?;8fxWETWICIA3ntk`VSXIu5Prp)8FL(!U>qI^cOva3F<*ZIeb`&y&%N88ZL zb<@)c=DQ%xnT+OtY%fS1e7U>TB54gHfpF3*0ryqj#Xg;%R zI05qKD;T^zt>f3}Eat=MINGB1*746UT1WTW&|Y3m8GXseGO|@h`=5s(uiWImO?QwP zeK(DvX7rsg2Pg3sI*H%mlNeqA000000000000000006+uA155vDx5CVkN^Mx07*qo IM6N<$f~*$ZhyVZp literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00002.png b/tests/snapshots/nanox/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..2b51f30cfe212df5691953efe741325df2f02f56 GIT binary patch literal 488 zcmVP)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00000.png b/tests/snapshots/nanox/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..7ff89fe67ebae7c5feed15f3d273201d88a44593 GIT binary patch literal 704 zcmV;x0zdtUP)k`f_=5JCtc-$~9n=ZwD!$^?`zuS>yM)3q=%PXn1f>rYDQXQA!5 zCYbxAx1D-3djCzB5JCtcgbd*|71GsvmKc>^XcM^t(P=i6%%7&_;7jW#xL4CKI|0|s zmv0EHbiFd)dg;Uky2MPPUXZx0)E8H6;JjFhYf&A?;7%m2QQ#fbyEB_sJej(Ax1=@H zXvXOdK{JA4xPB{i)-r*rCSt7F+Yrr<5p$qR!WqpL-B6stkeO?@X|W#bsm-syC5o8Y zKG6&%Ko^|xi5!~?>dBx*&-uG6(oh0sIfvBWyUWEYCai#@YJFT@kwrZ|Pz#%B_QYZn zdLz`MOmC-6qvlx{95~U3o2*Pn__oDAVqZmlpih@ekkImQb>4Y`BRp^dCK2yGf!-TN zeQ4?2J2X2AAg+@TYFG2JFJKfyGOyWwfL1+VjmyWXWa7K^Rd&&>>(PXfuN#pXaw z;~0u3R-B8>;X+kYGx8-594B;qL5oN(8|`SYqZEMjQ-iTN>@NkehzH_ib-$gP@9v9O znd#aUa}mVo$#t^H8F|o?Ga#{&mF;LfL%Y7V%!BfCdfLQ|=?;sN6L4V>#Mi>0QR-EO zuFhbWd%d*?DT7f0yl8?UYf{7(b~1XmC0yrZZa?0_?BmH4-svw%uNHj;A2#m@A%qY@ m2qAFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000V~o9dyRvL5 z49JW*UX@^`QF&F2EK1E;a|O55 zTdQusV>su9+)(oc6q!c8VSEe4o9B45QdQAw3@%!$p0?M!WD8oq0$RGetDLdKxBYGw zqE?=RU0YC?n;^C6yqkZ$>$jkRemB?qWTnH+aJFCo@{vI9l{tQF9?23~;={x!n%}zZ z^=WkN$rrSVEuHH1|M>A%JGpC@Ii<*`n zx2s|f+ISaKGjL7jZ01s=*MR}3F_(PHXw9clPvsvN*Tv5B9ssrf=9eu0<@gca10d(r z=kG-a_+P%~aC!KvZAxp?n5W@Q{cuz4uPy&0s+~;lyD_?&-gm|roWw4465qoo(Y*iw n0000000000000000Khg+?VzO^2+iqh00000NkvXXu0mjf`ftxg literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_public_key_m/49'/1'/1'/1/3_0_0/00002.png b/tests/snapshots/nanox/test_get_public_key_m/49'/1'/1'/1/3_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..2b51f30cfe212df5691953efe741325df2f02f56 GIT binary patch literal 488 zcmVP)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_public_key_m/49'/1'/1'/1/3_0_1/00000.png b/tests/snapshots/nanox/test_get_public_key_m/49'/1'/1'/1/3_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..bcb6eaba9c09b069c77350ebd7f39ae9702b9bcb GIT binary patch literal 673 zcmV;S0$%-zP)Ty z-EBa*T=_LVP4U@nfQlFoaW~Xj&+=L;sS_{R#pWGA97=WragA6=I=SkIjwWq+$$B2K z1BkPNYrn6D*5g`4SF-;MC=(9V+E6^F?>&2V2H=``n+ndH&MQaOsZr;d`KOffvvF)Y zCy3{ycARP}`uT@200000z&n|84JA(-Q9MXp{z&~`bK@c_UR%XJ#j)B#(xE%|=|mou z*~ce&Dt9z@f4FV!4zMn-zTq?ac(Cv4 zaB^SIWBfba^cZ}10Hy-h?F8Q63B11(?)@9oQ0;A*y>D@0hby3(-aranT{9w-+Mn`^ z@^W7Mj3~scxXNhv6YMQs?&_(=Sg!UtGV7=sDz58PvcjuA<##ZTzq1g!w@okfy> z_MX%rvJ5wr^rNYAw#}rz7PFwu!I1N6LFxA%H8hw3T}4`y$xFSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y?HO`vxM7Ol$FH$A~I^McdZUzUj8m2^UBD--ZHdN|38Y!la7y%p z0QeR22i>rpt}zq~^57XMZ0VcuJ}_A zd*mD%{F%vQXB)C_wZd?BaaPkHmu3F@0OzI+Udyvq0000alKB&*Da6!PFpZc7xeiPG zPT0u}7rOg-QUJ<4A$A=e761{ay16DxtD#>20Z8UyDaaOL!L_{7(MUnbAOHXW06-G| XY?FSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y#`IwXZvf#ah$gK`~LhQiP;GLkRJi=06i-O8j{~MUh+|QMSIl3b~&4C?g=BmvUQI z=I<7(7raayWX}jF(%Pgx6Wl6dA^QGi2eb~u?qMsYtX*)lg2VHm%i(E%^TE?9@A zuL0xNH%|%Xwx|?4`}(PyyP=b;(Cu0)eJrOS{iCBusc%5*XG>j(BDU#&AJe}nwsOyH q`~7h<1w9oU00000000003;6{|sbSt^8CgsK0000Ar-C6KkUw$D9Bas*F%x^NfG ze_elE%zHvYm&}6T#|;1gtk+IC)I3$KADF#*+vC0C6~jTSCrp!Kv{@b}LT>a@*>)cv z*^YL&w-+nWgJwaVui4%gR=e_Z_S^Wb#r=hAK~lSPoPw5f)6}}#zcVO7y_(=}@su^Q zWg=F%2bG{XwRR7R_?5v|zgwG1&^oH71?KCX%C_!}>rF!sqkE3=A33O3sVPw5Gtq;g z{>Ys7*}6$4``Z|)Ci|Ol5AH-2x)cAycOtz2000000000000000006);KL>2jcgl{F Q2LJ#707*qoM6N<$f-N`P)c^nh literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_public_key_m/86'/1'/4'/1/12_0_0/00002.png b/tests/snapshots/nanox/test_get_public_key_m/86'/1'/4'/1/12_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..2b51f30cfe212df5691953efe741325df2f02f56 GIT binary patch literal 488 zcmVP)^d--*AwG`}}woP$8B8SIU8I^qq5`w>vN>pKuhT?-WNskc3+_`c5|i z+fYqF?IA2jG6C^Zx3(@)p_hPs%_E%yu>{msoVqy>OF&Ru^XM*w006)WPN{+)pIMcY~Dj|q_7``4C z%dh4iiwzZziyh7z8deDS)DbXt(CApLa8J{hCp*gziz_+Kqi{o6rT46}*lMFg%QCz{ zUk7D8IN#Gf%o1XBdlQj(%8Z-SF9FBJa#mEH|U!#!hl_DL-R1F7M8b zJ^fepz~GR0v`D@W*vUgvQ0%dLf0MZa0DvV(tSoO?;;*9{o0{>-{$lwC=hUrDdHws8 zJ^vf?V{H%H?d^MeEEwn~VVW_U7xbbw@yB^D?=AJKtzt)(iju e00000U}yg(M{|m7&jrN*0000Fhh_{#FMtqMU_{ zX5X0`0g*_z-R#?D?v)<^006gmv0JGz`x_Q%cI0n#xvLMm)nGR2_YUU{Rj29raQddocgu@F<%J1)`w8GUu)drF#oXOFGd z9`utefIKI^tRwj%bie_GpFT?4%LXG||v3vdhrQ;@#Z vD$blSEH-k|bYI03v={{d0000005AFiGA2h|m7Zv`00000NkvXXu0mjfFKfp$ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_get_public_key_m/86'/1'/4'/1/12_0_1/00000.png b/tests/snapshots/nanox/test_get_public_key_m/86'/1'/4'/1/12_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..596276aa98c524ec030a587743c547a2db457a1e GIT binary patch literal 714 zcmV;*0yX`KP)DK0Ypu2XCD8xv z_}y(lIbHcNJ{{t3w*et;Jlt%kwI1!YR@EopvWv|bpd6~QLAl0lRD+y-Tt_Qe+wwdw zkpaqC$+*Yu! z6DmBjy3xhzz)CWg0qT+(zZ-z7)lfTky}oM<(Z|GAQ*%FFa|rJ_jf|?@5Fk4;755SY=0B@)uN}K*h#Yw4&&C|C@1h6G2Kvspj^V zQs+_Y-Z_YaaZ%R|0kEdn)y6hjR28p4S9V|I>e>ucsFlhtwo=@c$}>|7QsrD*qO#M| z7KqA76(tgp_k3J>?5yuPK{aNW$pGxQ%sSAu(k9JgPjAT(g5uSXx>avSZk({ ziGGT}9#n>nR!?sy8-OUbw*H5!kLqrt`&WCi6>)W~z`gN@i>!|lJvDwRFY*6?Z)WG~ w=@IxiN(do@5JCtcgb+dqA%qY@2zev^0hk^orB-ja6951J07*qoM6N<$f@z~!FSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=YLCyMefdy-1W~8P?HcY<=Z< zw%7s0S;n>R(@=U`is+N9uL0qPqIwmCmebePo|OT}cV4D~l+$Zr%Q{tL_RK#agntX? z)^h?|C#7;Kt?2!WFaQ7m008h43ltgYBN@mxd{{|#tnpyQ+S8o6zRl*1>r87!^gd0e z4jS9oaX*-sjX590s{FfT)rhqTF#zPKQl47L9X6flwzAiib@PrrV2^uELGhbkk<{d3 zx2H5j+TBEemDgqT7Q2H!`&od*`p^}X0 zt+5-ffX{JOnS3XR!FmvbmB9Nef%jKp^}f<_uw0jBl9~h-6ZM_}Yf{}OP;e|vwhz(l zj&x|R2hR$Cq|;)kF#x?f=LVo@XGT1TS&p)-O?6*LX;LWd}Bhe|XE%$3I zMhDL91=Xj=1X<%P5I$p4jFan}u&}v+s*?jIfCHsvT#Gf6$o1V9Hv>%Gc8$W+Zuj zD2D(5zQjp2pzA>pOy-%!!1EmZ7%DZzus?2rZNAsPAGcAC*#Tu={!MHAuy;e>FSd4J{-YHcY(QO5;J{<~e9q=7F?O4)!WO}6UUdH! zS+Hz=(4})vCM2-VD4nt3W%LdvkyzeG%km#`1t_mu*zR}#jNB{EKZnW}g5-=Bym-_% z`=7%C>zxJL|9msNSMXnbQRayy^)nr>EU7olTHqoc^vG(B%bo(Id*|kR{84!`z2x6n zZ`;PkbrPvd6U}A>Y0chs_tyHmLi6kw6c{>JvYiQ=+MTFTx8d*9^V|R0+_75oZt9or zLetinU!`YMvFyLCb8XxElhO0{v2rTkNR$jMW7~4}*8a52+MC^J%KMbxPN-JRb2RNP zEsp0ebAPS3=e2G53#Z$XZAI6Yd=Y5YKJ%(KU&1ONcAAJx@!`E?Y1^<~WN}zCyXs#X zo?o6k@9c|LZskJhD8km*o@uZbHa}-B?&(7HD5C%IYmwHRbJ)2) z`V`bZme<8JnX>F>hL3vOBL0b~>J+pM|9!ySI57nP0000WkROv_^0k3i)wKWs002ov JPDHLkV1lAe!YTj& literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_message_1_0/00001.png b/tests/snapshots/nanox/test_sign_message_1_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..4ea64dab2914fd437ebb5d5ff135dd16925a83ba GIT binary patch literal 923 zcmV;M17!S(P)btwu-twuaN$>@Ad7!YlNF|;T5x{@SGk|arz?||+vp(a%QXQj=4Hxi&#l%j@f3#9_S zM3oCFs~X7Qau!>WEn$o*hS@uyj=Xy1ovgN`{BViOYwO@HWD_R1tPHNpYQ+EqSJ*p1 zrG^F*#9c9Gx^P=Ds$!^d0>P;}ppB?TFAbNS^jgwQ>JIfXx-I}#aCO;PNG#^S5@apV zDtP_DbSo9Fa47PUXk;N^Y6*J!t26r2mKRWBO_?s5+66C3h8+rmpZT&xF0*Ur&_=qf zff0H|&!z}@4lr3VbKM}$N%%0U?iU*TwO9K5NQU%66wJxtfGLZH^%hJMrzgcoBSopuxMbnGO|A4ex) z@~Ex@XR=S`fvGk&0P3Z>%U`YhobOlVXy~?>(IYRAG<2DnG3y0gA`$Aq44vs?gVZhS zZI&nXY`v=%3;=_*sUTs7q}$Tq`jdJj;XAt@033*sE1l8qbwVv6?McfGjV;8h^t5$c zg{>H*_Feb!OE8n1**}Jo>dgLOatz)iSD`m?lAL3(6`5ZDjTq@f0_zm-(5>AYurpof za#E)oN8JIF85l$L`MNIE53)}Ej8CK>Ch#@gt}OwvI998`VcUNx|53K+B>S%AkQ>@U z+E}BeraWgdt*k=+v^*LoEVAQ}7j)SkWVfoe#sE0et48CHqW~Cs?PYaA+D*X$h)w_4 z7Hhe2*0Inb58yuo7G8GwVO7BY0Ot;{d_J`rs9<@Jma}+y>$tioS^HNYjJcNBqb1OF zk|arzB+2&>{B3B=Tm%i(YL@G%Hot5~K?cOeDr3GfCh^pneA2mW>oBe)s77`-hv^w5_bWByNm2@%P zXOCJ(rTdD>#*`g>Cfy`q4NTVd-OVTdn<|-_$x%FPwXT|T{vT{&ZdKm7?8=vHL)8}# xrTODJ*w?gPT7WvPS}Q+Ek|arzBuVlS`~@8mJE*@$*MI;3002ovPDHLkV1mXpx5xkh literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_message_1_1/00000.png b/tests/snapshots/nanox/test_sign_message_1_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..1285e85e98c1394a44d0affe0f70b994a6fff8b1 GIT binary patch literal 554 zcmV+_0@eMAP)>Qn#HMdqql1x?cej0kEYgYYV}4veBNTl8aSIV zB*lA?%%1i>8U{Ax?ha_vZe}iG>Miw;qUzrJ#6##uGUD1f$ji+I2^ms5pqDeHYe(^m-YjBK3(OqE5CNXJ*>>_|9=RYp(Sp1N zZ4&pN7}2Tn5l$&zRtWwLj2^dI&^cIJ(Zy;nfyG-dLd_f^ACi`x5)tvY?G@_k zzgCJ*wSVmCJ!1L~?+ue~W-br1>NRxFdfBrim*#T!By2JpasIfNKMy~}=XIXqG>!W$ zC?k~|F(25q>)1Tc?*P$T_pczYt(*78vD=1Ro}U1b!2bQK-zcGXIzI*%lPjHJ&^|xV^n(A+cId~Jg(3=d3%p5F*@&W(= s00000000000000000000001oG7s@gS!EywZ$N&HU07*qoM6N<$f)L;RkpKVy literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_message_1_1/00001.png b/tests/snapshots/nanox/test_sign_message_1_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..e7ffedd90f5279e10fd67907e6122c12c1bbafd7 GIT binary patch literal 457 zcmV;)0XF`LP)Bo7fQz-)#Q&A!PMpz3O%n|+fjfT!4#E}eZd``R7A6>%04 z&A!Rq0acf7-Rx_VTk-<{0APxR-Amm`Z_ezOhUqW=r@`mED)n>^wO4fWLn<5k8hwp+ z*c7VQlDSFeL7Ml1+K3Zc$L1++d!-5U?%MEvn{hd75c|*Sy20_M8!B3Zc2Y_%-kP`W z6B3uv5sEp6+7}?3cGS-jo%#RmC+k+Iq6=2ZCt{yO@|m#fhCEXc001~`+bXE-Sq__* zaSL|sh|S-mJG0AswVnF_Z;Zqai5F&=srY7G+YlXo%RjEI;O00000NkvXXu0mjf&CAl) literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_0/00000.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..73cd118fdd24fc9be59f2356f1e8ca08df127b43 GIT binary patch literal 418 zcmV;T0bTxyP)d9^P)FJrgx2V?00000003YXFYf@(Q`N04 zB94)KBIN+s)LR*cA>ROO*|+I#ZcO3FJAjjlM5oJpR;p^(pZ?nvvd#dw**ncMp8iYT z8BpXpW9nD={sk@k4GrQuF2n!;0D#*?zhG2jwBt=7T`qK}MQPJ9l3UqB%TWum)1p}g zs*BRi?alV{L?r0x)y&Z)jr!G*4dB-?j;8({$DvP%NmcEkg&Tl1xFU%|wYJEGxgz`F z^p~Jw&!L^0?FhonfSUcuIy`-bb_M_d03H?RfyU^?xO1u5>s4=ezch7wE~vg-vbk8> z#gjkH2Z0WI)!*3vkSQEi5&9d4dez_CoCjkEaGmH&(AS$~0E$~QaY}Nt48Xd?i^$gS zj_99HHFU3L*(oL$_X*zVwU^~M*-s|Ux^badmY}d000000008iyKWtAmNzx`H{Qv*} M07*qoM6N<$f{cj6jsO4v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_0/00001.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..05ccaac79741aac66e30b935ffdee643ba8e1b43 GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|Jr`_=;_!R_^H9`=wn<4ooIqU_I)Z`|U##Z%AYRL;xirLie-7Wb zneWTLu$FXsoZH#5(#&i3ybCsqs%I9S3HY@|S0JDtB$JLl%jxcqAO;r(;iUPwLN|*i;g<@5<7jB47D? zn&0)uRswC`7-!68T5TO~@ZxImEZM&&&c-gQ&%QVDenG&Km$H_Xe-c)(_EzV9bbfPk z+O?)xtWVBP-=>*&Kkp^WjQ0frelwo|c`PoJ!|=Tm%Vwy85}Sb4q9e07_i0YybcN literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_0/00002.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..9d8efd1df120d50b84cd15a7884717514b7c131c GIT binary patch literal 724 zcmV;_0xSKAP)j{ZUbD*c$mB4IF76RI1Vu;-m;6$J3u&8>;~Z)vr!1iV@yYjcXiAC zJYok3X9d@OpM=umUPSL?{~3@L9I8h_syTh{*|ReMdFEv*xN^E499gGe%ro;(O6g~# zZk!X$bJ9Cby%qiZLzoak2qA>DQN6E%0;k!S@meBsw9LpD?+PuZv*OCOsubbfr#!%y z{)hqCWpN`T()vIF5WXlcu3~_$nwdAF>Wgt>yx!b}Yj#bl^tnUNUh}qNPs`mcO?qx}+GV_h2M}&ULP*LTmZV zaRy47jYG0n0a(h{0!4VD(+qJnYE54 zYw_ti9U$NBdXe`#?nKWCfZh8d?|0*U*Dli4Jm4E*@DM&B3%!?$lNp1h+~HocoFH1d z1?tC$4IPTG+4?c4;#Rz(&`1D+63qHcldjUmxQI09{f1i5X_Wv=3-Y6P*D%}l#i!}w zR;u$X^txux&b8v@Yr6jRJVYA2dAfNU6JN zy9Xrbj_K=bqU%@3a{8@;5JCtcgb+dqA%qY@2qA=!&)^>!)Ke!g;}B literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_0/00003.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..0a22ed9c048e1c509e4db8bb538a09179382d08c GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|>}8ba4!+nDh2#Am1Sc0oRKc zcL;ymuk!5?JEvmnwkuibaeJSyRt)^uD?4EpBTyF!;K^XIuI0vnmuluBIu;=7LF=pwdVFK5RvW*sptdHLn+n}@cI{$FA}Oll|ZX6|ym zv+E^4$J-}Qw*A>Az5dSkz%5cnFXPh$Okc+LNL4K2u1u2s=CbF;;vKu~m9N=9{MYha zTwZY10sZ%!KAFne?ELQTryeXiAb8GzN%q)U*^OTlbNjEn{+IM4Dt=?sgqcgH{7Q+I zR=)jKHRSoqLt7UZ8y@``d%nAfeardKTg&xoml-QN8=e+U<(-lF`shs89kuD*QImdm oYP)0002s-}zlITITZM$M#37_F*2YcQcLS@s@`23cFYdn^|)y zTYqM$SHI1Y;;$HEvD@|!IK5lmqnF*Rx2J{Eod*XllV4Xg8>*}5`!v8(^~mF;0pupq zYwB_TwWS_~G%FSpqlc*y0002EQBg=pY|?CdV17JiSwW zp_v-jf+&o`Fn15WNBWKaWTf}v!C`Uh70u(!%G94SG0k;)k9E< xUEOWZ#B@A)hE@W#z8pzb00000007{j{s6i#4}-hd;qCwc002ovPDHLkV1jp(v}6DP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_1/00001.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..cc9e51b573b9d37c00067cae1a9752839985bd45 GIT binary patch literal 359 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|`hqba4!+nDh3Ax6mO4o`%Gd zJ)ZCCm)tq(>dscF$0GFV|Jtk)tC+gvs8tc{?$+lo4MxmCclI?(@OjK zA{u;tMI70x*?e`r<(Dmf2|l68rt7%{Jy*x@#wA@?%lxh3)%`vGE`F6v=dv9i?q0C* zLgduTrU9YbvkM%!yH>fr3AtAPpEG^y0+WiJ2i15O7(UFOCgZ$1_{_hL8~^yOkdu+m!bz04_Bb=W!AUOZ%QZ|Bu7-HBoLRxf>jOxvc{P`6~_TuzHEr4r%iPCIR1 z`+H;Fob>xmbEezr$Su32-%z~U{ig8jqDrn)-x`X%C7xZl>2xaEw{uG7|D*!pZAW-# zxi0&4JH*TPt9df7&c#-pjr`Gz_5i(%3=SCOUo_*oGs|$R4@lV4)z4*}Q$iB}A#;`! literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_1/00002.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_pkh_1to1_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000d9^P)FJrgx2V?00000003YXFYf@(Q`N04 zB94)KBIN+s)LR*cA>ROO*|+I#ZcO3FJAjjlM5oJpR;p^(pZ?nvvd#dw**ncMp8iYT z8BpXpW9nD={sk@k4GrQuF2n!;0D#*?zhG2jwBt=7T`qK}MQPJ9l3UqB%TWum)1p}g zs*BRi?alV{L?r0x)y&Z)jr!G*4dB-?j;8({$DvP%NmcEkg&Tl1xFU%|wYJEGxgz`F z^p~Jw&!L^0?FhonfSUcuIy`-bb_M_d03H?RfyU^?xO1u5>s4=ezch7wE~vg-vbk8> z#gjkH2Z0WI)!*3vkSQEi5&9d4dez_CoCjkEaGmH&(AS$~0E$~QaY}Nt48Xd?i^$gS zj_99HHFU3L*(oL$_X*zVwU^~M*-s|Ux^badmY}d000000008iyKWtAmNzx`H{Qv*} M07*qoM6N<$f{cj6jsO4v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00001.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..760425304657bf273b8136e3420d3c5248b7561d GIT binary patch literal 410 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|>x2ba4!+nDh2#w9p|19*2uB zb_jplzvRu){&NOC6;q--3-&zc{_Vh{n!A_-sOiJ@kkHV@?t%{_Z5ae7%2aK)ypg^y z{vz{>psQ0Z2`;;1aqDNpvuU4nF89A&WuxQuhsz*5>F39e*qa9JPxmg551cpew&v0s zFHZ9b7wiz}wt6)C$z=XFlbY(xo6K3)HyD{-Ke=~#oc6<+Pm-gTEHKiHw^~{$zBXT? z`SSm=r;H2?N2=DmzGd_9YHD*_=<>>>yTzX)H{VO$cIL_ypZ5K~Cn*}~eEqV`Cr`d4 zRqE`zG`B||7Hv4%eZ#6;FK&Le{Q|KoK1>@=@0q!yrcK0v@mV`>7uRbO?kkGd59(>2 z_&j|+o7H_ww(S%0Z!VR2o3<~+y#9}D8I#Pk#P9^K2 z=S}F`H`{GR=RV_S3PO<@mpmuTY+lNt4-6z^u;Gk!umflBpK!TUkg%t#pUXO@geCxp Cz_pVA literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00002.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..fda030d56c962bf18cefd5b175cf5f284825a115 GIT binary patch literal 767 zcmVJK#dKP) zNf80eSi!kJrh!`A^5~uH-vi2mP4yrY&**#io}CUjM^2Z5*P1ScBlEN&lXLwkrF?B{ zyS*l;`=qsA)7pfM;q}+ zMfPx(T2*s=L>9}lp)6T{CsUS3D>oGvXpF_U8ate-@GKfWC^R4d>@!ni@X10msPj!BV7o=UmFm)0mo^3D%`wS=k%bmi23` zv5hUhBdR%{;dUp`n-^>!*Lssn5w(#n#XH~5K}B#<5tU$-1nKJQ*r|+V+0;JEp0kdr z!KBs-Mz;E~V?6BHvZI_1(sQadIXt(D`p|H2FnX>RT0?GFe_Ad`CVbqsS;cr;Qg|$4 zhMQA~51EqU$GH?Xouy?X_brxMS3qr-)pC2-MLGwt+p+lA+CGq8WG;!f+a>8bzU6>; z-tiP`-@{351J^aG=0&xNNN28SBE-lho&$G7-pj*p#PXAF510;HNH^Y50{}oacK(Z! zWbH`~#7S~Syn*bepsHO7uv3jJVUeUNNkTdYM9zrqI}p`RX-Ve*IcFtrVc8(>`X+qw xN1u6kR|h}8ba4!+nDh2#Am1Sc0oRKc zcL;ymuk!5?JEvmnwkuibaeJSyRt)^uD?4EpBTyF!;K^XIuI0vnmuluBIu;=7LF=pwdVFK5RvW*sptdHLn+n}@cI{$FA}Oll|ZX6|ym zv+E^4$J-}Qw*A>Az5dSkz%5cnFXPh$Okc+LNL4K2u1u2s=CbF;;vKu~m9N=9{MYha zTwZY10sZ%!KAFne?ELQTryeXiAb8GzN%q)U*^OTlbNjEn{+IM4Dt=?sgqcgH{7Q+I zR=)jKHRSoqLt7UZ8y@``d%nAfeardKTg&xoml-QN8=e+U<(-lF`shs89kuD*QImdm oYP)0002s-}zlITITZM$M#37_F*2YcQcLS@s@`23cFYdn^|)y zTYqM$SHI1Y;;$HEvD@|!IK5lmqnF*Rx2J{Eod*XllV4Xg8>*}5`!v8(^~mF;0pupq zYwB_TwWS_~G%FSpqlc*y0002EQBg=pY|?CdV17JiSwW zp_v-jf+&o`Fn15WNBWKaWTf}v!C`Uh70u(!%G94SG0k;)k9E< xUEOWZ#B@A)hE@W#z8pzb00000007{j{s6i#4}-hd;qCwc002ovPDHLkV1jp(v}6DP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00001.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..0a11ccdf7184c11729310cd4da5a2c8d124bcdb2 GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|{s{ba4!+nDh3AC*NTO9*4lF zuWI}LPpp})rxYo|Q^FDa>%P{)z-FHUnRcKa2A=ZSwvAGuz5cE#*L;3eo|)%xTlI0C zSww@&9^IVWPmbR=vEEJhU*H?6JL`C3$C1D?c7C%RYk2Q5zDtf%SK9ri;crkt1@8)0 ztInc5Y^!#?k;<9S)FXYwE9Lrm`^5DkBK&fCAB5N#7=HMtPg|Jxc~hL}v+FGDvr1lH zyyU;U=gIx@+gG-FntcA}xN`9Yne~6JzGQ!Y=dXx$Eoc0tj<^ZC=T5(M^qR%0^Q*3u z|2o>idg6AH4k$cMefVqz6veXyv&Ciu@lvQ_4 zzxPb%uGM{Eu5^z2HA4b;d<()=I&YYYVgwaf1Q_ c36y+hS@ib*hrM_1&IO5jy85}Sb4q9e0LUPxasU7T literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00002.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000d9^P)FJrgx2V?00000003YXFYf@(Q`N04 zB94)KBIN+s)LR*cA>ROO*|+I#ZcO3FJAjjlM5oJpR;p^(pZ?nvvd#dw**ncMp8iYT z8BpXpW9nD={sk@k4GrQuF2n!;0D#*?zhG2jwBt=7T`qK}MQPJ9l3UqB%TWum)1p}g zs*BRi?alV{L?r0x)y&Z)jr!G*4dB-?j;8({$DvP%NmcEkg&Tl1xFU%|wYJEGxgz`F z^p~Jw&!L^0?FhonfSUcuIy`-bb_M_d03H?RfyU^?xO1u5>s4=ezch7wE~vg-vbk8> z#gjkH2Z0WI)!*3vkSQEi5&9d4dez_CoCjkEaGmH&(AS$~0E$~QaY}Nt48Xd?i^$gS zj_99HHFU3L*(oL$_X*zVwU^~M*-s|Ux^badmY}d000000008iyKWtAmNzx`H{Qv*} M07*qoM6N<$f{cj6jsO4v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_0_0/00001.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..073b4ff597eccfee869a2e673a20fdc9a26808d2 GIT binary patch literal 374 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|_WMba4!+nDh2V^g1R*o`yu5 zLiIQGo_9}I&hU`p>RG&T?WcPGj>D?1r#v))nhtDpadBCcF8DydifQSTOHS{%u~lCC zEoa-PDY$a0Tw+%1;yZE@*ItCh+Q)|f+Nkl-dckkiSN-m9N)}eHsjaqZ$-8%I>$Mv% zrt@$Y>=5CW{;2Zv32S7~h3{@3d=FYXEKi$#C;d$v=Xn)t?iGJu&72j#ZO8waS8XEqzjzgN(6`Gz$@=sr zhEEH!nVvsZJDnOcy++)eS6*oAy~wfy6K+q8kgsXG9Hf7sucmBKE%&Q)4Am-g{PGK1 zZmfHA*v@>hx^qs^yQ8z%X1>@h*)r>ebuzEg#8#z3K6j-(K>s6y1IPa`?+y7|aM8si P5+v^F>gTe~DWM4f6K$a+ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_0_0/00002.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..dcf25e82e2e4c493e6cad0d5895a85127de65a18 GIT binary patch literal 701 zcmV;u0z&>p;!qt(b2aLJCUeI8%*+yU!`Z>cwG@W-Y0jD%|5 zsEa{w(Rf|nZFZbzboah5lDL)UWj}2>0Cq!<%zoN+0PMD&ItCl^T~%l|f+TYcZbhdz zekecv!&Ivja}UHrdow~ukTAo*qjiKPC!Pi1;;4Ubs5P2`C9V?t>Zad{`LCg##wX#{ zT}3x=Mv@f{>!*5pj~Klf_TCnS0Vm) z{3#MKHULAVKuo1kDbz1YmkZ17fQ2J1y3p%sih6-YCccmh`HVf_!JuzN5JCtcgb+dq jA%qY@2qA}8ba4!+nDh2#Am1Sc0oRKc zcL;ymuk!5?JEvmnwkuibaeJSyRt)^uD?4EpBTyF!;K^XIuI0vnmuluBIu;=7LF=pwdVFK5RvW*sptdHLn+n}@cI{$FA}Oll|ZX6|ym zv+E^4$J-}Qw*A>Az5dSkz%5cnFXPh$Okc+LNL4K2u1u2s=CbF;;vKu~m9N=9{MYha zTwZY10sZ%!KAFne?ELQTryeXiAb8GzN%q)U*^OTlbNjEn{+IM4Dt=?sgqcgH{7Q+I zR=)jKHRSoqLt7UZ8y@``d%nAfeardKTg&xoml-QN8=e+U<(-lF`shs89kuD*QImdm oYP)0002s-}zlITITZM$M#37_F*2YcQcLS@s@`23cFYdn^|)y zTYqM$SHI1Y;;$HEvD@|!IK5lmqnF*Rx2J{Eod*XllV4Xg8>*}5`!v8(^~mF;0pupq zYwB_TwWS_~G%FSpqlc*y0002EQBg=pY|?CdV17JiSwW zp_v-jf+&o`Fn15WNBWKaWTf}v!C`Uh70u(!%G94SG0k;)k9E< xUEOWZ#B@A)hE@W#z8pzb00000007{j{s6i#4}-hd;qCwc002ovPDHLkV1jp(v}6DP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_1_0/00001.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_1_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..1806981156ba178e3ddb67d1e79d2272e5292d32 GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|{s}ba4!+nDh2V^rk}!JPnC9 zkNr0NS54J_zR;M*$z$s&)nE1gQ?Je9)IG9<1*prXJX*HFJ@j z_u`v76AHf^diQlfoM{%*t!oiQ;Wr}mOfssM={Y_OnqSVEUR@DzgoC6Hw8qS>Nj;+7=4E~|rCv(;YD&G)vjo+!g;Q^|hb!#` d1_m-XVDMkmSZis~zQsl$VNX{-mvv4FO#rpbr#1ip literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_1_0/00002.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_1_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000d9^P)FJrgx2V?00000003YXFYf@(Q`N04 zB94)KBIN+s)LR*cA>ROO*|+I#ZcO3FJAjjlM5oJpR;p^(pZ?nvvd#dw**ncMp8iYT z8BpXpW9nD={sk@k4GrQuF2n!;0D#*?zhG2jwBt=7T`qK}MQPJ9l3UqB%TWum)1p}g zs*BRi?alV{L?r0x)y&Z)jr!G*4dB-?j;8({$DvP%NmcEkg&Tl1xFU%|wYJEGxgz`F z^p~Jw&!L^0?FhonfSUcuIy`-bb_M_d03H?RfyU^?xO1u5>s4=ezch7wE~vg-vbk8> z#gjkH2Z0WI)!*3vkSQEi5&9d4dez_CoCjkEaGmH&(AS$~0E$~QaY}Nt48Xd?i^$gS zj_99HHFU3L*(oL$_X*zVwU^~M*-s|Ux^badmY}d000000008iyKWtAmNzx`H{Qv*} M07*qoM6N<$f{cj6jsO4v literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00001.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..073b4ff597eccfee869a2e673a20fdc9a26808d2 GIT binary patch literal 374 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|_WMba4!+nDh2V^g1R*o`yu5 zLiIQGo_9}I&hU`p>RG&T?WcPGj>D?1r#v))nhtDpadBCcF8DydifQSTOHS{%u~lCC zEoa-PDY$a0Tw+%1;yZE@*ItCh+Q)|f+Nkl-dckkiSN-m9N)}eHsjaqZ$-8%I>$Mv% zrt@$Y>=5CW{;2Zv32S7~h3{@3d=FYXEKi$#C;d$v=Xn)t?iGJu&72j#ZO8waS8XEqzjzgN(6`Gz$@=sr zhEEH!nVvsZJDnOcy++)eS6*oAy~wfy6K+q8kgsXG9Hf7sucmBKE%&Q)4Am-g{PGK1 zZmfHA*v@>hx^qs^yQ8z%X1>@h*)r>ebuzEg#8#z3K6j-(K>s6y1IPa`?+y7|aM8si P5+v^F>gTe~DWM4f6K$a+ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00002.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..dcf25e82e2e4c493e6cad0d5895a85127de65a18 GIT binary patch literal 701 zcmV;u0z&>p;!qt(b2aLJCUeI8%*+yU!`Z>cwG@W-Y0jD%|5 zsEa{w(Rf|nZFZbzboah5lDL)UWj}2>0Cq!<%zoN+0PMD&ItCl^T~%l|f+TYcZbhdz zekecv!&Ivja}UHrdow~ukTAo*qjiKPC!Pi1;;4Ubs5P2`C9V?t>Zad{`LCg##wX#{ zT}3x=Mv@f{>!*5pj~Klf_TCnS0Vm) z{3#MKHULAVKuo1kDbz1YmkZ17fQ2J1y3p%sih6-YCccmh`HVf_!JuzN5JCtcgb+dq jA%qY@2qA}8ba4!+nDh2#Am1Sc0oRKc zcL;ymuk!5?JEvmnwkuibaeJSyRt)^uD?4EpBTyF!;K^XIuI0vnmuluBIu;=7LF=pwdVFK5RvW*sptdHLn+n}@cI{$FA}Oll|ZX6|ym zv+E^4$J-}Qw*A>Az5dSkz%5cnFXPh$Okc+LNL4K2u1u2s=CbF;;vKu~m9N=9{MYha zTwZY10sZ%!KAFne?ELQTryeXiAb8GzN%q)U*^OTlbNjEn{+IM4Dt=?sgqcgH{7Q+I zR=)jKHRSoqLt7UZ8y@``d%nAfeardKTg&xoml-QN8=e+U<(-lF`shs89kuD*QImdm oYP)0002s-}zlITITZM$M#37_F*2YcQcLS@s@`23cFYdn^|)y zTYqM$SHI1Y;;$HEvD@|!IK5lmqnF*Rx2J{Eod*XllV4Xg8>*}5`!v8(^~mF;0pupq zYwB_TwWS_~G%FSpqlc*y0002EQBg=pY|?CdV17JiSwW zp_v-jf+&o`Fn15WNBWKaWTf}v!C`Uh70u(!%G94SG0k;)k9E< xUEOWZ#B@A)hE@W#z8pzb00000007{j{s6i#4}-hd;qCwc002ovPDHLkV1jp(v}6DP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00001.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..1806981156ba178e3ddb67d1e79d2272e5292d32 GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|{s}ba4!+nDh2V^rk}!JPnC9 zkNr0NS54J_zR;M*$z$s&)nE1gQ?Je9)IG9<1*prXJX*HFJ@j z_u`v76AHf^diQlfoM{%*t!oiQ;Wr}mOfssM={Y_OnqSVEUR@DzgoC6Hw8qS>Nj;+7=4E~|rCv(;YD&G)vjo+!g;Q^|hb!#` d1_m-XVDMkmSZis~zQsl$VNX{-mvv4FO#rpbr#1ip literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00002.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000P@)+k+{o#AVrq>NXZ&(m-qQmF&b8C0u4@%0{{R30002H__6N5eL3f| zoKiCE$$x|#02z8I;xNP;fHV3s+|9}meyuxjlL~aWxJQ+9mg~>>&k&-{0GR2W<`GZ- zBkl}Pv5pw}BHmTd!DXlu-?0$`0000U=Y7MNh1rG=b?M_=cU7e}4SVt^`PE|Ng5@R=p%*t)sXDK%dj6!<2#O1|G}r6v;1oA2B36K1#v3Z<~cE^ zqVLXl2~tN+9o#H?;BE%g0w98*SV!vk2qLsaEypUZyKnig7>SX@;l&E(4%$(WrT2xcKZc z042mJrL$1#&6j?gY-lfMIar<5eS&vd^&+e4$)3LJE3ejfS%TbR00000006*3e@pj9 U47?QzQ~&?~07*qoM6N<$f_Fp8NB{r; literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_0/00001.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..700453f77358dbd81ba0271da35c7fdc921d320c GIT binary patch literal 374 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|_WMba4!+nDh2VF5e*qo`yt| zdo91^SC)Td=Ty|);A)qBl#ov1C zx;8K#T^eztgZ-qse8;4wI`gLZqJ7M_uH;Pq-LW_Pj`7LkPD>V;X~w_0RNHln{n(P< z+sfsDPG5ig(a$T{^KHE)WWSbJ-oPtEZ@ytVtRVb1)oP*IukMZP^G-O;tKh3v+5-#$WN;w&-u?YQ#ZINg QaD#+BUHx3vIVCg!033IwcK`qY literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_0/00002.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..6c57d4dd591edcb595d432c52143dba70d3e23c6 GIT binary patch literal 917 zcmV;G18V$>=D9~t?h z{IRQ}DfJ(%;!*spFnSPom&O!F##+r*O1YlW-*%}PeurDMQQM%-hEhr^5O~U%4@TK= zmdt?GaH9cbPi33s&?}{=fo5f83adh9K#*03uy6)2kHN7&W`PE@)uRTkkrB(n4hSDC za-`F~ImdNWrQ5cy_$BCaozC<#Kr%BjzKlG``U5iT-XyC|L3F`oiEMBoYwMM#by8F_ zfK{kR09pl2+_^u0iup^%>TAmPneTuoPm&}_lEjZo-Rx$o1S19U=a&1|rgKqO4m=aP zt{A~W9(8>S0XG=c_Z=yM2A5rD)T@^Cua&_Iy-Tb8bm|c5-MbQPmANFFW2D$^VcDde zL0U6_MFGjC&e`swgcw)zx29&RRM+@qS(Sb71Fj)i8@kZZ7<5K{uLEG>PIkYLVIaX} zYs(C-_cnW2CC0^q>&&#b0()*9deXx|l@UnFl zw9?WQmNHWX=&-l>!~XF4ym7Q;pC>cl0eDLXr3iL0VTUN=OeJqL($tk%y(rNXDJoFK z$*_Z~5ynleY65NiVbUx6(I3W)ZjCa~c$AZ%1F~$_KDY!yGhl4#Fywn_e{A5~wWdjj zr6=IWy!{Tq<2XiFqXvtII0L#NWxnB+Crk}JeVU2mTej$vD2MwqV0e203%cyv+v#0M zug0{}S)LG!C-~sv9WP`)Ow23E8>U;sha^do1m{;b$Nc&(HIsP>1+nARosNn7;3~Wd zC}?C-C`IhJst9T3817S$sv~w22aF#Ly>kP#_l;@mDRmo^hx@LyejM-sWWS~Q=(PjR z0I9{Q3T0RFWb!BI5;&_IQp9AQ#H$q^ r#Q9W1Z{~4(z&Ch;Je(v+l02P19Wsnw&}-*700000NkvXXu0mjf-*>yw literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_0/00003.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..562b8c3a7d73de03a021e86dd7b6a40d2558ecef GIT binary patch literal 504 zcmVO-XHi(D?sxm170001wQA#PL_zxNNXZ1&1 z%kD#4C#ZYxh(_z%h-m+;HjX*xq;;<@Z|g+d&foMF4eAZ3Gco7fi-NyI)jQ-oeY*K8 zKm=5*261m{Vd~6THPGVRwxoB7vwDl>M^P(4bk{leueDGI*BNe6?bPI$D{26y&y;qi z*JE=`eCI_y)s{WICa0ipzw1O^C)#b^@}9GFGcJPXdupin zsklJMcC^9X-R*7o_@}43IES^?@btPAZOz4qMi7i|4c`*+w*s9gr&S`x6w z=0a2J7sTom)Z^dF^gA-o=DRn$3_uDP1F<<;=NyrLZX{FCf^MCPvOOwx;`XO?bx$>t`F?6Bp*+#>Hie;far@KWQ^ZuZl^ziwpypp)(tgdu)rY5 uj6o>E3jhEB000000000000000g!uq`W2>+d#rh`z0000hKx> literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_0/00004.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_0/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..0a22ed9c048e1c509e4db8bb538a09179382d08c GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|>}8ba4!+nDh2#Am1Sc0oRKc zcL;ymuk!5?JEvmnwkuibaeJSyRt)^uD?4EpBTyF!;K^XIuI0vnmuluBIu;=7LF=pwdVFK5RvW*sptdHLn+n}@cI{$FA}Oll|ZX6|ym zv+E^4$J-}Qw*A>Az5dSkz%5cnFXPh$Okc+LNL4K2u1u2s=CbF;;vKu~m9N=9{MYha zTwZY10sZ%!KAFne?ELQTryeXiAb8GzN%q)U*^OTlbNjEn{+IM4Dt=?sgqcgH{7Q+I zR=)jKHRSoqLt7UZ8y@``d%nAfeardKTg&xoml-QN8=e+U<(-lF`shs89kuD*QImdm oYP)0002s-}zlITITZM$M#37_F*2YcQcLS@s@`23cFYdn^|)y zTYqM$SHI1Y;;$HEvD@|!IK5lmqnF*Rx2J{Eod*XllV4Xg8>*}5`!v8(^~mF;0pupq zYwB_TwWS_~G%FSpqlc*y0002EQBg=pY|?CdV17JiSwW zp_v-jf+&o`Fn15WNBWKaWTf}v!C`Uh70u(!%G94SG0k;)k9E< xUEOWZ#B@A)hE@W#z8pzb00000007{j{s6i#4}-hd;qCwc002ovPDHLkV1jp(v}6DP literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_1/00001.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..53d797266cb3ed3c2a86d4d076d29d4f3c5e0b67 GIT binary patch literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|@9jba4!+nDh2V?xbb~o`%G- z<>n{<_8*D;)^03m=CVQ8DdYb0>Aq`^Dafm;0(B+qntzpZ%ab{$`;|6nP5x~Yrhei3 z#L{qSlZL=D?%df{FXo9|c>jv!SJAnsvyUBIPHF8v*vxkLRsvr^{AV-4n@ic>n6oVX z&wABqw$}9A3B`Q3*`#?KPw6Ht-t_VK{4Li7LfH7_4LF$@7;2U?o(?EKziDs8n)9Cb zk}k%!&8sz4DN=n~mUMbX*0tMg>C&8cD;@_q^W9;Yx9hic*)MgQn3nJ#$M!00f9_WC zOmFh?N`bqnQlE6p%^dbxPfO~XXPb8H(lg0Vc4y_99!;++GXML^Qen~b^lw$7OMIUE zl0EzL*^RxAHw&77E|W^XzH`y%)rzmRw#*fq`O5$Clv%I*-K5tX(byvN`GeOKabQRw bgB@q(m)ug6ywthW8YJxL>gTe~DWM4fBlD&g literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_1/00002.png b/tests/snapshots/nanox/test_sign_psbt_singlesig_wpkh_2to2_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_0/00001.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..538f3218042a9c109feb262a20e2e64009b25057 GIT binary patch literal 8810 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 VyH|PRfRE7dfDFy=pl`eV{a>X>YK8y+ literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_1/00001.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..746852babe56dd942b18f9e440877cf9bdfd83f6 GIT binary patch literal 7127 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 J;tA-@{{rt_E?fWr literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_2/00000.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_2/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..13499fcc9366bb214269b05db05ce8ae4380ce24 GIT binary patch literal 5035 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_0/00000.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..00c634ffe88af03190fd5e8f27080725368bf29a GIT binary patch literal 9271 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_0/00001.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..538f3218042a9c109feb262a20e2e64009b25057 GIT binary patch literal 8810 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 bJ%n^@z4q>7pB3=s3!9;y>D{tB&f)(9{b41a literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_1/00001.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..f82843b86d59ccc8753f0d1c4c13a3cf5d67d832 GIT binary patch literal 7123 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_0/00000.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..00c634ffe88af03190fd5e8f27080725368bf29a GIT binary patch literal 9271 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_0/00001.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..538f3218042a9c109feb262a20e2e64009b25057 GIT binary patch literal 8810 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_1/00001.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..1d4e1de778297ffe7ec6b06a8ba109b30d639942 GIT binary patch literal 7393 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00000.png b/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..00c634ffe88af03190fd5e8f27080725368bf29a GIT binary patch literal 9271 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00001.png b/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..538f3218042a9c109feb262a20e2e64009b25057 GIT binary patch literal 8810 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 MdM0Hvj+t literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00001.png b/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..a5d6f39400111fe3147779f50066e5c3e0e04273 GIT binary patch literal 7845 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

e<>8+PV+c37lwd*_8Z z06L!su*^O0g|*ob)2|$cZ!0@pKg?mdVxC%UazE%Dr8cP#?qDnFcDUxi?9h|A%M8?d zU4eD-qEc=g?~m~YsejxD1nd@NW_`-v)J*ZxA= z>iPG?nSb`6f5Kx|s?|+jK#2#W3LrZ`l$sY8j^Lq1+5kQPD(#AH3!%@IYorUdmkqrR z$p_%GHXIKq$`8)G;m0DfiWdo7n1xm*kl|70>SgJ{xl0$zyW&)^0$L`bVbYO!q!hn5t-Q>KqL#*Bq9KTU}h(d9y=m)^uO`R`UfoucH z43`^tVpmrX4!A_lE(^(z?ZWC&*rG`wJZBnETXMM5$O?Dt4sBDLv3n}5hYF}XZ!LNd zu49?L(rF~myg~z)N`y3iEe0crbOM7>${orrN3uGAnM9d~4W)|yEa)zY!Pn>kTT@3` zhQWyU6lnMZy{C+EK(h@I1qgQ`NQ3*|za#_U0%$!5?lK!AeS``dYSZeZJ%ENGthTka zRqbxF{J0>OTi342>bM49y-r}ZwM;peXsr3rW%*rZW@db$X+bwIxs*q5a?Zs_TjVhpCI z7i$OrzNDFR-DJ>4xFY2?|C|8T^CI{eNlIssifoOrIp@YC0C1xomuLuA<^BBD}Xt>dG+OezX z`VJs!o)K_^bl+65M3NKVHs0uB6*@X?-j6wUeVq5!+=k8c>%G_Rc;6~l}x=_=CV#B`X z0LzQnDL;sgv;=>kT+GAn0=+hq=`HhirU4Mj6%31iDdOj}r3RmLrpcp}_5G9vArJnd z7~h78;I^y?wVS2i^ zkU!x&P=y5BHOI(4(JI?J&Bg>(fOsbRUKWdANGhahDj1&HJRTL1t6 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_2/00000.png b/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_2/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..13499fcc9366bb214269b05db05ce8ae4380ce24 GIT binary patch literal 5035 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_0/00000.png b/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..00c634ffe88af03190fd5e8f27080725368bf29a GIT binary patch literal 9271 zcmeHtdpMK-|G%VCgd$NwrBaqd%5g~LttCntmUEKGoXwe#$|1`6v?;{fVGhHX(?}@8 zL{802IjmuG7>3z=Z}02(`{(=5=emB^_51#Qf4uk4z1`RLdfu;l&%@(z$J{qDJbdWH zAs!x{!;ssz9`Nw&dB?-U`+=VqIHPs1sg#H3EEjT1|6xE5oxGTt*TP<3UI-02VSlIf zXeA$LkI_E|{X6fD7VydM0S>dQ$t`yVXy?|C?}R|S^nyw$U*uV;-09ZbL7JGs`#mq} zSUa{hdw4S9T6sV0kJxwpFt5Oi6MW)4*Z4s^t|FE^KV&O;{?@nOb3f|eFZ_ES{>_K~ zv%2UEuPEp7eNMu9*T6|wbm#~ZOkwE|1=^MQBb5d1ETJJhyaGlw@N6d-ifTMqe{jgI ztmKm8T~o1@J0g5uQii6}ffK?*$7H67G~d{~KSM(=P8a~^P}I#^CcQ@tzAp#JVLe4V zE0rxs*zDe?)niX!2-JxP#vj{%Ev>B?m49d7ONg zgb!GnfN8Q;ge3LY0deQowoqA^>7r- z69|%Pr5%N$+9;+IX3nJNZ?$;DzYmYDsf?7Z#62ZhGj*n~$c6|qhF|QA(GlvGJxIo; zV&B%7?wGIWr}2X~-AITwz8_e49f`gf(o!p{do*I7W4sG#czyEe9A&zletN(D{WK?2 zG3@L54XrPE^5bih>SrtMd+5Cijy+-cijqr$?NubvefpCqDL2wEv&o6m2qqo`NibgT zbG%E!+S%E~#Thxe&VGiaUCyYO479Zw83zjpHnflblw6RIx+4=;ppoE#q}X#OCVe3@ zOE7*=hIVzUj;j2$qDASDYa>}m$mWwv(DSF{%#sa3KJm03HP1D}bh(18!f(uw>M_BI z`Af!w*@gIf6tFa&FJg^E4j27i)ry(6wcympOa*Yw7nq=>>?4+VGUsCd!LqhZbMK1M zzPLIR{dDDZdk(@MTRB}7MKBMT2S4By;2ZW}{cVIqSGCUh^Be??$HwI2$w=1oMgRGM zt81Zn`Pf32Co}pYa*%;Utku13l|Mq~6S#x0po znXSE+s>ckf9-*aeWkSFWFD=XUKI${}i@y5xMXHpJAb{?JZrVHG!t7589gwU`(%$Uw z8n>Gb0Au0orPsHo)IS()kjOp;%U=XRIJ@1vcT+>Qc@vp^RG*zlRFV0y+=$jKx_D7* zkEG=l>mj{1XBktkL2-}Ek-|5D-Nngt`mM!EJztt7I7m!nrPlnjXZ3yNNpdSaZOVd! zSLsdKDj+|qn^K$3cIyYWhyQbX9I?a8n1bP)hWQYaVat-w95@Ju8NATI^lI~yB)O<| zplsJF2ri`c;mmnpMS=M`CYZ?LXr|MQ?T-8kw9P7X$?6WZcawhGF^)E?dS=@uVyWDD z%k=7nN-POY4b&HT>7b!<&9{s=>NPL=z@s5hT=$sGjSP(h=k-HQpQ&MZyNZ$Bl~(0f(FqvP0grO!PUE_@pk{lJ zTRb(;&xV4R4msNJa^v+~OFMI{OBRTLCDCv0uN=7gNp-hH*my}@fUNw~l7oEyfml6a zDeZ^;jj9MaA~T`utV{GkKJh|1$b*qJ;U{T} zY(E=S_h=VB@$z@y?i1&wgHSBTDtfz3 zUEq27oYH2bZt+(gAj?Mnd4=I+tYrxpy>M>X$oxO0*wWGxn-}nx@lPze^O~`$&GuYE zldu7lBT_U-JE=N)55ym-Nhor0jmsfYoh=r(ofluoq32bhYb zI^paMCtl~3gb6;f^cmY5_B8Gy(TD9L@rqb7Y=@$b*~YM|pJkmVTwzl-Dx61LZ=k62 zYYi0T%!&7T@`y$mHUBo;LOeLnj9OUT588)|?^*AA>uk@w;SU=gQE>WYO+z;EEp+UVhF?nAP*V2SVD>H^Y zqcjre{g5;#$D0K2gu7u3){F6u6>$0y6(TcI_D$Y1H>m>oLz=i*c1!#lCz!dI0SODt zre_bsCC6SiotrN%=@xoArd(Sw8X0OlIGPH6vZRnOMRs?#U~~qB8@in%KdT-RYVT)p zxaWUjFUNj1C$Tv4vHQ~(Qo1o^aI4~*B76=K37jFxvXUl6XzK6vW9;8KS@t|OpR;>t z#~L_oRjP)LT_IuyQ3eZbA_k^5BaCHHgZCiE_U|pf6B^gX+OAo7J}#OCIoi;V##Sjg zgd1v6r?j^6?I}~ao)WJ_^8*~i?K|(Rm0ns{R4_JU;mb{q^ysHAsrdv&yN6d&9=nnd z&9;ry1uZA_?A}$_S2}_{s+*#dbN)PJ44L&zb>a(>cYV~>hlB+N-GZoM?BnXORe!TP zI4VN>lX>Y7#^pHxbSmvpR1zK0b}0PXBg;CB40)2KS9e)9+(vsmN;P2$15!#ivKeuY z`#_1U$~<%MPasNg@2Nz?;4s&vicnaZ6YOW|0sZ^j8MPU=N}=J+;pBJ=E6a33N0<=j zRp(>^kQ>ZRH~%jz4$}^)R!qt{*uLbeHRMN6yLQuY-Mv^o78o=(Bfv5aVc*Awhs4uX z*&&pBgAZLvkZlyxPo#T7u*N=p84yHY%x!OxQepX&6^9=II zxNc8g2+?gcbfl7L`igAE=rpMA;&cl`n#XbKF^ey)(Ts!NTt~Nk&uh_CB}d6huo+}g zON3mbjOgdEBu2%gYjG9+rVsD)%ENwsaS~r7hI_{sA3J~ea%$8Y|NFB}@MyTj=w5HP zlsSk6=(WQ$3zB4475h)%#NG>C7EnJ8sm{N$(p<7Sg-qT;p+Rr_Y)FYgCKp+2*>ekQ z?&R2YcG3J?YO1FS+95_GVaAG-IX)Sd%D(VwT<`=ttD&84Jh+OVCpL1=LXKwEyr<$w z&#U)#5)_r^;`c~8W);4_TUO#)M>=NkJ=3rugMBb@2pfL5x9362BEf@RXf)O}tH`IX ztk#-%kZ<^?T4lV7foZ+-*a9!-f%|Rr$b6}lBv=`B+|pDGV*d?yBe;O9$#E^aj3c|x zyy<0v37FS4B4!$!Ye|Ddx)$jDEi6m-a8{#+c%28Zg{WdZiCYKe%5vJmipkv%}VRyNeVS1 zmrgiF$_8|rHn@FtiDWz5KknQ5<*6Yhgox1mG_D$B-OIhfH|&l5{@w|;6Z=~?6Q!t^ zNDeQTj|IjpFxi7!!gaH;3=^IFKqoFoL^_q1(J>GeW$ewwbHWz6y??A9>(~rk2tAPz z)%wWY)4gxCZVdT!2%k{qlGXe4top+MsAx}f)m(dpjF`7@46x{=R5bh#&Ogx;S6zxF z!7o%J8j)~$+{xOaD>D}TFaW{S$#jfD?rjTpR;DG}Iyk?guF^JT`4>{&fQdWXo1$G+ zR~2LPJlSWJz{+{@-p{?A!LOJ-zj%$~eqMwmwf~a+#08czFcslTLSr8S(?VnO#U_7QV}Z*YS0AN%xY_59SEcZ8 z=?FcdPN1{2FRN6=JECuU4~W8oV>0mh_CQ9ZHfSP*hae zbiBmG;a#rs4O6C?4((gTm*}?2HoR0W^e?_IW-xefe2;CUxOluuXP;fFmqK6MFP$R* z0L@Sql(g$&=Ns|=2Ng)vF#KBZyf%g95$fKn;}qcpAYfOZ88_QjjLh#7rs0Y}m4g3W zOY%&+pP46LQi2hVe@}I?(ScZqMTf@!4es&d1~yv}eny8<(yfNSMwOAUZ}a}%=~oW4 zEDpWX+oN-3M_21UYCUMp>ykk1WOI&5k;k+CK#5#n;8i_v6y_QYuCm#r*~o3yX(xJU zEf8b=XXy50F$1J=yw0j}Y#w3e3f9c=;uJf~W+d@ar1~v;n&+BJp}xqfQL2;X_lKIf zMA3-a`m&Rj$k!bW5q>!9{W9m~8Q<-n8mC|BT;2Oj|47pXUZXuM)54a;T%xmP5&`2Y z+`+9FfXf(|`s(HqFyLI`z_=%ceqi`FMy*orJD3=k_a^|{J(xj%?A|-2p-5Qq#{KZ4 z|K+0>Jrl8lHCKBEpat}Uq92iG0<8GbfJr9}F7HgxVr8mxz;ob$W`N~6k*zK#)+Qx% z<=b=`tNha4`5gcjVz}Y`VI#GN@6>hFeBhrDkNDI+u-TRND7 z!jxC31P2e*0Letm`1|JIRW;w=8fgbw%%N*QRlafn^36@N6vm?QC1uBCDl6l~MBqqhGbPGLPo9mo1@1sRC7IV<>x);27Sg21EUR!p%ag>9 zj6^<($&-g14Q8gv$GVMi+nVYZa$2_-25_k^?`8+*Mx@IhMx(w+fy*VCXm*fu=g$Ai zPSK))5Q=~HK@P?-SvrJ*w^rOOn1!C!EtHo)Y+K;^;Go8SkK@%qLW(+C9(w68ic^Vt zGqo}IZ36>JmZRO(kIj3w#ZY0TBX2S&${FXqr0f)rvoN>n%&~s76|j==U_&|Eu=lLV|CCXY`BZP20x7ALY^~|OuDI`xj<3j(a#!jMl z`P7I1*tGt8Kl)eO{#WDwAM`r7!G8O6@1Uq~lC2FW_6(63_CXhK4u!(fBpnmFrb_1{ z4bN0c7nhV2x|A!<2HJ`l=-tmvC@BFGnV~yWU?@asL&c)EXZ|j^#28=^!_EH{BjuY4>9|X{!bAmSW7i z<+@Bm-}W$>a3z^@wKu-qT}Ww6va%p4X>%GfaEtW^BGw+m(xA{8p&@olu3QZJlSkH5 zJjJLB03}}|PDjet|4exomTWVGXrv!^BdvRC)OX<**`{K>Jzv7Sh|J#_46)qmV`DHP z^NBM#x?Q;jK14%e6sn>asutRo!+=^1CrKxEnFw_&eJ2CE(sL_YGFC?aN)>t?B`C~p zk>S%9;X_fs?NP-x3C4c=+?i2Q(kYGw6MYVh6u3E;!GVhrCAN^R_Wttx%G{o_t?&5c zj-o=;aIcrqR_~+fhu#7VV)R@E<3|Q-aKNI8gG@U4XPLYFOp#)5B8yNcMCF#zcNNE5Q5hDSSSkh|U^42$XuplME6 zr1zkCfdJ5swG=?HH})R_qI@VVZBAWyScJ=Rf|-gjTBb~aF!77*t|=8rQXk~zxBRwE zYX^yj<_okS0E}KBe0?ZLQ@~Y_P+2+d+471P`!Ay8Vru;5oR7PGO4eVo(_XI`-D{zs zJ(Orf6UM@=#5#1K1~L(AcLowALY^;e(A4wYcAn2>1m#LSj6z;?@x5CSm=};$*fnK3 z(cq^LMU`0y*t`{5sDr2#)jp>*pb(6Xj9!2= zbPS4}qwUYXrKa9I8}pmZ39BRF0viGp^u8q&`~5Bs@Ai0Hp^fA|E;Kz*C(7`{)%+)@0x8q=-?f^CjVXZY(MS$L zQ4^ZvAZM6(?Q1GbcXDc>OHsY`rDxo?AGPbe=S|3GWAi|SpI9;-ff%?c@d~LbhbY>@ z-*UVw!l#70+~u4fy>`XhaF6E1lcxaSa*!|yAvk3<-hH25b12fDOMg6Ywe~l z&Hyjw+WXCSJ_$QvUbIgQ$t#PLZnU z892l*hw2HoTUZ<*8rX9HMC4v)rHQp+b957?rj|F79+4~LV*$-CJ|^!?>sEm8!SLuj zdGk`J9{N_A6Cm`zF69GVw-42Iu>##bP(BoF`ze8q*uiN!Tm1GwiS(a!aAhPwd*Rk3ldEH{A_m`kbA@V7SL#}46?%h%QR>*9%@C8phYhjo1|+KmpY{$w zUX2DwR~KKxt%0&D0U4>I6n6zb1k`=q&qV1w z#9KF)yfioc##n*Ex>sZdOH+H$i>HT@>f`eM1`!&{$?!3^bCqGoc<0;4QfR)c!c?bB zIS9ZVb&;oTVCd)7Z_PDejT$OgcB`Qj8+53SV0)heQUU`x!PmB$v~gRoAzVY-aP_>t zi0@w&<*|8R>GOa?rAN=8;F%Ad-y^RQ)5Iv^$HF zM59^GFO7*|ClIfC+-d-?u`daG!gz4J+P@$8Q$5$;wbT~ZlHK91;MibDf6tkkg2^+L zx;b#dbf7MR1I)5_ik1?u24H{)nq-cm8kmZ0*VVF3>s=q*v1fQI+vY4NE?7WtpFj)-gFg^k*QwP*Pw z0dqIbM)A1+ySOpST!1inc!8yfRG%W~IW)SVT)TpB3NsEU{FA4rU>H=}^Mi1!Z;E4h zjqei4au8S=761WAlMC4egjuA1oF1Ur>>yj6lfVBh%U?dReSJTAc09--!fJ7NslfI6 mkzK^-dvMSHvnN5g!tXrS(rPk8M}Y@|cpwHQx5{tWNB$Rr`r<+W literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_0/00001.png b/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..538f3218042a9c109feb262a20e2e64009b25057 GIT binary patch literal 8810 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_1/00001.png b/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..97d95bf286dacb200942c23bf032c259cbca15db GIT binary patch literal 7548 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 a>Nz)>YhLk5I0trBRZcm$o~$~Kyz)P^UNF!A literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_2/00000.png b/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_2/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..13499fcc9366bb214269b05db05ce8ae4380ce24 GIT binary patch literal 5035 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/84'/1'/2'/0/10_0_0/00000.png b/tests/snapshots/stax/test_get_public_key_m/84'/1'/2'/0/10_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..00c634ffe88af03190fd5e8f27080725368bf29a GIT binary patch literal 9271 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/84'/1'/2'/0/10_0_0/00001.png b/tests/snapshots/stax/test_get_public_key_m/84'/1'/2'/0/10_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..0ba005e17c141adb6d507f12ee201932a0fa0ebe GIT binary patch literal 13624 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�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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_0/00000.png b/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..00c634ffe88af03190fd5e8f27080725368bf29a GIT binary patch literal 9271 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_0/00001.png b/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..538f3218042a9c109feb262a20e2e64009b25057 GIT binary patch literal 8810 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˹KY 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 E1BN$182|tP literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_1/00001.png b/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_1/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..7df57e9e77399eb7829336ab46ba34f62b6e2394 GIT binary patch literal 7795 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 G`#%7oK)o3N literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_2/00000.png b/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_2/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..13499fcc9366bb214269b05db05ce8ae4380ce24 GIT binary patch literal 5035 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_message_0_0/00000.png b/tests/snapshots/stax/test_sign_message_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..00c634ffe88af03190fd5e8f27080725368bf29a GIT binary patch literal 9271 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_message_0_0/00001.png b/tests/snapshots/stax/test_sign_message_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..6b7c4de4283c4cbc3a83181fb1434f647894ed54 GIT binary patch literal 14119 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_message_0_1/00000.png b/tests/snapshots/stax/test_sign_message_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..13499fcc9366bb214269b05db05ce8ae4380ce24 GIT binary patch literal 5035 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_message_1_0/00000.png b/tests/snapshots/stax/test_sign_message_1_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..25b48b6b1ad0dde224bc7e7f0dffcac5f1de12f6 GIT binary patch literal 8620 zcmeHN`#;nD-=|a#AyLkzD@wJCL~S|NRq87jQq6gD*o8FA9Ov96QI1`@qR3pA`qJev zrx<3$GDWOfHf*C2(%3AAjm_L2*M0v9_vwf0r#&8@?fv?^53kqzd3f#qRhP@kiaLri zGBV1J|GIchMn?95jLeQd;&L8Orm}5+lcwN>|p6PMP$(XKPzvu#s4HEZp-2Cor6O z$?cP69?{sb(1zL!wxCGfw@%%a{9S>zNfw6BLQ6XE+z#B=Pp6x}%*D80lpq|fgZQ92 zxM}g=OjC8WHR^za8=L_Gfoev+Nwa#zhMsK$!OiOu$x2dO!BkVrSeSvh0Sl8;nrxt_ zrlv*^nB5SK@dyGiVsFdRkLh=h!C)z=sc~>2q5MsV0Bx`KTn(H%9(IPiy3xPejy^sV zOy(UrvJdRrIu?dIH8B=Juv9|IA2h|f*XfnqHJ4LLVJ@!Wyp0{BpnBhJTnoS8!e3P1 zTKl&B&aHqtQgqm(Ag_{2A{%&hyU!F9r&bSyoXh-r$Wv56rBbaeILt3D1NSR#5}5i0 z{mbjV8hxt;$T~RqpfF4Uq1w~C70>-67#o;pO�xWweNUjNfTRb64)+xzNXV_W|Ft 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_message_1_0/00001.png b/tests/snapshots/stax/test_sign_message_1_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..bbf4f05a8c9259cc3f951f26f2447a14c0645742 GIT binary patch literal 15024 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 Bs!IR> literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_message_1_0/00002.png b/tests/snapshots/stax/test_sign_message_1_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..45566d4ec16b906960c67010f64ba5d4c3ee02ae GIT binary patch literal 9017 zcmeI2c|4SF`}ZYlvXrup5J^kWE*B| zWva1Mma)VnF)_x_m>G=WclqAGf1dxJ`+lB3?my1gYhLGdUFUL~$9W!~<9*JPE0?Uq z_bBY)+=@ZB3{xbCo{`!TF*=`=sEF+ zipcRR@h8UpfmbHA3E&hXLWx*YVLgCkxcUAV-#uxirV)^WtIQOqd`6MG9Y8S8b zwzdd!mv&Y5YN0Kw_h+(?Ukdx%$@~ZZ@-5~-caaNU!LOszR=zTEw*Lp{p%%C%`s~X2I(Yeq6_&4e_F(D75*I$7l_KreuUz<)Ik=kjTR%9SuOYCSvT?qyJSYnowpWdW44>VF|DehLlgsIN+P-1of6JM>UXUi!welZ@T?Ny2>S5NExLt zix3}@qIV8}&Q|B$w|*fDN__K5cIPXoiJ%AP&o|zaWqWv3;;Ne_=wYp9g#(f!Hb*l{ z<~bZrU{h4I!x~6H>L-v=s^>#yBch50IwLIGIO(rOk4;q4N}5U;Zl5VJW7B{z(r70Xa*l2Kw`nQcXye@qQ;JWfwN*US9wDglx2 zL_2aMYcd=kbx+@KStC%wBM%KQ7bS&hxG>P|aW*`!L_jQw>0tph!~&M)7lzh3^iivD zfGWy72qGROrKR6~kiT?=6S&tPbjgNc>nNAV=?}URd-Xc{HPjxyH_~32m}0u&)iWsqShA?Cu+17s=A`*Atz@1T8~n^!(v z6yYwE1##;OYXzp9oIjf~YsI+Aa&FDrW|}esFY1&C z%=wdB4}$p^^oIG1L|{-RY%aidOjPY|>F{@Z$QKUJC`Hj+Y4kYjM}T&6$QrOPg-cWJ zW0a?!iV$xuxC;3T<5DN_tQL~bt1{?DtI8344p`>5=Au>asAOLyv+#Okd5;JCMoL3K zM8u@-qj_`^9L<_Pwq$>=3=GOQL z9z)-rwad`+WT+8nX(P$^)GdxYMBui6oTJSwk}w&_z&+V2kK{4vVHH&UoOHwA+YOxG zv><}@U}%?bl}4d7zg9N{tXZ5fbsRxnL9vC=I1Bc74ll->^j+)2@*Wuj(Un4V>!k&> zd=70uAoCR6J>t>`UIX+#zTpsTEp^6-6O)|0lri>RuQPAOZf|7y!cE)w(8ca9a|28t zJYEg&@iyodTc6J1x)9!uP1y@+vOQkE)=cV8*IKQkv6)Og4>y&fYhgkqqPW4)2G;-t7a2KAu@i?n^4V^G8#X zcA@qQ9o|>uBzLCvi)|rl+S?=zL_D2;X=u-G5t+pE4%f0~#qwrxfi78#Oe{cjZ>KQ;Iqc)hYmlD2(C5Q0bMq#9c*i`TX%nF7c6B)-TI_$5-5^hOzTAh!Pg^!6d&+0A%~vY8DyOa`TTV`G{|=BrObu~hu zlV4Sc`~R(qD5$8W;i@TknGTyxBxlb>M<}#_3Wd&ZBj98Xij3e^#~OiBh;JN^B^4Q^ zxV_8jh(!HwVDg;*V`>hP$R-u@)X0d-rRfZAGKq!*_PoJ%6y8;dh+MkP?@!d2zWb=# zqjfS22vSh!Fc7dn63HYbqVB``ZE^RL2BJYa7{qlcfk>TVLrMD&KwmVRhunCRecJg) z&*&EJG6DM~%F6w)W4~itt1;d#o~gsL_s8gAJ~c8EsE(_3)<(agA(+@E|Kf~4rrOr~ zneD!Lggbq4sqZzWrSwAonAR``&kQips=vQ?dqW(D3Xg&gmQ=qz`7W1dvfa2qM#^zk=OL}sq?E0W3PP#Zyudm$07 z^bV0+Kmf$^EsnL2`36aiqh^{gW?ot__dE!ll>`D=a{B7%;Uzk@H?n1}i9t>1%lsalAow>%~W}tZo}{`{WZn91f6a4Pe{W19Z(%l~N%KcV#px zJo$!w^Ar4pLu^)&t;2zb_;Gqu&oAe@f27euXvDc0R0ZW=>7cKj#0J{CojBe;#-1oc z2}Vi%;>OH0cH1s_Y1h^jc)N`If2&SI?lv^Y1-!2X8s+7;Eq`ZITt_V6$W-OC86$SO z`LsrfQvL(Et36R}4WBNHD2R;QWd~vU5R;loLhK)_f}~BQKv^s7_JV{!g12FYPinh;azL2(?SE$xjLtgZGNl( z*4birr$RB9#J)mW222b8Di7uk_)^k?+-|$4*D@P9F<0DWM%N+wskjhdc5TH`OsYgH=yAn^|iK(Dry5?@0Me%x<~j*aCKVngQM zCtyOWL*Qg66n;WB>JOZ{yM?o}(!iK;sSGZGK@6_EJqYMJrdIQ0Ah9>JDb`!KdJz{$ z(dP6`5VG;(=H}*xH9_spZ#2J!WDHT(ZHx&%7htXDr2~uR%}v?!h8G}j0TWvlNa^bg zq7D&*yL7;$Z&TggDhMMV(aSJxqyl50Nb{#rpy_ESwAdFnL63=v8MkcaX#6Ae0-7e6 z>)+R2^c%Sl*@bgWXRfzV7>cAq8Wh7$=um~>SJ&lM+aFQo z^C)w=in8p&-=+g5;g7FD4;#XgKiQ;$iHm<~$^kJl|M?meVXACmzFR&-nhR1421!O| z-HQ4J#n40_+)BT922SR-+qD>vQC0CRFs^fB5Tp5b{98pUNPoQ@itl;Z1xm}Op6~CK zZy-j>^^8;7{01V-&E8VEXX5i|u4y|O(i9u7olSysyRv$KSXbDJ zay@r^fLT~r$cqVzRWBu;2W&r=0THLS3rh#yze+7lSa|TyR*~rKR&d`IWSiEQS-sOO zeHZ+Y@Z?Q0TqhWm?Oi50^u;8VF8-W=grTg&*nLrpdTkw|%-Wdk{1^HKHg1~b&(I#1Kf60rEvQqded@xW75(dxebD6!Le z??@0WUnOxG(DM10x`j>0%~__}JE8KYQKNQH<);LUz7yDbKT0|z!iN%{w^?ojh>Aakqc-v@Q4o!EdlYN)z1xb8~asP-#1Z zUM@FN#3Te=fey#CZ*OfaVUBymp6PF+KKuc_ArOXZFTi(`IH;)XWmaTEcwdTX=|R^x z=ewe#>d~q6F#pStMbqX|U1!B0Vg)-aU_ar}>3z*kJns`<3%ypN+BMt!f`}rt`~}A9(R?z>XELyOVm~&Q~;x)}X1dEH1Hb#UvkifE?`~nzV zXuhrM^+pjH)o)D4VM6w-*HiahU2PgrdeqIcJJmh3tHT5i$LA>$7PpsCmANuC?4BS9 zo;>U5-4^`zgNPXHUGebe2vX8MuzQQl4J|sW!m2jz;q{2Bcd|9=o%~rB&sV*3u0Gbu zFJpD3>Ron~4p3)#v+5nW(g3JCe+PK4(sW0J1NCQDmu;fh=Tu=Ghbmt=jbBv}`PYM~ zpi|vibfn}X_gzx)?z@5->!&l>e+&PMxyFTGp9MbaIj08Wdk=g%Q5g|Y+_%Liy0iaA zO5XzdnHF9nxcq#*J>k$m2v3s2q2m9@0V2Aoc*dxjHWkGL2+#I3u6o7@TlsB2KxSrE z-ex2fX{OAC*GOb+#L+G2G@5^ZO~u8uU*V9_!B61zxlAlr&-n!De%3(|^cig(5wxhG z;fti1h%A;1n#S^L{|TUuN&f^2MKJp4JgIl>@0C+-sh^pq_E(EDW{gOnHlvgoqZIjw zYTsXvFLy&KchVC8I#IFxBPS1A|3ns0k=AK#QSjQEBo&Ts*M{7hj|LKk@?*srR3w2BRlxapk_o8k?_iz1-J(%p z{Zwo{1g4*@SsYDaY(BfsCZ?5?jU8Z_4j|yny7)d*7?4sxo)4SMlmqIU3{<}SEyjwk zcRmFeZj|*#Cp$+hUNvXg;<#&#!`tEyt14pK8MRD$X~rK^J5$5Z{4hAFhzbAOTn4m# z)MMsNQ{v$K>YAtgNRvJpF=4A1bA6*gn%C+PGZb;jZf$ioU+E>=g?>bCZ5CNat{lBN zFmc~dl!luMFhE7s1Ic%QfsX?DVm8UUb#h_lZ1?oN=5XJczAYG_O*XQepu;}c`RHf) zLIvrQfrj_18Yk{jPYvo%(!>Mqx7ij ziR3C>;i91Qoz!Owo~i(6e2{>>IC_gvo9 z0xIIfpt5YQT;-?K;(=wG1#_WfF>Zkj^W|z4M&7)U(J$ddg*0O%H`DE-FnbkaWwl|s z(@`%2o?sH7(A;DZuDB;w+pw@ty!qw{pTUwK2+m9ZL()@zDr!Lu1oPx6IS6cFx-QKC zAT69b5J#`{h1p{T!ip33?-{g?B+A zM|l=mK$y!h{}E;+l;xY!vNImr1D3vd3s%?24Y^6PxatDlkl~ESIIgAIq|FKRvRN}3 ztG0Pvk6cW)Ilg|iYh}r%ce#~DXW(C?7HcK}EXn@{G_&9W0B=IbPNNelr{;!F_g}ZD z%J}V`%VEPAP1A?kXa~Zjcly~$k4Q!-@v5~!Z%dsfZ+3m8U%A9R@^!iK^_S~q-a@1) zj;@ZQj=2Ihb->O|y>e$U}>BB_#_QScxC=!S%I*Bh>fo(Kb-#GB_(-pUD#`UJdg?hq< z4HN3&0ma94VV@(lS(d-<8Rf*Lju97)QhXmkHk(oTw*_qbcrXAsMwJ<0?5PKr6yA){ zMwGqaC$cf!`rwyv&G`n$r{Y<;$DmMXRCw?7J)PKft_HM$C_9&jfH$Sa*QFM;JQY0; zh2|?drJ836@%DL8FBGn?UP-1kn|%#$om5V>!i&F^h4@&>Wie{Z!UWIo3*J^KNymvjhA9ET`$Fu=zcNch z^y16w&(*Ev5(z*ORwMi8nP+C46#)KE-oLe~IE<*0j2^VAdlqfDK;!U+K-N^`)J?r3 z#NJCeY?#o}*Y^&E!K*Kd5hrhxzhUaI+S}<>UhUsrA%)XUq8}Qb3_2DAE%2D^%R^zq zzhV+18q3SsTpkdzW7-*QXr6_-u-*(^WW>sL@Y;ZlN#Q`U^kFgrPhs?d>IgN%9q~?W zG@iUFw1=V|C6jdPT`!|;Om<9EI{FijC6{#3YXAKFTt&J;&Szrrz zQvZ^2wW>wJF4{08S`hs7ix1wXK~$#J=w}|Q{-6e|W51~1h?aAv`!2D=MK0Q|*1${T zE(~j9SPj-ubiC0e$feG_rrnk={HrglzcVo?KvNBTCh_6khN)JCXSIB~Qzk>#&+3ZG zsP@vZ4GGtL1;nK0PmNu_RIZN}6k)do96t_K=;VK|7mRGXNm|UXsEuRY`Q>BRF5~)E z2+%lLm2%0QreMBXQvas1>0ndryRkIP7dHV2IkalTKSC~GKmU#>`F~bs23no@v@@ye zv-iu&ZMJJ@IEMrH@J!`vJE+j+C>epG#BvsXwEUxmfGd=FP9y!EQG!Q=asE`jQ!0rW z-A>U0W}^zL0AQfiM`kp3?45sc{s5I8#{CK9*HDGgN{LPgxK=TU_yo`{^)y!AKOxfC z=OsT_9+N-|Hv-vJeXb7$S-C9%w1QhrQ`VBUu}@dg1GUjS}j z00KYl?|LHp#nWLDsD&SfRkx0*b0yP;+eTcn5U#|OEyP;J?|E2dJDjnOdj*&?CStOw+NX zuKqz*d4FV%@d8I?ue44V7fNRn%h1wug`V=!`b@RyN6! zQA;fS3#Jv$e1qGCfS3A4w%lA5ewb?5HH3wC_ngp6Z=4JyH5J zrI-wj)5A&>Lh2+%6_C;w9BcPgX6kw7>f3Wu+D|K|MoRZ`Q24q=3IkCEB8s9rxHKx2 z`U2ftU4a3h@JIW8b?c2eSKYRaGr%;XDd8aC+7VaH;i7J10U})B;um&2w{ExtoFHmf zdm`Ib4Mt_UY@Z8KTu_2;XmFP7yOVxVgk}fl9p%`0UvFnvtFVngH8(FEGAtK+X2Fh%d_T z^||6%a!1C}BQMjYrqDVv9cxnzx{V^@dM)OAy7p~k1?%5HfBdq6Iy zWy$CgWtU-cMXsxz#0U_X*uRE_2AI|43c~mf3%IYV=s!8CzImW@@F=Oi=dDd@9B5V}`*nmNERUKEL}fxF6j2{op$fu9?^MI_Emi>pb7f@ji}s>Rn3{o)dy6SXfwi zOmE-1$HH>t6$=aNKb)+<9c`=5Y8DphanoCd_alo|rt!J(JNRVxaRXb{P|i?J0oLTF z;%Bam`sP<_``{(L% zLt|mn;T_WfZBZqJLfaBzE_io+y#c?nTFN(bEFsC^WD1fTfy)PDH}{`&K@-$%1KV{H zVl_xJDEh^5cK&4HlPQ%yBQjAEg-Ocn{2aPhKeGS(%Lz5VUebI5xfZK0ZF(koP7nNz z7Q6K)62#7bFd8;p99FHF`A$Z=*s>C9s(<{Mn^C0j$z!z_`wiXZ6iZ7>BfdT#kZQkz zqIF_Pq3uq!I6r6wtr8nH?bXy?DH*8;Jf*4m9=4~!cr_%iXRz^&fnP4 z$xWhu&A`lx148I=sl$;$0VX`pdTF}5cDH%1a^KAHt3ay}ZU(UR56=4X?36O&dVC^n z0@LR0S4-P+j6~Gt9lT#S<39d*Iu!=&r%oxx%;dA#rTW>Z5?olZRwAtG@D(qETbUa< zxOfkgt98=}BKi;nqKB@bIprc}HkNaVQ7Oo`wPcyJuOe1_$!{US^<-_rHm;bE3pRD@ zn~$1mrrdHp;AfjX14GYQxo2ih|_rLgw)z??FC43|xB*n*C{T=e~ zE8%Mnb`E*+%Ln?*waCuntmNtG!&4&-z1J2T?3kZSvpo--h8S|dvTGtD;!kKMs7(;= zl!PtDe%gG*n{f2+a0g^I?qn@&b~NriJ3laN`-5X~Mnms%Da#pq`?Sn=)KxUGW!s9} zD982eA2__#AN<>0pu%@5tF`?6fluf$VH3i%!Qp-g<`0e><{Xa>>jL$3ciRqeDJI(7 zsKEvHLaX3#zyee9k11yTy+i#WW|f#)=2Mn67SQ(Yyv(?GeZ7l8eJ1K%v*SR{ezqiu zH$=M_Q5&;k_I~}O=H=Lk?O)cqBWz|Rc1^%x;Xh*SR~ZMpv8#k1w2wxAH)UpenXh1y z%?w(-cYbH+sx1F-Fi9p-nSH#&k$J5a7O^0Z$m^O}=HqL756POawaS0g7Fw}^?vqJt zlnd!D_Q^vuwdK!Vi2G-RIW5m4$LP{*C7HAuNcyctsa$noQ>%&a?iurXAcVr+tnk&I z7~(?(A9fejlJn?JmB~jR*;CQmOfk--Ulkec3X`B5rOF>-*74A~>zRpL zAFWd}lgK_E&_;t8a3f{Xq!7uO#VXo)-Qr;*$fh;8=H=)4k^@6cH%MzynnLQZVH66r ze3E>1=4PL8-5OvP@h-`TP`N1o{C(%V@?SwJ(#e3om)V)es6a7mQjrhXbTKqId@7(V z-T1ZL*dPJFV!NkWkfQM|euWvR8O2Qn}f^kEUw{E$5#mc)Ol@!`;Z} zrfxG*HoG=Hxb*d35kIJuNi%A9lU;gZ@uLYLY`#74;L#Tg-G4nBwaqNAYj|CBtuj)o zUSvm-g9P9EP-UnyRlk-GoU&1_gqHFfYjZPfTu=PBbm)rLwcd9;T$zK5*LH%El*1AJ z>acVE?jEs(KX%}OD(9{anOH^0NiE8zSV!Rmiqr`Y(?$}1+vw2li3lq3HPPDXYHMFWAkzNJbj^) zqW^wUkaLsZ1XhYt$T_3+@;*{1qFpXn$Wfo}N5De{^*j>9FSMt(>v5tR-hv}CxM3Z*drG0H#XE+DY4!xnY1x6rCH1@Dc!3gkqL>eUoYsk`MRAZ3wQ^?d zt$!GC0?ENbytXLwWg~08$MoWlaf`9dBdxRG^RAumZq@6~sv!%b59JqBv7ejWHluzrA#j6fa z+|xV{7plZo8FXl7!YUeg1-#v@DzOvd%3Wd(d0K;N>RfnxrK5&Qt+QrkJ}>>dWzr~7 z!>-jD5d{t9Axk?Sa(Df@tlgaJa1Esrr<32FYCy z2l_R3@#k9#tGVJaU98J-WwI88`Pn3j(%ShExc6#Ru7v5NG0;&Y;w?4>D;LzLc#cCeuSJ ze9T-?I%~$<+CDk|@>4YU;7Q$CdrP}W;&p_>h*D1i zTK^ICER#^yARPMm(9xNj*4{)bJPsB9sgMfcP!2Mz(O1UyJf?p!-QlW=Ko~7Hsj2v4*rn5gDdPVng{Q`$J7WpT^ zCj7mxtlm_oK^K1EF88zR+Cmxf2W4lbko!Xxd@4kNsQ*J>uMzVT7X0C4Kd;mY~i>yuJeU7}FaAvkx zW0Q6YqO1C&PPBzvVbhJX_RP$q9;naX5?vjb(&%~5M9^=E?@P)DYj=$~le`K;%=F(sj9qXTkEO^#&#>;F~x|bP;XPAY;HX?TMu85x@$XL*nw??? zT%0}Q$^_!fRFAU9@E8aroCOphJFn;zt&lgacXu60g_KK*XYA>EwRCD_J*@Dnh@m5B z%&TdVy6u6hH$R`Ciy58?q0uu@{K%II7GGTID!dN-Dh`oj)mi~Amz{3GtzpAUG+Ic| z({o#y4QHTZesR1)4CXKi|j9z04(IO)bVH&vQBH;=`A-YyXd$2nId=Li&1=sjM10sK3-ArbIWa_UY z8i(Vu-rrJZ3eL7APdjjXZyu~K6`g;X8}t&g9}{2uYAUHcN-~xSF$m9=1Tvh_Yj9zE zoqv5~b(V6>Sdx1IxNr!4@aqED`FKyVx@#VI)GILlQ|RANh&J^TLXEC2sitasoVK@8 zr!5g1gzx{-O}x0jrBdX5!?FfJs!aN2!`%_Cw8O#?bLbL*GwN~hrug!B*c5!?5M=M0 z5N6#L^1u#jFr|lTuD&e*T$LOf{n3)Dgv~$7LEM2SY+drVPabG#^=GWy+PIa_SFB^2 zP2SRmtfNUknh^uDB@Z`Y6Zt2DZ1TY9#4@RpWX;9UI8g>I_qR@)q zZbaqt#@#*q?d$-#6I6%ljenB*w7%P^RMJ=vuB82zpISbU(r~}sL7JU@5eRyzyzQ!( z-)4FT!zd-4l-eHuM%ef~LYkvqd8@a&KOBL1;H-hN+o%A@v3GVlm)Y0){~OfUvpdc> z-zc8avNGV@)}V^I#Y_>XRv;?pSV9KG&xJ>4DM<6%MFFg8i)+Cq*A-d#$p<2@UlN9% z-#=74l}I_}l9f9D>G1Pj-AuZAk%r;EY+4%ps9McoK|XUJB&^iAC_7r{ecZAx07ihlFOw0?o2;m3tY)h7RfS+%I(yEX;Ju(5`^LdS_!TEJSA3$K5zip) zp!3)-ec2&c-#Zz>&WB@R#hrCdwc$zb0!Aa7`1K0YoQ!?>x|sIeC$DPB-y2oytdAp= zGUpqTv*B>hBjq2K&eGh4P#T2(djM1hdA-h&-0co8lr*I?y7s4AKXwIJTzDoHk@6E%X~w=l53Pc?+i3kT=cA4W$w9`cO3cG+FOXw7HQsTn;q@pG^4usNd( zt&%z4S8cuI^O`Fvv91{!sj%S8f1-1C%jCN8sf;)Tc6plAt&=}nKo z+g%|co${8)^8t#3M#Bc2YXyO}c6WW_8i*5*)je$d@N^ojiQroGH)4Chc{3a3+VCr( zR$o@ab?k3u}kP$MNeK9bfS zO4wd;9@qbgA<}MLD58lGWr}-z=tm}99})FPS6RtV+Ew|bS^JeJm525xVuvSQ(2WM- zd{+WjZhCB0^jxqv(?G!_>JLIfTs3w_3CQPNrNdR87SuOSSad|8(I(lFiCEP!_R4Iq zsCc5ml!ux3ROMcax;u_jWCE+ljch2UmGmOoPYsFxLqt6O;Fk#*F&8hk>Y2JnPTq7G-(gsB+kj>eSXc0&WxGb9dY+!hLD!eq}wupI;wzQy-tE5}om__p%YS+YAT@lvr$LSI~aC zxLc6WK*}(Jv9XUkgukD-3cHl z=ntwMQvO1O5X^->Hc_N1#0i43w&P10@WUqFKUxyE1^M8vS1{>76h;33L=VD+0ls!= z^vHK7PS&|Vs_wMlFuYPSB&>U!nvh+9x~M;q6`mm_t7z@*Y^6%cJM zQO_T=+O(2m7WaGUvGmyLYwE|obx-A9Sx4(~$ zeE?H^FkniUwcBWeuuM$X>}fzv`<4-C+P*bNsYwnn1?oK@Ao5aWB+r{`z=mf93&KMr zw29N`-<0i`CQZu}dzJB<>Uy?il^t`<{$^SFmFF9=zA~Bfa)YC)VGr`X&?EYi{YpcP zH8N>(gA@!yueF$K-!!`jU_VK!5MF4N#LH=Q&&=inq2ep3;G&AEs5co*u{X!)p>4yR zhE%^9V@h4G++en3gT}){<7Z*8123!XbFlg1)AsSCh=&w|LQjOp_UOec6`0VkB}ySp zHunzIkvdtg8lG?%26eggDAogxT9=U8y9aGMU1>KvVeHgEI$neN{bo(kA+Oj{nxWAY zpP2p&MCiHg9q`Fj)r6FyHsO>Db^xk{{J-nmjTPa3EooYdBO~j?zv~TH4z_hpEa}w# zHtU%zllfYLR0EFi%{k3ar_;*>@Gr8aH|^&{J7Pp$YUO`eMC(UQ5hsM*)0cc)d5W~u zqE^dQKmT$~)*6}ylEuNsNfScbY0(anvgls{%JTS;|0q)b5#IjK3XorWFbch9R|Xr& z2w38mU<%`a_YKh>KtIHGVie%fli)sy)Am{SabfsYjbi|%n>jBkll89FkFcF6wzKOH zU)q-hhu?|QT1K2iu9+Gk=Yi3Gb%KRZXFFWjDR%T6pV3Ix`Qd8vUZgIE;VbYY2E&BC zl)s-Xc@KH%qYHP!)@{qKD!D;KtscfKd%^T_v`sg)(sz$?Z+4xt#uZR?TK%QbI7F?= zu*fT$yV z3@kCll`A=r-g55XOsHRE1&~*Uk%p(9y8|UPmGPwaC68jp!)x`#s4(X&p2s`gff}^~ zpDZ2mb3w0UOLklTCL;U1#o_XLll;crZpBGY(XVF2OKh;?(Is}E+zT5^H!=!KDEAug zj;;kNzKQ)504=!AL-w6&Rg-rLSJ{v2$rtsnTr`tC>I;SLy%1XQ$J39sn&u8STW$M! zqUNn{U;_{ehcC)}_JmB9h0%YqZKFzH(cjD3zg-Ek=0mer!?Tn7VO(l|mOS&blb*n< zqkwtAiaH`mg5y|r!yxTqAOk1}-Vx!U6VuAR>BnT-@KUYF1KOkKZlZH3nBhXGQvgiB z`Cjh@Jqw#E>TPswL3)nihAWodJjEt`m1``^OiPr4sD;C0($e%<$%PBL57(;u06r<> z8qrk+|C6!skDzX0_8rvb8);)qBPCROz|M?#Et1*SoNx8Ud&)yvr{V5~xOWmS>dG8# zEKGij&m*Y5fz~L-x$xf0nV6cI4&IpCd@Vcp%#|g_q_~y8fGpeY^eeix0caPO1qER^y5w8sa9cKt>V?F z1?B*hS~3{OZ!}^P&>U^WK90TpK&$wv)XOo$h4XP+EBe>^`W`)t)hw2f@~n(`Jgt@Q z+MnuW<8>}6o<|j7;Bcr}>Ql86asJwQl5K>|oA(!Ao++IE`;rDiCjsUIjU5ZwHLb81 zPOUt++>@GgZOmJjA6QLAz{7ZZ(AX_EEy5jMxxg7cZI3V^5?MxAYz5;z!|AJFqx}vx zv+!h}pp{?F6((I+v#FS4#i5fw1#w-$;9KPf??rp)wYtr|S@X@71o(k4XXv9EB}9ySsf`2eYXma7HY z>^WRiBlnZ6cWK>j?#s2TtGbUm_7)4{q!7X4Nf|&x|R$G zdJu!bMxci5a={QovL&y*tg2+`xlsAMjvAy{(EJGcbsMs)n^q>1_Dl?jws@*?XJeU6_Zp%WS3NmSq(ub@U^jEX zh0I-2=n3SH8OMI5P^pK4J)^4rP^nChn4LZ?mpVJ|dNED_A{L1wl|t$EHcvG(&({h2 z+;r>uBsaJaNr%KgE}-oefeVXdp}fPB4@-p=!rgdI0tE~u%2^@50h*tqX@PxtPRs%u zcLWfbue)_=<^askkSI`OPOOJ^xxgxva~hj4?VW(Mvm4ur92_{EV{3Q{D9_rR%-=`H z!3h zhA4-jo7H%%2p~13p1mn$ic~5RIir|rynWt#?}fsdSxh?u-NAGOoo*rqe*eJerRE;d@PGq!qtX zByOQR)!OAv`sZ}Q*6$(lu4Z@(e#QKeZW_ew$B^|0(>`P1g>CY$3_hV8z<>l;>1NG0 zFfaw=rsj>m;9)HbDDSMEu^WmNjl4UP|efAFwec{_ZJ0_5h;Rve?jG6Y01m7 WMf+JCmw-k;7E>e3TeUabp8Y>hhU?b= literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_0/00001.png b/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..467b940319479183771b4b28b166288862907d49 GIT binary patch literal 14666 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_0/00002.png b/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..3516b6f023bef923a96ed0ed47367af75f0ed24f GIT binary patch literal 7060 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 CEI;c2 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_0/00003.png b/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..e42a0293f9ba5398da58d6025a48412e81ba360e GIT binary patch literal 11704 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 WMf+JCmw-k;7E>e3TeUabp8Y>hhU?b= literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00001.png b/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..d8ecabfc08eb37de1a575c68d7c670b8b040b524 GIT binary patch literal 15753 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 z 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00002.png b/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..ddae32d910c169ecde1d2ee93d83229b0f311de5 GIT binary patch literal 3660 zcmeH~ZB)`%9LKTMu`*@LGiQcTbGoxdYPPBK0jgEjX0Y1kC=E58o(d_n3?Bfet+o_t z$C5cRn{9cT8IUV*D5OrYp|XvU5+K&!`41KT5d!kO|F+k??}hipJ?D4tJ@@<`KHuLx z_v?@FX@M)lRw59Hz&*Qn>_;H{E+7y~t}b5!uOtz=+YyMM;5|FGeL}lz)IQo5rdv{# zTMWi;4ftUx=8KCtAFPkeS#hws@oMDm75l3%UX7gcCR#SH3I#a%uS3={#?C}cZ37*g zGkrr43WXpD23IxMTkI2lRl?Pn_3!hmR`o84TN*I*@}jYrgGCNrTrJf3B=(@ESFm*F zyqxFpdR%C2FfCxq|FUg6lO8n+eHGjPT>k^oaPQ3SJhJ)uCtmPA;B`$T-y>+XS`;pk zJ2Gu?oJ{h#Toy?@cVvv0{bs{`001hW0B9>8uT!a1rDD4I#^1$dbh?LQ2kAPUj-?+g z=xkDeP*1YEs9MF(ing;ABLyY@jZPf}f*?Ir=Dn>tYIVC)n(?ZcJm<-ZiV6n9J0b2x z(!K67u@0M(fo&u5J#_td$T~{Vt0F2T3*$JY99k%1Iq_-(&XJ@lRz)?*;(KT-$E$B4Eo*&?i!J+zdmf6xqL5rGvm&8lpj;PgYZL)q=f`fOvD~0`f37v~?bD@hW z&)?6FYf;G7)obcG9FFg?U7j4*pG4&i^9MKe!S^z>Is=n>J@&g|21DYTgfl|BuT&~c zz0^0*b*NX=Ef4Dgqd9WmP|_8@y=_X5kVd10BE1j!fDz4{5%l{b>)EAzh4^4oZZozw z=@f72v6MT>W_9>4E}1*F-t7S@3sK|ks+qP3xSTS_G-dqOCD*Q@(zaG0YT7(hvqhE= zR1ry(wYB<7S>}+Kj3Z~#`S_MvQy@2W*6N&|F3_f49x3o|`><0zN84r)#rhr_C(X}v zmt3FinwXe?QK|bt5=TxEX(mH)qkjb1EDN%hAlEn4nR54JK6KPcus12eu#A4u#gZHW zaczr602-HCm6id+6y&_E>7&#DE5}5{yF?7k{s2(R@w)8#!J>5$0{1CcL(EE|WKQd`&5n$)r-LB_*9C z-q@@aR!M%`fsPD+&Mz>I3G{o?LMQWeVjx@&=@wmRngP}jH6mhv-Y_{n`N}(Sv5pV$pJOJ#$4!?x!$I8|u1LwUJ?W9`2RcV)peM zK0Qoe&JE~@(Hy(o&StZfhWUl_DruPQxG}mR9A{0ttH@qYMECW6`IHW5)|UqV_}MOo z$9W3VT}~fQ{9fY`=_oRNiiy2uV|P@=$J~S%L;``3_i?A1eCJ?CM!T*d`>tb^k%tla_jI$9WpP8Egr+`Lm>(QTx2f&=5~>^HD^3 z#qtSJ<73uZcPE_h@*XTHD#^5ZVgEfP7`*{K1dEarlO05%P~y2%&hO=RW#QQYe^@?P z38BC@`}yDzsJQE7(bW8k5cH4;D5FvZzEjr#DCBf@-@seJ7;GaoZ@$M~ojny6a$y5; v>)9N?HPy@VmoFNNIauW2h0?;H58=MB+nW2vrAGLdh}g3ezvI^Soa%o79W1m6 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..400d335244a8747702fa0ed36faa9a5dd8d5a128 GIT binary patch literal 7650 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 Z=KZhjUiLe3fU{c-S7-P0q_e@9{|Vd$qBZ~k literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00001.png b/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..e42a0293f9ba5398da58d6025a48412e81ba360e GIT binary patch literal 11704 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 WMf+JCmw-k;7E>e3TeUabp8Y>hhU?b= literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_0_0/00001.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..b020179e587dff9e67d63b284ae8bd2cc3516428 GIT binary patch literal 13920 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_1_0/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_1_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..ed9bb0bd711a47d7be4d78796478b215a5af8fa5 GIT binary patch literal 7399 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 WMf+JCmw-k;7E>e3TeUabp8Y>hhU?b= literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00001.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..b020179e587dff9e67d63b284ae8bd2cc3516428 GIT binary patch literal 13920 zcmeIZS5#Bo+bdq>C!~NP(lwK6cH2@BtYmONRc8XKoDXG zf{4_p0Rn~ukrG{0XjHdYg!K zecZX5b+e4swM$)7La{vod_4hYnN0A*AtV%aA=oQdtRJa$D3J3 zqn}kYHk|@fE8yiG#|HZ9@bQP^Pf4~e^2S|+JKVAY-+T1Q*P-G_Z7UqFq}zx}^dX{Z zm)dHz8F59zPq^t;2>0A_BNHf^#B%EmrL_Vy%Z67PjKOktt%Yf6=&r!fDBsi`H=YET z3I4^j8ZJojoWv+U$4Skq0lBZ&f|%AKj1cuAVl#1XJ>~XLRaF&YGU>|FlNOcBD)C14 zdghP33PK!LY4nP@?P0zXp9bK*wqo@M&$gwKggy z!rbEAz|?H)k@4r8JLFuY6LxAhiH?~-S5>>y5xL_h`FGf zXjP_BL-%TzkN(%$&2XsP6T1)un^a}8_JFX&f>w<>!xOi?jtJXL_=%4bEWhoHSgd&x zETDn=&wu5Xr*-h+_m;-{rtgK`%bCuO!?plsV{{bJ-zsgybNZA}`aK=Yk@`HhaH+ zF)65ZSkHj2Y$#pXQ%RX#DHuC5bgrYn#-bCMqcD^m!v=>6%L=KOxFrOyc&dOYx+$(Xs<(nCZ_3XNa+%<>2~@3ZmoQL~SNHkRy(qGeO5Wht z@G}rc!bbRNvQhVx|L!IQH&?fP>HL#xHxTs$d6NZMgV{FpZA9K;8<`6Gbi{d+kR&Q4 zVH+aY4DEbRAFb({svq~cdjo{AmU3ms^xfZhf8`PEem8Ko8p89mKuk-S^#fNHfvrRq zO3&)=pVTvdP-nyY>x9~Pb-XXJ93mO} zZ(ZO?Fo2JBeWTnun|-xc0wgSb+18Z@;VuztG-CFvblJ7Ny}hamnaK1c&AQca9%84e zI$I;}3@Y-?>`m5m9qH9uW|2HW1Gr^>-E-@tBw@KS=d zoPtV*tY?ARaiw%W#+ zR#={8g5+*^$$~aN@Yqr|TdS&sPW?g+Zbo4)W6T{1t~?tn3cr=DYtHA|Xy@sGjU5Sz zUAGL=Ku#{*9SU_39AMQ((5IjFPeo@_#FOA6tZ~1iz%&lAx|f#*ormNwf-q$hOG2~u zEzdg`=MbG19SCt$ktT1%>~hPy+0`IT(gd%Tf};ejwvzsWBsA!PuU>d$}K-Q2 zwG^G^N{-#D)~r$zrSY!fmB6{fD^WJpP4MI?8a?_flY+k^K}>nEEu}=9t*adJ3zaDr zrP&C)eUS$$u$TrP2PBtc5XzQQqezoubI(P3Daba?C}9}A9YpJmqwgJE=?TCqSy^q1 zy_kvPs*J)m+ToNG2* zW>#u1vhx8*%R3XOlvgg8ZS>r`VR4pehgDE7E&e`V4=hLTwDk^Gsg&4=YNS^=SdFq@ zkbY~!87Bz}dkVBJ`}P8|!A7VbK9VQFRQ>J|z209$`3pHI`}WMtopo}p6;g}o(%PN= zlZa9{X^#KERs3t3j%_(_lJSV&^;9?3Bqs)hDgn?E6t1;|GH3I`P}vKuOse! z{wJ#TALHF6qkR(?E6CrqP{LNxC3gkRjAL;o>y?x<<2SCihR@l zZs_4RspW}`nkG8l#!6XHLt9S^MHn#orOyD^Ne! z?J)4A_N)t&p)D&44`i~6g_29=16ykv#@yI2xsQ)_iqvP--(|Uv)9<9JrPL9Y2DTa6 zz>@VFTCr-@g_LAj)Z}3djf>@(&|Q4+FBag_Iq!5PpnB%U4ze!a;8vX?25o*Js7X2A zp7mWDAMKhKwfmpm!ro`Rt?^0b;{x3?tfyWV!%e8fNvXK@B@Gk)m2+elC zHupYFt|pg+t!GePwG*k!EmIzLVh-pk$<4hOY!>gI#wBJp`}+8iYAGYdILp4r84C8?=}IDYE<+bXpBJI?p&5k%fD)79c(;^1yqUtV;N*oM<>gj(wPr^ zkZcxy6juh3bXQtv8ll#qiPXm}oxCwnR_{2eerSsW?EsQH=dbn`Vt91b9Y%#0=9Lmx zX=u`r&q!OXYTh7cC474GV4@@Gla?x*VNX&2ES%Dczhg<*F4Bp0!b@U(D!o2S$Rb^` z`nwOJH42Un_BQ__18j`1$`y&I@s`VhvPy`Jpz3%SrHgeYjZx1WsQlm}&ctUD%u&(N zq*dBBLzy>b|HpuYnSdkI?`VI2u>iOkkX>d$LcTmmN%;AGPR|%cv?Ly(UA?JNdQG z`2|_k60%KM&X|T*GAB>(0=v##f@YuK%F`2I&PAhZo8Y%|*Vbg|2OSDXsl3q-QOLBz zi+5lOw*Gx*WNdTG2}|2C*vVBIuoZJ#mL)7ZJ1xLh>vPN14`&58#yOZ2bH>9ren9VC zIUf6zV_B#kLC^AJ9c&L9G-2M=kNU@@*%wXkpL~1dGwUrzf54x_qWP%jm>@1k~oJdYj3vDYN#2aQ$EhDWq;X1a^X zqKY=Z4U)?iNoRImVDvhBEemzpFwt>BZ;axHKH4En$d7N<;aF=D&BVFgelCu8$9%)O z=q7K;)r*;hr~Np@1&e*CPr$KCDLyYwzbDgC*Dxl0eax|5EhW-ez9Kk)R#eDgz> z0vx5PDo*GzaWqD8lg9*q-%43wu8^1KiPH^h*1_tc0YQ*lPtwy7C6lvE7Hd}?(GYC~LLsl(u7ju2s#SAua0E86{2rnC_S(T`ka45+6-22) zZg~J-5zZ5*KA|+Y5R5!|7yf8oZ&3IoG}i+=ndq8L*_-lzqt%Br{;7B>4&`fBkgWgUN0!+8K^i1&iILgY6a#6cDp;KM=Iy)_S zBfMO$LT10*BckYsPKbN$UPNoLLP{%ttXRT8Vu)jZCX?o?I~*)7Qb^#_X6!y(dOr$G@k-`g>iD#M z7b40+LBac+UYhoyT1s+By{`X^3uw*(TyKmVyC}a$ghXULo>#fTY)$g|)p3oj3yKIY z7Z%Lj$gK>~5LNS>NPBi7+iy>@xDDYvW@U)7nT_9d?RnqJm<%*d8&E{=&py3p!2eimnOrRxZTLH`+f)a< zQ_qiEq}AVpaJuZ#eJiULh7rsfZMZ|ATy5umt8oN`ITmewS76(kvxkkvC0Fzcsq8B^ zTQC^tR0^FLou#*`T41AtZ!1`K){HBvB+=3}L<8kr;=_x!-EIF)y|)7{vY}*dVAnO1 zeA||YGNrdH$U8;54a0*0(3z>x9t@qSBjV-xcaH!V z49@>_#JQOSxX3Cqd8rOMp)~Ug`D3-I>_zCy*FJmlGYjpW+$*gH)*Bn+SWI6)1Bs zM^VnEt!vQ(Pi`iBmaiMRtX>~}8FQeTR3c*VRo2Rp;ISp1^i%1ux2{^w0nD@Bo?2Bk zqkZS|X5Q>Jxmnl=c97i?d&gX9LzHsi&Sm7}>MW)xypUT@-qWHMfM~HQn<=l9OnOq? zv1w~l9YF76i$aqU5-w{%-ifz8kU6r;a37C6`z0U>yGn z{m*odfXl$2an1Fq&Rw7brs)qcF^$q_FFJUE>1yE;%ZuD|Vkb((zt;WwRZH-u4fFEu zPTk1z5IF3QAf$vHuDhiMVkZSL7OCYsJ z3s-P~9;OAmzQX5ghsbodLzHdqagLwU?JgrfrAlA;+b!Mg1XA^{cYn>7lU)PmhM1;A zV1B*Z&H65LL7Ok^RsZZYKQ*TV%3?+Sb%9m(8UV$$CzZUv;z?Kd-T(&uI^DB8nArRe-Dc5Ka%_O57g-Yu z+;OB-x|LcHZf9MZKzg(vNVNdV3#PQ9Mo=GoW>CIeav2R;geQO0WcmXKLT)s+>k=p0 z$&x{<`~!BCQvHwaHtrk1vlSPkzzhr8E7M-V-bnWs6 z480vgJd{|=s9&L>F}=%0Z_5mAJytw=ixfOGv)mypjowTiZhf+zt0}ZBjYM8=yb=|4 z18DUW3JJ^JkCaL(5lC-TP|0(giO}d?e)p1X-S=Azj$eG`BV_wH*?aJ3{2h@ z{X-9q_OT@0@$3~Z->n0&Z3KOwp)Jh2BZ*%h+ulBaOa7rWNFdk{QL#q{3x}}A@mH&U zJKNjtF?``Z9Fd9&9R-xC3~jVquT#AaTi4pu zh`2*;InV;a!CM!+xG%SLSGUztNuB`0)XmdKx)u}%D5#znOQj@Yi52T{nw?v6fj}oC z>(VeisjR$~2~>sWAJtOOXaiF##aHjDssPlhg?4JJx!(z==7|{CA%IP|XCBxdvM4mP zO)5T*IGmo4&XTt3L=w5t*+zVHUg7tb*Ae(+jmm%+zrpZLUUjd(HSDKGvP64 z610W59@fN3TFGr+-wi1L9=V5W2ajoyEX-ayoVAg<`#8CG_IWTI1A(i|XaZ(4w}TTW)>>A_n;l%U#3j!^KJbJh8*ps^Eytqv`d5G=> zzsXN`bax5CHq*Rm4w2ZM6nATK;n4RDPGx!Ua3l}AiS%E&Sv$++0DXYQ4=8cjVvO9c zkzXnXWpHj+$}4VjBgIZ43e+%%R|nNqnm{`;DJ%i_}N#Mjpz>YzAd* zG5V)`Dqf=LV%|KW=NH>V0l1}i>^9^K93xU*7DMts}z(m`F;99Zm@wU%$}PK-#oEs@K$z z`bpYXzWy$b;yPYxR=;1+2SnLF0k5_Ey|<&sM3bBbf@02-0|$SFoEqX>aoM zV$b?)U>fzBzSmz#(RH9vv%Eo*zNcyR>yVL(>sdApn%5ff+nj&4=$--R0i!>QHtY{P2}kk_PZZw{f~2^urSW zKn%~+_X+OOO2fzYJyc3yScD#qfTFI*9zRHc5eWpszvSx(Gwze%;mT2PcsOvLWBZ3{zA3f*K9Wd{NQb8J1GVm+L0^0FXyF{EdQ9mh$fXfeaxp-%REF^+ zvQRSDh~Q5yTNO02(a8;g;e??{-(5Dk$o!%_0eo!ST;m%u5z4nndnGV~dmpWbt%0drDQl;uDg&D4Q;w2%L%I zk0GI7nyTX`$ui$2Qw!aco4hcLV?Fzpss&?LCKe8b*n4-xs7`c6#<7B5)ahchJZ1Tm zXL!E%^C4-zA@_Dw0i8nW-{UA1`preyLcPsk4hM;Mze0UuCnGVLx;pwhNIR=d?>N~M^4U&Cr&eZEJOF>{|1vk3V0KsnYcZxVIGc0L{ZQRe^v~B` zVik+UQhPN!R}$SMpF(icAZyL)IZlSy-Cg@*m8h!05_Eu;gVla42Q%V&rT{p~<5x<3>P_5p zLNViS#~!n+#x-F<0tNeigqVYfv3<52T~C5i9ykhI(_5cjR|_61gG6AQwDmJ5WJgWT zhTD^8&@T>BdZxcKqow*+Xmsz|s~l+`?75x?9o{gpr1xS|x~9I1q5yIh%9*gI z`A;EeL|VxakmDGCQ}}d-1O)BwAUxxPQ!j1qzDWym{vt~UOTBU>w{st~9EKgtZ}c3r zU|)-vy;SmJiyEAzRAifY>A)8Nd0?Y>_||B4<-xkYzE6t-gv$&+Tw2A@y}d@W$!|d)Pi;Q%RXQ(Le1zl5m|$RIp*0 zjOp&!;*O3?-^5*yHndzt%TnGtFoKldpJ(`gcGcG#v`Mq$+8eYkjy}$l0-O6eHefG9 zfq+>%_}<~G3hmI|81sKx65GP12$nMoMxWm`uPB`P?JSA=r?1Vd&~NP^IeGbdoOC2x z>J^YPV*-{zF(1H<;R;Ja;zQE12H! zV`uaDK(@bL5b0Ac7v7Fpjb3YP*+KTKdA>E=9pg=P+^McIbn;N$Dy)?Un43pqj^cAq zPu1fx*BcT^om??AI;JASQ^&`pOy36EeNBJZY^}knlX?8a1>C z@*^8vjzrzFOq|yhCbJc<0_1z27;+i?&oEH!y84FhU0e>+iiwV9j&*)8MxSt^Y{z*x z1Ux zo{7iJZk*#*_0SRAP#js6CC3Uu*pX6p)}ddP3Uacd=p+aVnA_hIjq;gS{-a}uaNlu| zE6Z<&13s4f8U{-)&*0WGSJegllb59{k=fL$hcriU(A?4w6rgBkV$((JrX8;cdQ3^W zT3O9mU9;eU=FSCc^d@dFb&~Pq;}sveHVJbw{&Mu={UGBrHJf`rcb2u!=9SCKisO*R zLuc*I(W^#htdgezq-vKyZplAWd9v3ffG~0HR;>+*4}A&=o)*Zv7llKvd)pb99HjqQN9z4^~~?)OXkOH0)>hWQw*;CSSF zUkA&=2tRlKDES`K6B52Tyf@cqPjkEnS~Ra^ewMJ7bj`sOQucr)Cqa9re}K92Lv4xJ z0n^KU>P2W$fw6hFOo6m*r-Ji#JITh0Sxd>?(llT+^!-8Lzqs`9UG!eRO#Q0|nvI{) zR|dzq|HYtAGTh_Oc3KM0BP2d#FJPYz1=s^Z&jO$FR3T!0~@5~ zqOERE5ykMeIy4{dMeFHtOvEmS*a_EbVKKUS4KyF6#xq^@p*4FptXM3TdMC89IJ81= zYc_3jc~ zaeoK&cld5T&B5nEO0`OptH*^5M`+yBj1IM7DpMLs=MvWV5y2*Uvv)B94{1| zmeRTYp&dh<^hj7>LGXK;KAT=*?9V?oD@Y=-tF@k6tUN~*rn=rfZ|msoD7rOq!S5KU zP8b@vv|?`h{f&oTiWpGDp%kFsYd3so!;ZzDlT z)l56xCOCz#c7?1Kq*Uap5#wy&hXd`SfAXRO@P)&>kyk4QZ8TzgCoOyg)vvuO8o`s| zQ`C7y7>r|?gCf3xJmikGAA2k67gAIp*Uh+J0W>C}aqP_Wq!_-PM1__6tr7h=Rrp7X z79Rrc%z$jqY+wT#oBHWT^hVSy=R&7Opw!rC+unHN^r2_-@_h;BY=#Wdif}Z#s>%=_ zJj3|p7s^q2NML88A=bVdhNhzErqdY#NhM=GDjT%#j_sYtkE_UjRH(i=R|tK4Tr(74 zx`>?bkuk3z-T8nTc*}OhU#8z;C7C16rG=;+^?AQ(Pk`g3qO~0Y2Yu6=>Z&}tl&Gxq z3hMzi#UiB!-|YO;2TkWV;lT|)maNge2LcOaO7wV-}j6OHNA^I5%b&0%%uP?WyuM8mNBfr$%y17kG}i8*}tBNCNu*}3fIc`|#N$R@Xy z?tVNM)<)Sg(uOH*6^8BXjq;Pg7Y0}^FCIY$RugAsALUpHoE|JL1ONwS4S6MaAn~aG zIiA7WL%t%?nwS?X-cvD1AdBH(g|;(1M`HB}YQDWgDWMv!9Q-||j-;Hsw3wk{D?nky zB$i7VMVfJLmnboQ^JO36TK3bv^5qD!?Kwei%fxc8`7XYxMVPKz_xIfA%QK5dPDNH|xwhj_8KJtqX>Pky=gPW)xB(5%LA_{} zMyF%-{rw6i!50PF_W=@dRx8qew{9}j$f+~kkW&zh#~dh4tt;%DkGNEa)}YZ3dss%} zADXUKi$;W7#Mn0s1&wVjNTq)$G4wbxVsRX^rRU6}U}F{sb>k%7}E4cTl$q+i`<%Q?Xqota1ZbDpGJ zMv%b&HO6TB@dqimV#ZDfbg9MPMSGjY5EORW>Yx9lb^YHl%Kwg&{x8L94^~NM*35?} zK|~biNh7=xTNk$!P6vo;;upA>KCg#G(U2|%Or!8cK%AYMa&hG;hwR7A1`PjKxU;Tk zJ0ilSs!DQi_WhDZ%CxF9FGAl%S|Y`bJ^=Zf#}rS>$4eN%vt;e>5w`!v4}g#-0T(T* zdn405C!_vuHK(qNbgzUe;McX)J`?(eTsAS(Zv|6Uijs%tW~x!XvsjG7*G7w-+l2)_p%0EJ4`*)J39bnDp?SBtYd5YW6xY;f`@==bYZjd)6wl%3!GTE3G%x+I-IqAMK0otz z`F3O(Qi@)W>J*HFvabfK@s)jpX5ol?Tf0>J^tBut^{et_ z0>m2-Pc6PEPO6v$sqq2yrmMMLKg<10*F9t}_;pc1GMkSW57R9xE01r9HpH(o`?I)CZ)mB`o>M30l`nAkq+iQ}6s;h> z0qNZMa#C>g5s-n4<=5}yADV|-18R1LWnpge{iprNU@=>(OeHSxgGwjP>vSnQiHeUA z8U;XDkHBwK9KWq%&c*+)|B##j*T)>T0=ZRhGmGt0N2o$$VMqDW+DEZaFR#GXLB+Px zCyEh;6bo`%et{hK^=C8Kaw-JLeEr6ak=I6*oG4!htC4&?J?^L5rWUF5hgGzLg-h>@ z54|7dMP%jQ$7D)K1n*WXU&e?hO|OePYinkampIEY6OCFi{idUh78_TaJG;$Aqp)qY zW%&=cI8^S-CYRimRK{zVg~=d#6OR<_+M~xBedZp-h}n5mX47KI0?K047?uj!vQCwq zl572_G=49rnQL;{^kPcIP;YP0Uau3j@yMNNlz87tG$d(PHt0v+q)$^qIV9pn#ZjUD z=gAtoNEsbFxQJitkHyK`E|}M)nRwQ3ZtvNyVb{|AXlblFmoCic#-?Py*`|%q{L$Pn-lggY=R>Ln8Ab`8_{F0UpFEl##^E8MHNL`Uk>b&d-y~uWSMOTrs zv1~Y)R=xn_wTZA6VvZ@N0bI@I?to!P=)<#20eslm2EL-#z;66@fq5n>y^!4mFJkaV zy{{|}9h{cclr$Z7F#Ry8MDBW~qec2rz6FDV(Y3>?J^9C^A7u!y(7qy_EKeIR4v1|N z-IHBexzDgWz^5)FxNbV&ocFF3LX@CJu7>aedN#YuWQryg!al^5`0G_nC!V)_y=M5) zPq=a*5@}IHd+|l^x#Sc*q-c#od5KyN%3mAd5$5)JZ5iYgK z;s5qgi`_{yH%Jx;-#Zda@ZVzJiT7k>E5dpmTDK{b(jDWN#3P{aT(0_37-bfHr~JqKh- zhj)POy$M*CbYC01k}nYm3+biBerv1MH?=NT4?MBf+lM^(N@<&1^>7AE1G1|z-prh9 zhte}G5A>(UFQ>w=-nAYPo4nmzQx6}C%yKi0$e6dwT)`<(YBArpK>3rEw{ zdhi2tu0U|2tD4flY@kHaKUGO{x|R;h0GHvYAwR7nRBP8QZEM`$2s}@Lq1mNx0x1b* zq530crqM*j)^zvr-G*91HNP2vaAD{igYj|71E+yaKqnZRnw@!JP%WO+hXfMVViwPi z5j2x2852A}0nw!8@Ejk}`Xh0(&t5RaGoK45xL8 zCoT8p;?hL|zyS}xi9q;zj;^k!Jq|whFHfDf{G$f5uM;rD57#aM*%Qoi7`SMbv*PG+ z7HNhP&)6jso5NhaWY4?2UI$$1M3+$r5PvEB+mdJhnL2nSw=iy^ThTjkn+QXPBq;qg z6Z4y&-T6DIimgVy4^)`9g`32V^etiiViD#mPq(Lx?SSgTNs0wJTIp$o$jkeqFmyqw z6;A>r_iL=LN}f9FdA+npfJh@;o$qePv5hGS+vdCmEHYfgl?UZZL{XtFOM^hjT}a!= z1P_;R2#>gG?7~o8>wUf6v;xSZgy=%v!_5nQO}b7_kLKe%AI=AB0M;WN00DsEX{-~5 ze|8_tdgPDn(0HHd|nlm+G(w^UhP5}uyKuRO;?NYvfm~wW}`6|TL zB?Y*yL5039G#9z&ym-A$z&IBzfVLz+>lhU452toxZ0B_GoJ+uMD`wW};-wz9F9prA+JnYJ8-Dp`Fh~!Y?BugMhjkUg%tB)9CXzK@Wik+hY|U zuU7-ww)|6^*a!0fKAouDr%Lv(!?!w_aNrNFW!+D%{pA_|uWIlAhwR`$$0>MCMx!?X S13WnfGSD-_;H{E+7y~t}b5!uOtz=+YyMM;5|FGeL}lz)IQo5rdv{# zTMWi;4ftUx=8KCtAFPkeS#hws@oMDm75l3%UX7gcCR#SH3I#a%uS3={#?C}cZ37*g zGkrr43WXpD23IxMTkI2lRl?Pn_3!hmR`o84TN*I*@}jYrgGCNrTrJf3B=(@ESFm*F zyqxFpdR%C2FfCxq|FUg6lO8n+eHGjPT>k^oaPQ3SJhJ)uCtmPA;B`$T-y>+XS`;pk zJ2Gu?oJ{h#Toy?@cVvv0{bs{`001hW0B9>8uT!a1rDD4I#^1$dbh?LQ2kAPUj-?+g z=xkDeP*1YEs9MF(ing;ABLyY@jZPf}f*?Ir=Dn>tYIVC)n(?ZcJm<-ZiV6n9J0b2x z(!K67u@0M(fo&u5J#_td$T~{Vt0F2T3*$JY99k%1Iq_-(&XJ@lRz)?*;(KT-$E$B4Eo*&?i!J+zdmf6xqL5rGvm&8lpj;PgYZL)q=f`fOvD~0`f37v~?bD@hW z&)?6FYf;G7)obcG9FFg?U7j4*pG4&i^9MKe!S^z>Is=n>J@&g|21DYTgfl|BuT&~c zz0^0*b*NX=Ef4Dgqd9WmP|_8@y=_X5kVd10BE1j!fDz4{5%l{b>)EAzh4^4oZZozw z=@f72v6MT>W_9>4E}1*F-t7S@3sK|ks+qP3xSTS_G-dqOCD*Q@(zaG0YT7(hvqhE= zR1ry(wYB<7S>}+Kj3Z~#`S_MvQy@2W*6N&|F3_f49x3o|`><0zN84r)#rhr_C(X}v zmt3FinwXe?QK|bt5=TxEX(mH)qkjb1EDN%hAlEn4nR54JK6KPcus12eu#A4u#gZHW zaczr602-HCm6id+6y&_E>7&#DE5}5{yF?7k{s2(R@w)8#!J>5$0{1CcL(EE|WKQd`&5n$)r-LB_*9C z-q@@aR!M%`fsPD+&Mz>I3G{o?LMQWeVjx@&=@wmRngP}jH6mhv-Y_{n`N}(Sv5pV$pJOJ#$4!?x!$I8|u1LwUJ?W9`2RcV)peM zK0Qoe&JE~@(Hy(o&StZfhWUl_DruPQxG}mR9A{0ttH@qYMECW6`IHW5)|UqV_}MOo z$9W3VT}~fQ{9fY`=_oRNiiy2uV|P@=$J~S%L;``3_i?A1eCJ?CM!T*d`>tb^k%tla_jI$9WpP8Egr+`Lm>(QTx2f&=5~>^HD^3 z#qtSJ<73uZcPE_h@*XTHD#^5ZVgEfP7`*{K1dEarlO05%P~y2%&hO=RW#QQYe^@?P z38BC@`}yDzsJQE7(bW8k5cH4;D5FvZzEjr#DCBf@-@seJ7;GaoZ@$M~ojny6a$y5; v>)9N?HPy@VmoFNNIauW2h0?;H58=MB+nW2vrAGLdh}g3ezvI^Soa%o79W1m6 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..ed9bb0bd711a47d7be4d78796478b215a5af8fa5 GIT binary patch literal 7399 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 WMf+JCmw-k;7E>e3TeUabp8Y>hhU?b= literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_0/00001.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..402a5312b958c11a801971571e49bf5342e17347 GIT binary patch literal 19470 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

&VPG78&8NRIGSZBdc>j;uRxj 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 U?zGC(q$O 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_0/00003.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_0/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..e42a0293f9ba5398da58d6025a48412e81ba360e GIT binary patch literal 11704 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 da?hsvu>gw{^^4hNKt;BYt+o9H+ Date: Wed, 27 Mar 2024 11:24:18 +0100 Subject: [PATCH 71/85] Bye Bye btchip --- include/apdu_constants.h | 154 +++++ include/{btchip_base58.h => base58.h} | 8 +- include/{btchip_bcd.h => bcd.h} | 8 +- include/btchip.h | 10 +- include/btchip_apdu_constants.h | 158 ----- include/{btchip_config.h => config.h} | 4 +- include/{btchip_context.h => context.h} | 112 +-- include/{btchip_ecc.h => ecc.h} | 6 +- include/{btchip_filesystem.h => filesystem.h} | 54 +- ...btchip_filesystem_tx.h => filesystem_tx.h} | 8 +- include/{btchip_helpers.h => helpers.h} | 56 +- .../{btchip_secure_value.h => secure_value.h} | 4 +- include/swap_lib_calls.h | 4 +- ...coin_version.c => apdu_get_coin_version.c} | 16 +- ..._version.c => apdu_get_firmware_version.c} | 12 +- ...ation_mode.c => apdu_get_operation_mode.c} | 18 +- ...ip_apdu_get_random.c => apdu_get_random.c} | 12 +- ...usted_input.c => apdu_get_trusted_input.c} | 70 +- ...lic_key.c => apdu_get_wallet_public_key.c} | 92 +-- ...lic_key.h => apdu_get_wallet_public_key.h} | 6 +- src/apdu_hash_input_finalize_full.c | 653 ++++++++++++++++++ ..._input_start.c => apdu_hash_input_start.c} | 86 +-- ...chip_apdu_hash_sign.c => apdu_hash_sign.c} | 130 ++-- ...ation_mode.c => apdu_set_operation_mode.c} | 36 +- src/{btchip_apdu_setup.c => apdu_setup.c} | 22 +- ...pdu_sign_message.c => apdu_sign_message.c} | 170 ++--- src/apdu_verify_pin.c | 23 + ...ip_bagl_extensions.h => bagl_extensions.h} | 34 +- src/{btchip_base58.c => base58.c} | 6 +- src/{btchip_bcd.c => bcd.c} | 8 +- src/bip32_path.c | 4 +- src/btchip.c | 62 +- src/btchip_apdu_hash_input_finalize_full.c | 653 ------------------ src/btchip_apdu_verify_pin.c | 23 - src/btchip_display_variables.c | 3 - src/btchip_internal.h | 31 - src/btchip_public_ram_variables.h | 30 - src/{btchip_context.c => context.c} | 30 +- src/display_variables.c | 3 + ...isplay_variables.h => display_variables.h} | 4 +- src/{btchip_ecc.c => ecc.c} | 4 +- src/{btchip_filesystem.c => filesystem.c} | 6 +- src/handle_check_address.c | 22 +- src/handle_check_address.h | 4 +- src/handle_get_printable_amount.c | 6 +- src/handle_get_printable_amount.h | 4 +- src/handle_swap_sign_transaction.c | 12 +- src/handle_swap_sign_transaction.h | 4 +- src/{btchip_helpers.c => helpers.c} | 76 +- src/internal.h | 31 + src/main.c | 184 ++--- src/{btchip_nvram.c => nvram.c} | 6 +- ...ram_variables.c => public_ram_variables.c} | 6 +- src/public_ram_variables.h | 30 + ...btchip_rom_variables.c => rom_variables.c} | 108 +-- ...btchip_rom_variables.h => rom_variables.h} | 8 +- src/{btchip_secure_value.c => secure_value.c} | 2 +- src/{btchip_transaction.c => transaction.c} | 576 +++++++-------- src/{btchip_transaction.h => transaction.h} | 8 +- src/ui_bagl.c | 24 +- src/ui_menu_nbgl.c | 6 +- src/ui_nbgl.c | 28 +- 62 files changed, 1987 insertions(+), 1991 deletions(-) create mode 100644 include/apdu_constants.h rename include/{btchip_base58.h => base58.h} (84%) rename include/{btchip_bcd.h => bcd.h} (78%) delete mode 100644 include/btchip_apdu_constants.h rename include/{btchip_config.h => config.h} (94%) rename include/{btchip_context.h => context.h} (77%) rename include/{btchip_ecc.h => ecc.h} (88%) rename include/{btchip_filesystem.h => filesystem.h} (61%) rename include/{btchip_filesystem_tx.h => filesystem_tx.h} (90%) rename include/{btchip_helpers.h => helpers.h} (58%) rename include/{btchip_secure_value.h => secure_value.h} (96%) rename src/{btchip_apdu_get_coin_version.c => apdu_get_coin_version.c} (83%) rename src/{btchip_apdu_get_firmware_version.c => apdu_get_firmware_version.c} (86%) rename src/{btchip_apdu_get_operation_mode.c => apdu_get_operation_mode.c} (74%) rename src/{btchip_apdu_get_random.c => apdu_get_random.c} (82%) rename src/{btchip_apdu_get_trusted_input.c => apdu_get_trusted_input.c} (54%) rename src/{btchip_apdu_get_wallet_public_key.c => apdu_get_wallet_public_key.c} (72%) rename src/{btchip_apdu_get_wallet_public_key.h => apdu_get_wallet_public_key.h} (57%) create mode 100644 src/apdu_hash_input_finalize_full.c rename src/{btchip_apdu_hash_input_start.c => apdu_hash_input_start.c} (68%) rename src/{btchip_apdu_hash_sign.c => apdu_hash_sign.c} (53%) rename src/{btchip_apdu_set_operation_mode.c => apdu_set_operation_mode.c} (67%) rename src/{btchip_apdu_setup.c => apdu_setup.c} (71%) rename src/{btchip_apdu_sign_message.c => apdu_sign_message.c} (56%) create mode 100644 src/apdu_verify_pin.c rename src/{btchip_bagl_extensions.h => bagl_extensions.h} (57%) rename src/{btchip_base58.c => base58.c} (96%) rename src/{btchip_bcd.c => bcd.c} (90%) delete mode 100644 src/btchip_apdu_hash_input_finalize_full.c delete mode 100644 src/btchip_apdu_verify_pin.c delete mode 100644 src/btchip_display_variables.c delete mode 100644 src/btchip_internal.h delete mode 100644 src/btchip_public_ram_variables.h rename src/{btchip_context.c => context.c} (67%) create mode 100644 src/display_variables.c rename src/{btchip_display_variables.h => display_variables.h} (93%) rename src/{btchip_ecc.c => ecc.c} (90%) rename src/{btchip_filesystem.c => filesystem.c} (87%) rename src/{btchip_helpers.c => helpers.c} (86%) create mode 100644 src/internal.h rename src/{btchip_nvram.c => nvram.c} (87%) rename src/{btchip_public_ram_variables.c => public_ram_variables.c} (87%) create mode 100644 src/public_ram_variables.h rename src/{btchip_rom_variables.c => rom_variables.c} (56%) rename src/{btchip_rom_variables.h => rom_variables.h} (94%) rename src/{btchip_secure_value.c => secure_value.c} (97%) rename src/{btchip_transaction.c => transaction.c} (57%) rename src/{btchip_transaction.h => transaction.h} (92%) diff --git a/include/apdu_constants.h b/include/apdu_constants.h new file mode 100644 index 00000000..34a1441a --- /dev/null +++ b/include/apdu_constants.h @@ -0,0 +1,154 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#ifndef APDU_CONSTANTS_H + +#define APDU_CONSTANTS_H + +#define CLA 0xE0 +#define ADM_CLA 0xD0 +#define NFCPAYMENT_CLA 0xF0 + +#define INS_SETUP 0x20 +#define INS_VERIFY_PIN 0x22 +#define INS_GET_OPERATION_MODE 0x24 +#define INS_SET_OPERATION_MODE 0x26 +#define INS_SET_KEYBOARD_CFG 0x28 +#define INS_GET_WALLET_PUBLIC_KEY 0x40 +#define INS_GET_TRUSTED_INPUT 0x42 +#define INS_HASH_INPUT_START 0x44 +#define INS_HASH_INPUT_FINALIZE 0x46 +#define INS_HASH_SIGN 0x48 +#define INS_HASH_INPUT_FINALIZE_FULL 0x4A +#define INS_GET_INTERNAL_CHAIN_INDEX 0x4C +#define INS_SIGN_MESSAGE 0x4E +#define INS_GET_TRANSACTION_LIMIT 0xA0 +#define INS_SET_TRANSACTION_LIMIT 0xA2 +#define INS_IMPORT_PRIVATE_KEY 0xB0 +#define INS_GET_PUBLIC_KEY 0xB2 +#define INS_DERIVE_BIP32_KEY 0xB4 +#define INS_SIGNVERIFY_IMMEDIATE 0xB6 +#define INS_GET_RANDOM 0xC0 +#define INS_GET_ATTESTATION 0xC2 +#define INS_GET_FIRMWARE_VERSION 0xC4 +#define INS_COMPOSE_MOFN_ADDRESS 0xC6 +#define INS_GET_POS_SEED 0xCA +#define INS_DEBUG 0xD0 + +#define INS_ADM_INIT_KEYS 0x20 +#define INS_ADM_INIT_ATTESTATION 0x22 +#define INS_ADM_GET_UPDATE_ID 0x24 +#define INS_ADM_SET_KEYCARD_SEED 0x26 +#define INS_ADM_FIRMWARE_UPDATE 0x42 + +#define INS_SET_USER_KEYCARD 0x10 +#define INS_SETUP_SECURE_SCREEN 0x12 +#define INS_SET_ALTERNATE_COIN_VER 0x14 +#define INS_GET_COIN_VER 0x16 + +#define INS_STORE_TRUST_ROOT_BIP70 0x30 +#define INS_CREATE_CERTIFICATE_BIP70 0x32 +#define INS_CREATE_PAYMENT_REQ_BIP70 0x34 +#define INS_PROCESS_CERTIFICATE_BIP70 0x36 +#define INS_PARSE_PAYMENT_REQ_BIP70 0x38 +#define INS_HASH_INPUT_FINALIZE_BIP70 0x3A +#define INS_ADM_SET_ROOT_BIP70 0x28 +#define INS_ADM_SET_BIP39_SHUFFLE 0x2A + +#define INS_NFCPAYMENT_SET_CONFIG 0x20 +#define INS_NFCPAYMENT_GET_CONFIG 0x22 +#define INS_NFCPAYMENT_STORE_UTXO 0x40 +#define INS_NFCPAYMENT_STORE_SCRIPT 0x42 +#define INS_NFCPAYMENT_GET_UTXO 0x44 +#define INS_NFCPAYMENT_DELETE_UTXO 0x46 +#define INS_NFCPAYMENT_GET_PAYMENT_TX 0x50 +#define INS_NFCPAYMENT_GET_LAST_TX 0x52 +#define INS_NFCPAYMENT_CONFIRM_TX 0x54 +#define INS_NFCPAYMENT_CONFIRM_CHANGE 0x56 +#define INS_NFCPAYMENT_GET_LAST_STAT 0x58 +#define INS_NFCPAYMENT_GET_DATA 0xC0 + +#define SW_PIN_REMAINING_ATTEMPTS 0x63C0 +#define SW_INCORRECT_LENGTH 0x6700 +#define SW_COMMAND_INCOMPATIBLE_FILE_STRUCTURE 0x6981 +#define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 +#define SW_CONDITIONS_OF_USE_NOT_SATISFIED 0x6985 +#define SW_INCORRECT_DATA 0x6A80 +#define SW_NOT_ENOUGH_MEMORY_SPACE 0x6A84 +#define SW_REFERENCED_DATA_NOT_FOUND 0x6A88 +#define SW_FILE_ALREADY_EXISTS 0x6A89 +#define SW_SWAP_WITHOUT_TRUSTED_INPUTS 0x6A8A +#define SW_INCORRECT_P1_P2 0x6B00 +#define SW_INS_NOT_SUPPORTED 0x6D00 +#define SW_CLA_NOT_SUPPORTED 0x6E00 +#define SW_TECHNICAL_PROBLEM 0x6F00 +#define SW_OK 0x9000 +#define SW_MEMORY_PROBLEM 0x9240 +#define SW_NO_EF_SELECTED 0x9400 +#define SW_INVALID_OFFSET 0x9402 +#define SW_FILE_NOT_FOUND 0x9404 +#define SW_INCONSISTENT_FILE 0x9408 +#define SW_ALGORITHM_NOT_SUPPORTED 0x9484 +#define SW_INVALID_KCV 0x9485 +#define SW_CODE_NOT_INITIALIZED 0x9802 +#define SW_ACCESS_CONDITION_NOT_FULFILLED 0x9804 +#define SW_CONTRADICTION_SECRET_CODE_STATUS 0x9808 +#define SW_CONTRADICTION_INVALIDATION 0x9810 +#define SW_CODE_BLOCKED 0x9840 +#define SW_MAX_VALUE_REACHED 0x9850 +#define SW_GP_AUTH_FAILED 0x6300 +#define SW_LICENSING 0x6F42 +#define SW_HALTED 0x6FAA +#define SW_APP_HALTED SW_CONDITIONS_OF_USE_NOT_SATISFIED + +#define ISO_OFFSET_CLA 0x00 +#define ISO_OFFSET_INS 0x01 +#define ISO_OFFSET_P1 0x02 +#define ISO_OFFSET_P2 0x03 +#define ISO_OFFSET_LC 0x04 +#define ISO_OFFSET_CDATA 0x05 + +#define BITID_DERIVE 0xB11D +#define BITID_DERIVE_MULTIPLE 0xB11E + +#include "os.h" +#include "secure_value.h" + +void commit_operation_mode(secu8 operationMode); + +unsigned short apdu_setup(void); +unsigned short apdu_verify_pin(void); +unsigned short apdu_get_operation_mode(void); +unsigned short apdu_set_operation_mode(void); +unsigned short apdu_get_wallet_public_key(void); +unsigned short apdu_get_trusted_input(void); +unsigned short apdu_hash_input_start(void); +unsigned short apdu_hash_input_finalize(void); +unsigned short apdu_hash_sign(void); +unsigned short apdu_hash_input_finalize_full(void); +unsigned short apdu_import_private_key(void); +unsigned short apdu_get_public_key(void); +unsigned short apdu_derive_bip32_key(void); +unsigned short apdu_signverify_immediate(void); +unsigned short apdu_sign_message(void); + +unsigned short apdu_get_random(void); +unsigned short apdu_get_firmware_version(void); + +unsigned short apdu_get_coin_version(void); + +#endif diff --git a/include/btchip_base58.h b/include/base58.h similarity index 84% rename from include/btchip_base58.h rename to include/base58.h index 38d3f6c5..453f8593 100644 --- a/include/btchip_base58.h +++ b/include/base58.h @@ -15,16 +15,16 @@ * limitations under the License. ********************************************************************************/ -#ifndef BTCHIP_BASE58_H +#ifndef BASE58_H -#define BTCHIP_BASE58_H +#define BASE58_H #include -int btchip_decode_base58(const char *in, size_t length, +int decode_base58(const char *in, size_t length, unsigned char *out, size_t *outlen); -int btchip_encode_base58(const unsigned char *in, size_t length, +int encode_base58(const unsigned char *in, size_t length, unsigned char *out, size_t *outlen); #endif diff --git a/include/btchip_bcd.h b/include/bcd.h similarity index 78% rename from include/btchip_bcd.h rename to include/bcd.h index 51fd54c4..42eb41ff 100644 --- a/include/btchip_bcd.h +++ b/include/bcd.h @@ -15,14 +15,14 @@ * limitations under the License. ********************************************************************************/ -#ifndef BTCHIP_BCD_H +#ifndef BCD_H -#define BTCHIP_BCD_H +#define BCD_H unsigned char -btchip_convert_hex_amount_to_displayable_no_globals(unsigned char *amount, unsigned int config_flag, unsigned char* out); +convert_hex_amount_to_displayable_no_globals(unsigned char *amount, unsigned int config_flag, unsigned char* out); unsigned char -btchip_convert_hex_amount_to_displayable(unsigned char *amount); +convert_hex_amount_to_displayable(unsigned char *amount); #endif diff --git a/include/btchip.h b/include/btchip.h index 03d108dc..f53e0e1d 100644 --- a/include/btchip.h +++ b/include/btchip.h @@ -15,11 +15,11 @@ * limitations under the License. ********************************************************************************/ -#ifndef BTCHIP_H +#ifndef H -#define BTCHIP_H +#define H -#include "btchip_config.h" +#include "config.h" #include "os.h" #include "os_io_seproxyhal.h" @@ -29,8 +29,8 @@ #define L_DEBUG_NOPREFIX(x) -#define SW_TECHNICAL_DETAILS(x) BTCHIP_SW_TECHNICAL_PROBLEM +#define SW_TECHNICAL_DETAILS(x) SW_TECHNICAL_PROBLEM -#include "btchip_secure_value.h" +#include "secure_value.h" #endif diff --git a/include/btchip_apdu_constants.h b/include/btchip_apdu_constants.h deleted file mode 100644 index 2a6e258b..00000000 --- a/include/btchip_apdu_constants.h +++ /dev/null @@ -1,158 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef BTCHIP_APDU_CONSTANTS_H - -#define BTCHIP_APDU_CONSTANTS_H - -#define BTCHIP_CLA 0xE0 -#define BTCHIP_ADM_CLA 0xD0 -#define BTCHIP_NFCPAYMENT_CLA 0xF0 - -#define BTCHIP_INS_SETUP 0x20 -#define BTCHIP_INS_VERIFY_PIN 0x22 -#define BTCHIP_INS_GET_OPERATION_MODE 0x24 -#define BTCHIP_INS_SET_OPERATION_MODE 0x26 -#define BTCHIP_INS_SET_KEYBOARD_CFG 0x28 -#define BTCHIP_INS_GET_WALLET_PUBLIC_KEY 0x40 -#define BTCHIP_INS_GET_TRUSTED_INPUT 0x42 -#define BTCHIP_INS_HASH_INPUT_START 0x44 -#define BTCHIP_INS_HASH_INPUT_FINALIZE 0x46 -#define BTCHIP_INS_HASH_SIGN 0x48 -#define BTCHIP_INS_HASH_INPUT_FINALIZE_FULL 0x4A -#define BTCHIP_INS_GET_INTERNAL_CHAIN_INDEX 0x4C -#define BTCHIP_INS_SIGN_MESSAGE 0x4E -#define BTCHIP_INS_GET_TRANSACTION_LIMIT 0xA0 -#define BTCHIP_INS_SET_TRANSACTION_LIMIT 0xA2 -#define BTCHIP_INS_IMPORT_PRIVATE_KEY 0xB0 -#define BTCHIP_INS_GET_PUBLIC_KEY 0xB2 -#define BTCHIP_INS_DERIVE_BIP32_KEY 0xB4 -#define BTCHIP_INS_SIGNVERIFY_IMMEDIATE 0xB6 -#define BTCHIP_INS_GET_RANDOM 0xC0 -#define BTCHIP_INS_GET_ATTESTATION 0xC2 -#define BTCHIP_INS_GET_FIRMWARE_VERSION 0xC4 -#define BTCHIP_INS_COMPOSE_MOFN_ADDRESS 0xC6 -#define BTCHIP_INS_GET_POS_SEED 0xCA -#define BTCHIP_INS_DEBUG 0xD0 - -#define BTCHIP_INS_ADM_INIT_KEYS 0x20 -#define BTCHIP_INS_ADM_INIT_ATTESTATION 0x22 -#define BTCHIP_INS_ADM_GET_UPDATE_ID 0x24 -#define BTCHIP_INS_ADM_SET_KEYCARD_SEED 0x26 -#define BTCHIP_INS_ADM_FIRMWARE_UPDATE 0x42 - -#define BTCHIP_INS_SET_USER_KEYCARD 0x10 -#define BTCHIP_INS_SETUP_SECURE_SCREEN 0x12 -#define BTCHIP_INS_SET_ALTERNATE_COIN_VER 0x14 -#define BTCHIP_INS_GET_COIN_VER 0x16 - -#define BTCHIP_INS_STORE_TRUST_ROOT_BIP70 0x30 -#define BTCHIP_INS_CREATE_CERTIFICATE_BIP70 0x32 -#define BTCHIP_INS_CREATE_PAYMENT_REQ_BIP70 0x34 -#define BTCHIP_INS_PROCESS_CERTIFICATE_BIP70 0x36 -#define BTCHIP_INS_PARSE_PAYMENT_REQ_BIP70 0x38 -#define BTCHIP_INS_HASH_INPUT_FINALIZE_BIP70 0x3A -#define BTCHIP_INS_ADM_SET_ROOT_BIP70 0x28 -#define BTCHIP_INS_ADM_SET_BIP39_SHUFFLE 0x2A - -#define BTCHIP_INS_NFCPAYMENT_SET_CONFIG 0x20 -#define BTCHIP_INS_NFCPAYMENT_GET_CONFIG 0x22 -#define BTCHIP_INS_NFCPAYMENT_STORE_UTXO 0x40 -#define BTCHIP_INS_NFCPAYMENT_STORE_SCRIPT 0x42 -#define BTCHIP_INS_NFCPAYMENT_GET_UTXO 0x44 -#define BTCHIP_INS_NFCPAYMENT_DELETE_UTXO 0x46 -#define BTCHIP_INS_NFCPAYMENT_GET_PAYMENT_TX 0x50 -#define BTCHIP_INS_NFCPAYMENT_GET_LAST_TX 0x52 -#define BTCHIP_INS_NFCPAYMENT_CONFIRM_TX 0x54 -#define BTCHIP_INS_NFCPAYMENT_CONFIRM_CHANGE 0x56 -#define BTCHIP_INS_NFCPAYMENT_GET_LAST_STAT 0x58 -#define BTCHIP_INS_NFCPAYMENT_GET_DATA 0xC0 - -#define BTCHIP_SW_PIN_REMAINING_ATTEMPTS 0x63C0 -#define BTCHIP_SW_INCORRECT_LENGTH 0x6700 -#define BTCHIP_SW_COMMAND_INCOMPATIBLE_FILE_STRUCTURE 0x6981 -#define BTCHIP_SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 -#define BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED 0x6985 -#define BTCHIP_SW_INCORRECT_DATA 0x6A80 -#define BTCHIP_SW_NOT_ENOUGH_MEMORY_SPACE 0x6A84 -#define BTCHIP_SW_REFERENCED_DATA_NOT_FOUND 0x6A88 -#define BTCHIP_SW_FILE_ALREADY_EXISTS 0x6A89 -#define BTCHIP_SW_SWAP_WITHOUT_TRUSTED_INPUTS 0x6A8A -#define BTCHIP_SW_INCORRECT_P1_P2 0x6B00 -#define BTCHIP_SW_INS_NOT_SUPPORTED 0x6D00 -#define BTCHIP_SW_CLA_NOT_SUPPORTED 0x6E00 -#define BTCHIP_SW_TECHNICAL_PROBLEM 0x6F00 -#define BTCHIP_SW_OK 0x9000 -#define BTCHIP_SW_MEMORY_PROBLEM 0x9240 -#define BTCHIP_SW_NO_EF_SELECTED 0x9400 -#define BTCHIP_SW_INVALID_OFFSET 0x9402 -#define BTCHIP_SW_FILE_NOT_FOUND 0x9404 -#define BTCHIP_SW_INCONSISTENT_FILE 0x9408 -#define BTCHIP_SW_ALGORITHM_NOT_SUPPORTED 0x9484 -#define BTCHIP_SW_INVALID_KCV 0x9485 -#define BTCHIP_SW_CODE_NOT_INITIALIZED 0x9802 -#define BTCHIP_SW_ACCESS_CONDITION_NOT_FULFILLED 0x9804 -#define BTCHIP_SW_CONTRADICTION_SECRET_CODE_STATUS 0x9808 -#define BTCHIP_SW_CONTRADICTION_INVALIDATION 0x9810 -#define BTCHIP_SW_CODE_BLOCKED 0x9840 -#define BTCHIP_SW_MAX_VALUE_REACHED 0x9850 -#define BTCHIP_SW_GP_AUTH_FAILED 0x6300 -#define BTCHIP_SW_LICENSING 0x6F42 -#define BTCHIP_SW_HALTED 0x6FAA -#define BTCHIP_SW_APP_HALTED BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED - -#define ISO_OFFSET_CLA 0x00 -#define ISO_OFFSET_INS 0x01 -#define ISO_OFFSET_P1 0x02 -#define ISO_OFFSET_P2 0x03 -#define ISO_OFFSET_LC 0x04 -#define ISO_OFFSET_CDATA 0x05 - -#define BTCHIP_2FA_NONE 0x00 -#define BTCHIP_2FA_KEYBOARD 0x01 -#define BTCHIP_2FA_SECURE_SCREEN 0x02 - -#define BITID_DERIVE 0xB11D -#define BITID_DERIVE_MULTIPLE 0xB11E - -#include "os.h" -#include "btchip_secure_value.h" - -void btchip_commit_operation_mode(secu8 operationMode); - -unsigned short btchip_apdu_setup(void); -unsigned short btchip_apdu_verify_pin(void); -unsigned short btchip_apdu_get_operation_mode(void); -unsigned short btchip_apdu_set_operation_mode(void); -unsigned short btchip_apdu_get_wallet_public_key(void); -unsigned short btchip_apdu_get_trusted_input(void); -unsigned short btchip_apdu_hash_input_start(void); -unsigned short btchip_apdu_hash_input_finalize(void); -unsigned short btchip_apdu_hash_sign(void); -unsigned short btchip_apdu_hash_input_finalize_full(void); -unsigned short btchip_apdu_import_private_key(void); -unsigned short btchip_apdu_get_public_key(void); -unsigned short btchip_apdu_derive_bip32_key(void); -unsigned short btchip_apdu_signverify_immediate(void); -unsigned short btchip_apdu_sign_message(void); - -unsigned short btchip_apdu_get_random(void); -unsigned short btchip_apdu_get_firmware_version(void); - -unsigned short btchip_apdu_get_coin_version(void); - -#endif diff --git a/include/btchip_config.h b/include/config.h similarity index 94% rename from include/btchip_config.h rename to include/config.h index 56b49880..dac4e214 100644 --- a/include/btchip_config.h +++ b/include/config.h @@ -15,9 +15,9 @@ * limitations under the License. ********************************************************************************/ -#ifndef BTCHIP_CONFIG_H +#ifndef CONFIG_H -#define BTCHIP_CONFIG_H +#define CONFIG_H //#define DISABLE_SECURE_VALUE diff --git a/include/btchip_context.h b/include/context.h similarity index 77% rename from include/btchip_context.h rename to include/context.h index db9656d3..90ba37ae 100644 --- a/include/btchip_context.h +++ b/include/context.h @@ -15,14 +15,14 @@ * limitations under the License. ********************************************************************************/ -#ifndef BTCHIP_CONTEXT_H +#ifndef CONTEXT_H -#define BTCHIP_CONTEXT_H +#define CONTEXT_H #include "os.h" #include "cx.h" -#include "btchip_secure_value.h" -#include "btchip_filesystem_tx.h" +#include "secure_value.h" +#include "filesystem_tx.h" #ifdef HAVE_NBGL #include "nbgl_types.h" #endif // HAVE_NBGL @@ -38,64 +38,64 @@ #define ZCASH_USING_OVERWINTER 0x01 #define ZCASH_USING_OVERWINTER_SAPLING 0x02 -enum btchip_modes_e { - BTCHIP_MODE_ISSUER = 0x00, - BTCHIP_MODE_SETUP_NEEDED = 0xff, - BTCHIP_MODE_WALLET = 0x01, - BTCHIP_MODE_RELAXED_WALLET = 0x02, - BTCHIP_MODE_SERVER = 0x04, - BTCHIP_MODE_DEVELOPER = 0x08, +enum modes_e { + MODE_ISSUER = 0x00, + MODE_SETUP_NEEDED = 0xff, + MODE_WALLET = 0x01, + MODE_RELAXED_WALLET = 0x02, + MODE_SERVER = 0x04, + MODE_DEVELOPER = 0x08, }; -enum btchip_options_e { - BTCHIP_OPTION_UNCOMPRESSED_KEYS = 0x01, - BTCHIP_OPTION_DETERMINISTIC_SIGNATURE = 0x02, - BTCHIP_OPTION_FREE_SIGHASHTYPE = 0x04, - BTCHIP_OPTION_SKIP_2FA_P2SH = 0x08, - BTCHIP_OPTION_ALLOW_ARBITRARY_CHANGE = 0x10 +enum options_e { + OPTION_UNCOMPRESSED_KEYS = 0x01, + OPTION_DETERMINISTIC_SIGNATURE = 0x02, + OPTION_FREE_SIGHASHTYPE = 0x04, + OPTION_SKIP_2FA_P2SH = 0x08, + OPTION_ALLOW_ARBITRARY_CHANGE = 0x10 }; /** * Current state of an untrusted transaction hashing */ -enum btchip_transaction_state_e { +enum transaction_state_e { /** No transaction in progress */ - BTCHIP_TRANSACTION_NONE = 0x00, + TRANSACTION_NONE = 0x00, /** Transaction defined, waiting for an input to be hashed */ - BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT = 0x01, + TRANSACTION_DEFINED_WAIT_INPUT = 0x01, /** Transaction defined, input hashing in progress, pending input script data */ - BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT = 0x02, + TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT = 0x02, /** Transaction defined, input hashing done, pending output hashing for this input */ - BTCHIP_TRANSACTION_INPUT_HASHING_DONE = 0x03, + TRANSACTION_INPUT_HASHING_DONE = 0x03, /** Transaction defined, waiting for an output to be hashed */ - BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT = 0x04, + TRANSACTION_DEFINED_WAIT_OUTPUT = 0x04, /** Transaction defined, output hashing in progress for a complex script, pending output script data */ - BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT = 0x05, + TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT = 0x05, /** Transaction defined, output hashing done, pending finalization */ - BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE = 0x06, + TRANSACTION_OUTPUT_HASHING_DONE = 0x06, /** Extra data present */ - BTCHIP_TRANSACTION_PROCESS_EXTRA = 0x07, + TRANSACTION_PROCESS_EXTRA = 0x07, /** Transaction parsed */ - BTCHIP_TRANSACTION_PARSED = 0x08, + TRANSACTION_PARSED = 0x08, /** Transaction parsed, ready to prepare for signature after validating the user outputs */ - BTCHIP_TRANSACTION_PRESIGN_READY = 0x09, + TRANSACTION_PRESIGN_READY = 0x09, /** Transaction fully parsed, ready to be signed */ - BTCHIP_TRANSACTION_SIGN_READY = 0x0a, + TRANSACTION_SIGN_READY = 0x0a, }; -typedef enum btchip_transaction_state_e btchip_transaction_state_t; - -enum btchip_output_parsing_state_e { - BTCHIP_OUTPUT_PARSING_NONE = 0x00, - BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS = 0x01, - BTCHIP_OUTPUT_PARSING_OUTPUT = 0x02, - BTCHIP_OUTPUT_FINALIZE_TX = 0x03, - BTCHIP_BIP44_CHANGE_PATH_VALIDATION = 0x04 +typedef enum transaction_state_e transaction_state_t; + +enum output_parsing_state_e { + OUTPUT_PARSING_NONE = 0x00, + OUTPUT_PARSING_NUMBER_OUTPUTS = 0x01, + OUTPUT_PARSING_OUTPUT = 0x02, + OUTPUT_FINALIZE_TX = 0x03, + BIP44_CHANGE_PATH_VALIDATION = 0x04 }; -typedef enum btchip_output_parsing_state_e btchip_output_parsing_state_t; +typedef enum output_parsing_state_e output_parsing_state_t; typedef union multi_hash { @@ -115,7 +115,7 @@ struct segwit_cache_s { /** * Structure defining an operation on a transaction */ -struct btchip_transaction_context_s { +struct transaction_context_s { /** Transient over signing components */ /** Remaining number of inputs/outputs to process for this transaction */ @@ -127,7 +127,7 @@ struct btchip_transaction_context_s { /** Persistent over signing components */ - /** State of the transaction, type btchip_transaction_state_t */ + /** State of the transaction, type transaction_state_t */ unsigned char transactionState; /** Computed sum of transaction inputs or value of the output to convert to * a trusted input */ @@ -139,9 +139,9 @@ struct btchip_transaction_context_s { /** If the transaction consumes a P2SH input */ unsigned char consumeP2SH; }; -typedef struct btchip_transaction_context_s btchip_transaction_context_t; +typedef struct transaction_context_s transaction_context_t; -struct btchip_tmp_output_s { +struct tmp_output_s { /** Change address if initialized */ unsigned char changeAddress[20]; /** Flag set if the change address was initialized */ @@ -153,15 +153,15 @@ struct btchip_tmp_output_s { /** Flag set if the outputs have been fragmented */ unsigned char multipleOutput; }; -typedef struct btchip_tmp_output_s btchip_tmp_output_t; +typedef struct tmp_output_s tmp_output_t; -struct btchip_context_s { +struct context_s { /** Flag if dongle has been halted */ secu8 halted; /** Index of the output to convert into a trusted input in a transaction */ unsigned long int trustedInputIndex; /** (Integrity protected) transaction context */ - btchip_transaction_context_t transactionContext; + transaction_context_t transactionContext; /** Non protected transaction context */ @@ -216,13 +216,13 @@ struct btchip_context_s { unsigned char *tmp; // was previously in NVRAM - btchip_transaction_summary_t transactionSummary; + transaction_summary_t transactionSummary; unsigned short hashedMessageLength; union { - btchip_tmp_output_t output; + tmp_output_t output; } tmpCtx; unsigned char currentOutput[MAX_OUTPUT_TO_CHECK]; @@ -245,21 +245,21 @@ struct btchip_context_s { /*Is swap mode*/ unsigned char called_from_swap; }; -typedef struct btchip_context_s btchip_context_t; +typedef struct context_s context_t; /** * Structure to configure the bitcoin application for a given altcoin * */ -typedef enum btchip_coin_flags_e { +typedef enum coin_flags_e { FLAG_PEERCOIN_UNITS=1, FLAG_PEERCOIN_SUPPORT=2, FLAG_SEGWIT_CHANGE_SUPPORT=4 -} btchip_coin_flags_t; +} coin_flags_t; -typedef enum btchip_coin_kind_e { +typedef enum coin_kind_e { COIN_KIND_BITCOIN_TESTNET, COIN_KIND_BITCOIN, COIN_KIND_BITCOIN_CASH, @@ -289,9 +289,9 @@ typedef enum btchip_coin_kind_e { COIN_KIND_RESISTANCE, COIN_KIND_RAVENCOIN, COIN_KIND_HYDRA -} btchip_coin_kind_t; +} coin_kind_t; -typedef struct btchip_altcoin_config_s { +typedef struct altcoin_config_s { unsigned int bip44_coin_type; unsigned int bip44_coin_type2; unsigned short p2pkh_version; @@ -308,10 +308,10 @@ typedef struct btchip_altcoin_config_s { const char* native_segwit_prefix; // null if no segwit prefix unsigned int forkid; unsigned int zcash_consensus_branch_id; - btchip_coin_kind_t kind; + coin_kind_t kind; unsigned int flags; -} btchip_altcoin_config_t; +} altcoin_config_t; -void btchip_context_init(void); +void context_init(void); #endif diff --git a/include/btchip_ecc.h b/include/ecc.h similarity index 88% rename from include/btchip_ecc.h rename to include/ecc.h index de126401..4a07074d 100644 --- a/include/btchip_ecc.h +++ b/include/ecc.h @@ -15,12 +15,12 @@ * limitations under the License. ********************************************************************************/ -#ifndef BTCHIP_ECC_H +#ifndef ECC_H -#define BTCHIP_ECC_H +#define ECC_H #include "os.h" -void btchip_compress_public_key_value(unsigned char *value); +void compress_public_key_value(unsigned char *value); #endif diff --git a/include/btchip_filesystem.h b/include/filesystem.h similarity index 61% rename from include/btchip_filesystem.h rename to include/filesystem.h index 3bbdc04d..fe994dc9 100644 --- a/include/btchip_filesystem.h +++ b/include/filesystem.h @@ -15,29 +15,29 @@ * limitations under the License. ********************************************************************************/ -#ifndef BTCHIP_FS_H +#ifndef FS_H -#define BTCHIP_FS_H +#define FS_H #include "os.h" -#include "btchip_config.h" -#include "btchip_context.h" -#include "btchip_filesystem_tx.h" +#include "config.h" +#include "context.h" +#include "filesystem_tx.h" -enum btchip_supported_modes_e { - BTCHIP_SUPPORTED_MODE_WALLET = 0x01, - BTCHIP_SUPPORTED_MODE_RELAXED_WALLET = 0x02, - BTCHIP_SUPPORTED_MODE_SERVER = 0x04, - BTCHIP_SUPPORTED_MODE_DEVELOPER = 0x08 +enum supported_modes_e { + SUPPORTED_MODE_WALLET = 0x01, + SUPPORTED_MODE_RELAXED_WALLET = 0x02, + SUPPORTED_MODE_SERVER = 0x04, + SUPPORTED_MODE_DEVELOPER = 0x08 }; -enum btchip_family_e { - BTCHIP_FAMILY_BITCOIN = 0x01, - BTCHIP_FAMILY_PEERCOIN = 0x02, - BTCHIP_FAMILY_STEALTH = 0x04 +enum family_e { + FAMILY_BITCOIN = 0x01, + FAMILY_PEERCOIN = 0x02, + FAMILY_STEALTH = 0x04 }; -struct btchip_config_s { +struct config_s { secu8 supportedModes; secu8 operationMode; unsigned char options; @@ -53,34 +53,34 @@ struct btchip_config_s { // /** Current short Coin ID length */ // unsigned char shortCoinIdLength; }; -typedef struct btchip_config_s btchip_config_t; +typedef struct config_s config_t; -typedef struct btchip_backup_area_s { - btchip_config_t config; +typedef struct backup_area_s { + config_t config; uint8_t trustedinput_key[32]; -} btchip_backup_area_t; +} backup_area_t; -typedef struct btchip_storage_s { +typedef struct storage_s { unsigned char storageInitialized; unsigned char config_valid; - btchip_backup_area_t bkp; + backup_area_t bkp; unsigned char fidoTransport; uint8_t pubKeyRequestRestriction; -} btchip_storage_t; +} storage_t; // the global nvram memory variable #if 0 -extern btchip_storage_t N_btchip_real; -#define N_btchip (*(btchip_storage_t *)PIC(&N_btchip_real)) +extern storage_t N_real; +#define N_btchip (*(storage_t *)PIC(&N_real)) #else -extern btchip_storage_t const N_btchip_real; -#define N_btchip (*(volatile btchip_storage_t *)PIC(&N_btchip_real)) +extern storage_t const N_real; +#define N_btchip (*(volatile storage_t *)PIC(&N_real)) #endif -void btchip_set_operation_mode(unsigned char operationMode); +void set_operation_mode(unsigned char operationMode); #endif diff --git a/include/btchip_filesystem_tx.h b/include/filesystem_tx.h similarity index 90% rename from include/btchip_filesystem_tx.h rename to include/filesystem_tx.h index fce2fe01..e9f13f84 100644 --- a/include/btchip_filesystem_tx.h +++ b/include/filesystem_tx.h @@ -15,9 +15,9 @@ * limitations under the License. ********************************************************************************/ -#ifndef BTCHIP_FS_TX_H +#ifndef FS_TX_H -#define BTCHIP_FS_TX_H +#define FS_TX_H #include "os.h" @@ -32,7 +32,7 @@ #define MAX_BIP44_ACCOUNT_RECOMMENDED 100 #define MAX_BIP44_ADDRESS_INDEX_RECOMMENDED 50000 -struct btchip_transaction_summary_s { +struct transaction_summary_s { unsigned char active; unsigned char payToAddressVersion; unsigned char payToScriptHashVersion; @@ -42,6 +42,6 @@ struct btchip_transaction_summary_s { unsigned short messageLength; unsigned char sighashType; }; -typedef struct btchip_transaction_summary_s btchip_transaction_summary_t; +typedef struct transaction_summary_s transaction_summary_t; #endif diff --git a/include/btchip_helpers.h b/include/helpers.h similarity index 58% rename from include/btchip_helpers.h rename to include/helpers.h index 21c67a6a..e60f8d7a 100644 --- a/include/btchip_helpers.h +++ b/include/helpers.h @@ -15,9 +15,9 @@ * limitations under the License. ********************************************************************************/ -#ifndef BTCHIP_HELPERS_H +#ifndef HELPERS_H -#define BTCHIP_HELPERS_H +#define HELPERS_H #include "os.h" #include "cx.h" @@ -30,37 +30,37 @@ #define OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET 3 -unsigned char btchip_output_script_is_regular(unsigned char *buffer); -unsigned char btchip_output_script_is_p2sh(unsigned char *buffer); -unsigned char btchip_output_script_is_op_return(unsigned char *buffer); -unsigned char btchip_output_script_is_native_witness(unsigned char *buffer); +unsigned char output_script_is_regular(unsigned char *buffer); +unsigned char output_script_is_p2sh(unsigned char *buffer); +unsigned char output_script_is_op_return(unsigned char *buffer); +unsigned char output_script_is_native_witness(unsigned char *buffer); -unsigned char btchip_output_script_is_op_create(unsigned char *buffer, +unsigned char output_script_is_op_create(unsigned char *buffer, size_t size); -unsigned char btchip_output_script_is_op_call(unsigned char *buffer, +unsigned char output_script_is_op_call(unsigned char *buffer, size_t size); -void btchip_sleep16(unsigned short delay); -void btchip_sleep32(unsigned long int delayEach, unsigned long int delayRepeat); +void sleep16(unsigned short delay); +void sleep32(unsigned long int delayEach, unsigned long int delayRepeat); -unsigned long int btchip_read_u32(unsigned char *buffer, unsigned char be, +unsigned long int read_u32(unsigned char *buffer, unsigned char be, unsigned char skipSign); -void btchip_write_u32_be(unsigned char *buffer, unsigned long int value); -void btchip_write_u32_le(unsigned char *buffer, unsigned long int value); +void write_u32_be(unsigned char *buffer, unsigned long int value); +void write_u32_le(unsigned char *buffer, unsigned long int value); -void btchip_perform_double_hash(unsigned char *in, unsigned short inlen, +void perform_double_hash(unsigned char *in, unsigned short inlen, unsigned char *out, unsigned char hash1Algorithm, unsigned char hash2Algorithm); -void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, +void public_key_hash160(unsigned char *in, unsigned short inlen, unsigned char *out); -unsigned short btchip_public_key_to_encoded_base58( +unsigned short public_key_to_encoded_base58( unsigned char *in, unsigned short inlen, unsigned char *out, unsigned short outlen, unsigned short version, unsigned char alreadyHashed); -unsigned short btchip_decode_base58_address(unsigned char *in, +unsigned short decode_base58_address(unsigned char *in, unsigned short inlen, unsigned char *out, unsigned short outlen); @@ -69,25 +69,25 @@ unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_pa unsigned char enforce_bip44_coin_type(unsigned char *bip32Path, bool for_pubkey); unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned char max_out_len); -// void btchip_set_check_internal_structure_integrity(unsigned char +// void set_check_internal_structure_integrity(unsigned char // setParameter); -#define btchip_set_check_internal_structure_integrity(x) -void btchip_swap_bytes(unsigned char *target, unsigned char *source, +#define set_check_internal_structure_integrity(x) +void swap_bytes(unsigned char *target, unsigned char *source, unsigned char size); -int btchip_sign_finalhash(unsigned char *path, size_t path_len, +int sign_finalhash(unsigned char *path, size_t path_len, unsigned char *in, unsigned short inlen, unsigned char *out, size_t* outlen, unsigned char rfc6979); -void btchip_transaction_add_output(unsigned char *hash160Address, +void transaction_add_output(unsigned char *hash160Address, unsigned char *amount, unsigned char p2sh); -unsigned char btchip_rng_u8_modulo(unsigned char modulo); -unsigned char btchip_secure_memcmp(const void *buf1, const void *buf2, +unsigned char rng_u8_modulo(unsigned char modulo); +unsigned char secure_memcmp(const void *buf1, const void *buf2, unsigned short length); -unsigned char btchip_decrease_2fa(void); -void btchip_reset_2fa(void); -void btchip_reset_token(void); -int btchip_get_public_key(unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode); +unsigned char decrease_2fa(void); +void reset_2fa(void); +void reset_token(void); +int get_public_key(unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode); #endif diff --git a/include/btchip_secure_value.h b/include/secure_value.h similarity index 96% rename from include/btchip_secure_value.h rename to include/secure_value.h index 0aa5d103..8052084a 100644 --- a/include/btchip_secure_value.h +++ b/include/secure_value.h @@ -15,9 +15,9 @@ * limitations under the License. ********************************************************************************/ -#ifndef BTCHIP_SECURE_VALUE_H +#ifndef SECURE_VALUE_H -#define BTCHIP_SECURE_VALUE_H +#define SECURE_VALUE_H #include "os.h" diff --git a/include/swap_lib_calls.h b/include/swap_lib_calls.h index 0f59a452..806e5f09 100644 --- a/include/swap_lib_calls.h +++ b/include/swap_lib_calls.h @@ -8,7 +8,7 @@ #include "stdbool.h" #include "stdint.h" -#include "btchip_context.h" +#include "context.h" #define RUN_APPLICATION 1 @@ -72,7 +72,7 @@ typedef struct create_transaction_parameters_s { typedef struct libargs_s { unsigned int id; unsigned int command; - btchip_altcoin_config_t *coin_config; + altcoin_config_t *coin_config; union { check_address_parameters_t *check_address; create_transaction_parameters_t *create_transaction; diff --git a/src/btchip_apdu_get_coin_version.c b/src/apdu_get_coin_version.c similarity index 83% rename from src/btchip_apdu_get_coin_version.c rename to src/apdu_get_coin_version.c index 7da3b8ab..cc754fe4 100644 --- a/src/btchip_apdu_get_coin_version.c +++ b/src/apdu_get_coin_version.c @@ -15,20 +15,20 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" +#include "internal.h" +#include "apdu_constants.h" #define P1_VERSION_ONLY 0x00 #define P1_VERSION_COINID 0x01 -unsigned short btchip_apdu_get_coin_version() { +unsigned short apdu_get_coin_version() { uint8_t offset = 0; SB_CHECK(N_btchip.bkp.config.operationMode); if ((SB_GET(N_btchip.bkp.config.operationMode) == - BTCHIP_MODE_SETUP_NEEDED) || - (SB_GET(N_btchip.bkp.config.operationMode) == BTCHIP_MODE_ISSUER)) { - return BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + MODE_SETUP_NEEDED) || + (SB_GET(N_btchip.bkp.config.operationMode) == MODE_ISSUER)) { + return SW_CONDITIONS_OF_USE_NOT_SATISFIED; } G_io_apdu_buffer[offset++] = G_coin_config->p2pkh_version >> 8; @@ -44,7 +44,7 @@ unsigned short btchip_apdu_get_coin_version() { memmove(G_io_apdu_buffer + offset, G_coin_config->name_short, strlen(G_coin_config->name_short)); offset += strlen(G_coin_config->name_short); - btchip_context_D.outLength = offset; + context_D.outLength = offset; - return BTCHIP_SW_OK; + return SW_OK; } diff --git a/src/btchip_apdu_get_firmware_version.c b/src/apdu_get_firmware_version.c similarity index 86% rename from src/btchip_apdu_get_firmware_version.c rename to src/apdu_get_firmware_version.c index 6fc12aac..48364bb2 100644 --- a/src/btchip_apdu_get_firmware_version.c +++ b/src/apdu_get_firmware_version.c @@ -15,8 +15,8 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" +#include "internal.h" +#include "apdu_constants.h" #define FEATURES_COMPRESSED_KEYS 0x01 #define FEATURES_SELF_SCREEN_BUTTONS 0x02 @@ -41,9 +41,9 @@ void get_firmware_version(unsigned char *buffer) { buffer[5] = TCS_LOADER_PATCH_VERSION; } -unsigned short btchip_apdu_get_firmware_version() { +unsigned short apdu_get_firmware_version() { G_io_apdu_buffer[0] = - (((N_btchip.bkp.config.options & BTCHIP_OPTION_UNCOMPRESSED_KEYS) != 0) + (((N_btchip.bkp.config.options & OPTION_UNCOMPRESSED_KEYS) != 0) ? 0x00 : 0x01); @@ -58,7 +58,7 @@ unsigned short btchip_apdu_get_firmware_version() { G_io_apdu_buffer[7] |= MODE_SETUP; G_io_apdu_buffer[7] |= MODE_OPERATION; - btchip_context_D.outLength = 0x08; + context_D.outLength = 0x08; - return BTCHIP_SW_OK; + return SW_OK; } diff --git a/src/btchip_apdu_get_operation_mode.c b/src/apdu_get_operation_mode.c similarity index 74% rename from src/btchip_apdu_get_operation_mode.c rename to src/apdu_get_operation_mode.c index 6c35a100..13f90fb0 100644 --- a/src/btchip_apdu_get_operation_mode.c +++ b/src/apdu_get_operation_mode.c @@ -15,18 +15,18 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" +#include "internal.h" +#include "apdu_constants.h" #define P1_GET_OPERATION_MODE 0x00 #define P1_GET_SECOND_FACTOR_MODE 0x01 -unsigned short btchip_apdu_get_operation_mode() { +unsigned short apdu_get_operation_mode() { SB_CHECK(N_btchip.bkp.config.operationMode); if ((SB_GET(N_btchip.bkp.config.operationMode) == - BTCHIP_MODE_SETUP_NEEDED) || - (SB_GET(N_btchip.bkp.config.operationMode) == BTCHIP_MODE_ISSUER)) { - return BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + MODE_SETUP_NEEDED) || + (SB_GET(N_btchip.bkp.config.operationMode) == MODE_ISSUER)) { + return SW_CONDITIONS_OF_USE_NOT_SATISFIED; } switch (G_io_apdu_buffer[ISO_OFFSET_P1]) { @@ -35,10 +35,10 @@ unsigned short btchip_apdu_get_operation_mode() { break; default: - return BTCHIP_SW_INCORRECT_P1_P2; + return SW_INCORRECT_P1_P2; } - btchip_context_D.outLength = 1; + context_D.outLength = 1; - return BTCHIP_SW_OK; + return SW_OK; } diff --git a/src/btchip_apdu_get_random.c b/src/apdu_get_random.c similarity index 82% rename from src/btchip_apdu_get_random.c rename to src/apdu_get_random.c index 83a11433..0f7d605e 100644 --- a/src/btchip_apdu_get_random.c +++ b/src/apdu_get_random.c @@ -15,24 +15,24 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" +#include "internal.h" +#include "apdu_constants.h" #define MAX_LENGTH 248 -unsigned short btchip_apdu_get_random() { +unsigned short apdu_get_random() { unsigned char length = G_io_apdu_buffer[ISO_OFFSET_LC]; if (length == 0) { length = MAX_LENGTH; } if (length > MAX_LENGTH) { - return BTCHIP_SW_INCORRECT_LENGTH; + return SW_INCORRECT_LENGTH; } cx_rng(G_io_apdu_buffer, length); - btchip_context_D.outLength = length; + context_D.outLength = length; - return BTCHIP_SW_OK; + return SW_OK; } diff --git a/src/btchip_apdu_get_trusted_input.c b/src/apdu_get_trusted_input.c similarity index 54% rename from src/btchip_apdu_get_trusted_input.c rename to src/apdu_get_trusted_input.c index 38d6f644..5aec2411 100644 --- a/src/btchip_apdu_get_trusted_input.c +++ b/src/apdu_get_trusted_input.c @@ -15,67 +15,67 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" +#include "internal.h" +#include "apdu_constants.h" #define GET_TRUSTED_INPUT_P1_FIRST 0x00 #define GET_TRUSTED_INPUT_P1_NEXT 0x80 -unsigned short btchip_apdu_get_trusted_input() { +unsigned short apdu_get_trusted_input() { unsigned char apduLength; unsigned char dataOffset = 0; apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; SB_CHECK(N_btchip.bkp.config.operationMode); switch (SB_GET(N_btchip.bkp.config.operationMode)) { - case BTCHIP_MODE_WALLET: - case BTCHIP_MODE_RELAXED_WALLET: - case BTCHIP_MODE_SERVER: + case MODE_WALLET: + case MODE_RELAXED_WALLET: + case MODE_SERVER: break; default: - return BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + return SW_CONDITIONS_OF_USE_NOT_SATISFIED; } if (G_io_apdu_buffer[ISO_OFFSET_P1] == GET_TRUSTED_INPUT_P1_FIRST) { // Initialize - btchip_context_D.transactionTargetInput = - btchip_read_u32(G_io_apdu_buffer + ISO_OFFSET_CDATA, 1, 0); - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; - btchip_context_D.trustedInputProcessed = 0; - btchip_context_D.transactionContext.consumeP2SH = 0; - btchip_set_check_internal_structure_integrity(1); + context_D.transactionTargetInput = + read_u32(G_io_apdu_buffer + ISO_OFFSET_CDATA, 1, 0); + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + context_D.trustedInputProcessed = 0; + context_D.transactionContext.consumeP2SH = 0; + set_check_internal_structure_integrity(1); dataOffset = 4; - btchip_context_D.transactionHashOption = TRANSACTION_HASH_FULL; - btchip_context_D.usingSegwit = 0; - btchip_context_D.usingOverwinter = 0; + context_D.transactionHashOption = TRANSACTION_HASH_FULL; + context_D.usingSegwit = 0; + context_D.usingOverwinter = 0; } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != GET_TRUSTED_INPUT_P1_NEXT) { - return BTCHIP_SW_INCORRECT_P1_P2; + return SW_INCORRECT_P1_P2; } if (G_io_apdu_buffer[ISO_OFFSET_P2] != 0x00) { - return BTCHIP_SW_INCORRECT_P1_P2; + return SW_INCORRECT_P1_P2; } - btchip_context_D.transactionBufferPointer = + context_D.transactionBufferPointer = G_io_apdu_buffer + ISO_OFFSET_CDATA + dataOffset; - btchip_context_D.transactionDataRemaining = apduLength - dataOffset; + context_D.transactionDataRemaining = apduLength - dataOffset; transaction_parse(PARSE_MODE_TRUSTED_INPUT); - if (btchip_context_D.transactionContext.transactionState == - BTCHIP_TRANSACTION_PARSED) { + if (context_D.transactionContext.transactionState == + TRANSACTION_PARSED) { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; - btchip_set_check_internal_structure_integrity(1); - if (!btchip_context_D.trustedInputProcessed) { + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + set_check_internal_structure_integrity(1); + if (!context_D.trustedInputProcessed) { // Output was not found - return BTCHIP_SW_INCORRECT_DATA; + return SW_INCORRECT_DATA; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, + if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, CX_LAST, NULL, 0, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32)) { - return BTCHIP_SW_TECHNICAL_PROBLEM; + return SW_TECHNICAL_PROBLEM; } // Otherwise prepare @@ -84,15 +84,15 @@ unsigned short btchip_apdu_get_trusted_input() { G_io_apdu_buffer[1] = 0x00; cx_hash_sha256(G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32, G_io_apdu_buffer + 4, 32); - btchip_write_u32_le(G_io_apdu_buffer + 4 + 32, - btchip_context_D.transactionTargetInput); + write_u32_le(G_io_apdu_buffer + 4 + 32, + context_D.transactionTargetInput); memmove(G_io_apdu_buffer + 4 + 32 + 4, - btchip_context_D.transactionContext.transactionAmount, 8); + context_D.transactionContext.transactionAmount, 8); cx_hmac_sha256((uint8_t *)N_btchip.bkp.trustedinput_key, sizeof(N_btchip.bkp.trustedinput_key), G_io_apdu_buffer, TRUSTED_INPUT_SIZE, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32); - btchip_context_D.outLength = TRUSTED_INPUT_TOTAL_SIZE; + context_D.outLength = TRUSTED_INPUT_TOTAL_SIZE; } - return BTCHIP_SW_OK; + return SW_OK; } diff --git a/src/btchip_apdu_get_wallet_public_key.c b/src/apdu_get_wallet_public_key.c similarity index 72% rename from src/btchip_apdu_get_wallet_public_key.c rename to src/apdu_get_wallet_public_key.c index 74f49bea..04f9a605 100644 --- a/src/btchip_apdu_get_wallet_public_key.c +++ b/src/apdu_get_wallet_public_key.c @@ -15,27 +15,27 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" +#include "internal.h" +#include "apdu_constants.h" -#include "btchip_bagl_extensions.h" +#include "bagl_extensions.h" #include "segwit_addr.h" #include "cashaddr.h" -#include "btchip_apdu_get_wallet_public_key.h" +#include "apdu_get_wallet_public_key.h" int get_public_key_chain_code(unsigned char* keyPath, size_t keyPath_len, bool uncompressedPublicKeys, unsigned char* publicKey, unsigned char* chainCode) { uint8_t public_key[65]; int keyLength = 0; - if (btchip_get_public_key(keyPath, keyPath_len, public_key, chainCode)) { + if (get_public_key(keyPath, keyPath_len, public_key, chainCode)) { return keyLength; } // Then encode it if (uncompressedPublicKeys) { keyLength = 65; } else { - btchip_compress_public_key_value(public_key); + compress_public_key_value(public_key); keyLength = 33; } @@ -44,10 +44,10 @@ int get_public_key_chain_code(unsigned char* keyPath, size_t keyPath_len, bool u return keyLength; } -unsigned short btchip_apdu_get_wallet_public_key() { +unsigned short apdu_get_wallet_public_key() { unsigned char keyLength; unsigned char uncompressedPublicKeys = - ((N_btchip.bkp.config.options & BTCHIP_OPTION_UNCOMPRESSED_KEYS) != 0); + ((N_btchip.bkp.config.options & OPTION_UNCOMPRESSED_KEYS) != 0); uint32_t request_token; unsigned char chainCode[32]; uint8_t is_derivation_path_unusual = 0; @@ -58,8 +58,8 @@ unsigned short btchip_apdu_get_wallet_public_key() { bool segwit = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_SEGWIT); bool nativeSegwit = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NATIVE_SEGWIT); bool cashAddr = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_CASHADDR); - if (display && btchip_context_D.called_from_swap) { - return BTCHIP_SW_INCORRECT_DATA; + if (display && context_D.called_from_swap) { + return SW_INCORRECT_DATA; } switch (G_io_apdu_buffer[ISO_OFFSET_P1]) { case P1_NO_DISPLAY: @@ -67,13 +67,13 @@ unsigned short btchip_apdu_get_wallet_public_key() { case P1_REQUEST_TOKEN: break; default: - return BTCHIP_SW_INCORRECT_P1_P2; + return SW_INCORRECT_P1_P2; } switch (G_io_apdu_buffer[ISO_OFFSET_P2]) { case P2_NATIVE_SEGWIT: if (!(G_coin_config->native_segwit_prefix)) { - return BTCHIP_SW_INCORRECT_P1_P2; + return SW_INCORRECT_P1_P2; } __attribute__((fallthrough)); case P2_LEGACY: @@ -81,15 +81,15 @@ unsigned short btchip_apdu_get_wallet_public_key() { break; case P2_CASHADDR: if (G_coin_config->kind != COIN_KIND_BITCOIN_CASH) { - return BTCHIP_SW_INCORRECT_P1_P2; + return SW_INCORRECT_P1_P2; } break; default: - return BTCHIP_SW_INCORRECT_P1_P2; + return SW_INCORRECT_P1_P2; } if (G_io_apdu_buffer[ISO_OFFSET_LC] < 0x01) { - return BTCHIP_SW_INCORRECT_LENGTH; + return SW_INCORRECT_LENGTH; } if (display) { is_derivation_path_unusual = set_key_path_to_display(G_io_apdu_buffer + ISO_OFFSET_CDATA); @@ -97,21 +97,21 @@ unsigned short btchip_apdu_get_wallet_public_key() { if(display_request_token){ uint8_t request_token_offset = ISO_OFFSET_CDATA + G_io_apdu_buffer[ISO_OFFSET_CDATA]*4 + 1; - request_token = btchip_read_u32(G_io_apdu_buffer + request_token_offset, true, false); + request_token = read_u32(G_io_apdu_buffer + request_token_offset, true, false); } SB_CHECK(N_btchip.bkp.config.operationMode); switch (SB_GET(N_btchip.bkp.config.operationMode)) { - case BTCHIP_MODE_WALLET: - case BTCHIP_MODE_RELAXED_WALLET: - case BTCHIP_MODE_SERVER: + case MODE_WALLET: + case MODE_RELAXED_WALLET: + case MODE_SERVER: break; default: - return BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + return SW_CONDITIONS_OF_USE_NOT_SATISFIED; } if (os_global_pin_is_validated() != BOLOS_UX_OK) { - return BTCHIP_SW_SECURITY_STATUS_NOT_SATISFIED; + return SW_SECURITY_STATUS_NOT_SATISFIED; } PRINTF("pin ok\n"); @@ -122,18 +122,18 @@ unsigned short btchip_apdu_get_wallet_public_key() { keyLength = get_public_key_chain_code(G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH, uncompressedPublicKeys, G_io_apdu_buffer + 1, chainCode); if (keyLength == 0) { - return BTCHIP_SW_TECHNICAL_PROBLEM; + return SW_TECHNICAL_PROBLEM; } if (cashAddr) { uint8_t tmp[20]; - btchip_public_key_hash160(G_io_apdu_buffer + 1, // IN + public_key_hash160(G_io_apdu_buffer + 1, // IN keyLength, // INLEN tmp); keyLength = cashaddr_encode(tmp, 20, G_io_apdu_buffer + 67, 50, CASHADDR_P2PKH); } else if (!(segwit || nativeSegwit)) { - keyLength = btchip_public_key_to_encoded_base58( + keyLength = public_key_to_encoded_base58( G_io_apdu_buffer + 1, // IN keyLength, // INLEN G_io_apdu_buffer + 67, // OUT @@ -143,12 +143,12 @@ unsigned short btchip_apdu_get_wallet_public_key() { uint8_t tmp[22]; tmp[0] = 0x00; tmp[1] = 0x14; - btchip_public_key_hash160(G_io_apdu_buffer + 1, // IN + public_key_hash160(G_io_apdu_buffer + 1, // IN keyLength, // INLEN tmp + 2 // OUT ); if (!nativeSegwit) { - keyLength = btchip_public_key_to_encoded_base58( + keyLength = public_key_to_encoded_base58( tmp, // IN 22, // INLEN G_io_apdu_buffer + 67, // OUT @@ -175,7 +175,7 @@ unsigned short btchip_apdu_get_wallet_public_key() { // output chain code memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, sizeof(chainCode)); - btchip_context_D.outLength = 1 + 65 + 1 + keyLength + sizeof(chainCode); + context_D.outLength = 1 + 65 + 1 + keyLength + sizeof(chainCode); // privacy : force display the address if the path isn't standard // and could reveal another fork holdings according to BIP 44 rules @@ -185,49 +185,49 @@ unsigned short btchip_apdu_get_wallet_public_key() { if (display) { if (keyLength > 50) { - return BTCHIP_SW_INCORRECT_DATA; + return SW_INCORRECT_DATA; } // Hax, avoid wasting space memmove(G_io_apdu_buffer + 200, G_io_apdu_buffer + 67, keyLength); G_io_apdu_buffer[200 + keyLength] = '\0'; - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_bagl_display_public_key(is_derivation_path_unusual); + context_D.io_flags |= IO_ASYNCH_REPLY; + bagl_display_public_key(is_derivation_path_unusual); } // If the token requested has already been approved in a previous call, the source is trusted so don't ask for approval again else if(display_request_token && - (!btchip_context_D.has_valid_token || memcmp(&request_token, btchip_context_D.last_token, 4))) + (!context_D.has_valid_token || memcmp(&request_token, context_D.last_token, 4))) { // disable the has_valid_token flag and store the new token - btchip_context_D.has_valid_token = false; - memcpy(btchip_context_D.last_token, &request_token, 4); + context_D.has_valid_token = false; + memcpy(context_D.last_token, &request_token, 4); // Hax, avoid wasting space snprintf((char *)G_io_apdu_buffer + 200, 9, "%08X", request_token); G_io_apdu_buffer[200 + 8] = '\0'; - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_bagl_display_token(); + context_D.io_flags |= IO_ASYNCH_REPLY; + bagl_display_token(); } else if(require_user_approval) { - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_bagl_request_pubkey_approval(); + context_D.io_flags |= IO_ASYNCH_REPLY; + bagl_request_pubkey_approval(); } - return BTCHIP_SW_OK; + return SW_OK; } -void btchip_bagl_user_action_display(unsigned char confirming) { - unsigned short sw = BTCHIP_SW_OK; +void bagl_user_action_display(unsigned char confirming) { + unsigned short sw = SW_OK; // confirm and finish the apdu exchange //spaghetti if (confirming) { - btchip_context_D.outLength -= + context_D.outLength -= 2; // status was already set by the last call } else { - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; - btchip_context_D.outLength = 0; + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + context_D.outLength = 0; } - G_io_apdu_buffer[btchip_context_D.outLength++] = sw >> 8; - G_io_apdu_buffer[btchip_context_D.outLength++] = sw; + G_io_apdu_buffer[context_D.outLength++] = sw >> 8; + G_io_apdu_buffer[context_D.outLength++] = sw; - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, btchip_context_D.outLength); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, context_D.outLength); } diff --git a/src/btchip_apdu_get_wallet_public_key.h b/src/apdu_get_wallet_public_key.h similarity index 57% rename from src/btchip_apdu_get_wallet_public_key.h rename to src/apdu_get_wallet_public_key.h index c359dda3..429076d6 100644 --- a/src/btchip_apdu_get_wallet_public_key.h +++ b/src/apdu_get_wallet_public_key.h @@ -1,5 +1,5 @@ -#ifndef _BTCHIP_APDU_GET_WALLET_PUBLIC_KEY_H_ -#define _BTCHIP_APDU_GET_WALLET_PUBLIC_KEY_H_ +#ifndef _APDU_GET_WALLET_PUBLIC_KEY_H_ +#define _APDU_GET_WALLET_PUBLIC_KEY_H_ #define P1_NO_DISPLAY 0x00 #define P1_DISPLAY 0x01 @@ -10,4 +10,4 @@ #define P2_NATIVE_SEGWIT 0x02 #define P2_CASHADDR 0x03 -#endif //_BTCHIP_APDU_GET_WALLET_PUBLIC_KEY_H_ \ No newline at end of file +#endif //_APDU_GET_WALLET_PUBLIC_KEY_H_ \ No newline at end of file diff --git a/src/apdu_hash_input_finalize_full.c b/src/apdu_hash_input_finalize_full.c new file mode 100644 index 00000000..bbc00d90 --- /dev/null +++ b/src/apdu_hash_input_finalize_full.c @@ -0,0 +1,653 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +// TODO Trustlet, BAGL : process each output separately. +// review nvm_write policy + +#include "internal.h" +#include "apdu_constants.h" +#include "bagl_extensions.h" +#include "ui.h" +#include "lib_standard_app/crypto_helpers.h" + +#define FINALIZE_P1_MORE 0x00 +#define FINALIZE_P1_LAST 0x80 +#define FINALIZE_P1_CHANGEINFO 0xFF + +#define FINALIZE_P2_DEFAULT 0x00 + +#define FLAG_SIGNATURE 0x01 +#define FLAG_CHANGE_VALIDATED 0x80 + +void apdu_hash_input_finalize_full_reset(void) { + context_D.currentOutputOffset = 0; + context_D.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; + memset(context_D.totalOutputAmount, 0, + sizeof(context_D.totalOutputAmount)); + context_D.changeOutputFound = 0; + set_check_internal_structure_integrity(1); +} + +static bool check_output_displayable() { + bool displayable = true; + unsigned char amount[8], isOpReturn, isP2sh, isNativeSegwit, j, + nullAmount = 1; + unsigned char isOpCreate, isOpCall; + + for (j = 0; j < 8; j++) { + if (context_D.currentOutput[j] != 0) { + nullAmount = 0; + break; + } + } + if (!nullAmount) { + swap_bytes(amount, context_D.currentOutput, 8); + transaction_amount_add_be(context_D.totalOutputAmount, + context_D.totalOutputAmount, amount); + } + isOpReturn = + output_script_is_op_return(context_D.currentOutput + 8); + isP2sh = output_script_is_p2sh(context_D.currentOutput + 8); + isNativeSegwit = output_script_is_native_witness( + context_D.currentOutput + 8); + isOpCreate = + output_script_is_op_create(context_D.currentOutput + 8, + sizeof(context_D.currentOutput) - 8); + isOpCall = + output_script_is_op_call(context_D.currentOutput + 8, + sizeof(context_D.currentOutput) - 8); + if (((G_coin_config->kind == COIN_KIND_HYDRA) && + !output_script_is_regular(context_D.currentOutput + 8) && + !isP2sh && !(nullAmount && isOpReturn) && !isOpCreate && !isOpCall) || + (!(G_coin_config->kind == COIN_KIND_HYDRA) && + !output_script_is_regular(context_D.currentOutput + 8) && + !isP2sh && !(nullAmount && isOpReturn))) { + PRINTF("Error : Unrecognized output script"); + THROW(EXCEPTION); + } + if (context_D.tmpCtx.output.changeInitialized && !isOpReturn) { + bool changeFound = false; + unsigned char addressOffset = + (isNativeSegwit ? OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET + : isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH + : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); + if (!isP2sh && + memcmp(context_D.currentOutput + 8 + addressOffset, + context_D.tmpCtx.output.changeAddress, + 20) == 0) { + changeFound = true; + } else if (isP2sh && context_D.usingSegwit) { + unsigned char changeSegwit[22]; + changeSegwit[0] = 0x00; + changeSegwit[1] = 0x14; + memmove(changeSegwit + 2, + context_D.tmpCtx.output.changeAddress, 20); + public_key_hash160(changeSegwit, 22, changeSegwit); + if (memcmp(context_D.currentOutput + 8 + addressOffset, + changeSegwit, 20) == 0) { + if (G_coin_config->flags & FLAG_SEGWIT_CHANGE_SUPPORT) { + changeFound = true; + } else { + // Attempt to avoid fatal failures on Bitcoin Cash + PRINTF("Error : Non spendable Segwit change"); + THROW(EXCEPTION); + } + } + } + if (changeFound) { + if (context_D.changeOutputFound) { + PRINTF("Error : Multiple change output found"); + THROW(EXCEPTION); + } + context_D.changeOutputFound = true; + displayable = false; + } + } + + return displayable; +} + +bool handle_output_state() { + uint32_t discardSize = 0; + context_D.discardSize = 0; + bool processed = false; + switch (context_D.outputParsingState) { + case OUTPUT_PARSING_NUMBER_OUTPUTS: { + context_D.totalOutputs = 0; + if (context_D.currentOutputOffset < 1) { + break; + } + if (context_D.currentOutput[0] < 0xFD) { + context_D.totalOutputs = context_D.remainingOutputs = + context_D.currentOutput[0]; + discardSize = 1; + context_D.outputParsingState = OUTPUT_PARSING_OUTPUT; + processed = true; + break; + } + if (context_D.currentOutput[0] == 0xFD) { + if (context_D.currentOutputOffset < 3) { + break; + } + context_D.totalOutputs = context_D.remainingOutputs = + (context_D.currentOutput[2] << 8) | + context_D.currentOutput[1]; + discardSize = 3; + context_D.outputParsingState = OUTPUT_PARSING_OUTPUT; + processed = true; + break; + } else if (context_D.currentOutput[0] == 0xFE) { + if (context_D.currentOutputOffset < 5) { + break; + } + context_D.totalOutputs = context_D.remainingOutputs = + read_u32(context_D.currentOutput + 1, 0, 0); + discardSize = 5; + context_D.outputParsingState = OUTPUT_PARSING_OUTPUT; + processed = true; + break; + } else { + THROW(EXCEPTION); + } + } break; + + case OUTPUT_PARSING_OUTPUT: { + unsigned int scriptSize; + if (context_D.currentOutputOffset < 9) { + break; + } + if (context_D.currentOutput[8] < 0xFD) { + scriptSize = context_D.currentOutput[8]; + discardSize = 1; + } else if (context_D.currentOutput[8] == 0xFD) { + if (context_D.currentOutputOffset < 9 + 2) { + break; + } + scriptSize = + read_u32(context_D.currentOutput + 9, 0, 0); + discardSize = 3; + } else { + // Unrealistically large script + THROW(EXCEPTION); + } + if (context_D.currentOutputOffset < + 8 + discardSize + scriptSize) { + discardSize = 0; + break; + } + + processed = true; + + discardSize += 8 + scriptSize; + + if (check_output_displayable()) { + context_D.io_flags |= IO_ASYNCH_REPLY; + + // The output can be processed by the UI + + context_D.discardSize = discardSize; + discardSize = 0; + } else { + context_D.remainingOutputs--; + } + } break; + + default: + THROW(EXCEPTION); + } + + if (discardSize != 0) { + memmove(context_D.currentOutput, + context_D.currentOutput + discardSize, + context_D.currentOutputOffset - discardSize); + context_D.currentOutputOffset -= discardSize; + } + + return processed; +} + +// out should be 32 bytes, even only 20 bytes is significant for output +int get_pubkey_hash160(unsigned char* keyPath, size_t keyPath_len, unsigned char* out) { + cx_ecfp_public_key_t public_key; + int keyLength; + if (get_public_key(keyPath, keyPath_len, public_key.W, NULL)) { + return -1; + } + if (((N_btchip.bkp.config.options & + OPTION_UNCOMPRESSED_KEYS) != 0)) { + keyLength = 65; + } else { + compress_public_key_value(public_key.W); + keyLength = 33; + } + public_key_hash160( + public_key.W, // IN + keyLength, // INLEN + out // OUT + ); + return 0; +} + +unsigned short apdu_hash_input_finalize_full_internal( + transaction_summary_t *transactionSummary) { + unsigned char authorizationHash[32]; + unsigned char apduLength; + unsigned short sw = SW_OK; + unsigned char *target = G_io_apdu_buffer; + unsigned char p1 = G_io_apdu_buffer[ISO_OFFSET_P1]; + unsigned char hashOffset = 0; + + apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; + + if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && + (p1 != FINALIZE_P1_CHANGEINFO)) { + return SW_INCORRECT_P1_P2; + } + + // See if there is a hashing offset + if (context_D.usingSegwit && + (context_D.tmpCtx.output.multipleOutput == 0)) { + unsigned char firstByte = G_io_apdu_buffer[ISO_OFFSET_CDATA]; + if (firstByte < 0xfd) { + hashOffset = 1; + } else if (firstByte == 0xfd) { + hashOffset = 3; + } else if (firstByte == 0xfe) { + hashOffset = 5; + } + } + + // Check state + set_check_internal_structure_integrity(0); + if (context_D.transactionContext.transactionState != + TRANSACTION_PRESIGN_READY) { + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } + + if (p1 == FINALIZE_P1_CHANGEINFO) { + if (!context_D.transactionContext.firstSigned) { + // Already validated, should be prevented on the client side +return_OK: + return SW_OK; + } + if (!context_D.tmpCtx.output.changeAccepted) { + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } + memset(transactionSummary, 0, + sizeof(transaction_summary_t)); + if (G_io_apdu_buffer[ISO_OFFSET_CDATA] == 0x00) { + // Called with no change path, abort, should be prevented on + // the client side + goto return_OK; + } + memmove(transactionSummary->keyPath, + G_io_apdu_buffer + ISO_OFFSET_CDATA, + MAX_BIP32_PATH_LENGTH); + + if (get_pubkey_hash160(transactionSummary->keyPath, sizeof(transactionSummary->keyPath), context_D.tmpCtx.output.changeAddress)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + PRINTF("Change address = %.*H\n", 20, context_D.tmpCtx.output.changeAddress); + + context_D.tmpCtx.output.changeInitialized = 1; + context_D.tmpCtx.output.changeAccepted = 0; + + // if the bip44 change path provided is not canonical or its index are unsual, ask for user approval + if(bip44_derivation_guard(transactionSummary->keyPath, true)) { + if (context_D.called_from_swap) { + PRINTF("In swap mode only standart path is allowed\n"); + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } + context_D.io_flags |= IO_ASYNCH_REPLY; + context_D.outputParsingState = BIP44_CHANGE_PATH_VALIDATION; + bagl_request_change_path_approval(transactionSummary->keyPath); + } + + goto return_OK; + } + + // Always update the transaction & authorization hashes with the + // given data + // For SegWit, this has been reset to hold hashOutputs + if (!context_D.segwitParsedOnce) { + if ((int)(apduLength - hashOffset) < 0) { + sw = SW_INCORRECT_DATA; + goto discardTransaction; + } + if (context_D.usingOverwinter) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, apduLength - hashOffset, NULL, 0)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + } + else { + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", apduLength - hashOffset, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset); + if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, + G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, + apduLength - hashOffset, NULL, 0)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + } + } + + if (context_D.transactionContext.firstSigned) { + if ((context_D.currentOutputOffset + apduLength) > + sizeof(context_D.currentOutput)) { + PRINTF("Output is too long to be checked\n"); + sw = SW_INCORRECT_DATA; + goto discardTransaction; + } + memmove(context_D.currentOutput + + context_D.currentOutputOffset, + G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength); + context_D.currentOutputOffset += apduLength; + + while (handle_output_state() && + (!(context_D.io_flags & IO_ASYNCH_REPLY))) + ; + + // Finalize the TX if necessary + + if ((context_D.remainingOutputs == 0) && + (!(context_D.io_flags & IO_ASYNCH_REPLY))) { + context_D.io_flags |= IO_ASYNCH_REPLY; + context_D.outputParsingState = + OUTPUT_FINALIZE_TX; + } + } + + if (G_io_apdu_buffer[ISO_OFFSET_P1] == FINALIZE_P1_MORE) { + if (!context_D.usingSegwit) { + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", apduLength, G_io_apdu_buffer + ISO_OFFSET_CDATA); + if (cx_hash_no_throw( + &context_D.transactionHashAuthorization.header, + 0, G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength, + NULL, 0)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + } + G_io_apdu_buffer[0] = 0x00; + context_D.outLength = 1; + context_D.tmpCtx.output.multipleOutput = 1; + goto return_OK; + } + + if (!context_D.usingSegwit) { + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", apduLength, G_io_apdu_buffer + ISO_OFFSET_CDATA); + if (cx_hash_no_throw(&context_D.transactionHashAuthorization.header, + CX_LAST, G_io_apdu_buffer + ISO_OFFSET_CDATA, + apduLength, authorizationHash, 32)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + } + + if (context_D.usingSegwit) { + if (!context_D.segwitParsedOnce) { + if (context_D.usingOverwinter) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, CX_LAST, context_D.segwit.cache.hashedOutputs, 0, context_D.segwit.cache.hashedOutputs, 32)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + } + else { + if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, + CX_LAST, + context_D.segwit.cache.hashedOutputs, 0, + context_D.segwit.cache.hashedOutputs, 32)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + if (cx_sha256_init_no_throw(&context_D.transactionHashFull.sha256)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, + CX_LAST, + context_D.segwit.cache.hashedOutputs, + sizeof(context_D.segwit.cache.hashedOutputs), + context_D.segwit.cache.hashedOutputs, 32)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + } + PRINTF("hashOutputs\n%.*H\n",32,context_D.segwit.cache.hashedOutputs); + if (cx_hash_no_throw( + &context_D.transactionHashAuthorization.header, + CX_LAST, G_io_apdu_buffer, 0, authorizationHash, 32)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); + } else { + if (cx_hash_no_throw( + &context_D.transactionHashAuthorization.header, + CX_LAST, + (unsigned char *)&context_D.segwit.cache, + sizeof(context_D.segwit.cache), + authorizationHash, 32)) { + sw = SW_TECHNICAL_DETAILS(0x0F); + goto discardTransaction; + } + PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); + } + } + + if (context_D.transactionContext.firstSigned) { + if (!context_D.tmpCtx.output.changeInitialized) { + memset(transactionSummary, 0, + sizeof(transaction_summary_t)); + } + + transactionSummary->payToAddressVersion = + G_coin_config->p2pkh_version; + transactionSummary->payToScriptHashVersion = + G_coin_config->p2sh_version; + + // Generate new nonce + + cx_rng(transactionSummary->transactionNonce, 8); + } + + G_io_apdu_buffer[0] = 0x00; + target++; + + *target = 0x00; + target++; + + context_D.outLength = (target - G_io_apdu_buffer); + + // Check that the input being signed is part of the same + // transaction, otherwise abort + // (this is done to keep the transaction counter limit per session + // synchronized) + if (context_D.transactionContext.firstSigned) { + memmove(transactionSummary->authorizationHash, + authorizationHash, + sizeof(transactionSummary->authorizationHash)); + goto return_OK; + } else { + if (secure_memcmp( + authorizationHash, + transactionSummary->authorizationHash, + sizeof(transactionSummary->authorizationHash))) { + PRINTF("Authorization hash not matching, aborting\n"); + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } + + if (context_D.usingSegwit && + !context_D.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context_D.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + } else { + context_D.transactionContext.transactionState = + TRANSACTION_SIGN_READY; + } + sw = SW_OK; + } + apdu_hash_input_finalize_full_reset(); + return sw; + +discardTransaction: + apdu_hash_input_finalize_full_reset(); + ui_transaction_error(); + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + context_D.outLength = 0; + + memmove(G_io_apdu_buffer, context_D.currentOutput, + context_D.currentOutputOffset); + context_D.outLength = context_D.currentOutputOffset; + return sw; +} + +unsigned short apdu_hash_input_finalize_full() { + PRINTF("state=%d\n", context_D.outputParsingState); + unsigned short sw = apdu_hash_input_finalize_full_internal( + &context_D.transactionSummary); + if (context_D.io_flags & IO_ASYNCH_REPLY) { + // if the UI reject the processing of the request, then reply + // immediately + bool status; + if(context_D.outputParsingState == BIP44_CHANGE_PATH_VALIDATION) { + context_D.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; + return sw; + } + else if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { + status = bagl_finalize_tx(); + } + else { + status = bagl_confirm_single_output(); + } + if (!status) { + ui_transaction_error(); + context_D.io_flags &= ~IO_ASYNCH_REPLY; + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + context_D.outLength = 0; + sw = SW_INCORRECT_DATA; + } + } + return sw; +} + +unsigned char bagl_user_action(unsigned char confirming) { + unsigned short sw = SW_OK; + + // confirm and finish the apdu exchange //spaghetti + + if (confirming) { + // Check if all inputs have been confirmed + + if (context_D.outputParsingState == + OUTPUT_PARSING_OUTPUT) { + context_D.remainingOutputs--; + } + + while (context_D.remainingOutputs != 0) { + memmove(context_D.currentOutput, + context_D.currentOutput + + context_D.discardSize, + context_D.currentOutputOffset - + context_D.discardSize); + context_D.currentOutputOffset -= + context_D.discardSize; + context_D.io_flags &= ~IO_ASYNCH_REPLY; + while (handle_output_state() && + (!(context_D.io_flags & IO_ASYNCH_REPLY))) + ; + if (context_D.io_flags & IO_ASYNCH_REPLY) { + if (!bagl_confirm_single_output()) { + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + sw = SW_INCORRECT_DATA; + break; + } else { + // Let the UI play + return 1; + } + } else { + // Out of data to process, wait for the next call + break; + } + } + + if ((context_D.outputParsingState == + OUTPUT_PARSING_OUTPUT) && + (context_D.remainingOutputs == 0)) { + context_D.outputParsingState = OUTPUT_FINALIZE_TX; + if (!bagl_finalize_tx()) { + context_D.outputParsingState = + OUTPUT_PARSING_NONE; + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + sw = SW_INCORRECT_DATA; + } else { + // Let the UI play + return 1; + } + } + + if (context_D.outputParsingState == + OUTPUT_FINALIZE_TX) { + context_D.transactionContext.firstSigned = 0; + + if (context_D.usingSegwit && + !context_D.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context_D.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + } else { + context_D.transactionContext.transactionState = + TRANSACTION_SIGN_READY; + } + } + context_D.outLength -= + 2; // status was already set by the last call + } else { + // Discard transaction + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + context_D.outLength = 0; + } + G_io_apdu_buffer[context_D.outLength++] = sw >> 8; + G_io_apdu_buffer[context_D.outLength++] = sw; + + if ((context_D.outputParsingState == OUTPUT_FINALIZE_TX) || + (sw != SW_OK)) { + + // we've finished the processing of the input + apdu_hash_input_finalize_full_reset(); + } + + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, context_D.outLength); + + return 0; +} diff --git a/src/btchip_apdu_hash_input_start.c b/src/apdu_hash_input_start.c similarity index 68% rename from src/btchip_apdu_hash_input_start.c rename to src/apdu_hash_input_start.c index d7119c55..233fddfb 100644 --- a/src/btchip_apdu_hash_input_start.c +++ b/src/apdu_hash_input_start.c @@ -15,9 +15,9 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" -#include "btchip_bagl_extensions.h" +#include "internal.h" +#include "apdu_constants.h" +#include "bagl_extensions.h" #define P1_FIRST 0x00 #define P1_NEXT 0x80 @@ -39,28 +39,28 @@ && G_io_apdu_buffer[ISO_OFFSET_CDATA + 2] == MAGIC_TRUSTED_INPUT \ && G_io_apdu_buffer[ISO_OFFSET_CDATA + 3] == 0x00) -unsigned short btchip_apdu_hash_input_start() { +unsigned short apdu_hash_input_start() { unsigned char apduLength; apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; SB_CHECK(N_btchip.bkp.config.operationMode); switch (SB_GET(N_btchip.bkp.config.operationMode)) { - case BTCHIP_MODE_WALLET: - case BTCHIP_MODE_RELAXED_WALLET: - case BTCHIP_MODE_SERVER: + case MODE_WALLET: + case MODE_RELAXED_WALLET: + case MODE_SERVER: break; default: - return BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + return SW_CONDITIONS_OF_USE_NOT_SATISFIED; } if (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_FIRST) { // Initialize - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; - btchip_set_check_internal_structure_integrity(1); - btchip_context_D.transactionHashOption = TRANSACTION_HASH_BOTH; + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + set_check_internal_structure_integrity(1); + context_D.transactionHashOption = TRANSACTION_HASH_BOTH; } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != P1_NEXT) { - return BTCHIP_SW_INCORRECT_P1_P2; + return SW_INCORRECT_P1_P2; } if ((G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW) || @@ -68,8 +68,8 @@ unsigned short btchip_apdu_hash_input_start() { (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_CASHADDR) || (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_OVERWINTER) || (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_SAPLING)) { - // btchip_context_D.transactionContext.consumeP2SH = - // ((N_btchip.bkp.config.options & BTCHIP_OPTION_SKIP_2FA_P2SH) != 0); + // context_D.transactionContext.consumeP2SH = + // ((N_btchip.bkp.config.options & OPTION_SKIP_2FA_P2SH) != 0); if (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_FIRST) { unsigned char usingSegwit = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT) || @@ -84,68 +84,68 @@ unsigned short btchip_apdu_hash_input_start() { // Thus allowing for numerous output to be processed in the // background without // requiring to disable autolock/autopoweroff - if (!btchip_context_D.transactionContext.firstSigned && + if (!context_D.transactionContext.firstSigned && os_global_pin_is_validated() != BOLOS_UX_OK) { - return BTCHIP_SW_SECURITY_STATUS_NOT_SATISFIED; + return SW_SECURITY_STATUS_NOT_SATISFIED; } // Master transaction reset - btchip_context_D.transactionContext.firstSigned = 1; - btchip_context_D.transactionContext.consumeP2SH = 0; - btchip_context_D.transactionContext.relaxed = 0; - btchip_context_D.usingSegwit = usingSegwit; - btchip_context_D.usingCashAddr = + context_D.transactionContext.firstSigned = 1; + context_D.transactionContext.consumeP2SH = 0; + context_D.transactionContext.relaxed = 0; + context_D.usingSegwit = usingSegwit; + context_D.usingCashAddr = (G_coin_config->kind == COIN_KIND_BITCOIN_CASH ? usingCashAddr : 0); - btchip_context_D.usingOverwinter = 0; + context_D.usingOverwinter = 0; if ((G_coin_config->kind == COIN_KIND_ZCASH) || (G_coin_config->kind == COIN_KIND_KOMODO) || (G_coin_config->kind == COIN_KIND_ZCLASSIC) || (G_coin_config->kind == COIN_KIND_RESISTANCE)) { if (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_OVERWINTER) { - btchip_context_D.usingOverwinter = ZCASH_USING_OVERWINTER; + context_D.usingOverwinter = ZCASH_USING_OVERWINTER; } else if (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_SAPLING) { - btchip_context_D.usingOverwinter = ZCASH_USING_OVERWINTER_SAPLING; + context_D.usingOverwinter = ZCASH_USING_OVERWINTER_SAPLING; } } - btchip_context_D.overwinterSignReady = 0; - btchip_context_D.segwitParsedOnce = 0; - btchip_set_check_internal_structure_integrity(1); + context_D.overwinterSignReady = 0; + context_D.segwitParsedOnce = 0; + set_check_internal_structure_integrity(1); // Initialize for screen pairing - memset(&btchip_context_D.tmpCtx.output, 0, - sizeof(btchip_context_D.tmpCtx.output)); - btchip_context_D.tmpCtx.output.changeAccepted = 1; + memset(&context_D.tmpCtx.output, 0, + sizeof(context_D.tmpCtx.output)); + context_D.tmpCtx.output.changeAccepted = 1; // Reset segwitWarningSeen flag to prevent displaying the warning for each // segwit input when coontinuing from a previous session (P2=0x80) - btchip_context_D.segwitWarningSeen = 0; + context_D.segwitWarningSeen = 0; } } else if (G_io_apdu_buffer[ISO_OFFSET_P2] != P2_CONTINUE) { - return BTCHIP_SW_INCORRECT_P1_P2; + return SW_INCORRECT_P1_P2; } // In segwit mode, warn user one time only to update its client wallet... - if (btchip_context_D.usingSegwit - && !btchip_context_D.segwitWarningSeen + if (context_D.usingSegwit + && !context_D.segwitWarningSeen &&(G_io_apdu_buffer[ISO_OFFSET_P1] == P1_NEXT) && (G_io_apdu_buffer[ISO_OFFSET_P2] != P2_CONTINUE) // ...if input is not passed as a TrustedInput && IS_INPUT() && !IS_INPUT_TRUSTED()) { - if(btchip_context_D.called_from_swap){ + if(context_D.called_from_swap){ /* There is no point in displaying a warning when the app is signing in silent mode, as its UI is hidden behind the exchange app*/ - return BTCHIP_SW_SWAP_WITHOUT_TRUSTED_INPUTS; + return SW_SWAP_WITHOUT_TRUSTED_INPUTS; } - btchip_context_D.segwitWarningSeen = 1; - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_bagl_request_segwit_input_approval(); + context_D.segwitWarningSeen = 1; + context_D.io_flags |= IO_ASYNCH_REPLY; + bagl_request_segwit_input_approval(); } // Start parsing of the 1st chunk - btchip_context_D.transactionBufferPointer = + context_D.transactionBufferPointer = G_io_apdu_buffer + ISO_OFFSET_CDATA; - btchip_context_D.transactionDataRemaining = apduLength; + context_D.transactionDataRemaining = apduLength; transaction_parse(PARSE_MODE_SIGNATURE); - return BTCHIP_SW_OK; + return SW_OK; } diff --git a/src/btchip_apdu_hash_sign.c b/src/apdu_hash_sign.c similarity index 53% rename from src/btchip_apdu_hash_sign.c rename to src/apdu_hash_sign.c index 286fd1b7..a17044f0 100644 --- a/src/btchip_apdu_hash_sign.c +++ b/src/apdu_hash_sign.c @@ -15,16 +15,16 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" -#include "btchip_bagl_extensions.h" -#include "btchip_display_variables.h" +#include "internal.h" +#include "apdu_constants.h" +#include "bagl_extensions.h" +#include "display_variables.h" #include "ui.h" #include "ledger_assert.h" #define SIGHASH_ALL 0x01 -unsigned short btchip_apdu_hash_sign() { +unsigned short apdu_hash_sign() { unsigned long int lockTime; uint32_t sighashType; unsigned char dataBuffer[8]; @@ -34,117 +34,117 @@ unsigned short btchip_apdu_hash_sign() { SB_CHECK(N_btchip.bkp.config.operationMode); switch (SB_GET(N_btchip.bkp.config.operationMode)) { - case BTCHIP_MODE_WALLET: - case BTCHIP_MODE_RELAXED_WALLET: - case BTCHIP_MODE_SERVER: + case MODE_WALLET: + case MODE_RELAXED_WALLET: + case MODE_SERVER: break; default: - return BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + return SW_CONDITIONS_OF_USE_NOT_SATISFIED; } if ((G_io_apdu_buffer[ISO_OFFSET_P1] != 0) || (G_io_apdu_buffer[ISO_OFFSET_P2] != 0)) { - return BTCHIP_SW_INCORRECT_P1_P2; + return SW_INCORRECT_P1_P2; } if (G_io_apdu_buffer[ISO_OFFSET_LC] < (1 + 1 + 4 + 1)) { - return BTCHIP_SW_INCORRECT_LENGTH; + return SW_INCORRECT_LENGTH; } // Check state - btchip_set_check_internal_structure_integrity(0); + set_check_internal_structure_integrity(0); // Zcash special - store parameters for later - if ((btchip_context_D.usingOverwinter) && - (!btchip_context_D.overwinterSignReady) && - (btchip_context_D.segwitParsedOnce) && - (btchip_context_D.transactionContext.transactionState == BTCHIP_TRANSACTION_NONE)) { + if ((context_D.usingOverwinter) && + (!context_D.overwinterSignReady) && + (context_D.segwitParsedOnce) && + (context_D.transactionContext.transactionState == TRANSACTION_NONE)) { unsigned long int expiryHeight; parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; authorizationLength = *(parameters++); parameters += authorizationLength; - lockTime = btchip_read_u32(parameters, 1, 0); + lockTime = read_u32(parameters, 1, 0); parameters += 4; sighashType = *(parameters++); - expiryHeight = btchip_read_u32(parameters, 1, 0); - btchip_write_u32_le(btchip_context_D.nLockTime, lockTime); - btchip_write_u32_le(btchip_context_D.sigHashType, sighashType); - btchip_write_u32_le(btchip_context_D.nExpiryHeight, expiryHeight); - btchip_context_D.overwinterSignReady = 1; - return BTCHIP_SW_OK; + expiryHeight = read_u32(parameters, 1, 0); + write_u32_le(context_D.nLockTime, lockTime); + write_u32_le(context_D.sigHashType, sighashType); + write_u32_le(context_D.nExpiryHeight, expiryHeight); + context_D.overwinterSignReady = 1; + return SW_OK; } - if (btchip_context_D.transactionContext.transactionState != - BTCHIP_TRANSACTION_SIGN_READY) { - PRINTF("Invalid transaction state %d\n", btchip_context_D.transactionContext.transactionState); - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + if (context_D.transactionContext.transactionState != + TRANSACTION_SIGN_READY) { + PRINTF("Invalid transaction state %d\n", context_D.transactionContext.transactionState); + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; } - if (btchip_context_D.usingOverwinter && !btchip_context_D.overwinterSignReady) { + if (context_D.usingOverwinter && !context_D.overwinterSignReady) { PRINTF("Overwinter not ready to sign\n"); - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; } // Read parameters if (G_io_apdu_buffer[ISO_OFFSET_CDATA] > MAX_BIP32_PATH) { - sw = BTCHIP_SW_INCORRECT_DATA; + sw = SW_INCORRECT_DATA; goto discardTransaction; } - memmove(btchip_context_D.transactionSummary.keyPath, + memmove(context_D.transactionSummary.keyPath, G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH); parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; authorizationLength = *(parameters++); parameters += authorizationLength; - lockTime = btchip_read_u32(parameters, 1, 0); + lockTime = read_u32(parameters, 1, 0); parameters += 4; sighashType = *(parameters++); - btchip_context_D.transactionSummary.sighashType = sighashType; + context_D.transactionSummary.sighashType = sighashType; if (((N_btchip.bkp.config.options & - BTCHIP_OPTION_FREE_SIGHASHTYPE) == 0)) { + OPTION_FREE_SIGHASHTYPE) == 0)) { // if bitcoin cash OR forkid is set, then use the fork id if (G_coin_config->kind == COIN_KIND_BITCOIN_CASH || (G_coin_config->forkid)) { #define SIGHASH_FORKID 0x40 if (sighashType != (SIGHASH_ALL | SIGHASH_FORKID)) { - sw = BTCHIP_SW_INCORRECT_DATA; + sw = SW_INCORRECT_DATA; goto discardTransaction; } sighashType |= (G_coin_config->forkid << 8); } else { if (sighashType != SIGHASH_ALL) { - sw = BTCHIP_SW_INCORRECT_DATA; + sw = SW_INCORRECT_DATA; goto discardTransaction; } } } // Finalize the hash - if (!btchip_context_D.usingOverwinter) { - btchip_write_u32_le(dataBuffer, lockTime); - btchip_write_u32_le(dataBuffer + 4, sighashType); + if (!context_D.usingOverwinter) { + write_u32_le(dataBuffer, lockTime); + write_u32_le(dataBuffer + 4, sighashType); PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(dataBuffer), dataBuffer); - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, dataBuffer, sizeof(dataBuffer), NULL, 0)) { goto discardTransaction; } } // Check if the path needs to be enforced - if (!enforce_bip44_coin_type(btchip_context_D.transactionSummary.keyPath, false)) { - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_bagl_request_sign_path_approval(btchip_context_D.transactionSummary.keyPath); + if (!enforce_bip44_coin_type(context_D.transactionSummary.keyPath, false)) { + context_D.io_flags |= IO_ASYNCH_REPLY; + bagl_request_sign_path_approval(context_D.transactionSummary.keyPath); } else { // Sign immediately - btchip_bagl_user_action_signtx(1, 1); + bagl_user_action_signtx(1, 1); } - sw = BTCHIP_SW_OK; - if (btchip_context_D.called_from_swap) { + sw = SW_OK; + if (context_D.called_from_swap) { // if we signed all outputs we should exit, // but only after sending response, so lets raise the // vars.swap_data.should_exit flag and check it on timer later @@ -155,25 +155,25 @@ unsigned short btchip_apdu_hash_sign() { } // Then discard the transaction and reply - btchip_set_check_internal_structure_integrity(1); + set_check_internal_structure_integrity(1); return sw; discardTransaction: - btchip_set_check_internal_structure_integrity(1); - btchip_context_D.transactionContext.transactionState = BTCHIP_TRANSACTION_NONE; + set_check_internal_structure_integrity(1); + context_D.transactionContext.transactionState = TRANSACTION_NONE; return sw; } -void btchip_bagl_user_action_signtx(unsigned char confirming, unsigned char direct) { - unsigned short sw = BTCHIP_SW_OK; +void bagl_user_action_signtx(unsigned char confirming, unsigned char direct) { + unsigned short sw = SW_OK; // confirm and finish the apdu exchange //spaghetti if (confirming) { unsigned char hash[32]; - if (btchip_context_D.usingOverwinter) { - LEDGER_ASSERT(cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, hash, 0, hash, 32) == CX_OK, "Hash Failed"); + if (context_D.usingOverwinter) { + LEDGER_ASSERT(cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, CX_LAST, hash, 0, hash, 32) == CX_OK, "Hash Failed"); } else { - LEDGER_ASSERT(cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, + LEDGER_ASSERT(cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, CX_LAST, hash, 0, hash, 32) == CX_OK, "Hash Failed"); PRINTF("Hash1\n%.*H\n", sizeof(hash), hash); @@ -183,28 +183,28 @@ void btchip_bagl_user_action_signtx(unsigned char confirming, unsigned char dire PRINTF("Hash2\n%.*H\n", sizeof(hash), hash); // Sign size_t out_len = sizeof(G_io_apdu_buffer); - btchip_sign_finalhash( - btchip_context_D.transactionSummary.keyPath, - sizeof(btchip_context_D.transactionSummary.keyPath), + sign_finalhash( + context_D.transactionSummary.keyPath, + sizeof(context_D.transactionSummary.keyPath), hash, sizeof(hash), G_io_apdu_buffer, &out_len, ((N_btchip.bkp.config.options & - BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); + OPTION_DETERMINISTIC_SIGNATURE) != 0)); - btchip_context_D.outLength = G_io_apdu_buffer[1] + 2; - G_io_apdu_buffer[btchip_context_D.outLength++] = btchip_context_D.transactionSummary.sighashType; + context_D.outLength = G_io_apdu_buffer[1] + 2; + G_io_apdu_buffer[context_D.outLength++] = context_D.transactionSummary.sighashType; ui_transaction_finish(); } else { - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; - btchip_context_D.outLength = 0; + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + context_D.outLength = 0; } if (!direct) { - G_io_apdu_buffer[btchip_context_D.outLength++] = sw >> 8; - G_io_apdu_buffer[btchip_context_D.outLength++] = sw; + G_io_apdu_buffer[context_D.outLength++] = sw >> 8; + G_io_apdu_buffer[context_D.outLength++] = sw; - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, btchip_context_D.outLength); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, context_D.outLength); } } diff --git a/src/btchip_apdu_set_operation_mode.c b/src/apdu_set_operation_mode.c similarity index 67% rename from src/btchip_apdu_set_operation_mode.c rename to src/apdu_set_operation_mode.c index f5689774..7ab8a27b 100644 --- a/src/btchip_apdu_set_operation_mode.c +++ b/src/apdu_set_operation_mode.c @@ -17,56 +17,56 @@ // TODO BAGL : validate operation mode change -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" +#include "internal.h" +#include "apdu_constants.h" #define P1_DISABLE_KEYCARD 0x00 #define P1_ENABLE_KEYCARD 0x01 #define P1_ENABLE_KEYCARD_PERMANENTLY 0x02 -unsigned short btchip_apdu_set_operation_mode() { +unsigned short apdu_set_operation_mode() { unsigned char operationMode; if (G_io_apdu_buffer[ISO_OFFSET_LC] != 0x01) { - return BTCHIP_SW_INCORRECT_LENGTH; + return SW_INCORRECT_LENGTH; } SB_CHECK(N_btchip.bkp.config.operationMode); if ((SB_GET(N_btchip.bkp.config.operationMode) == - BTCHIP_MODE_SETUP_NEEDED) || - (SB_GET(N_btchip.bkp.config.operationMode) == BTCHIP_MODE_ISSUER)) { - return BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + MODE_SETUP_NEEDED) || + (SB_GET(N_btchip.bkp.config.operationMode) == MODE_ISSUER)) { + return SW_CONDITIONS_OF_USE_NOT_SATISFIED; } if (os_global_pin_is_validated() != BOLOS_UX_OK) { - return BTCHIP_SW_SECURITY_STATUS_NOT_SATISFIED; + return SW_SECURITY_STATUS_NOT_SATISFIED; } operationMode = G_io_apdu_buffer[ISO_OFFSET_CDATA]; - if (operationMode == BTCHIP_MODE_WALLET) { + if (operationMode == MODE_WALLET) { } if (operationMode == SB_GET(N_btchip.bkp.config.operationMode)) { - return BTCHIP_SW_OK; + return SW_OK; } switch (operationMode) { - case BTCHIP_MODE_WALLET: - case BTCHIP_MODE_RELAXED_WALLET: - case BTCHIP_MODE_SERVER: - case BTCHIP_MODE_DEVELOPER: + case MODE_WALLET: + case MODE_RELAXED_WALLET: + case MODE_SERVER: + case MODE_DEVELOPER: break; default: - return BTCHIP_SW_INCORRECT_DATA; + return SW_INCORRECT_DATA; } SB_CHECK(N_btchip.bkp.config.supportedModes); if ((SB_GET(N_btchip.bkp.config.supportedModes) & operationMode) == 0) { - return BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + return SW_CONDITIONS_OF_USE_NOT_SATISFIED; } // commit new operation - btchip_set_operation_mode(operationMode); + set_operation_mode(operationMode); - return BTCHIP_SW_OK; + return SW_OK; } diff --git a/src/btchip_apdu_setup.c b/src/apdu_setup.c similarity index 71% rename from src/btchip_apdu_setup.c rename to src/apdu_setup.c index f7d8db87..2e9cb88c 100644 --- a/src/btchip_apdu_setup.c +++ b/src/apdu_setup.c @@ -15,24 +15,24 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" +#include "internal.h" +#include "apdu_constants.h" -unsigned short btchip_apdu_setup() { - return BTCHIP_SW_INS_NOT_SUPPORTED; +unsigned short apdu_setup() { + return SW_INS_NOT_SUPPORTED; } // Setup with WALLET mode only, deterministic signatures only -void btchip_autosetup() { - btchip_config_t config; +void autosetup() { + config_t config; unsigned char i; unsigned char tmp[32]; - memset(&config, 0, sizeof(btchip_config_t)); - config.options |= BTCHIP_OPTION_DETERMINISTIC_SIGNATURE; - config.options |= BTCHIP_OPTION_SKIP_2FA_P2SH; // TODO : remove when + memset(&config, 0, sizeof(config_t)); + config.options |= OPTION_DETERMINISTIC_SIGNATURE; + config.options |= OPTION_SKIP_2FA_P2SH; // TODO : remove when // supporting multi output - SB_SET(config.supportedModes, BTCHIP_MODE_WALLET); - SB_SET(config.operationMode, BTCHIP_MODE_WALLET); + SB_SET(config.supportedModes, MODE_WALLET); + SB_SET(config.operationMode, MODE_WALLET); nvm_write((void *)&N_btchip.bkp.config, &config, sizeof(config)); cx_rng(tmp, sizeof(tmp)); diff --git a/src/btchip_apdu_sign_message.c b/src/apdu_sign_message.c similarity index 56% rename from src/btchip_apdu_sign_message.c rename to src/apdu_sign_message.c index b6717b8f..21fa496d 100644 --- a/src/btchip_apdu_sign_message.c +++ b/src/apdu_sign_message.c @@ -15,9 +15,9 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" -#include "btchip_bagl_extensions.h" +#include "internal.h" +#include "apdu_constants.h" +#include "bagl_extensions.h" #define P1_PREPARE 0x00 #define P1_SIGN 0x80 @@ -31,20 +31,20 @@ //#define SLIP_13 0x8000000D -unsigned short btchip_compute_hash(void); +unsigned short compute_hash(void); unsigned char checkBitId(unsigned char *bip32Path) { unsigned char i; unsigned char bip32PathLength = bip32Path[0]; bip32Path++; /* - if ((bip32PathLength != 0) && (btchip_read_u32(bip32Path, 1, 0) == SLIP_13)) + if ((bip32PathLength != 0) && (read_u32(bip32Path, 1, 0) == SLIP_13)) { return BITID_MULTIPLE; } */ for (i = 0; i < bip32PathLength; i++) { - unsigned short account = btchip_read_u32(bip32Path, 1, 0); + unsigned short account = read_u32(bip32Path, 1, 0); bip32Path += 4; if (account == BITID_DERIVE) { @@ -59,24 +59,24 @@ unsigned char checkBitId(unsigned char *bip32Path) { // TODO : support longer messages -unsigned short btchip_apdu_sign_message_internal() { - unsigned short sw = BTCHIP_SW_OK; +unsigned short apdu_sign_message_internal() { + unsigned short sw = SW_OK; unsigned char p1 = G_io_apdu_buffer[ISO_OFFSET_P1]; unsigned char p2 = G_io_apdu_buffer[ISO_OFFSET_P2]; unsigned char apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; unsigned short offset = ISO_OFFSET_CDATA; if ((p1 != P1_PREPARE) && (p1 != P1_SIGN)) { - return BTCHIP_SW_INCORRECT_P1_P2; + return SW_INCORRECT_P1_P2; } if (p1 == P1_PREPARE) { if ((p2 != P2_FIRST) && (p2 != P2_OTHER) && (p2 != P2_LEGACY)) { - return BTCHIP_SW_INCORRECT_P1_P2; + return SW_INCORRECT_P1_P2; } } if (os_global_pin_is_validated() != BOLOS_UX_OK) { - return BTCHIP_SW_SECURITY_STATUS_NOT_SATISFIED; + return SW_SECURITY_STATUS_NOT_SATISFIED; } if (p1 == P1_PREPARE) { @@ -84,44 +84,44 @@ unsigned short btchip_apdu_sign_message_internal() { unsigned char chunkLength; unsigned char messageLength[3]; unsigned char messageLengthSize; - memset(&btchip_context_D.transactionSummary, 0, - sizeof(btchip_transaction_summary_t)); + memset(&context_D.transactionSummary, 0, + sizeof(transaction_summary_t)); if (G_io_apdu_buffer[offset] > MAX_BIP32_PATH) { PRINTF("Invalid path\n"); - sw = BTCHIP_SW_INCORRECT_DATA; + sw = SW_INCORRECT_DATA; goto discard; } - btchip_context_D.transactionSummary.payToAddressVersion = + context_D.transactionSummary.payToAddressVersion = G_coin_config->p2pkh_version; - btchip_context_D.transactionSummary.payToScriptHashVersion = + context_D.transactionSummary.payToScriptHashVersion = G_coin_config->p2sh_version; memmove( - btchip_context_D.transactionSummary.keyPath, + context_D.transactionSummary.keyPath, G_io_apdu_buffer + offset, MAX_BIP32_PATH_LENGTH); offset += (4 * G_io_apdu_buffer[offset]) + 1; if (p2 == P2_LEGACY) { - btchip_context_D.transactionSummary.messageLength = + context_D.transactionSummary.messageLength = G_io_apdu_buffer[offset]; offset++; } else { - btchip_context_D.transactionSummary.messageLength = + context_D.transactionSummary.messageLength = (G_io_apdu_buffer[offset] << 8) | (G_io_apdu_buffer[offset + 1]); offset += 2; } - if (btchip_context_D.transactionSummary.messageLength == + if (context_D.transactionSummary.messageLength == 0) { PRINTF("Null message length\n"); - sw = BTCHIP_SW_INCORRECT_DATA; + sw = SW_INCORRECT_DATA; goto discard; } - btchip_context_D.hashedMessageLength = 0; - if (cx_sha256_init_no_throw(&btchip_context_D.transactionHashFull.sha256)) { + context_D.hashedMessageLength = 0; + if (cx_sha256_init_no_throw(&context_D.transactionHashFull.sha256)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } if (cx_sha256_init_no_throw( - &btchip_context_D.transactionHashAuthorization)) { + &context_D.transactionHashAuthorization)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } @@ -130,137 +130,137 @@ unsigned short btchip_apdu_sign_message_internal() { const char* magicHeader = (G_coin_config->kind != COIN_KIND_HORIZEN) ? G_coin_config->coinid : "Zcash"; chunkLength = strlen(magicHeader) + SIGNMAGIC_LENGTH; - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, &chunkLength, 1, NULL, 0)) { goto discard; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, (uint8_t *)magicHeader, strlen(magicHeader), NULL, 0)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, (unsigned char *)SIGNMAGIC, SIGNMAGIC_LENGTH, NULL, 0)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } - if (btchip_context_D.transactionSummary.messageLength < + if (context_D.transactionSummary.messageLength < 0xfd) { messageLength[0] = - btchip_context_D.transactionSummary.messageLength; + context_D.transactionSummary.messageLength; messageLengthSize = 1; } else { messageLength[0] = 0xfd; messageLength[1] = - (btchip_context_D.transactionSummary.messageLength & + (context_D.transactionSummary.messageLength & 0xff); - messageLength[2] = ((btchip_context_D.transactionSummary + messageLength[2] = ((context_D.transactionSummary .messageLength >> 8) & 0xff); messageLengthSize = 3; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, messageLength, messageLengthSize, NULL, 0)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } chunkLength = apduLength - (offset - ISO_OFFSET_CDATA); - if ((btchip_context_D.hashedMessageLength + chunkLength) > - btchip_context_D.transactionSummary.messageLength) { + if ((context_D.hashedMessageLength + chunkLength) > + context_D.transactionSummary.messageLength) { PRINTF("Invalid data length\n"); - sw = BTCHIP_SW_INCORRECT_DATA; + sw = SW_INCORRECT_DATA; goto discard; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, G_io_apdu_buffer + offset, chunkLength, NULL, 0)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } if (cx_hash_no_throw( - &btchip_context_D.transactionHashAuthorization.header, + &context_D.transactionHashAuthorization.header, 0, G_io_apdu_buffer + offset, chunkLength, NULL, 0)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } - btchip_context_D.hashedMessageLength += chunkLength; + context_D.hashedMessageLength += chunkLength; G_io_apdu_buffer[0] = 0x00; - if (btchip_context_D.hashedMessageLength == - btchip_context_D.transactionSummary.messageLength) { + if (context_D.hashedMessageLength == + context_D.transactionSummary.messageLength) { G_io_apdu_buffer[1] = 0x00; - btchip_context_D.outLength = 2; + context_D.outLength = 2; } else { - btchip_context_D.outLength = 1; + context_D.outLength = 1; } } else { - if ((btchip_context_D.hashedMessageLength + apduLength) > - btchip_context_D.transactionSummary.messageLength) { + if ((context_D.hashedMessageLength + apduLength) > + context_D.transactionSummary.messageLength) { PRINTF("Invalid data length\n"); - sw = BTCHIP_SW_INCORRECT_DATA; + sw = SW_INCORRECT_DATA; goto discard; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, + if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, G_io_apdu_buffer + offset, apduLength, NULL, 0)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } if (cx_hash_no_throw( - &btchip_context_D.transactionHashAuthorization.header, + &context_D.transactionHashAuthorization.header, 0, G_io_apdu_buffer + offset, apduLength, NULL, 0)) { sw = SW_TECHNICAL_DETAILS(0x0F); goto discard; } - btchip_context_D.hashedMessageLength += apduLength; + context_D.hashedMessageLength += apduLength; G_io_apdu_buffer[0] = 0x00; - if (btchip_context_D.hashedMessageLength == - btchip_context_D.transactionSummary.messageLength) { + if (context_D.hashedMessageLength == + context_D.transactionSummary.messageLength) { G_io_apdu_buffer[1] = 0x00; - btchip_context_D.outLength = 2; + context_D.outLength = 2; } else { - btchip_context_D.outLength = 1; + context_D.outLength = 1; } } } else { - if ((btchip_context_D.transactionSummary.messageLength == 0) || - (btchip_context_D.hashedMessageLength != - btchip_context_D.transactionSummary.messageLength)) { + if ((context_D.transactionSummary.messageLength == 0) || + (context_D.hashedMessageLength != + context_D.transactionSummary.messageLength)) { PRINTF("Invalid length to sign\n"); - sw = BTCHIP_SW_INCORRECT_DATA; + sw = SW_INCORRECT_DATA; goto discard; } - if (checkBitId(btchip_context_D.transactionSummary.keyPath) != BITID_NONE) { - sw = btchip_compute_hash(); + if (checkBitId(context_D.transactionSummary.keyPath) != BITID_NONE) { + sw = compute_hash(); } else { - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - return BTCHIP_SW_OK; + context_D.io_flags |= IO_ASYNCH_REPLY; + return SW_OK; } } return sw; discard : - memset(&btchip_context_D.transactionSummary, 0, - sizeof(btchip_transaction_summary_t)); + memset(&context_D.transactionSummary, 0, + sizeof(transaction_summary_t)); return sw; } -unsigned short btchip_apdu_sign_message() { - if (btchip_context_D.called_from_swap) { - return BTCHIP_SW_SECURITY_STATUS_NOT_SATISFIED; +unsigned short apdu_sign_message() { + if (context_D.called_from_swap) { + return SW_SECURITY_STATUS_NOT_SATISFIED; } - unsigned short sw = btchip_apdu_sign_message_internal(); - if (btchip_context_D.io_flags & IO_ASYNCH_REPLY) { - btchip_bagl_confirm_message_signature(); + unsigned short sw = apdu_sign_message_internal(); + if (context_D.io_flags & IO_ASYNCH_REPLY) { + bagl_confirm_message_signature(); } return sw; } -unsigned short btchip_compute_hash() { +unsigned short compute_hash() { unsigned char hash[32]; - unsigned short sw = BTCHIP_SW_OK; + unsigned short sw = SW_OK; - btchip_context_D.outLength = 0; - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, CX_LAST, hash, + context_D.outLength = 0; + if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, CX_LAST, hash, 0, hash, 32)) { goto discard; } @@ -270,16 +270,16 @@ unsigned short btchip_compute_hash() { } size_t out_len = 100; - btchip_sign_finalhash( - btchip_context_D.transactionSummary.keyPath, - sizeof(btchip_context_D.transactionSummary.keyPath), + sign_finalhash( + context_D.transactionSummary.keyPath, + sizeof(context_D.transactionSummary.keyPath), hash, sizeof(hash), // IN G_io_apdu_buffer, &out_len, // OUT ((N_btchip.bkp.config.options & - BTCHIP_OPTION_DETERMINISTIC_SIGNATURE) != 0)); - btchip_context_D.outLength = G_io_apdu_buffer[1] + 2; - memset(&btchip_context_D.transactionSummary, 0, - sizeof(btchip_transaction_summary_t)); + OPTION_DETERMINISTIC_SIGNATURE) != 0)); + context_D.outLength = G_io_apdu_buffer[1] + 2; + memset(&context_D.transactionSummary, 0, + sizeof(transaction_summary_t)); return sw; discard: @@ -287,15 +287,15 @@ unsigned short btchip_compute_hash() { return sw; } -void btchip_bagl_user_action_message_signing(unsigned char confirming) { +void bagl_user_action_message_signing(unsigned char confirming) { unsigned short sw; if (confirming) { - sw = btchip_compute_hash(); + sw = compute_hash(); } else { - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; } - G_io_apdu_buffer[btchip_context_D.outLength++] = sw >> 8; - G_io_apdu_buffer[btchip_context_D.outLength++] = sw; + G_io_apdu_buffer[context_D.outLength++] = sw >> 8; + G_io_apdu_buffer[context_D.outLength++] = sw; - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, btchip_context_D.outLength); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, context_D.outLength); } diff --git a/src/apdu_verify_pin.c b/src/apdu_verify_pin.c new file mode 100644 index 00000000..3d78f8f3 --- /dev/null +++ b/src/apdu_verify_pin.c @@ -0,0 +1,23 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include "internal.h" +#include "apdu_constants.h" + +unsigned short apdu_verify_pin() { + return SW_INS_NOT_SUPPORTED; +} diff --git a/src/btchip_bagl_extensions.h b/src/bagl_extensions.h similarity index 57% rename from src/btchip_bagl_extensions.h rename to src/bagl_extensions.h index 3e1c1ba7..c3029694 100644 --- a/src/btchip_bagl_extensions.h +++ b/src/bagl_extensions.h @@ -15,44 +15,44 @@ * limitations under the License. ********************************************************************************/ -#ifndef _BTCHIP_BAGL_H_ -#define _BTCHIP_BAGL_H_ +#ifndef _BAGL_H_ +#define _BAGL_H_ // btchip asking the per-output UI -unsigned int btchip_bagl_confirm_single_output(void); +unsigned int bagl_confirm_single_output(void); // btchip display token -void btchip_bagl_display_token(void); +void bagl_display_token(void); // btchip finalizing the transaction -unsigned int btchip_bagl_finalize_tx(void); +unsigned int bagl_finalize_tx(void); // UI response to btchip to finish the exchange -unsigned char btchip_bagl_user_action(unsigned char confirming); +unsigned char bagl_user_action(unsigned char confirming); // request the UI to redisplay the idle screen -void btchip_bagl_idle(void); +void bagl_idle(void); // btchip asking message signing confirmation -void btchip_bagl_confirm_message_signature(void); +void bagl_confirm_message_signature(void); // UI response to message signature -void btchip_bagl_user_action_message_signing(unsigned char confirming); +void bagl_user_action_message_signing(unsigned char confirming); // Public key display uint8_t set_key_path_to_display(unsigned char* keyPath); -void btchip_bagl_display_public_key(uint8_t is_derivation_path_unusual); -void btchip_bagl_user_action_display(unsigned char confirming); +void bagl_display_public_key(uint8_t is_derivation_path_unusual); +void bagl_user_action_display(unsigned char confirming); -void btchip_bagl_request_pubkey_approval(void); -void btchip_bagl_request_change_path_approval(unsigned char* change_path); +void bagl_request_pubkey_approval(void); +void bagl_request_change_path_approval(unsigned char* change_path); // UI to confirm processing of tx with segwit inputs -void btchip_bagl_request_segwit_input_approval(void); +void bagl_request_segwit_input_approval(void); // UI to confirm signing path -void btchip_bagl_request_sign_path_approval(unsigned char *derivation_path); -void btchip_bagl_user_action_signtx(unsigned char confirming, unsigned char direct); +void bagl_request_sign_path_approval(unsigned char *derivation_path); +void bagl_user_action_signtx(unsigned char confirming, unsigned char direct); -#endif /* _BTCHIP_BAGL_H_ */ +#endif /* _BAGL_H_ */ diff --git a/src/btchip_base58.c b/src/base58.c similarity index 96% rename from src/btchip_base58.c rename to src/base58.c index 2f19b0f6..42e58e02 100644 --- a/src/btchip_base58.c +++ b/src/base58.c @@ -15,12 +15,12 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" +#include "internal.h" #define MAX_DEC_INPUT_SIZE 164 #define MAX_ENC_INPUT_SIZE 120 -int btchip_decode_base58(const char *in, size_t length, +int decode_base58(const char *in, size_t length, unsigned char *out, size_t *outlen) { unsigned char tmp[MAX_DEC_INPUT_SIZE]; unsigned char buffer[MAX_DEC_INPUT_SIZE] = {0}; @@ -76,7 +76,7 @@ int btchip_decode_base58(const char *in, size_t length, return 0; } -int btchip_encode_base58(const unsigned char *in, size_t length, +int encode_base58(const unsigned char *in, size_t length, unsigned char *out, size_t *outlen) { size_t i = 0, j; size_t startAt, stopAt; diff --git a/src/btchip_bcd.c b/src/bcd.c similarity index 90% rename from src/btchip_bcd.c rename to src/bcd.c index df35eefb..9c200d29 100644 --- a/src/btchip_bcd.c +++ b/src/bcd.c @@ -15,12 +15,12 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" +#include "internal.h" #define SCRATCH_SIZE 21 unsigned char -btchip_convert_hex_amount_to_displayable_no_globals(unsigned char *amount, unsigned int config_flag, unsigned char* out) { +convert_hex_amount_to_displayable_no_globals(unsigned char *amount, unsigned int config_flag, unsigned char* out) { unsigned char LOOP1; unsigned char LOOP2; if (!(config_flag & FLAG_PEERCOIN_UNITS)) { @@ -98,6 +98,6 @@ btchip_convert_hex_amount_to_displayable_no_globals(unsigned char *amount, unsig } unsigned char -btchip_convert_hex_amount_to_displayable(unsigned char *amount) { - return btchip_convert_hex_amount_to_displayable_no_globals(amount, G_coin_config->flags, btchip_context_D.tmp); +convert_hex_amount_to_displayable(unsigned char *amount) { + return convert_hex_amount_to_displayable_no_globals(amount, G_coin_config->flags, context_D.tmp); } diff --git a/src/bip32_path.c b/src/bip32_path.c index a5cc8a5c..4a8d08a0 100644 --- a/src/bip32_path.c +++ b/src/bip32_path.c @@ -1,5 +1,5 @@ #include "bip32_path.h" -#include "btchip_helpers.h" +#include "helpers.h" bool parse_serialized_path(bip32_path_t* path, unsigned char* serialized_path, unsigned char serialized_path_length) { if (serialized_path_length < 1 || @@ -9,7 +9,7 @@ bool parse_serialized_path(bip32_path_t* path, unsigned char* serialized_path, u path->length = serialized_path[0]; serialized_path++; for (int i = 0; i < path->length; i += 1, serialized_path += 4) { - path->path[i] = btchip_read_u32(serialized_path, 1, 0); + path->path[i] = read_u32(serialized_path, 1, 0); } return true; } diff --git a/src/btchip.c b/src/btchip.c index a6b6430c..d815e739 100644 --- a/src/btchip.c +++ b/src/btchip.c @@ -17,16 +17,16 @@ #include "os.h" -#include "btchip_internal.h" +#include "internal.h" #include "os_io_seproxyhal.h" -#include "btchip_apdu_constants.h" -#include "btchip_display_variables.h" +#include "apdu_constants.h" +#include "display_variables.h" #include "handle_swap_sign_transaction.h" -#define BTCHIP_TECHNICAL_NOT_IMPLEMENTED 0x99 +#define TECHNICAL_NOT_IMPLEMENTED 0x99 #define COMMON_CLA 0xB0 @@ -36,13 +36,13 @@ void app_dispatch(void) { unsigned char dispatched; // nothing to reply for now - btchip_context_D.outLength = 0; - btchip_context_D.io_flags = 0; + context_D.outLength = 0; + context_D.io_flags = 0; // If halted, then notify - SB_CHECK(btchip_context_D.halted); - if (SB_GET(btchip_context_D.halted)) { - btchip_context_D.sw = BTCHIP_SW_TECHNICAL_PROBLEM; + SB_CHECK(context_D.halted); + if (SB_GET(context_D.halted)) { + context_D.sw = SW_TECHNICAL_PROBLEM; goto sendSW; } @@ -55,20 +55,20 @@ void app_dispatch(void) { } } if (dispatched == DISPATCHER_APDUS) { - btchip_context_D.sw = BTCHIP_SW_INS_NOT_SUPPORTED; + context_D.sw = SW_INS_NOT_SUPPORTED; goto sendSW; } if (DISPATCHER_DATA_IN[dispatched]) { if (G_io_apdu_buffer[ISO_OFFSET_LC] == 0x00 || - btchip_context_D.inLength - 5 == 0) { - btchip_context_D.sw = BTCHIP_SW_INCORRECT_LENGTH; + context_D.inLength - 5 == 0) { + context_D.sw = SW_INCORRECT_LENGTH; goto sendSW; } // notify we need to receive data // io_exchange(CHANNEL_APDU | IO_RECEIVE_DATA, 0); } // call the apdu handler - btchip_context_D.sw = ((apduProcessingFunction)PIC( + context_D.sw = ((apduProcessingFunction)PIC( DISPATCHER_FUNCTIONS[dispatched]))(); // an APDU has been replied. request for power off time extension from the @@ -78,18 +78,18 @@ void app_dispatch(void) { #endif // IO_APP_ACTIVITY sendSW: - if (btchip_context_D.called_from_swap) { - btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; - if(btchip_context_D.sw != BTCHIP_SW_OK) { + if (context_D.called_from_swap) { + context_D.io_flags &= ~IO_ASYNCH_REPLY; + if(context_D.sw != SW_OK) { vars.swap_data.should_exit = 1; } } // prepare SW after replied data - G_io_apdu_buffer[btchip_context_D.outLength] = - (btchip_context_D.sw >> 8); - G_io_apdu_buffer[btchip_context_D.outLength + 1] = - (btchip_context_D.sw & 0xff); - btchip_context_D.outLength += 2; + G_io_apdu_buffer[context_D.outLength] = + (context_D.sw >> 8); + G_io_apdu_buffer[context_D.outLength + 1] = + (context_D.sw & 0xff); + context_D.outLength += 2; return; } @@ -99,27 +99,27 @@ void app_main(void) { // Process the incoming APDUs // first exchange, no out length :) only wait the apdu - btchip_context_D.outLength = 0; - btchip_context_D.io_flags = 0; + context_D.outLength = 0; + context_D.io_flags = 0; for (;;) { // memset(G_io_apdu_buffer, 0, 255); // paranoia - if (btchip_context_D.called_from_swap && vars.swap_data.should_exit) { - btchip_context_D.io_flags |= IO_RETURN_AFTER_TX; + if (context_D.called_from_swap && vars.swap_data.should_exit) { + context_D.io_flags |= IO_RETURN_AFTER_TX; } // receive the whole apdu using the 7 bytes headers (ledger transport) - btchip_context_D.inLength = - io_exchange(CHANNEL_APDU | btchip_context_D.io_flags, + context_D.inLength = + io_exchange(CHANNEL_APDU | context_D.io_flags, // use the previous outlength as the reply - btchip_context_D.outLength); + context_D.outLength); - if (btchip_context_D.called_from_swap && vars.swap_data.should_exit) { - finalize_exchange_sign_transaction(btchip_context_D.sw == BTCHIP_SW_OK); + if (context_D.called_from_swap && vars.swap_data.should_exit) { + finalize_exchange_sign_transaction(context_D.sw == SW_OK); } - PRINTF("New APDU received:\n%.*H\n", btchip_context_D.inLength, G_io_apdu_buffer); + PRINTF("New APDU received:\n%.*H\n", context_D.inLength, G_io_apdu_buffer); app_dispatch(); diff --git a/src/btchip_apdu_hash_input_finalize_full.c b/src/btchip_apdu_hash_input_finalize_full.c deleted file mode 100644 index e023aa73..00000000 --- a/src/btchip_apdu_hash_input_finalize_full.c +++ /dev/null @@ -1,653 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -// TODO Trustlet, BAGL : process each output separately. -// review nvm_write policy - -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" -#include "btchip_bagl_extensions.h" -#include "ui.h" -#include "lib_standard_app/crypto_helpers.h" - -#define FINALIZE_P1_MORE 0x00 -#define FINALIZE_P1_LAST 0x80 -#define FINALIZE_P1_CHANGEINFO 0xFF - -#define FINALIZE_P2_DEFAULT 0x00 - -#define FLAG_SIGNATURE 0x01 -#define FLAG_CHANGE_VALIDATED 0x80 - -void btchip_apdu_hash_input_finalize_full_reset(void) { - btchip_context_D.currentOutputOffset = 0; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; - memset(btchip_context_D.totalOutputAmount, 0, - sizeof(btchip_context_D.totalOutputAmount)); - btchip_context_D.changeOutputFound = 0; - btchip_set_check_internal_structure_integrity(1); -} - -static bool check_output_displayable() { - bool displayable = true; - unsigned char amount[8], isOpReturn, isP2sh, isNativeSegwit, j, - nullAmount = 1; - unsigned char isOpCreate, isOpCall; - - for (j = 0; j < 8; j++) { - if (btchip_context_D.currentOutput[j] != 0) { - nullAmount = 0; - break; - } - } - if (!nullAmount) { - btchip_swap_bytes(amount, btchip_context_D.currentOutput, 8); - transaction_amount_add_be(btchip_context_D.totalOutputAmount, - btchip_context_D.totalOutputAmount, amount); - } - isOpReturn = - btchip_output_script_is_op_return(btchip_context_D.currentOutput + 8); - isP2sh = btchip_output_script_is_p2sh(btchip_context_D.currentOutput + 8); - isNativeSegwit = btchip_output_script_is_native_witness( - btchip_context_D.currentOutput + 8); - isOpCreate = - btchip_output_script_is_op_create(btchip_context_D.currentOutput + 8, - sizeof(btchip_context_D.currentOutput) - 8); - isOpCall = - btchip_output_script_is_op_call(btchip_context_D.currentOutput + 8, - sizeof(btchip_context_D.currentOutput) - 8); - if (((G_coin_config->kind == COIN_KIND_HYDRA) && - !btchip_output_script_is_regular(btchip_context_D.currentOutput + 8) && - !isP2sh && !(nullAmount && isOpReturn) && !isOpCreate && !isOpCall) || - (!(G_coin_config->kind == COIN_KIND_HYDRA) && - !btchip_output_script_is_regular(btchip_context_D.currentOutput + 8) && - !isP2sh && !(nullAmount && isOpReturn))) { - PRINTF("Error : Unrecognized output script"); - THROW(EXCEPTION); - } - if (btchip_context_D.tmpCtx.output.changeInitialized && !isOpReturn) { - bool changeFound = false; - unsigned char addressOffset = - (isNativeSegwit ? OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET - : isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH - : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); - if (!isP2sh && - memcmp(btchip_context_D.currentOutput + 8 + addressOffset, - btchip_context_D.tmpCtx.output.changeAddress, - 20) == 0) { - changeFound = true; - } else if (isP2sh && btchip_context_D.usingSegwit) { - unsigned char changeSegwit[22]; - changeSegwit[0] = 0x00; - changeSegwit[1] = 0x14; - memmove(changeSegwit + 2, - btchip_context_D.tmpCtx.output.changeAddress, 20); - btchip_public_key_hash160(changeSegwit, 22, changeSegwit); - if (memcmp(btchip_context_D.currentOutput + 8 + addressOffset, - changeSegwit, 20) == 0) { - if (G_coin_config->flags & FLAG_SEGWIT_CHANGE_SUPPORT) { - changeFound = true; - } else { - // Attempt to avoid fatal failures on Bitcoin Cash - PRINTF("Error : Non spendable Segwit change"); - THROW(EXCEPTION); - } - } - } - if (changeFound) { - if (btchip_context_D.changeOutputFound) { - PRINTF("Error : Multiple change output found"); - THROW(EXCEPTION); - } - btchip_context_D.changeOutputFound = true; - displayable = false; - } - } - - return displayable; -} - -bool handle_output_state() { - uint32_t discardSize = 0; - btchip_context_D.discardSize = 0; - bool processed = false; - switch (btchip_context_D.outputParsingState) { - case BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS: { - btchip_context_D.totalOutputs = 0; - if (btchip_context_D.currentOutputOffset < 1) { - break; - } - if (btchip_context_D.currentOutput[0] < 0xFD) { - btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = - btchip_context_D.currentOutput[0]; - discardSize = 1; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; - processed = true; - break; - } - if (btchip_context_D.currentOutput[0] == 0xFD) { - if (btchip_context_D.currentOutputOffset < 3) { - break; - } - btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = - (btchip_context_D.currentOutput[2] << 8) | - btchip_context_D.currentOutput[1]; - discardSize = 3; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; - processed = true; - break; - } else if (btchip_context_D.currentOutput[0] == 0xFE) { - if (btchip_context_D.currentOutputOffset < 5) { - break; - } - btchip_context_D.totalOutputs = btchip_context_D.remainingOutputs = - btchip_read_u32(btchip_context_D.currentOutput + 1, 0, 0); - discardSize = 5; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_OUTPUT; - processed = true; - break; - } else { - THROW(EXCEPTION); - } - } break; - - case BTCHIP_OUTPUT_PARSING_OUTPUT: { - unsigned int scriptSize; - if (btchip_context_D.currentOutputOffset < 9) { - break; - } - if (btchip_context_D.currentOutput[8] < 0xFD) { - scriptSize = btchip_context_D.currentOutput[8]; - discardSize = 1; - } else if (btchip_context_D.currentOutput[8] == 0xFD) { - if (btchip_context_D.currentOutputOffset < 9 + 2) { - break; - } - scriptSize = - btchip_read_u32(btchip_context_D.currentOutput + 9, 0, 0); - discardSize = 3; - } else { - // Unrealistically large script - THROW(EXCEPTION); - } - if (btchip_context_D.currentOutputOffset < - 8 + discardSize + scriptSize) { - discardSize = 0; - break; - } - - processed = true; - - discardSize += 8 + scriptSize; - - if (check_output_displayable()) { - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - - // The output can be processed by the UI - - btchip_context_D.discardSize = discardSize; - discardSize = 0; - } else { - btchip_context_D.remainingOutputs--; - } - } break; - - default: - THROW(EXCEPTION); - } - - if (discardSize != 0) { - memmove(btchip_context_D.currentOutput, - btchip_context_D.currentOutput + discardSize, - btchip_context_D.currentOutputOffset - discardSize); - btchip_context_D.currentOutputOffset -= discardSize; - } - - return processed; -} - -// out should be 32 bytes, even only 20 bytes is significant for output -int get_pubkey_hash160(unsigned char* keyPath, size_t keyPath_len, unsigned char* out) { - cx_ecfp_public_key_t public_key; - int keyLength; - if (btchip_get_public_key(keyPath, keyPath_len, public_key.W, NULL)) { - return -1; - } - if (((N_btchip.bkp.config.options & - BTCHIP_OPTION_UNCOMPRESSED_KEYS) != 0)) { - keyLength = 65; - } else { - btchip_compress_public_key_value(public_key.W); - keyLength = 33; - } - btchip_public_key_hash160( - public_key.W, // IN - keyLength, // INLEN - out // OUT - ); - return 0; -} - -unsigned short btchip_apdu_hash_input_finalize_full_internal( - btchip_transaction_summary_t *transactionSummary) { - unsigned char authorizationHash[32]; - unsigned char apduLength; - unsigned short sw = BTCHIP_SW_OK; - unsigned char *target = G_io_apdu_buffer; - unsigned char p1 = G_io_apdu_buffer[ISO_OFFSET_P1]; - unsigned char hashOffset = 0; - - apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - - if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && - (p1 != FINALIZE_P1_CHANGEINFO)) { - return BTCHIP_SW_INCORRECT_P1_P2; - } - - // See if there is a hashing offset - if (btchip_context_D.usingSegwit && - (btchip_context_D.tmpCtx.output.multipleOutput == 0)) { - unsigned char firstByte = G_io_apdu_buffer[ISO_OFFSET_CDATA]; - if (firstByte < 0xfd) { - hashOffset = 1; - } else if (firstByte == 0xfd) { - hashOffset = 3; - } else if (firstByte == 0xfe) { - hashOffset = 5; - } - } - - // Check state - btchip_set_check_internal_structure_integrity(0); - if (btchip_context_D.transactionContext.transactionState != - BTCHIP_TRANSACTION_PRESIGN_READY) { - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - - if (p1 == FINALIZE_P1_CHANGEINFO) { - if (!btchip_context_D.transactionContext.firstSigned) { - // Already validated, should be prevented on the client side -return_OK: - return BTCHIP_SW_OK; - } - if (!btchip_context_D.tmpCtx.output.changeAccepted) { - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - memset(transactionSummary, 0, - sizeof(btchip_transaction_summary_t)); - if (G_io_apdu_buffer[ISO_OFFSET_CDATA] == 0x00) { - // Called with no change path, abort, should be prevented on - // the client side - goto return_OK; - } - memmove(transactionSummary->keyPath, - G_io_apdu_buffer + ISO_OFFSET_CDATA, - MAX_BIP32_PATH_LENGTH); - - if (get_pubkey_hash160(transactionSummary->keyPath, sizeof(transactionSummary->keyPath), btchip_context_D.tmpCtx.output.changeAddress)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - PRINTF("Change address = %.*H\n", 20, btchip_context_D.tmpCtx.output.changeAddress); - - btchip_context_D.tmpCtx.output.changeInitialized = 1; - btchip_context_D.tmpCtx.output.changeAccepted = 0; - - // if the bip44 change path provided is not canonical or its index are unsual, ask for user approval - if(bip44_derivation_guard(transactionSummary->keyPath, true)) { - if (btchip_context_D.called_from_swap) { - PRINTF("In swap mode only standart path is allowed\n"); - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_context_D.outputParsingState = BTCHIP_BIP44_CHANGE_PATH_VALIDATION; - btchip_bagl_request_change_path_approval(transactionSummary->keyPath); - } - - goto return_OK; - } - - // Always update the transaction & authorization hashes with the - // given data - // For SegWit, this has been reset to hold hashOutputs - if (!btchip_context_D.segwitParsedOnce) { - if ((int)(apduLength - hashOffset) < 0) { - sw = BTCHIP_SW_INCORRECT_DATA; - goto discardTransaction; - } - if (btchip_context_D.usingOverwinter) { - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, apduLength - hashOffset, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - } - else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", apduLength - hashOffset, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset); - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, - G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, - apduLength - hashOffset, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - } - } - - if (btchip_context_D.transactionContext.firstSigned) { - if ((btchip_context_D.currentOutputOffset + apduLength) > - sizeof(btchip_context_D.currentOutput)) { - PRINTF("Output is too long to be checked\n"); - sw = BTCHIP_SW_INCORRECT_DATA; - goto discardTransaction; - } - memmove(btchip_context_D.currentOutput + - btchip_context_D.currentOutputOffset, - G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength); - btchip_context_D.currentOutputOffset += apduLength; - - while (handle_output_state() && - (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) - ; - - // Finalize the TX if necessary - - if ((btchip_context_D.remainingOutputs == 0) && - (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) { - btchip_context_D.io_flags |= IO_ASYNCH_REPLY; - btchip_context_D.outputParsingState = - BTCHIP_OUTPUT_FINALIZE_TX; - } - } - - if (G_io_apdu_buffer[ISO_OFFSET_P1] == FINALIZE_P1_MORE) { - if (!btchip_context_D.usingSegwit) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", apduLength, G_io_apdu_buffer + ISO_OFFSET_CDATA); - if (cx_hash_no_throw( - &btchip_context_D.transactionHashAuthorization.header, - 0, G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength, - NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - } - G_io_apdu_buffer[0] = 0x00; - btchip_context_D.outLength = 1; - btchip_context_D.tmpCtx.output.multipleOutput = 1; - goto return_OK; - } - - if (!btchip_context_D.usingSegwit) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", apduLength, G_io_apdu_buffer + ISO_OFFSET_CDATA); - if (cx_hash_no_throw(&btchip_context_D.transactionHashAuthorization.header, - CX_LAST, G_io_apdu_buffer + ISO_OFFSET_CDATA, - apduLength, authorizationHash, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - } - - if (btchip_context_D.usingSegwit) { - if (!btchip_context_D.segwitParsedOnce) { - if (btchip_context_D.usingOverwinter) { - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, btchip_context_D.segwit.cache.hashedOutputs, 0, btchip_context_D.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - } - else { - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, - CX_LAST, - btchip_context_D.segwit.cache.hashedOutputs, 0, - btchip_context_D.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - if (cx_sha256_init_no_throw(&btchip_context_D.transactionHashFull.sha256)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, - CX_LAST, - btchip_context_D.segwit.cache.hashedOutputs, - sizeof(btchip_context_D.segwit.cache.hashedOutputs), - btchip_context_D.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - } - PRINTF("hashOutputs\n%.*H\n",32,btchip_context_D.segwit.cache.hashedOutputs); - if (cx_hash_no_throw( - &btchip_context_D.transactionHashAuthorization.header, - CX_LAST, G_io_apdu_buffer, 0, authorizationHash, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); - } else { - if (cx_hash_no_throw( - &btchip_context_D.transactionHashAuthorization.header, - CX_LAST, - (unsigned char *)&btchip_context_D.segwit.cache, - sizeof(btchip_context_D.segwit.cache), - authorizationHash, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); - } - } - - if (btchip_context_D.transactionContext.firstSigned) { - if (!btchip_context_D.tmpCtx.output.changeInitialized) { - memset(transactionSummary, 0, - sizeof(btchip_transaction_summary_t)); - } - - transactionSummary->payToAddressVersion = - G_coin_config->p2pkh_version; - transactionSummary->payToScriptHashVersion = - G_coin_config->p2sh_version; - - // Generate new nonce - - cx_rng(transactionSummary->transactionNonce, 8); - } - - G_io_apdu_buffer[0] = 0x00; - target++; - - *target = 0x00; - target++; - - btchip_context_D.outLength = (target - G_io_apdu_buffer); - - // Check that the input being signed is part of the same - // transaction, otherwise abort - // (this is done to keep the transaction counter limit per session - // synchronized) - if (btchip_context_D.transactionContext.firstSigned) { - memmove(transactionSummary->authorizationHash, - authorizationHash, - sizeof(transactionSummary->authorizationHash)); - goto return_OK; - } else { - if (btchip_secure_memcmp( - authorizationHash, - transactionSummary->authorizationHash, - sizeof(transactionSummary->authorizationHash))) { - PRINTF("Authorization hash not matching, aborting\n"); - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - - if (btchip_context_D.usingSegwit && - !btchip_context_D.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - btchip_context_D.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; - } else { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_SIGN_READY; - } - sw = BTCHIP_SW_OK; - } - btchip_apdu_hash_input_finalize_full_reset(); - return sw; - -discardTransaction: - btchip_apdu_hash_input_finalize_full_reset(); - ui_transaction_error(); - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; - btchip_context_D.outLength = 0; - - memmove(G_io_apdu_buffer, btchip_context_D.currentOutput, - btchip_context_D.currentOutputOffset); - btchip_context_D.outLength = btchip_context_D.currentOutputOffset; - return sw; -} - -unsigned short btchip_apdu_hash_input_finalize_full() { - PRINTF("state=%d\n", btchip_context_D.outputParsingState); - unsigned short sw = btchip_apdu_hash_input_finalize_full_internal( - &btchip_context_D.transactionSummary); - if (btchip_context_D.io_flags & IO_ASYNCH_REPLY) { - // if the UI reject the processing of the request, then reply - // immediately - bool status; - if(btchip_context_D.outputParsingState == BTCHIP_BIP44_CHANGE_PATH_VALIDATION) { - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; - return sw; - } - else if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) { - status = btchip_bagl_finalize_tx(); - } - else { - status = btchip_bagl_confirm_single_output(); - } - if (!status) { - ui_transaction_error(); - btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; - btchip_context_D.outLength = 0; - sw = BTCHIP_SW_INCORRECT_DATA; - } - } - return sw; -} - -unsigned char btchip_bagl_user_action(unsigned char confirming) { - unsigned short sw = BTCHIP_SW_OK; - - // confirm and finish the apdu exchange //spaghetti - - if (confirming) { - // Check if all inputs have been confirmed - - if (btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_PARSING_OUTPUT) { - btchip_context_D.remainingOutputs--; - } - - while (btchip_context_D.remainingOutputs != 0) { - memmove(btchip_context_D.currentOutput, - btchip_context_D.currentOutput + - btchip_context_D.discardSize, - btchip_context_D.currentOutputOffset - - btchip_context_D.discardSize); - btchip_context_D.currentOutputOffset -= - btchip_context_D.discardSize; - btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; - while (handle_output_state() && - (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) - ; - if (btchip_context_D.io_flags & IO_ASYNCH_REPLY) { - if (!btchip_bagl_confirm_single_output()) { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; - sw = BTCHIP_SW_INCORRECT_DATA; - break; - } else { - // Let the UI play - return 1; - } - } else { - // Out of data to process, wait for the next call - break; - } - } - - if ((btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_PARSING_OUTPUT) && - (btchip_context_D.remainingOutputs == 0)) { - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_FINALIZE_TX; - if (!btchip_bagl_finalize_tx()) { - btchip_context_D.outputParsingState = - BTCHIP_OUTPUT_PARSING_NONE; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; - sw = BTCHIP_SW_INCORRECT_DATA; - } else { - // Let the UI play - return 1; - } - } - - if (btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_FINALIZE_TX) { - btchip_context_D.transactionContext.firstSigned = 0; - - if (btchip_context_D.usingSegwit && - !btchip_context_D.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - btchip_context_D.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; - } else { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_SIGN_READY; - } - } - btchip_context_D.outLength -= - 2; // status was already set by the last call - } else { - // Discard transaction - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; - sw = BTCHIP_SW_CONDITIONS_OF_USE_NOT_SATISFIED; - btchip_context_D.outLength = 0; - } - G_io_apdu_buffer[btchip_context_D.outLength++] = sw >> 8; - G_io_apdu_buffer[btchip_context_D.outLength++] = sw; - - if ((btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) || - (sw != BTCHIP_SW_OK)) { - - // we've finished the processing of the input - btchip_apdu_hash_input_finalize_full_reset(); - } - - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, btchip_context_D.outLength); - - return 0; -} diff --git a/src/btchip_apdu_verify_pin.c b/src/btchip_apdu_verify_pin.c deleted file mode 100644 index 33a6c9d9..00000000 --- a/src/btchip_apdu_verify_pin.c +++ /dev/null @@ -1,23 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" - -unsigned short btchip_apdu_verify_pin() { - return BTCHIP_SW_INS_NOT_SUPPORTED; -} diff --git a/src/btchip_display_variables.c b/src/btchip_display_variables.c deleted file mode 100644 index 55305669..00000000 --- a/src/btchip_display_variables.c +++ /dev/null @@ -1,3 +0,0 @@ -#include "btchip_display_variables.h" - -union display_variables vars; diff --git a/src/btchip_internal.h b/src/btchip_internal.h deleted file mode 100644 index d6b455dd..00000000 --- a/src/btchip_internal.h +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef BTCHIP_INTERNAL_H -#define BTCHIP_INTERNAL_H - -#include "btchip.h" -#include "btchip_public_ram_variables.h" -#include "btchip_rom_variables.h" -#include "btchip_filesystem.h" -#include "btchip_base58.h" -#include "btchip_bcd.h" -#include "btchip_ecc.h" -#include "btchip_helpers.h" -#include "btchip_transaction.h" - -#endif diff --git a/src/btchip_public_ram_variables.h b/src/btchip_public_ram_variables.h deleted file mode 100644 index 52522eea..00000000 --- a/src/btchip_public_ram_variables.h +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef _BTCHIP_PUBLIC_RAM_VARIABLES_H_ -#define _BTCHIP_PUBLIC_RAM_VARIABLES_H_ - -#include "btchip_config.h" - -#include "btchip_secure_value.h" -#include "btchip_context.h" - -extern btchip_context_t btchip_context_D; - -extern btchip_altcoin_config_t *G_coin_config; - -#endif /* _BTCHIP_PUBLIC_RAM_VARIABLES_H_ */ diff --git a/src/btchip_context.c b/src/context.c similarity index 67% rename from src/btchip_context.c rename to src/context.c index 0aeec435..bb176cf6 100644 --- a/src/btchip_context.c +++ b/src/context.c @@ -15,36 +15,36 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" +#include "internal.h" -void btchip_autosetup(void); +void autosetup(void); /** * Initialize the application context on boot */ -void btchip_context_init() { +void context_init() { PRINTF("Context init\n"); PRINTF("Backup size %d\n", sizeof(N_btchip.bkp)); - memset(&btchip_context_D, 0, sizeof(btchip_context_D)); - SB_SET(btchip_context_D.halted, 0); - btchip_context_D.called_from_swap = 0; - btchip_context_D.currentOutputOffset = 0; - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_PARSING_NUMBER_OUTPUTS; - memset(btchip_context_D.totalOutputAmount, 0, - sizeof(btchip_context_D.totalOutputAmount)); - btchip_context_D.changeOutputFound = 0; - btchip_context_D.segwitWarningSeen = 0; + memset(&context_D, 0, sizeof(context_D)); + SB_SET(context_D.halted, 0); + context_D.called_from_swap = 0; + context_D.currentOutputOffset = 0; + context_D.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; + memset(context_D.totalOutputAmount, 0, + sizeof(context_D.totalOutputAmount)); + context_D.changeOutputFound = 0; + context_D.segwitWarningSeen = 0; if (N_btchip.config_valid != 0x01) { - btchip_autosetup(); + autosetup(); } if (!N_btchip.config_valid) { unsigned char defaultMode; PRINTF("No configuration found\n"); - defaultMode = BTCHIP_MODE_SETUP_NEEDED; + defaultMode = MODE_SETUP_NEEDED; - btchip_set_operation_mode(defaultMode); + set_operation_mode(defaultMode); } else { SB_CHECK(N_btchip.bkp.config.operationMode); } diff --git a/src/display_variables.c b/src/display_variables.c new file mode 100644 index 00000000..7d2e6d57 --- /dev/null +++ b/src/display_variables.c @@ -0,0 +1,3 @@ +#include "display_variables.h" + +union display_variables vars; diff --git a/src/btchip_display_variables.h b/src/display_variables.h similarity index 93% rename from src/btchip_display_variables.h rename to src/display_variables.h index f62263cb..a7655cc1 100644 --- a/src/btchip_display_variables.h +++ b/src/display_variables.h @@ -1,5 +1,5 @@ -#ifndef _BTCHIP_DISPLAY_VARIABLES_H_ -#define _BTCHIP_DISPLAY_VARIABLES_H_ +#ifndef _DISPLAY_VARIABLES_H_ +#define _DISPLAY_VARIABLES_H_ // A path contains 10 elements max, which max length in ascii is 1 whitespace + 10 char + optional quote "'" + "/" + \0" #define MAX_DERIV_PATH_ASCII_LENGTH 1 + 10*(10+2) + 1 diff --git a/src/btchip_ecc.c b/src/ecc.c similarity index 90% rename from src/btchip_ecc.c rename to src/ecc.c index 514fc0aa..69092c81 100644 --- a/src/btchip_ecc.c +++ b/src/ecc.c @@ -15,8 +15,8 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" +#include "internal.h" -void btchip_compress_public_key_value(unsigned char *value) { +void compress_public_key_value(unsigned char *value) { value[0] = ((value[64] & 1) ? 0x03 : 0x02); } diff --git a/src/btchip_filesystem.c b/src/filesystem.c similarity index 87% rename from src/btchip_filesystem.c rename to src/filesystem.c index f0b81efc..11a12efe 100644 --- a/src/btchip_filesystem.c +++ b/src/filesystem.c @@ -15,11 +15,11 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" +#include "internal.h" -#include "btchip_public_ram_variables.h" +#include "public_ram_variables.h" -void btchip_set_operation_mode(unsigned char operationMode) { +void set_operation_mode(unsigned char operationMode) { secu8 opMode; SB_SET(opMode, operationMode); diff --git a/src/handle_check_address.c b/src/handle_check_address.c index 6ecbb3b0..e993dacf 100644 --- a/src/handle_check_address.c +++ b/src/handle_check_address.c @@ -1,9 +1,9 @@ #include "handle_check_address.h" #include "os.h" -#include "btchip_helpers.h" +#include "helpers.h" #include "bip32_path.h" -#include "btchip_ecc.h" -#include "btchip_apdu_get_wallet_public_key.h" +#include "ecc.h" +#include "apdu_get_wallet_public_key.h" #include "cashaddr.h" #include "segwit_addr.h" #include @@ -14,11 +14,11 @@ bool derive_compressed_public_key( UNUSED(public_key_length); uint8_t pubKey[65]; - if (btchip_get_public_key(serialized_path, serialized_path_length, pubKey, NULL)){ + if (get_public_key(serialized_path, serialized_path_length, pubKey, NULL)){ return false; } - btchip_compress_public_key_value(pubKey); + compress_public_key_value(pubKey); memcpy(public_key, pubKey, 33); return true; } @@ -38,15 +38,15 @@ bool get_address_from_compressed_public_key( int address_length; if (cashAddr) { uint8_t tmp[20]; - btchip_public_key_hash160(compressed_pub_key, // IN + public_key_hash160(compressed_pub_key, // IN 33, // INLEN tmp); if (!cashaddr_encode(tmp, 20, (uint8_t *)address, max_address_length, CASHADDR_P2PKH)) return false; } else if (!(segwit || nativeSegwit)) { - // btchip_public_key_to_encoded_base58 doesn't add terminating 0, + // public_key_to_encoded_base58 doesn't add terminating 0, // so we will do this ourself - address_length = btchip_public_key_to_encoded_base58( + address_length = public_key_to_encoded_base58( compressed_pub_key, // IN 33, // INLEN (uint8_t *)address, // OUT @@ -57,12 +57,12 @@ bool get_address_from_compressed_public_key( uint8_t tmp[22]; tmp[0] = 0x00; tmp[1] = 0x14; - btchip_public_key_hash160(compressed_pub_key, // IN + public_key_hash160(compressed_pub_key, // IN 33, // INLEN tmp + 2 // OUT ); if (!nativeSegwit) { - address_length = btchip_public_key_to_encoded_base58( + address_length = public_key_to_encoded_base58( tmp, // IN 22, // INLEN (uint8_t *)address, // OUT @@ -87,7 +87,7 @@ static int os_strcmp(const char* s1, const char* s2) { return memcmp(s1, s2, size); } -int handle_check_address(check_address_parameters_t* params, btchip_altcoin_config_t* coin_config) { +int handle_check_address(check_address_parameters_t* params, altcoin_config_t* coin_config) { unsigned char compressed_public_key[33]; PRINTF("Params on the address %d\n",(unsigned int)params); PRINTF("Address to check %s\n",params->address_to_check); diff --git a/src/handle_check_address.h b/src/handle_check_address.h index b1956900..d45ed63d 100644 --- a/src/handle_check_address.h +++ b/src/handle_check_address.h @@ -2,8 +2,8 @@ #define _HANDLE_CHECK_ADDRESS_H_ #include "swap_lib_calls.h" -#include "btchip_context.h" +#include "context.h" -int handle_check_address(check_address_parameters_t* check_address_params, btchip_altcoin_config_t* coin_config); +int handle_check_address(check_address_parameters_t* check_address_params, altcoin_config_t* coin_config); #endif // _HANDLE_CHECK_ADDRESS_H_ \ No newline at end of file diff --git a/src/handle_get_printable_amount.c b/src/handle_get_printable_amount.c index 79bfc885..5af59581 100644 --- a/src/handle_get_printable_amount.c +++ b/src/handle_get_printable_amount.c @@ -1,8 +1,8 @@ #include "handle_get_printable_amount.h" -#include "btchip_bcd.h" +#include "bcd.h" #include -int handle_get_printable_amount( get_printable_amount_parameters_t* params, btchip_altcoin_config_t *config) { +int handle_get_printable_amount( get_printable_amount_parameters_t* params, altcoin_config_t *config) { params->printable_amount[0] = 0; if (params->amount_length > 8) { PRINTF("Amount is too big"); @@ -14,7 +14,7 @@ int handle_get_printable_amount( get_printable_amount_parameters_t* params, btch unsigned char coin_name_length = strlen(config->name_short); memmove(params->printable_amount, config->name_short, coin_name_length); params->printable_amount[coin_name_length] = ' '; - int res_length = btchip_convert_hex_amount_to_displayable_no_globals(amount, config->flags, (uint8_t *)params->printable_amount + coin_name_length + 1); + int res_length = convert_hex_amount_to_displayable_no_globals(amount, config->flags, (uint8_t *)params->printable_amount + coin_name_length + 1); params->printable_amount[res_length + coin_name_length + 1] = '\0'; return 1; diff --git a/src/handle_get_printable_amount.h b/src/handle_get_printable_amount.h index 9e634cce..f6beb7e0 100644 --- a/src/handle_get_printable_amount.h +++ b/src/handle_get_printable_amount.h @@ -2,8 +2,8 @@ #define _HANDLE_GET_PRINTABLE_AMOUNT_H_ #include "swap_lib_calls.h" -#include "btchip_context.h" +#include "context.h" -int handle_get_printable_amount(get_printable_amount_parameters_t* get_printable_amount_params, btchip_altcoin_config_t *config); +int handle_get_printable_amount(get_printable_amount_parameters_t* get_printable_amount_params, altcoin_config_t *config); #endif // _HANDLE_GET_PRINTABLE_AMOUNT_H_ \ No newline at end of file diff --git a/src/handle_swap_sign_transaction.c b/src/handle_swap_sign_transaction.c index 1c2dc971..9cfe9473 100644 --- a/src/handle_swap_sign_transaction.c +++ b/src/handle_swap_sign_transaction.c @@ -1,8 +1,8 @@ #include "handle_swap_sign_transaction.h" #include "os_io_seproxyhal.h" -#include "btchip_public_ram_variables.h" -#include "btchip_display_variables.h" -#include "btchip_context.h" +#include "public_ram_variables.h" +#include "display_variables.h" +#include "context.h" #include "usbd_core.h" #include "ux.h" @@ -40,10 +40,10 @@ bool copy_transaction_parameters(create_transaction_parameters_t* sign_transacti return true; } -void handle_swap_sign_transaction(btchip_altcoin_config_t *config) { +void handle_swap_sign_transaction(altcoin_config_t *config) { G_coin_config = config; - btchip_context_init(); - btchip_context_D.called_from_swap = 1; + context_init(); + context_D.called_from_swap = 1; io_seproxyhal_init(); UX_INIT(); #ifdef HAVE_NBGL diff --git a/src/handle_swap_sign_transaction.h b/src/handle_swap_sign_transaction.h index 85f5bd86..c66caacc 100644 --- a/src/handle_swap_sign_transaction.h +++ b/src/handle_swap_sign_transaction.h @@ -2,11 +2,11 @@ #define _HANDLE_SWAP_SIGN_TRANSACTION_H_ #include "swap_lib_calls.h" -#include "btchip_context.h" +#include "context.h" bool copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params); -void handle_swap_sign_transaction(btchip_altcoin_config_t *config); +void handle_swap_sign_transaction(altcoin_config_t *config); void __attribute__((noreturn)) finalize_exchange_sign_transaction(bool is_success); diff --git a/src/btchip_helpers.c b/src/helpers.c similarity index 86% rename from src/btchip_helpers.c rename to src/helpers.c index b16fb540..fa9c5976 100644 --- a/src/btchip_helpers.c +++ b/src/helpers.c @@ -15,8 +15,8 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" +#include "internal.h" +#include "apdu_constants.h" #include "lib_standard_app/crypto_helpers.h" #include "bip32_path.h" #include "ledger_assert.h" @@ -61,7 +61,7 @@ const unsigned char ZEN_OUTPUT_SCRIPT_POST[] = { 0xb4 // OP_CHECKBLOCKATHEIGHT }; // BIP0115 Replay Protection -unsigned char btchip_output_script_is_regular(unsigned char *buffer) { +unsigned char output_script_is_regular(unsigned char *buffer) { if (G_coin_config->native_segwit_prefix) { if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || @@ -90,7 +90,7 @@ unsigned char btchip_output_script_is_regular(unsigned char *buffer) { return 0; } -unsigned char btchip_output_script_is_p2sh(unsigned char *buffer) { +unsigned char output_script_is_p2sh(unsigned char *buffer) { if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, @@ -110,7 +110,7 @@ unsigned char btchip_output_script_is_p2sh(unsigned char *buffer) { return 0; } -unsigned char btchip_output_script_is_native_witness(unsigned char *buffer) { +unsigned char output_script_is_native_witness(unsigned char *buffer) { if (G_coin_config->native_segwit_prefix) { if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || @@ -122,7 +122,7 @@ unsigned char btchip_output_script_is_native_witness(unsigned char *buffer) { return 0; } -unsigned char btchip_output_script_is_op_return(unsigned char *buffer) { +unsigned char output_script_is_op_return(unsigned char *buffer) { if (G_coin_config->kind == COIN_KIND_BITCOIN_CASH) { return ((buffer[1] == 0x6A) || ((buffer[1] == 0x00) && (buffer[2] == 0x6A))); } @@ -134,24 +134,24 @@ unsigned char btchip_output_script_is_op_return(unsigned char *buffer) { static unsigned char output_script_is_op_create_or_call(unsigned char *buffer, size_t size, unsigned char value) { - return (!btchip_output_script_is_regular(buffer) && - !btchip_output_script_is_p2sh(buffer) && - !btchip_output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && + return (!output_script_is_regular(buffer) && + !output_script_is_p2sh(buffer) && + !output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && (buffer[0] < size) && (buffer[buffer[0]] == value)); } -unsigned char btchip_output_script_is_op_create(unsigned char *buffer, +unsigned char output_script_is_op_create(unsigned char *buffer, size_t size) { return output_script_is_op_create_or_call(buffer, size, 0xC1); } -unsigned char btchip_output_script_is_op_call(unsigned char *buffer, +unsigned char output_script_is_op_call(unsigned char *buffer, size_t size) { return output_script_is_op_create_or_call(buffer, size, 0xC2); } -unsigned char btchip_rng_u8_modulo(unsigned char modulo) { +unsigned char rng_u8_modulo(unsigned char modulo) { unsigned int rng_max = 256 % modulo; unsigned int rng_limit = 256 - rng_max; unsigned char candidate; @@ -160,7 +160,7 @@ unsigned char btchip_rng_u8_modulo(unsigned char modulo) { return (candidate % modulo); } -unsigned char btchip_secure_memcmp(const void *buf1, const void *buf2, +unsigned char secure_memcmp(const void *buf1, const void *buf2, unsigned short length) { unsigned char error = 0; while (length--) { @@ -173,7 +173,7 @@ unsigned char btchip_secure_memcmp(const void *buf1, const void *buf2, return error; } -unsigned long int btchip_read_u32(unsigned char *buffer, unsigned char be, +unsigned long int read_u32(unsigned char *buffer, unsigned char be, unsigned char skipSign) { unsigned char i; unsigned long int result = 0; @@ -193,14 +193,14 @@ unsigned long int btchip_read_u32(unsigned char *buffer, unsigned char be, return result; } -void btchip_write_u32_be(unsigned char *buffer, unsigned long int value) { +void write_u32_be(unsigned char *buffer, unsigned long int value) { buffer[0] = ((value >> 24) & 0xff); buffer[1] = ((value >> 16) & 0xff); buffer[2] = ((value >> 8) & 0xff); buffer[3] = (value & 0xff); } -void btchip_write_u32_le(unsigned char *buffer, unsigned long int value) { +void write_u32_le(unsigned char *buffer, unsigned long int value) { buffer[0] = (value & 0xff); buffer[1] = ((value >> 8) & 0xff); buffer[2] = ((value >> 16) & 0xff); @@ -209,7 +209,7 @@ void btchip_write_u32_le(unsigned char *buffer, unsigned long int value) { -void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, +void public_key_hash160(unsigned char *in, unsigned short inlen, unsigned char *out) { cx_ripemd160_t riprip; unsigned char buffer[32]; @@ -218,7 +218,7 @@ void btchip_public_key_hash160(unsigned char *in, unsigned short inlen, LEDGER_ASSERT(cx_hash_no_throw(&riprip.header, CX_LAST, buffer, 32, out, 20) == CX_OK, "hash160"); } -void btchip_compute_checksum(unsigned char* in, unsigned short inlen, unsigned char * output) { +void compute_checksum(unsigned char* in, unsigned short inlen, unsigned char * output) { unsigned char checksumBuffer[32]; cx_hash_sha256(in, inlen, checksumBuffer, 32); cx_hash_sha256(checksumBuffer, 32, checksumBuffer, 32); @@ -227,7 +227,7 @@ void btchip_compute_checksum(unsigned char* in, unsigned short inlen, unsigned c memmove(output, checksumBuffer, 4); } -unsigned short btchip_public_key_to_encoded_base58( +unsigned short public_key_to_encoded_base58( unsigned char *in, unsigned short inlen, unsigned char *out, unsigned short outlen, unsigned short version, unsigned char alreadyHashed) { @@ -238,7 +238,7 @@ unsigned short btchip_public_key_to_encoded_base58( if (!alreadyHashed) { PRINTF("To hash\n%.*H\n",inlen,in); - btchip_public_key_hash160(in, inlen, tmpBuffer + versionSize); + public_key_hash160(in, inlen, tmpBuffer + versionSize); PRINTF("Hash160\n%.*H\n",20,(tmpBuffer + versionSize)); if (version > 255) { tmpBuffer[0] = (version >> 8); @@ -250,16 +250,16 @@ unsigned short btchip_public_key_to_encoded_base58( memmove(tmpBuffer, in, 20 + versionSize); } - btchip_compute_checksum(tmpBuffer, 20 + versionSize, tmpBuffer + 20 + versionSize); + compute_checksum(tmpBuffer, 20 + versionSize, tmpBuffer + 20 + versionSize); outputLen = outlen; - if (btchip_encode_base58(tmpBuffer, 24 + versionSize, out, &outputLen) < 0) { + if (encode_base58(tmpBuffer, 24 + versionSize, out, &outputLen) < 0) { THROW(EXCEPTION); } return outputLen; } -void btchip_swap_bytes(unsigned char *target, unsigned char *source, +void swap_bytes(unsigned char *target, unsigned char *source, unsigned char size) { unsigned char i; for (i = 0; i < size; i++) { @@ -267,13 +267,13 @@ void btchip_swap_bytes(unsigned char *target, unsigned char *source, } } -unsigned short btchip_decode_base58_address(unsigned char *in, +unsigned short decode_base58_address(unsigned char *in, unsigned short inlen, unsigned char *out, unsigned short outlen) { unsigned char hashBuffer[32]; size_t outputLen = outlen; - if (btchip_decode_base58((char *)in, inlen, out, &outputLen) < 0) { + if (decode_base58((char *)in, inlen, out, &outputLen) < 0) { THROW(EXCEPTION); } outlen = outputLen; @@ -382,7 +382,7 @@ unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned cha out[0] = ' '; offset=1; for (i = 0; i < bip32PathLength; i++) { - current_level = btchip_read_u32(bip32Path, 1, 0); + current_level = read_u32(bip32Path, 1, 0); hardened = (bool)(current_level & 0x80000000); if(hardened) { //remove hardening flag @@ -403,7 +403,7 @@ unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned cha return offset -1; } -void btchip_transaction_add_output(unsigned char *hash160Address, +void transaction_add_output(unsigned char *hash160Address, unsigned char *amount, unsigned char p2sh) { const unsigned char *pre = (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE : TRANSACTION_OUTPUT_SCRIPT_PRE); @@ -414,19 +414,19 @@ void btchip_transaction_add_output(unsigned char *hash160Address, unsigned char sizePost = (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST) : sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)); if (amount != NULL) { - btchip_swap_bytes(btchip_context_D.tmp, amount, 8); - btchip_context_D.tmp += 8; - } - memmove(btchip_context_D.tmp, (void *)pre, sizePre); - btchip_context_D.tmp += sizePre; - memmove(btchip_context_D.tmp, hash160Address, 20); - btchip_context_D.tmp += 20; - memmove(btchip_context_D.tmp, (void *)post, sizePost); - btchip_context_D.tmp += sizePost; + swap_bytes(context_D.tmp, amount, 8); + context_D.tmp += 8; + } + memmove(context_D.tmp, (void *)pre, sizePre); + context_D.tmp += sizePre; + memmove(context_D.tmp, hash160Address, 20); + context_D.tmp += 20; + memmove(context_D.tmp, (void *)post, sizePost); + context_D.tmp += sizePost; } -int btchip_sign_finalhash(unsigned char* path, size_t path_len, unsigned char *in, unsigned short inlen, +int sign_finalhash(unsigned char* path, size_t path_len, unsigned char *in, unsigned short inlen, unsigned char *out, size_t* outlen, unsigned char rfc6979) { @@ -464,7 +464,7 @@ int btchip_sign_finalhash(unsigned char* path, size_t path_len, unsigned char *i return 0; } -int btchip_get_public_key(unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode) { +int get_public_key(unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode) { bip32_path_t bip32Path; diff --git a/src/internal.h b/src/internal.h new file mode 100644 index 00000000..eeb7ff7e --- /dev/null +++ b/src/internal.h @@ -0,0 +1,31 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#ifndef INTERNAL_H +#define INTERNAL_H + +#include "btchip.h" +#include "public_ram_variables.h" +#include "rom_variables.h" +#include "filesystem.h" +#include "base58.h" +#include "bcd.h" +#include "ecc.h" +#include "helpers.h" +#include "transaction.h" + +#endif diff --git a/src/main.c b/src/main.c index fe9f1fc2..9454ccbe 100644 --- a/src/main.c +++ b/src/main.c @@ -20,15 +20,15 @@ #include "string.h" -#include "btchip_internal.h" +#include "internal.h" -#include "btchip_bagl_extensions.h" +#include "bagl_extensions.h" #include "segwit_addr.h" #include "cashaddr.h" #include "ux.h" -#include "btchip_display_variables.h" +#include "display_variables.h" #include "swap_lib_calls.h" #include "swap_lib_calls.h" @@ -133,32 +133,32 @@ uint8_t check_fee_swap() { unsigned char borrow; borrow = transaction_amount_sub_be( - fees, btchip_context_D.transactionContext.transactionAmount, - btchip_context_D.totalOutputAmount); + fees, context_D.transactionContext.transactionAmount, + context_D.totalOutputAmount); if ((borrow != 0) || (memcmp(fees, vars.swap_data.fees, 8) != 0)) return 0; - btchip_context_D.transactionContext.firstSigned = 0; + context_D.transactionContext.firstSigned = 0; - if (btchip_context_D.usingSegwit && !btchip_context_D.segwitParsedOnce) { + if (context_D.usingSegwit && !context_D.segwitParsedOnce) { // This input cannot be signed when using segwit - just restart. - btchip_context_D.segwitParsedOnce = 1; + context_D.segwitParsedOnce = 1; PRINTF("Segwit parsed once\n"); - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + context_D.transactionContext.transactionState = + TRANSACTION_NONE; } else { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_SIGN_READY; + context_D.transactionContext.transactionState = + TRANSACTION_SIGN_READY; } - btchip_context_D.sw = 0x9000; - btchip_context_D.outLength = 0; - G_io_apdu_buffer[btchip_context_D.outLength++] = 0x90; - G_io_apdu_buffer[btchip_context_D.outLength++] = 0x00; + context_D.sw = 0x9000; + context_D.outLength = 0; + G_io_apdu_buffer[context_D.outLength++] = 0x90; + G_io_apdu_buffer[context_D.outLength++] = 0x00; return 1; } uint8_t prepare_fees() { - if (btchip_context_D.transactionContext.relaxed) { + if (context_D.transactionContext.relaxed) { memmove(vars.tmp.feesAmount, "UNKNOWN", 7); vars.tmp.feesAmount[7] = '\0'; } else { @@ -167,8 +167,8 @@ uint8_t prepare_fees() { unsigned char borrow; borrow = transaction_amount_sub_be( - fees, btchip_context_D.transactionContext.transactionAmount, - btchip_context_D.totalOutputAmount); + fees, context_D.transactionContext.transactionAmount, + context_D.totalOutputAmount); if (borrow && G_coin_config->kind == COIN_KIND_KOMODO) { memmove(vars.tmp.feesAmount, "REWARD", 6); vars.tmp.feesAmount[6] = '\0'; @@ -181,10 +181,10 @@ uint8_t prepare_fees() { memmove(vars.tmp.feesAmount, G_coin_config->name_short, strlen(G_coin_config->name_short)); vars.tmp.feesAmount[strlen(G_coin_config->name_short)] = ' '; - btchip_context_D.tmp = + context_D.tmp = (unsigned char *)(vars.tmp.feesAmount + strlen(G_coin_config->name_short) + 1); - textSize = btchip_convert_hex_amount_to_displayable(fees); + textSize = convert_hex_amount_to_displayable(fees); vars.tmp.feesAmount[textSize + strlen(G_coin_config->name_short) + 1] = '\0'; } @@ -199,21 +199,21 @@ uint8_t prepare_fees() { #define USDT_ASSETID 31 void get_address_from_output_script(unsigned char* script, int script_size, char* out, int out_size) { - if (btchip_output_script_is_op_return(script)) { + if (output_script_is_op_return(script)) { strncpy(out, "OP_RETURN", out_size); return; } if ((G_coin_config->kind == COIN_KIND_HYDRA) && - btchip_output_script_is_op_create(script, script_size)) { + output_script_is_op_create(script, script_size)) { strncpy(out, "OP_CREATE", out_size); return; } if ((G_coin_config->kind == COIN_KIND_HYDRA) && - btchip_output_script_is_op_call(script, script_size)) { + output_script_is_op_call(script, script_size)) { strncpy(out, "OP_CALL", out_size); return; } - if (btchip_output_script_is_native_witness(script)) { + if (output_script_is_native_witness(script)) { if (G_coin_config->native_segwit_prefix) { segwit_addr_encode( out, (char *)PIC(G_coin_config->native_segwit_prefix), 0, @@ -228,7 +228,7 @@ void get_address_from_output_script(unsigned char* script, int script_size, char int addressOffset = 3; unsigned short version = G_coin_config->p2sh_version; - if (btchip_output_script_is_regular(script)) { + if (output_script_is_regular(script)) { addressOffset = 4; version = G_coin_config->p2pkh_version; } @@ -244,14 +244,14 @@ void get_address_from_output_script(unsigned char* script, int script_size, char memmove(address + versionSize, script + addressOffset, 20); // Prepare address - if (btchip_context_D.usingCashAddr) { + if (context_D.usingCashAddr) { cashaddr_encode( address + versionSize, 20, (uint8_t *)out, out_size, (version == G_coin_config->p2sh_version ? CASHADDR_P2SH : CASHADDR_P2PKH)); } else { - textSize = btchip_public_key_to_encoded_base58( + textSize = public_key_to_encoded_base58( address, 20 + versionSize, (unsigned char *)out, out_size, version, 1); out[textSize] = '\0'; @@ -265,20 +265,20 @@ uint8_t prepare_single_output() { unsigned short textSize; char tmp[80] = {0}; - btchip_swap_bytes(amount, btchip_context_D.currentOutput + offset, 8); + swap_bytes(amount, context_D.currentOutput + offset, 8); offset += 8; - get_address_from_output_script(btchip_context_D.currentOutput + offset, sizeof(btchip_context_D.currentOutput) - offset, tmp, sizeof(tmp)); + get_address_from_output_script(context_D.currentOutput + offset, sizeof(context_D.currentOutput) - offset, tmp, sizeof(tmp)); strncpy(vars.tmp.fullAddress, tmp, sizeof(vars.tmp.fullAddress) - 1); // Prepare amount // Handle Omni simple send - if ((btchip_context_D.currentOutput[offset + 2] == 0x14) && - (memcmp(btchip_context_D.currentOutput + offset + 3, "omni", 4) == 0) && - (memcmp(btchip_context_D.currentOutput + offset + 3 + 4, "\0\0\0\0", 4) == 0)) { + if ((context_D.currentOutput[offset + 2] == 0x14) && + (memcmp(context_D.currentOutput + offset + 3, "omni", 4) == 0) && + (memcmp(context_D.currentOutput + offset + 3 + 4, "\0\0\0\0", 4) == 0)) { uint8_t headerLength; - uint32_t omniAssetId = btchip_read_u32(btchip_context_D.currentOutput + offset + 3 + 4 + 4, 1, 0); + uint32_t omniAssetId = read_u32(context_D.currentOutput + offset + 3 + 4 + 4, 1, 0); switch(omniAssetId) { case OMNI_ASSETID: strcpy(vars.tmp.fullAmount, "OMNI "); @@ -294,18 +294,18 @@ uint8_t prepare_single_output() { break; } headerLength = strlen(vars.tmp.fullAmount); - btchip_context_D.tmp = (uint8_t *)vars.tmp.fullAmount + headerLength; - textSize = btchip_convert_hex_amount_to_displayable(btchip_context_D.currentOutput + offset + 3 + 4 + 4 + 4); + context_D.tmp = (uint8_t *)vars.tmp.fullAmount + headerLength; + textSize = convert_hex_amount_to_displayable(context_D.currentOutput + offset + 3 + 4 + 4 + 4); vars.tmp.fullAmount[textSize + headerLength] = '\0'; } else { memmove(vars.tmp.fullAmount, G_coin_config->name_short, strlen(G_coin_config->name_short)); vars.tmp.fullAmount[strlen(G_coin_config->name_short)] = ' '; - btchip_context_D.tmp = + context_D.tmp = (unsigned char *)(vars.tmp.fullAmount + strlen(G_coin_config->name_short) + 1); - textSize = btchip_convert_hex_amount_to_displayable(amount); + textSize = convert_hex_amount_to_displayable(amount); vars.tmp.fullAmount[textSize + strlen(G_coin_config->name_short) + 1] = '\0'; } @@ -316,7 +316,7 @@ uint8_t prepare_single_output() { uint8_t prepare_message_signature() { uint8_t buffer[32]; - if (cx_hash_no_throw(&btchip_context_D.transactionHashAuthorization.header, CX_LAST, + if (cx_hash_no_throw(&context_D.transactionHashAuthorization.header, CX_LAST, (uint8_t*)vars.tmp.fullAmount, 0, buffer, 32)) { return 0; } @@ -328,11 +328,11 @@ uint8_t prepare_message_signature() { extern bool handle_output_state(); -extern void btchip_apdu_hash_input_finalize_full_reset(void); +extern void apdu_hash_input_finalize_full_reset(void); -// Analog of btchip_bagl_confirm_single_output to work +// Analog of bagl_confirm_single_output to work // in silent mode, when called from SWAP app -unsigned int btchip_silent_confirm_single_output() { +unsigned int silent_confirm_single_output() { char tmp[80] = {0}; unsigned char amount[8]; while (true) { @@ -343,12 +343,12 @@ unsigned int btchip_silent_confirm_single_output() { } vars.swap_data.was_address_checked = 1; // check amount - btchip_swap_bytes(amount, btchip_context_D.currentOutput, 8); + swap_bytes(amount, context_D.currentOutput, 8); if (memcmp(amount, vars.swap_data.amount, 8) != 0) { PRINTF("Amount not matched\n"); return 0; } - get_address_from_output_script(btchip_context_D.currentOutput + 8, sizeof(btchip_context_D.currentOutput) - 8, tmp, sizeof(tmp)); + get_address_from_output_script(context_D.currentOutput + 8, sizeof(context_D.currentOutput) - 8, tmp, sizeof(tmp)); if (strcmp(tmp, vars.swap_data.destination_address) != 0) { PRINTF("Address not matched\n"); return 0; @@ -356,70 +356,70 @@ unsigned int btchip_silent_confirm_single_output() { // Check if all inputs have been confirmed - if (btchip_context_D.outputParsingState == - BTCHIP_OUTPUT_PARSING_OUTPUT) { - btchip_context_D.remainingOutputs--; - if (btchip_context_D.remainingOutputs == 0) + if (context_D.outputParsingState == + OUTPUT_PARSING_OUTPUT) { + context_D.remainingOutputs--; + if (context_D.remainingOutputs == 0) break; } - memmove(btchip_context_D.currentOutput, - btchip_context_D.currentOutput + - btchip_context_D.discardSize, - btchip_context_D.currentOutputOffset - - btchip_context_D.discardSize); - btchip_context_D.currentOutputOffset -= btchip_context_D.discardSize; - btchip_context_D.io_flags &= ~IO_ASYNCH_REPLY; + memmove(context_D.currentOutput, + context_D.currentOutput + + context_D.discardSize, + context_D.currentOutputOffset - + context_D.discardSize); + context_D.currentOutputOffset -= context_D.discardSize; + context_D.io_flags &= ~IO_ASYNCH_REPLY; while (handle_output_state() && - (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY))) + (!(context_D.io_flags & IO_ASYNCH_REPLY))) ; - if (!(btchip_context_D.io_flags & IO_ASYNCH_REPLY)) { + if (!(context_D.io_flags & IO_ASYNCH_REPLY)) { // Out of data to process, wait for the next call break; } } - if ((btchip_context_D.outputParsingState == BTCHIP_OUTPUT_PARSING_OUTPUT) && - (btchip_context_D.remainingOutputs == 0)) { - btchip_context_D.outputParsingState = BTCHIP_OUTPUT_FINALIZE_TX; + if ((context_D.outputParsingState == OUTPUT_PARSING_OUTPUT) && + (context_D.remainingOutputs == 0)) { + context_D.outputParsingState = OUTPUT_FINALIZE_TX; // check fees unsigned char fees[8]; if ((transaction_amount_sub_be(fees, - btchip_context_D.transactionContext.transactionAmount, - btchip_context_D.totalOutputAmount) != 0) || + context_D.transactionContext.transactionAmount, + context_D.totalOutputAmount) != 0) || (memcmp(fees, vars.swap_data.fees, 8) != 0)) { PRINTF("Fees is not matched\n"); return 0; } } - if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) { - btchip_context_D.transactionContext.firstSigned = 0; + if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { + context_D.transactionContext.firstSigned = 0; - if (btchip_context_D.usingSegwit && - !btchip_context_D.segwitParsedOnce) { + if (context_D.usingSegwit && + !context_D.segwitParsedOnce) { // This input cannot be signed when using segwit - just restart. - btchip_context_D.segwitParsedOnce = 1; + context_D.segwitParsedOnce = 1; PRINTF("Segwit parsed once\n"); - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; + context_D.transactionContext.transactionState = + TRANSACTION_NONE; } else { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_SIGN_READY; + context_D.transactionContext.transactionState = + TRANSACTION_SIGN_READY; } } - if (btchip_context_D.outputParsingState == BTCHIP_OUTPUT_FINALIZE_TX) { + if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { // we've finished the processing of the input - btchip_apdu_hash_input_finalize_full_reset(); + apdu_hash_input_finalize_full_reset(); } return 1; } -unsigned int btchip_bagl_confirm_single_output() { - if (btchip_context_D.called_from_swap) { - return btchip_silent_confirm_single_output(); +unsigned int bagl_confirm_single_output() { + if (context_D.called_from_swap) { + return silent_confirm_single_output(); } if (!prepare_single_output()) { return 0; @@ -429,8 +429,8 @@ unsigned int btchip_bagl_confirm_single_output() { return 1; } -unsigned int btchip_bagl_finalize_tx() { - if (btchip_context_D.called_from_swap) { +unsigned int bagl_finalize_tx() { + if (context_D.called_from_swap) { return check_fee_swap(); } @@ -442,7 +442,7 @@ unsigned int btchip_bagl_finalize_tx() { return 1; } -void btchip_bagl_confirm_message_signature() { +void bagl_confirm_message_signature() { if (!prepare_message_signature()) { return; } @@ -455,7 +455,7 @@ uint8_t set_key_path_to_display(unsigned char* keyPath) { return bip44_derivation_guard(keyPath, false); } -void btchip_bagl_display_public_key(uint8_t is_derivation_path_unusual) { +void bagl_display_public_key(uint8_t is_derivation_path_unusual) { // append a white space at the end of the address to avoid glitch on nano S strlcat((char *)G_io_apdu_buffer + 200, " ", sizeof(G_io_apdu_buffer) - 200); @@ -467,29 +467,29 @@ void btchip_bagl_display_public_key(uint8_t is_derivation_path_unusual) { } } -void btchip_bagl_display_token() +void bagl_display_token() { ui_display_token_flow(); } -void btchip_bagl_request_pubkey_approval() +void bagl_request_pubkey_approval() { ui_request_pubkey_approval_flow(); } -void btchip_bagl_request_change_path_approval(unsigned char* change_path) +void bagl_request_change_path_approval(unsigned char* change_path) { bip32_print_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); ui_request_change_path_approval_flow(); } -void btchip_bagl_request_sign_path_approval(unsigned char* change_path) +void bagl_request_sign_path_approval(unsigned char* change_path) { bip32_print_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); ui_request_sign_path_approval_flow(); } -void btchip_bagl_request_segwit_input_approval() +void bagl_request_segwit_input_approval() { ui_request_segwit_input_approval_flow(); } @@ -507,8 +507,8 @@ void app_exit(void) { END_TRY_L(exit); } -void init_coin_config(btchip_altcoin_config_t *coin_config) { - memset(coin_config, 0, sizeof(btchip_altcoin_config_t)); +void init_coin_config(altcoin_config_t *coin_config) { + memset(coin_config, 0, sizeof(altcoin_config_t)); coin_config->bip44_coin_type = BIP44_COIN_TYPE; coin_config->bip44_coin_type2 = BIP44_COIN_TYPE_2; coin_config->p2pkh_version = COIN_P2PKH_VERSION; @@ -540,8 +540,8 @@ void init_coin_config(btchip_altcoin_config_t *coin_config) { coin_config->kind = COIN_KIND; } -void coin_main(btchip_altcoin_config_t *coin_config) { - btchip_altcoin_config_t config; +void coin_main(altcoin_config_t *coin_config) { + altcoin_config_t config; if (coin_config == NULL) { init_coin_config(&config); G_coin_config = &config; @@ -562,7 +562,7 @@ void coin_main(btchip_altcoin_config_t *coin_config) { G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); #endif // TARGET_NANOX - btchip_context_init(); + context_init(); USB_power(0); USB_power(1); @@ -617,7 +617,7 @@ static void library_main_helper(libargs_t *args) { } void library_main(libargs_t *args) { - btchip_altcoin_config_t coin_config; + altcoin_config_t coin_config; if (args->coin_config == NULL) { init_coin_config(&coin_config); args->coin_config = &coin_config; @@ -646,7 +646,7 @@ __attribute__((section(".boot"))) int main(int arg0) { BEGIN_TRY { TRY { unsigned int libcall_params[5]; - btchip_altcoin_config_t coin_config; + altcoin_config_t coin_config; init_coin_config(&coin_config); PRINTF("Hello from litecoin\n"); // delegate to bitcoin app/lib diff --git a/src/btchip_nvram.c b/src/nvram.c similarity index 87% rename from src/btchip_nvram.c rename to src/nvram.c index 2f3990b6..a956708f 100644 --- a/src/btchip_nvram.c +++ b/src/nvram.c @@ -15,8 +15,8 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" +#include "internal.h" -#include "btchip_public_ram_variables.h" +#include "public_ram_variables.h" -btchip_storage_t const N_btchip_real; +storage_t const N_real; diff --git a/src/btchip_public_ram_variables.c b/src/public_ram_variables.c similarity index 87% rename from src/btchip_public_ram_variables.c rename to src/public_ram_variables.c index 9ca8a837..8537e3b3 100644 --- a/src/btchip_public_ram_variables.c +++ b/src/public_ram_variables.c @@ -15,8 +15,8 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_public_ram_variables.h" +#include "public_ram_variables.h" -btchip_context_t btchip_context_D; +context_t context_D; -btchip_altcoin_config_t *G_coin_config; \ No newline at end of file +altcoin_config_t *G_coin_config; \ No newline at end of file diff --git a/src/public_ram_variables.h b/src/public_ram_variables.h new file mode 100644 index 00000000..de0cfe55 --- /dev/null +++ b/src/public_ram_variables.h @@ -0,0 +1,30 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#ifndef _PUBLIC_RAM_VARIABLES_H_ +#define _PUBLIC_RAM_VARIABLES_H_ + +#include "config.h" + +#include "secure_value.h" +#include "context.h" + +extern context_t context_D; + +extern altcoin_config_t *G_coin_config; + +#endif /* _PUBLIC_RAM_VARIABLES_H_ */ diff --git a/src/btchip_rom_variables.c b/src/rom_variables.c similarity index 56% rename from src/btchip_rom_variables.c rename to src/rom_variables.c index 7ca8a8e1..daee33d1 100644 --- a/src/btchip_rom_variables.c +++ b/src/rom_variables.c @@ -15,8 +15,8 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" +#include "internal.h" +#include "apdu_constants.h" unsigned char const HEXDIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; @@ -53,65 +53,65 @@ unsigned char const OVERWINTER_PARAM_SIGHASH[16] = { 'Z', 'c', 'a', 's', 'h', 'S unsigned char const OVERWINTER_NO_JOINSPLITS[32] = { 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 }; unsigned char const DISPATCHER_CLA[] = { - BTCHIP_CLA, // btchip_apdu_setup, - BTCHIP_CLA, // btchip_apdu_verify_pin, - BTCHIP_CLA, // btchip_apdu_get_operation_mode, - BTCHIP_CLA, // btchip_apdu_set_operation_mode, - BTCHIP_CLA, // btchip_apdu_get_wallet_public_key, - BTCHIP_CLA, // btchip_apdu_get_trusted_input, - BTCHIP_CLA, // btchip_apdu_hash_input_start, - BTCHIP_CLA, // btchip_apdu_hash_sign, - BTCHIP_CLA, // btchip_apdu_hash_input_finalize_full, - BTCHIP_CLA, // btchip_apdu_sign_message, - BTCHIP_CLA, // btchip_apdu_get_random, - BTCHIP_CLA, // btchip_apdu_get_firmware_version, - BTCHIP_CLA, // btchip_apdu_get_coin_version + CLA, // apdu_setup, + CLA, // apdu_verify_pin, + CLA, // apdu_get_operation_mode, + CLA, // apdu_set_operation_mode, + CLA, // apdu_get_wallet_public_key, + CLA, // apdu_get_trusted_input, + CLA, // apdu_hash_input_start, + CLA, // apdu_hash_sign, + CLA, // apdu_hash_input_finalize_full, + CLA, // apdu_sign_message, + CLA, // apdu_get_random, + CLA, // apdu_get_firmware_version, + CLA, // apdu_get_coin_version }; unsigned char const DISPATCHER_INS[] = { - BTCHIP_INS_SETUP, // btchip_apdu_setup, - BTCHIP_INS_VERIFY_PIN, // btchip_apdu_verify_pin, - BTCHIP_INS_GET_OPERATION_MODE, // btchip_apdu_get_operation_mode, - BTCHIP_INS_SET_OPERATION_MODE, // btchip_apdu_set_operation_mode, - BTCHIP_INS_GET_WALLET_PUBLIC_KEY, // btchip_apdu_get_wallet_public_key, - BTCHIP_INS_GET_TRUSTED_INPUT, // btchip_apdu_get_trusted_input, - BTCHIP_INS_HASH_INPUT_START, // btchip_apdu_hash_input_start, - BTCHIP_INS_HASH_SIGN, // btchip_apdu_hash_sign, - BTCHIP_INS_HASH_INPUT_FINALIZE_FULL, // btchip_apdu_hash_input_finalize_full, - BTCHIP_INS_SIGN_MESSAGE, // btchip_apdu_sign_message, - BTCHIP_INS_GET_RANDOM, // btchip_apdu_get_random, - BTCHIP_INS_GET_FIRMWARE_VERSION, // btchip_apdu_get_firmware_version, - BTCHIP_INS_GET_COIN_VER, // btchip_apdu_get_coin_version + INS_SETUP, // apdu_setup, + INS_VERIFY_PIN, // apdu_verify_pin, + INS_GET_OPERATION_MODE, // apdu_get_operation_mode, + INS_SET_OPERATION_MODE, // apdu_set_operation_mode, + INS_GET_WALLET_PUBLIC_KEY, // apdu_get_wallet_public_key, + INS_GET_TRUSTED_INPUT, // apdu_get_trusted_input, + INS_HASH_INPUT_START, // apdu_hash_input_start, + INS_HASH_SIGN, // apdu_hash_sign, + INS_HASH_INPUT_FINALIZE_FULL, // apdu_hash_input_finalize_full, + INS_SIGN_MESSAGE, // apdu_sign_message, + INS_GET_RANDOM, // apdu_get_random, + INS_GET_FIRMWARE_VERSION, // apdu_get_firmware_version, + INS_GET_COIN_VER, // apdu_get_coin_version }; unsigned char const DISPATCHER_DATA_IN[] = { - 1, // btchip_apdu_setup, - 1, // btchip_apdu_verify_pin, - 0, // btchip_apdu_get_operation_mode, - 1, // btchip_apdu_set_operation_mode, - 1, // btchip_apdu_get_wallet_public_key, - 1, // btchip_apdu_get_trusted_input, - 1, // btchip_apdu_hash_input_start, - 1, // btchip_apdu_hash_sign, - 1, // btchip_apdu_hash_input_finalize_full, - 1, // btchip_apdu_sign_message, - 0, // btchip_apdu_get_random, - 0, // btchip_apdu_get_firmware_version, - 0, // btchip_apdu_get_coin_version + 1, // apdu_setup, + 1, // apdu_verify_pin, + 0, // apdu_get_operation_mode, + 1, // apdu_set_operation_mode, + 1, // apdu_get_wallet_public_key, + 1, // apdu_get_trusted_input, + 1, // apdu_hash_input_start, + 1, // apdu_hash_sign, + 1, // apdu_hash_input_finalize_full, + 1, // apdu_sign_message, + 0, // apdu_get_random, + 0, // apdu_get_firmware_version, + 0, // apdu_get_coin_version }; apduProcessingFunction const DISPATCHER_FUNCTIONS[] = { - btchip_apdu_setup, - btchip_apdu_verify_pin, - btchip_apdu_get_operation_mode, - btchip_apdu_set_operation_mode, - btchip_apdu_get_wallet_public_key, - btchip_apdu_get_trusted_input, - btchip_apdu_hash_input_start, - btchip_apdu_hash_sign, - btchip_apdu_hash_input_finalize_full, - btchip_apdu_sign_message, - btchip_apdu_get_random, - btchip_apdu_get_firmware_version, - btchip_apdu_get_coin_version, + apdu_setup, + apdu_verify_pin, + apdu_get_operation_mode, + apdu_set_operation_mode, + apdu_get_wallet_public_key, + apdu_get_trusted_input, + apdu_hash_input_start, + apdu_hash_sign, + apdu_hash_input_finalize_full, + apdu_sign_message, + apdu_get_random, + apdu_get_firmware_version, + apdu_get_coin_version, }; diff --git a/src/btchip_rom_variables.h b/src/rom_variables.h similarity index 94% rename from src/btchip_rom_variables.h rename to src/rom_variables.h index eae57c22..ef9cde4a 100644 --- a/src/btchip_rom_variables.h +++ b/src/rom_variables.h @@ -15,10 +15,10 @@ * limitations under the License. ********************************************************************************/ -#ifndef _BTCHIP_ROM_VARIABLES_ -#define _BTCHIP_ROM_VARIABLES_ +#ifndef _ROM_VARIABLES_ +#define _ROM_VARIABLES_ -#include "btchip_internal.h" +#include "internal.h" #define SIGNMAGIC_LENGTH 17 @@ -67,4 +67,4 @@ extern unsigned char const DISPATCHER_INS[DISPATCHER_APDUS]; extern unsigned char const DISPATCHER_DATA_IN[DISPATCHER_APDUS]; extern apduProcessingFunction const DISPATCHER_FUNCTIONS[DISPATCHER_APDUS]; -#endif /* _BTCHIP_ROM_VARIABLES_ */ \ No newline at end of file +#endif /* _ROM_VARIABLES_ */ \ No newline at end of file diff --git a/src/btchip_secure_value.c b/src/secure_value.c similarity index 97% rename from src/btchip_secure_value.c rename to src/secure_value.c index 4fd16228..03ca4c1b 100644 --- a/src/btchip_secure_value.c +++ b/src/secure_value.c @@ -15,7 +15,7 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" +#include "internal.h" void sbSet(secu8 *target, unsigned char source) { *target = (((unsigned char)~source) << 8) + source; diff --git a/src/btchip_transaction.c b/src/transaction.c similarity index 57% rename from src/btchip_transaction.c rename to src/transaction.c index f15fe553..5a381306 100644 --- a/src/btchip_transaction.c +++ b/src/transaction.c @@ -15,9 +15,9 @@ * limitations under the License. ********************************************************************************/ -#include "btchip_internal.h" -#include "btchip_apdu_constants.h" -#include "btchip_display_variables.h" +#include "internal.h" +#include "apdu_constants.h" +#include "display_variables.h" #include "ledger_assert.h" #define CONSENSUS_BRANCH_ID_OVERWINTER 0x5ba81b19 @@ -28,15 +28,15 @@ #define TRUSTED_INPUT_OVERWINTER ( (G_coin_config->kind == COIN_KIND_ZCASH || \ G_coin_config->kind == COIN_KIND_ZCLASSIC || \ G_coin_config->kind == COIN_KIND_KOMODO) && \ - (btchip_read_u32(btchip_context_D.transactionVersion, 0, 0) & (1<<31)) && \ - (btchip_read_u32(btchip_context_D.transactionVersion, 0, 0) ^ (1<<31)) >= 0x03 \ + (read_u32(context_D.transactionVersion, 0, 0) & (1<<31)) && \ + (read_u32(context_D.transactionVersion, 0, 0) ^ (1<<31)) >= 0x03 \ ) #define DEBUG_LONG "%d" void check_transaction_available(unsigned char x) { - if (btchip_context_D.transactionDataRemaining < x) { - PRINTF("Check transaction available failed %d < %d\n", btchip_context_D.transactionDataRemaining, x); + if (context_D.transactionDataRemaining < x) { + PRINTF("Check transaction available failed %d < %d\n", context_D.transactionDataRemaining, x); THROW(EXCEPTION); } } @@ -85,34 +85,34 @@ unsigned char transaction_amount_sub_be(unsigned char *target, } void transaction_offset(unsigned char value) { - if ((btchip_context_D.transactionHashOption & TRANSACTION_HASH_FULL) != 0) { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", value, btchip_context_D.transactionBufferPointer); - if (btchip_context_D.usingOverwinter) { - LEDGER_ASSERT(cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); + if ((context_D.transactionHashOption & TRANSACTION_HASH_FULL) != 0) { + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", value, context_D.transactionBufferPointer); + if (context_D.usingOverwinter) { + LEDGER_ASSERT(cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); } else { - LEDGER_ASSERT(cx_hash_no_throw(&btchip_context_D.transactionHashFull.sha256.header, 0, - btchip_context_D.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); + LEDGER_ASSERT(cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, + context_D.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); } } - if ((btchip_context_D.transactionHashOption & + if ((context_D.transactionHashOption & TRANSACTION_HASH_AUTHORIZATION) != 0) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", value, btchip_context_D.transactionBufferPointer); - LEDGER_ASSERT(cx_hash_no_throw(&btchip_context_D.transactionHashAuthorization.header, 0, - btchip_context_D.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", value, context_D.transactionBufferPointer); + LEDGER_ASSERT(cx_hash_no_throw(&context_D.transactionHashAuthorization.header, 0, + context_D.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); } } void transaction_offset_increase(unsigned char value) { transaction_offset(value); - btchip_context_D.transactionBufferPointer += value; - btchip_context_D.transactionDataRemaining -= value; + context_D.transactionBufferPointer += value; + context_D.transactionDataRemaining -= value; } unsigned long int transaction_get_varint(void) { unsigned char firstByte; check_transaction_available(1); - firstByte = *btchip_context_D.transactionBufferPointer; + firstByte = *context_D.transactionBufferPointer; if (firstByte < 0xFD) { transaction_offset_increase(1); return firstByte; @@ -121,8 +121,8 @@ unsigned long int transaction_get_varint(void) { transaction_offset_increase(1); check_transaction_available(2); result = - (unsigned long int)(*btchip_context_D.transactionBufferPointer) | - ((unsigned long int)(*(btchip_context_D.transactionBufferPointer + + (unsigned long int)(*context_D.transactionBufferPointer) | + ((unsigned long int)(*(context_D.transactionBufferPointer + 1)) << 8); transaction_offset_increase(2); @@ -132,7 +132,7 @@ unsigned long int transaction_get_varint(void) { transaction_offset_increase(1); check_transaction_available(4); result = - btchip_read_u32(btchip_context_D.transactionBufferPointer, 0, 0); + read_u32(context_D.transactionBufferPointer, 0, 0); transaction_offset_increase(4); return result; } else { @@ -144,153 +144,153 @@ unsigned long int transaction_get_varint(void) { void transaction_parse(unsigned char parseMode) { unsigned char optionP2SHSkip2FA = - ((N_btchip.bkp.config.options & BTCHIP_OPTION_SKIP_2FA_P2SH) != 0); - btchip_set_check_internal_structure_integrity(0); + ((N_btchip.bkp.config.options & OPTION_SKIP_2FA_P2SH) != 0); + set_check_internal_structure_integrity(0); BEGIN_TRY { TRY { for (;;) { - switch (btchip_context_D.transactionContext.transactionState) { - case BTCHIP_TRANSACTION_NONE: { + switch (context_D.transactionContext.transactionState) { + case TRANSACTION_NONE: { PRINTF("Init transaction parser\n"); // Reset transaction state - btchip_context_D.transactionContext + context_D.transactionContext .transactionRemainingInputsOutputs = 0; - btchip_context_D.transactionContext + context_D.transactionContext .transactionCurrentInputOutput = 0; - btchip_context_D.transactionContext.scriptRemaining = 0; + context_D.transactionContext.scriptRemaining = 0; memset( - btchip_context_D.transactionContext.transactionAmount, - 0, sizeof(btchip_context_D.transactionContext + context_D.transactionContext.transactionAmount, + 0, sizeof(context_D.transactionContext .transactionAmount)); // TODO : transactionControlFid // Reset hashes - if (btchip_context_D.usingOverwinter) { - if (btchip_context_D.segwitParsedOnce) { + if (context_D.usingOverwinter) { + if (context_D.segwitParsedOnce) { uint8_t parameters[16]; memmove(parameters, OVERWINTER_PARAM_SIGHASH, 16); if (G_coin_config->kind == COIN_KIND_ZCLASSIC) { - btchip_write_u32_le(parameters + 12, CONSENSUS_BRANCH_ID_ZCLASSIC); + write_u32_le(parameters + 12, CONSENSUS_BRANCH_ID_ZCLASSIC); } else { - btchip_write_u32_le(parameters + 12, - btchip_context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING ? + write_u32_le(parameters + 12, + context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING ? (G_coin_config->zcash_consensus_branch_id != 0 ? G_coin_config->zcash_consensus_branch_id : CONSENSUS_BRANCH_ID_SAPLING) : CONSENSUS_BRANCH_ID_OVERWINTER); } - if (cx_blake2b_init2_no_throw(&btchip_context_D.transactionHashFull.blake2b, 256, NULL, 0, parameters, 16)) { + if (cx_blake2b_init2_no_throw(&context_D.transactionHashFull.blake2b, 256, NULL, 0, parameters, 16)) { goto fail; } } } else { - if (cx_sha256_init_no_throw(&btchip_context_D.transactionHashFull.sha256)) { + if (cx_sha256_init_no_throw(&context_D.transactionHashFull.sha256)) { goto fail; } } if (cx_sha256_init_no_throw( - &btchip_context_D.transactionHashAuthorization)) { + &context_D.transactionHashAuthorization)) { goto fail; } - if (btchip_context_D.usingSegwit) { - btchip_context_D.transactionHashOption = 0; - if (!btchip_context_D.segwitParsedOnce) { - if (btchip_context_D.usingOverwinter) { - if (cx_blake2b_init2_no_throw(&btchip_context_D.segwit.hash.hashPrevouts.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_PREVOUTS, 16)) { + if (context_D.usingSegwit) { + context_D.transactionHashOption = 0; + if (!context_D.segwitParsedOnce) { + if (context_D.usingOverwinter) { + if (cx_blake2b_init2_no_throw(&context_D.segwit.hash.hashPrevouts.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_PREVOUTS, 16)) { goto fail; } - if (cx_blake2b_init2_no_throw(&btchip_context_D.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_SEQUENCE, 16)) { + if (cx_blake2b_init2_no_throw(&context_D.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_SEQUENCE, 16)) { goto fail; } } else { if (cx_sha256_init_no_throw( - &btchip_context_D.segwit.hash.hashPrevouts.sha256)) { + &context_D.segwit.hash.hashPrevouts.sha256)) { goto fail; } } } else { PRINTF("Resume SegWit hash\n"); - PRINTF("SEGWIT Version\n%.*H\n",sizeof(btchip_context_D.transactionVersion),btchip_context_D.transactionVersion); - PRINTF("SEGWIT HashedPrevouts\n%.*H\n",sizeof(btchip_context_D.segwit.cache.hashedPrevouts),btchip_context_D.segwit.cache.hashedPrevouts); - PRINTF("SEGWIT HashedSequence\n%.*H\n",sizeof(btchip_context_D.segwit.cache.hashedSequence),btchip_context_D.segwit.cache.hashedSequence); - if (btchip_context_D.usingOverwinter) { - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.transactionVersion, sizeof(btchip_context_D.transactionVersion), NULL, 0)) { + PRINTF("SEGWIT Version\n%.*H\n",sizeof(context_D.transactionVersion),context_D.transactionVersion); + PRINTF("SEGWIT HashedPrevouts\n%.*H\n",sizeof(context_D.segwit.cache.hashedPrevouts),context_D.segwit.cache.hashedPrevouts); + PRINTF("SEGWIT HashedSequence\n%.*H\n",sizeof(context_D.segwit.cache.hashedSequence),context_D.segwit.cache.hashedSequence); + if (context_D.usingOverwinter) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.transactionVersion, sizeof(context_D.transactionVersion), NULL, 0)) { goto fail; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.nVersionGroupId, sizeof(btchip_context_D.nVersionGroupId), NULL, 0)) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.nVersionGroupId, sizeof(context_D.nVersionGroupId), NULL, 0)) { goto fail; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.segwit.cache.hashedPrevouts, sizeof(btchip_context_D.segwit.cache.hashedPrevouts), NULL, 0)) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.segwit.cache.hashedPrevouts, sizeof(context_D.segwit.cache.hashedPrevouts), NULL, 0)) { goto fail; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.segwit.cache.hashedSequence, sizeof(btchip_context_D.segwit.cache.hashedSequence), NULL, 0)) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.segwit.cache.hashedSequence, sizeof(context_D.segwit.cache.hashedSequence), NULL, 0)) { goto fail; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.segwit.cache.hashedOutputs, sizeof(btchip_context_D.segwit.cache.hashedOutputs), NULL, 0)) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.segwit.cache.hashedOutputs, sizeof(context_D.segwit.cache.hashedOutputs), NULL, 0)) { goto fail; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { goto fail; } - if (btchip_context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { // sapling hashShieldedSpend) + if (context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { // sapling hashShieldedSpend) goto fail; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { // sapling hashShieldedOutputs + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { // sapling hashShieldedOutputs goto fail; } } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.nLockTime, sizeof(btchip_context_D.nLockTime), NULL, 0)) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.nLockTime, sizeof(context_D.nLockTime), NULL, 0)) { goto fail; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.nExpiryHeight, sizeof(btchip_context_D.nExpiryHeight), NULL, 0)) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.nExpiryHeight, sizeof(context_D.nExpiryHeight), NULL, 0)) { goto fail; } - if (btchip_context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { + if (context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { unsigned char valueBalance[8]; memset(valueBalance, 0, sizeof(valueBalance)); - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, valueBalance, sizeof(valueBalance), NULL, 0)) { // sapling valueBalance + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, valueBalance, sizeof(valueBalance), NULL, 0)) { // sapling valueBalance goto fail; } } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.sigHashType, sizeof(btchip_context_D.sigHashType), NULL, 0)) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.sigHashType, sizeof(context_D.sigHashType), NULL, 0)) { goto fail; } } else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(btchip_context_D.transactionVersion), btchip_context_D.transactionVersion); + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context_D.transactionVersion), context_D.transactionVersion); if (cx_hash_no_throw( - &btchip_context_D.transactionHashFull.sha256.header, 0, - btchip_context_D.transactionVersion, - sizeof(btchip_context_D.transactionVersion), + &context_D.transactionHashFull.sha256.header, 0, + context_D.transactionVersion, + sizeof(context_D.transactionVersion), NULL, 0)) { goto fail; } - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(btchip_context_D.segwit.cache.hashedPrevouts), btchip_context_D.segwit.cache.hashedPrevouts); + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context_D.segwit.cache.hashedPrevouts), context_D.segwit.cache.hashedPrevouts); if (cx_hash_no_throw( - &btchip_context_D.transactionHashFull.sha256.header, 0, - btchip_context_D.segwit.cache.hashedPrevouts, - sizeof(btchip_context_D.segwit.cache + &context_D.transactionHashFull.sha256.header, 0, + context_D.segwit.cache.hashedPrevouts, + sizeof(context_D.segwit.cache .hashedPrevouts), NULL, 0)) { goto fail; } - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(btchip_context_D.segwit.cache.hashedSequence), btchip_context_D.segwit.cache.hashedSequence); + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context_D.segwit.cache.hashedSequence), context_D.segwit.cache.hashedSequence); if (cx_hash_no_throw( - &btchip_context_D.transactionHashFull.sha256.header, 0, - btchip_context_D.segwit.cache.hashedSequence, - sizeof(btchip_context_D.segwit.cache + &context_D.transactionHashFull.sha256.header, 0, + context_D.segwit.cache.hashedSequence, + sizeof(context_D.segwit.cache .hashedSequence), NULL, 0)) { goto fail; } - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", sizeof(btchip_context_D.segwit.cache), (unsigned char *)&btchip_context_D.segwit.cache); - if (cx_hash_no_throw(&btchip_context_D + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", sizeof(context_D.segwit.cache), (unsigned char *)&context_D.segwit.cache); + if (cx_hash_no_throw(&context_D .transactionHashAuthorization.header, 0, - (unsigned char *)&btchip_context_D + (unsigned char *)&context_D .segwit.cache, - sizeof(btchip_context_D.segwit.cache), + sizeof(context_D.segwit.cache), NULL, 0)) { goto fail; } @@ -300,25 +300,25 @@ void transaction_parse(unsigned char parseMode) { // Parse the beginning of the transaction // Version check_transaction_available(4); - memmove(btchip_context_D.transactionVersion, - btchip_context_D.transactionBufferPointer, 4); + memmove(context_D.transactionVersion, + context_D.transactionBufferPointer, 4); transaction_offset_increase(4); - if (btchip_context_D.usingOverwinter || + if (context_D.usingOverwinter || TRUSTED_INPUT_OVERWINTER) { // nVersionGroupId check_transaction_available(4); - memmove(btchip_context_D.nVersionGroupId, - btchip_context_D.transactionBufferPointer, 4); + memmove(context_D.nVersionGroupId, + context_D.transactionBufferPointer, 4); transaction_offset_increase(4); } if (G_coin_config->flags & FLAG_PEERCOIN_SUPPORT) { if (((G_coin_config->family == - BTCHIP_FAMILY_PEERCOIN && - (btchip_context_D.transactionVersion[0] < 3))) || - ((G_coin_config->family == BTCHIP_FAMILY_STEALTH) && - (btchip_context_D.transactionVersion[0] < 2))) { + FAMILY_PEERCOIN && + (context_D.transactionVersion[0] < 3))) || + ((G_coin_config->family == FAMILY_STEALTH) && + (context_D.transactionVersion[0] < 2))) { // Timestamp check_transaction_available(4); transaction_offset_increase(4); @@ -326,40 +326,40 @@ void transaction_parse(unsigned char parseMode) { } // Number of inputs - btchip_context_D.transactionContext + context_D.transactionContext .transactionRemainingInputsOutputs = transaction_get_varint(); - PRINTF("Number of inputs : " DEBUG_LONG "\n",btchip_context_D.transactionContext.transactionRemainingInputsOutputs); - if (btchip_context_D.called_from_swap && parseMode == PARSE_MODE_SIGNATURE) { + PRINTF("Number of inputs : " DEBUG_LONG "\n",context_D.transactionContext.transactionRemainingInputsOutputs); + if (context_D.called_from_swap && parseMode == PARSE_MODE_SIGNATURE) { // remember number of inputs to know when to exit from library // we will count number of already signed inputs and compare with this value // As there are a lot of different states in which we can have different number of input // (when for ex. we sign segregated witness) if (vars.swap_data.totalNumberOfInputs == 0) { vars.swap_data.totalNumberOfInputs = - btchip_context_D.transactionContext.transactionRemainingInputsOutputs; + context_D.transactionContext.transactionRemainingInputsOutputs; } // Reseting the flag, because we should check address ones for each input vars.swap_data.was_address_checked = 0; } // Ready to proceed - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; + context_D.transactionContext.transactionState = + TRANSACTION_DEFINED_WAIT_INPUT; __attribute__((fallthrough)); } - case BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT: { + case TRANSACTION_DEFINED_WAIT_INPUT: { unsigned char trustedInputFlag = 1; PRINTF("Process input\n"); - if (btchip_context_D.transactionContext + if (context_D.transactionContext .transactionRemainingInputsOutputs == 0) { // No more inputs to hash, move forward - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_INPUT_HASHING_DONE; + context_D.transactionContext.transactionState = + TRANSACTION_INPUT_HASHING_DONE; continue; } - if (btchip_context_D.transactionDataRemaining < 1) { + if (context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } @@ -377,23 +377,23 @@ void transaction_parse(unsigned char parseMode) { // Expect the trusted input flag and trusted input length check_transaction_available(2); - switch (*btchip_context_D.transactionBufferPointer) { + switch (*context_D.transactionBufferPointer) { case 0: - if (btchip_context_D.usingSegwit) { + if (context_D.usingSegwit) { PRINTF("Non trusted input used in segwit mode\n"); goto fail; } trustedInputFlag = 0; break; case 1: - if (btchip_context_D.usingSegwit) { + if (context_D.usingSegwit) { // Segwit inputs can be passed as TrustedInput also PRINTF("Trusted input used in segwit mode\n"); } trustedInputFlag = 1; break; case 2: - if (!btchip_context_D.usingSegwit) { + if (!context_D.usingSegwit) { PRINTF("Segwit input not used in segwit mode\n"); goto fail; } @@ -405,7 +405,7 @@ void transaction_parse(unsigned char parseMode) { } /* trustedInputLength = - *(btchip_context_D.transactionBufferPointer + 1); + *(context_D.transactionBufferPointer + 1); if (trustedInputLength > sizeof(trustedInput)) { PRINTF("Trusted input too long\n"); goto fail; @@ -414,7 +414,7 @@ void transaction_parse(unsigned char parseMode) { // Check TrustedInput (TI) integrity, be it a non-segwit TI or a segwit TI if (trustedInputFlag) { trustedInputLength = *( - btchip_context_D.transactionBufferPointer + 1); + context_D.transactionBufferPointer + 1); if ((trustedInputLength > sizeof(trustedInput)) || (trustedInputLength < 8)) { PRINTF("Invalid trusted input size\n"); @@ -426,14 +426,14 @@ void transaction_parse(unsigned char parseMode) { cx_hmac_sha256( (uint8_t *)N_btchip.bkp.trustedinput_key, sizeof(N_btchip.bkp.trustedinput_key), - btchip_context_D.transactionBufferPointer + 2, + context_D.transactionBufferPointer + 2, trustedInputLength - 8, trustedInput, trustedInputLength); - PRINTF("====> Input HMAC: %.*H\n", 8, btchip_context_D.transactionBufferPointer + 2 + trustedInputLength - 8); + PRINTF("====> Input HMAC: %.*H\n", 8, context_D.transactionBufferPointer + 2 + trustedInputLength - 8); PRINTF("====> Computed HMAC: %.*H\n", 8, trustedInput); - if (btchip_secure_memcmp( + if (secure_memcmp( trustedInput, // Contains computed Hmac for now - btchip_context_D.transactionBufferPointer + + context_D.transactionBufferPointer + 2 + trustedInputLength - 8, 8) != 0) { PRINTF("Invalid signature\n"); @@ -442,68 +442,68 @@ void transaction_parse(unsigned char parseMode) { // Hmac is valid. If TrustedInput contains a segwit input, update data pointer & length // to fake the parser into believing a normal segwit input was received. Do not use // transaction_offset_increase() here as it could update the hash being computed. - if (btchip_context_D.usingSegwit) { + if (context_D.usingSegwit) { // Overwrite the no longer needed HMAC's 1st byte w/ the input script length byte. - *(btchip_context_D.transactionBufferPointer + 1 + TRUSTED_INPUT_SIZE + 1) = - *(btchip_context_D.transactionBufferPointer + 1 + TRUSTED_INPUT_TOTAL_SIZE + 1); + *(context_D.transactionBufferPointer + 1 + TRUSTED_INPUT_SIZE + 1) = + *(context_D.transactionBufferPointer + 1 + TRUSTED_INPUT_TOTAL_SIZE + 1); // Set tx data pointer on TI header's (i.e. 0x38||0x32||0x00||Nonce (2B)) last byte // before prevout tx hash. Also remove HMAC size from remaining data length. - btchip_context_D.transactionBufferPointer += 5; - btchip_context_D.transactionDataRemaining -= (5+8); + context_D.transactionBufferPointer += 5; + context_D.transactionDataRemaining -= (5+8); } } // Handle pure segwit inputs, whether trusted or not (i.e. InputHashStart 1st APDU's P2==02 // & data[0]=={0x01, 0x02}) - if (btchip_context_D.usingSegwit) { + if (context_D.usingSegwit) { transaction_offset_increase(1); // Set tx pointer on 1st byte of hash check_transaction_available( 36); // prevout : 32 hash + 4 index - if (!btchip_context_D.segwitParsedOnce) { - if (btchip_context_D.usingOverwinter) { - if (cx_hash_no_throw(&btchip_context_D.segwit.hash.hashPrevouts.blake2b.header, 0, btchip_context_D.transactionBufferPointer, 36, NULL, 0)) { + if (!context_D.segwitParsedOnce) { + if (context_D.usingOverwinter) { + if (cx_hash_no_throw(&context_D.segwit.hash.hashPrevouts.blake2b.header, 0, context_D.transactionBufferPointer, 36, NULL, 0)) { goto fail; } } else { if (cx_hash_no_throw( - &btchip_context_D.segwit.hash.hashPrevouts + &context_D.segwit.hash.hashPrevouts .sha256.header, 0, - btchip_context_D.transactionBufferPointer, + context_D.transactionBufferPointer, 36, NULL, 0)) { goto fail; } } transaction_offset_increase(36); check_transaction_available(8); // update amount - btchip_swap_bytes( + swap_bytes( amount, - btchip_context_D.transactionBufferPointer, + context_D.transactionBufferPointer, 8); if (transaction_amount_add_be( - btchip_context_D.transactionContext + context_D.transactionContext .transactionAmount, - btchip_context_D.transactionContext + context_D.transactionContext .transactionAmount, amount)) { PRINTF("Overflow\n"); goto fail; } - PRINTF("Adding amount\n%.*H\n",8,btchip_context_D.transactionBufferPointer); - PRINTF("New amount\n%.*H\n",8,btchip_context_D.transactionContext.transactionAmount); + PRINTF("Adding amount\n%.*H\n",8,context_D.transactionBufferPointer); + PRINTF("New amount\n%.*H\n",8,context_D.transactionContext.transactionAmount); transaction_offset_increase(8); } else { - btchip_context_D.transactionHashOption = + context_D.transactionHashOption = TRANSACTION_HASH_FULL; transaction_offset_increase(36); - btchip_context_D.transactionHashOption = 0; + context_D.transactionHashOption = 0; check_transaction_available(8); // save amount memmove( - btchip_context_D.inputValue, - btchip_context_D.transactionBufferPointer, + context_D.inputValue, + context_D.transactionBufferPointer, 8); transaction_offset_increase(8); - btchip_context_D.transactionHashOption = + context_D.transactionHashOption = TRANSACTION_HASH_FULL; } } @@ -513,36 +513,36 @@ void transaction_parse(unsigned char parseMode) { // modes SB_CHECK(N_btchip.bkp.config.operationMode); switch (SB_GET(N_btchip.bkp.config.operationMode)) { - case BTCHIP_MODE_WALLET: + case MODE_WALLET: if (!optionP2SHSkip2FA) { PRINTF("Untrusted input not authorized\n"); goto fail; } break; - case BTCHIP_MODE_RELAXED_WALLET: - case BTCHIP_MODE_SERVER: + case MODE_RELAXED_WALLET: + case MODE_SERVER: break; default: PRINTF("Untrusted input not authorized\n"); goto fail; } - btchip_context_D.transactionBufferPointer++; - btchip_context_D.transactionDataRemaining--; + context_D.transactionBufferPointer++; + context_D.transactionDataRemaining--; check_transaction_available( 36); // prevout : 32 hash + 4 index transaction_offset_increase(36); PRINTF("Marking relaxed input\n"); - btchip_context_D.transactionContext.relaxed = 1; + context_D.transactionContext.relaxed = 1; /* PRINTF("Clearing P2SH consumption\n"); - btchip_context_D.transactionContext.consumeP2SH = 0; + context_D.transactionContext.consumeP2SH = 0; */ } // Handle non-segwit TrustedInput (i.e. InputHashStart 1st APDU's P2==00 & data[0]==0x01) - else if (trustedInputFlag && !btchip_context_D.usingSegwit) { + else if (trustedInputFlag && !context_D.usingSegwit) { memmove( trustedInput, - btchip_context_D.transactionBufferPointer + 2, + context_D.transactionBufferPointer + 2, trustedInputLength - 8); if (trustedInput[0] != MAGIC_TRUSTED_INPUT) { PRINTF("Failed to verify trusted input signature\n"); @@ -550,33 +550,33 @@ void transaction_parse(unsigned char parseMode) { } // Update the hash with prevout data savePointer = - btchip_context_D.transactionBufferPointer; + context_D.transactionBufferPointer; /* // Check if a P2SH script is used if ((trustedInput[1] & FLAG_TRUSTED_INPUT_P2SH) == 0) { PRINTF("Clearing P2SH consumption\n"); - btchip_context_D.transactionContext.consumeP2SH = + context_D.transactionContext.consumeP2SH = 0; } */ - btchip_context_D.transactionBufferPointer = + context_D.transactionBufferPointer = trustedInput + 4; - PRINTF("Trusted input hash\n%.*H\n",36,btchip_context_D.transactionBufferPointer); + PRINTF("Trusted input hash\n%.*H\n",36,context_D.transactionBufferPointer); transaction_offset(36); - btchip_context_D.transactionBufferPointer = + context_D.transactionBufferPointer = savePointer + (2 + trustedInputLength); - btchip_context_D.transactionDataRemaining -= + context_D.transactionDataRemaining -= (2 + trustedInputLength); // Update the amount - btchip_swap_bytes(amount, trustedInput + 40, 8); + swap_bytes(amount, trustedInput + 40, 8); if (transaction_amount_add_be( - btchip_context_D.transactionContext + context_D.transactionContext .transactionAmount, - btchip_context_D.transactionContext + context_D.transactionContext .transactionAmount, amount)) { PRINTF("Overflow\n"); @@ -584,26 +584,26 @@ void transaction_parse(unsigned char parseMode) { } PRINTF("Adding amount\n%.*H\n",8,(trustedInput + 40)); - PRINTF("New amount\n%.*H\n",8,btchip_context_D.transactionContext.transactionAmount); + PRINTF("New amount\n%.*H\n",8,context_D.transactionContext.transactionAmount); } - if (!btchip_context_D.usingSegwit) { + if (!context_D.usingSegwit) { // Do not include the input script length + value in // the authentication hash - btchip_context_D.transactionHashOption = + context_D.transactionHashOption = TRANSACTION_HASH_FULL; } } // Read the script length - btchip_context_D.transactionContext.scriptRemaining = + context_D.transactionContext.scriptRemaining = transaction_get_varint(); - PRINTF("Script to read " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); + PRINTF("Script to read " DEBUG_LONG "\n",context_D.transactionContext.scriptRemaining); if ((parseMode == PARSE_MODE_SIGNATURE) && - !trustedInputFlag && !btchip_context_D.usingSegwit) { + !trustedInputFlag && !context_D.usingSegwit) { // Only proceeds if this is not to be signed - so length // should be null - if (btchip_context_D.transactionContext + if (context_D.transactionContext .scriptRemaining != 0) { PRINTF("Request to sign relaxed input\n"); if (!optionP2SHSkip2FA) { @@ -612,62 +612,62 @@ void transaction_parse(unsigned char parseMode) { } } // Move on - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; + context_D.transactionContext.transactionState = + TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; __attribute__((fallthrough)); } - case BTCHIP_TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { + case TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { unsigned char dataAvailable; - PRINTF("Process input script, remaining " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); - if (btchip_context_D.transactionDataRemaining < 1) { + PRINTF("Process input script, remaining " DEBUG_LONG "\n",context_D.transactionContext.scriptRemaining); + if (context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } // Scan for P2SH consumption - huge shortcut, but fine // enough // Also usable in SegWit mode - if (btchip_context_D.transactionContext.scriptRemaining == + if (context_D.transactionContext.scriptRemaining == 1) { - if (*btchip_context_D.transactionBufferPointer == + if (*context_D.transactionBufferPointer == OP_CHECKMULTISIG) { if (optionP2SHSkip2FA) { PRINTF("Marking P2SH consumption\n"); - btchip_context_D.transactionContext + context_D.transactionContext .consumeP2SH = 1; } } else { // When using the P2SH shortcut, all inputs must use // P2SH PRINTF("Disabling P2SH consumption\n"); - btchip_context_D.transactionContext.consumeP2SH = 0; + context_D.transactionContext.consumeP2SH = 0; } transaction_offset_increase(1); - btchip_context_D.transactionContext.scriptRemaining--; + context_D.transactionContext.scriptRemaining--; } - if (btchip_context_D.transactionContext.scriptRemaining == + if (context_D.transactionContext.scriptRemaining == 0) { if (parseMode == PARSE_MODE_SIGNATURE) { - if (!btchip_context_D.usingSegwit) { + if (!context_D.usingSegwit) { // Restore dual hash for signature + // authentication - btchip_context_D.transactionHashOption = + context_D.transactionHashOption = TRANSACTION_HASH_BOTH; } else { - if (btchip_context_D.segwitParsedOnce) { + if (context_D.segwitParsedOnce) { // Append the saved value - PRINTF("SEGWIT Add value\n%.*H\n",8,btchip_context_D.inputValue); - if (btchip_context_D.usingOverwinter) { - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.inputValue, 8, NULL, 0)) { + PRINTF("SEGWIT Add value\n%.*H\n",8,context_D.inputValue); + if (context_D.usingOverwinter) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.inputValue, 8, NULL, 0)) { goto fail; } } else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(btchip_context_D.inputValue), btchip_context_D.inputValue); - if (cx_hash_no_throw(&btchip_context_D + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context_D.inputValue), context_D.inputValue); + if (cx_hash_no_throw(&context_D .transactionHashFull.sha256.header, - 0, btchip_context_D.inputValue, 8, + 0, context_D.inputValue, 8, NULL, 0)) { goto fail; } @@ -677,19 +677,19 @@ void transaction_parse(unsigned char parseMode) { } // Sequence check_transaction_available(4); - if (btchip_context_D.usingSegwit && - !btchip_context_D.segwitParsedOnce) { - if (btchip_context_D.usingOverwinter) { - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, 0, btchip_context_D.transactionBufferPointer, 4, NULL, 0)) { + if (context_D.usingSegwit && + !context_D.segwitParsedOnce) { + if (context_D.usingOverwinter) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.transactionBufferPointer, 4, NULL, 0)) { goto fail; } } else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", 4, btchip_context_D.transactionBufferPointer); - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", 4, context_D.transactionBufferPointer); + if (cx_hash_no_throw(&context_D.transactionHashFull .sha256.header, 0, - btchip_context_D.transactionBufferPointer, + context_D.transactionBufferPointer, 4, NULL, 0)) { goto fail; } @@ -697,76 +697,76 @@ void transaction_parse(unsigned char parseMode) { } transaction_offset_increase(4); // Move to next input - btchip_context_D.transactionContext + context_D.transactionContext .transactionRemainingInputsOutputs--; - btchip_context_D.transactionContext + context_D.transactionContext .transactionCurrentInputOutput++; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_INPUT; + context_D.transactionContext.transactionState = + TRANSACTION_DEFINED_WAIT_INPUT; continue; } // Save the last script byte for the P2SH check dataAvailable = - (btchip_context_D.transactionDataRemaining > - btchip_context_D.transactionContext + (context_D.transactionDataRemaining > + context_D.transactionContext .scriptRemaining - 1 - ? btchip_context_D.transactionContext + ? context_D.transactionContext .scriptRemaining - 1 - : btchip_context_D.transactionDataRemaining); + : context_D.transactionDataRemaining); if (dataAvailable == 0) { goto ok; } transaction_offset_increase(dataAvailable); - btchip_context_D.transactionContext.scriptRemaining -= + context_D.transactionContext.scriptRemaining -= dataAvailable; break; } - case BTCHIP_TRANSACTION_INPUT_HASHING_DONE: { + case TRANSACTION_INPUT_HASHING_DONE: { PRINTF("Input hashing done\n"); if (parseMode == PARSE_MODE_SIGNATURE) { // inputs have been prepared, stop the parsing here - if (btchip_context_D.usingSegwit && - !btchip_context_D.segwitParsedOnce) { + if (context_D.usingSegwit && + !context_D.segwitParsedOnce) { unsigned char hashedPrevouts[32]; unsigned char hashedSequence[32]; // Flush the cache - if (btchip_context_D.usingOverwinter) { - if (cx_hash_no_throw(&btchip_context_D.segwit.hash.hashPrevouts.blake2b.header, CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32)) { + if (context_D.usingOverwinter) { + if (cx_hash_no_throw(&context_D.segwit.hash.hashPrevouts.blake2b.header, CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32)) { goto fail; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull.blake2b.header, CX_LAST, hashedSequence, 0, hashedSequence, 32)) { + if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, CX_LAST, hashedSequence, 0, hashedSequence, 32)) { goto fail; } } else { - if (cx_hash_no_throw(&btchip_context_D.segwit.hash.hashPrevouts + if (cx_hash_no_throw(&context_D.segwit.hash.hashPrevouts .sha256.header, CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32)) { goto fail; } if (cx_sha256_init_no_throw( - &btchip_context_D.segwit.hash.hashPrevouts.sha256)) { + &context_D.segwit.hash.hashPrevouts.sha256)) { goto fail; } - if (cx_hash_no_throw(&btchip_context_D.segwit.hash.hashPrevouts + if (cx_hash_no_throw(&context_D.segwit.hash.hashPrevouts .sha256.header, CX_LAST, hashedPrevouts, sizeof(hashedPrevouts), hashedPrevouts, 32)) { goto fail; } - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull + if (cx_hash_no_throw(&context_D.transactionHashFull .sha256.header, CX_LAST, hashedSequence, 0, hashedSequence, 32)) { goto fail; } if (cx_sha256_init_no_throw( - &btchip_context_D.transactionHashFull.sha256)) { + &context_D.transactionHashFull.sha256)) { goto fail; } PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(hashedSequence), hashedSequence); - if (cx_hash_no_throw(&btchip_context_D.transactionHashFull + if (cx_hash_no_throw(&context_D.transactionHashFull .sha256.header, CX_LAST, hashedSequence, sizeof(hashedSequence), hashedSequence, 32)) { @@ -775,153 +775,153 @@ void transaction_parse(unsigned char parseMode) { } memmove( - btchip_context_D.segwit.cache.hashedPrevouts, + context_D.segwit.cache.hashedPrevouts, hashedPrevouts, sizeof(hashedPrevouts)); memmove( - btchip_context_D.segwit.cache.hashedSequence, + context_D.segwit.cache.hashedSequence, hashedSequence, sizeof(hashedSequence)); - PRINTF("hashPrevout\n%.*H\n",32,btchip_context_D.segwit.cache.hashedPrevouts); - PRINTF("hashSequence\n%.*H\n",32,btchip_context_D.segwit.cache.hashedSequence); + PRINTF("hashPrevout\n%.*H\n",32,context_D.segwit.cache.hashedPrevouts); + PRINTF("hashSequence\n%.*H\n",32,context_D.segwit.cache.hashedSequence); } - if (btchip_context_D.usingSegwit && - btchip_context_D.segwitParsedOnce) { - if (!btchip_context_D.usingOverwinter) { - PRINTF("SEGWIT hashedOutputs\n%.*H\n",sizeof(btchip_context_D.segwit.cache.hashedOutputs),btchip_context_D.segwit.cache.hashedOutputs); + if (context_D.usingSegwit && + context_D.segwitParsedOnce) { + if (!context_D.usingOverwinter) { + PRINTF("SEGWIT hashedOutputs\n%.*H\n",sizeof(context_D.segwit.cache.hashedOutputs),context_D.segwit.cache.hashedOutputs); if (cx_hash_no_throw( - &btchip_context_D.transactionHashFull.sha256.header, 0, - btchip_context_D.segwit.cache.hashedOutputs, - sizeof(btchip_context_D.segwit.cache + &context_D.transactionHashFull.sha256.header, 0, + context_D.segwit.cache.hashedOutputs, + sizeof(context_D.segwit.cache .hashedOutputs), NULL, 0)) { goto fail; } } - btchip_context_D.transactionContext + context_D.transactionContext .transactionState = - BTCHIP_TRANSACTION_SIGN_READY; + TRANSACTION_SIGN_READY; } else { - btchip_context_D.transactionContext + context_D.transactionContext .transactionState = - BTCHIP_TRANSACTION_PRESIGN_READY; - if (btchip_context_D.usingOverwinter) { - if (cx_blake2b_init2_no_throw(&btchip_context_D.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_OUTPUTS, 16)) { + TRANSACTION_PRESIGN_READY; + if (context_D.usingOverwinter) { + if (cx_blake2b_init2_no_throw(&context_D.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_OUTPUTS, 16)) { goto fail; } } else - if (btchip_context_D.usingSegwit) { - if (cx_sha256_init_no_throw(&btchip_context_D.transactionHashFull.sha256)) { + if (context_D.usingSegwit) { + if (cx_sha256_init_no_throw(&context_D.transactionHashFull.sha256)) { goto fail; } } } continue; } - if (btchip_context_D.transactionDataRemaining < 1) { + if (context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } // Number of outputs - btchip_context_D.transactionContext + context_D.transactionContext .transactionRemainingInputsOutputs = transaction_get_varint(); - btchip_context_D.transactionContext + context_D.transactionContext .transactionCurrentInputOutput = 0; PRINTF("Number of outputs : " DEBUG_LONG "\n", - btchip_context_D.transactionContext.transactionRemainingInputsOutputs); + context_D.transactionContext.transactionRemainingInputsOutputs); // Ready to proceed - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; + context_D.transactionContext.transactionState = + TRANSACTION_DEFINED_WAIT_OUTPUT; __attribute__((fallthrough)); } - case BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT: { - if (btchip_context_D.transactionContext + case TRANSACTION_DEFINED_WAIT_OUTPUT: { + if (context_D.transactionContext .transactionRemainingInputsOutputs == 0) { // No more outputs to hash, move forward - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE; + context_D.transactionContext.transactionState = + TRANSACTION_OUTPUT_HASHING_DONE; continue; } - if (btchip_context_D.transactionDataRemaining < 1) { + if (context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } // Amount check_transaction_available(8); if ((parseMode == PARSE_MODE_TRUSTED_INPUT) && - (btchip_context_D.transactionContext + (context_D.transactionContext .transactionCurrentInputOutput == - btchip_context_D.transactionTargetInput)) { + context_D.transactionTargetInput)) { // Save the amount - memmove(btchip_context_D.transactionContext + memmove(context_D.transactionContext .transactionAmount, - btchip_context_D.transactionBufferPointer, + context_D.transactionBufferPointer, 8); - btchip_context_D.trustedInputProcessed = 1; + context_D.trustedInputProcessed = 1; } transaction_offset_increase(8); // Read the script length - btchip_context_D.transactionContext.scriptRemaining = + context_D.transactionContext.scriptRemaining = transaction_get_varint(); - PRINTF("Script to read " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); + PRINTF("Script to read " DEBUG_LONG "\n",context_D.transactionContext.scriptRemaining); // Move on - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; + context_D.transactionContext.transactionState = + TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; __attribute__((fallthrough)); } - case BTCHIP_TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { + case TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { unsigned char dataAvailable; - PRINTF("Process output script, remaining " DEBUG_LONG "\n",btchip_context_D.transactionContext.scriptRemaining); + PRINTF("Process output script, remaining " DEBUG_LONG "\n",context_D.transactionContext.scriptRemaining); /* // Special check if consuming a P2SH script if (parseMode == PARSE_MODE_TRUSTED_INPUT) { // Assume the full input script is sent in a single APDU, then do the ghetto validation - if ((btchip_context_D.transactionBufferPointer[0] == + if ((context_D.transactionBufferPointer[0] == OP_HASH160) && - (btchip_context_D.transactionBufferPointer[btchip_context_D.transactionDataRemaining + (context_D.transactionBufferPointer[context_D.transactionDataRemaining - 1] == OP_EQUAL)) { PRINTF("Marking P2SH output\n"); - btchip_context_D.transactionContext.consumeP2SH = 1; + context_D.transactionContext.consumeP2SH = 1; } } */ - if (btchip_context_D.transactionDataRemaining < 1) { + if (context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } - if (btchip_context_D.transactionContext.scriptRemaining == + if (context_D.transactionContext.scriptRemaining == 0) { // Move to next output - btchip_context_D.transactionContext + context_D.transactionContext .transactionRemainingInputsOutputs--; - btchip_context_D.transactionContext + context_D.transactionContext .transactionCurrentInputOutput++; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_DEFINED_WAIT_OUTPUT; + context_D.transactionContext.transactionState = + TRANSACTION_DEFINED_WAIT_OUTPUT; continue; } dataAvailable = - (btchip_context_D.transactionDataRemaining > - btchip_context_D.transactionContext + (context_D.transactionDataRemaining > + context_D.transactionContext .scriptRemaining - ? btchip_context_D.transactionContext + ? context_D.transactionContext .scriptRemaining - : btchip_context_D.transactionDataRemaining); + : context_D.transactionDataRemaining); if (dataAvailable == 0) { goto ok; } transaction_offset_increase(dataAvailable); - btchip_context_D.transactionContext.scriptRemaining -= + context_D.transactionContext.scriptRemaining -= dataAvailable; break; } - case BTCHIP_TRANSACTION_OUTPUT_HASHING_DONE: { + case TRANSACTION_OUTPUT_HASHING_DONE: { PRINTF("Output hashing done\n"); - if (btchip_context_D.transactionDataRemaining < 1) { + if (context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } @@ -929,64 +929,64 @@ void transaction_parse(unsigned char parseMode) { check_transaction_available(4); transaction_offset_increase(4); - if (btchip_context_D.transactionDataRemaining == 0) { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_PARSED; + if (context_D.transactionDataRemaining == 0) { + context_D.transactionContext.transactionState = + TRANSACTION_PARSED; continue; } else { - btchip_context_D.transactionHashOption = 0; - btchip_context_D.transactionContext.scriptRemaining = + context_D.transactionHashOption = 0; + context_D.transactionContext.scriptRemaining = transaction_get_varint(); - btchip_context_D.transactionHashOption = + context_D.transactionHashOption = TRANSACTION_HASH_FULL; - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_PROCESS_EXTRA; + context_D.transactionContext.transactionState = + TRANSACTION_PROCESS_EXTRA; continue; } } - case BTCHIP_TRANSACTION_PROCESS_EXTRA: { + case TRANSACTION_PROCESS_EXTRA: { unsigned char dataAvailable; - if (btchip_context_D.transactionContext.scriptRemaining == + if (context_D.transactionContext.scriptRemaining == 0) { - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_PARSED; + context_D.transactionContext.transactionState = + TRANSACTION_PARSED; continue; } - if (btchip_context_D.transactionDataRemaining < 1) { + if (context_D.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } dataAvailable = - (btchip_context_D.transactionDataRemaining > - btchip_context_D.transactionContext + (context_D.transactionDataRemaining > + context_D.transactionContext .scriptRemaining - ? btchip_context_D.transactionContext + ? context_D.transactionContext .scriptRemaining - : btchip_context_D.transactionDataRemaining); + : context_D.transactionDataRemaining); if (dataAvailable == 0) { goto ok; } transaction_offset_increase(dataAvailable); - btchip_context_D.transactionContext.scriptRemaining -= + context_D.transactionContext.scriptRemaining -= dataAvailable; break; } - case BTCHIP_TRANSACTION_PARSED: { + case TRANSACTION_PARSED: { PRINTF("Transaction parsed\n"); goto ok; } - case BTCHIP_TRANSACTION_PRESIGN_READY: { + case TRANSACTION_PRESIGN_READY: { PRINTF("Presign ready\n"); goto ok; } - case BTCHIP_TRANSACTION_SIGN_READY: { + case TRANSACTION_SIGN_READY: { PRINTF("Sign ready\n"); goto ok; } @@ -1000,15 +1000,15 @@ void transaction_parse(unsigned char parseMode) { } CATCH_OTHER(e) { PRINTF("Transaction parse - surprise fail\n"); - btchip_context_D.transactionContext.transactionState = - BTCHIP_TRANSACTION_NONE; - btchip_set_check_internal_structure_integrity(1); + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + set_check_internal_structure_integrity(1); THROW(e); } // before the finally to restore the surrounding context if an exception // is raised during finally FINALLY { - btchip_set_check_internal_structure_integrity(1); + set_check_internal_structure_integrity(1); } } END_TRY; diff --git a/src/btchip_transaction.h b/src/transaction.h similarity index 92% rename from src/btchip_transaction.h rename to src/transaction.h index bb340140..01b50048 100644 --- a/src/btchip_transaction.h +++ b/src/transaction.h @@ -15,10 +15,10 @@ * limitations under the License. ********************************************************************************/ -#ifndef _BTCHIP_TRANSACTION_H_ -#define _BTCHIP_TRANSACTION_H_ +#ifndef _TRANSACTION_H_ +#define _TRANSACTION_H_ -#include "btchip_secure_value.h" +#include "secure_value.h" #define TRANSACTION_HASH_NONE 0x00 #define TRANSACTION_HASH_FULL 0x01 @@ -43,4 +43,4 @@ unsigned char transaction_amount_sub_be(unsigned char *target, unsigned char *a, unsigned char *b); -#endif /* _BTCHIP_TRANSACTION_H_ */ +#endif /* _TRANSACTION_H_ */ diff --git a/src/ui_bagl.c b/src/ui_bagl.c index c5cf3fa4..6df29a7f 100644 --- a/src/ui_bagl.c +++ b/src/ui_bagl.c @@ -17,11 +17,11 @@ #ifdef HAVE_BAGL ////////////////////////////////////////////////////////////////////// -#include "btchip_display_variables.h" -#include "btchip_internal.h" +#include "display_variables.h" +#include "internal.h" #include "ui.h" -#include "btchip_bagl_extensions.h" +#include "bagl_extensions.h" bagl_element_t tmp_element; @@ -33,7 +33,7 @@ void settings_pubkey_export_change(unsigned int enabled) { static unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { UNUSED(e); // user denied the transaction, tell the USB side - if (!btchip_bagl_user_action(0)) { + if (!bagl_user_action(0)) { // redraw ui ui_idle_flow(); } @@ -43,7 +43,7 @@ static unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { static unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e) { UNUSED(e); // user accepted the transaction, tell the USB side - if (!btchip_bagl_user_action(1)) { + if (!bagl_user_action(1)) { // redraw ui ui_idle_flow(); } @@ -54,7 +54,7 @@ static unsigned int io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e) { UNUSED(e); // user denied the transaction, tell the USB side - btchip_bagl_user_action_message_signing(0); + bagl_user_action_message_signing(0); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -64,7 +64,7 @@ static unsigned int io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { UNUSED(e); // user accepted the transaction, tell the USB side - btchip_bagl_user_action_message_signing(1); + bagl_user_action_message_signing(1); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -74,7 +74,7 @@ static unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { UNUSED(e); // user denied the transaction, tell the USB side - btchip_bagl_user_action_display(0); + bagl_user_action_display(0); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -83,7 +83,7 @@ io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { static unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { UNUSED(e); // user accepted the transaction, tell the USB side - btchip_bagl_user_action_display(1); + bagl_user_action_display(1); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -92,7 +92,7 @@ static unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { static unsigned int io_seproxyhal_touch_sign_cancel(const bagl_element_t *e) { UNUSED(e); // user denied the transaction, tell the USB side - btchip_bagl_user_action_signtx(0, 0); + bagl_user_action_signtx(0, 0); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -101,7 +101,7 @@ static unsigned int io_seproxyhal_touch_sign_cancel(const bagl_element_t *e) { static unsigned int io_seproxyhal_touch_sign_ok(const bagl_element_t *e) { UNUSED(e); // user accepted the transaction, tell the USB side - btchip_bagl_user_action_signtx(1, 0); + bagl_user_action_signtx(1, 0); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -453,7 +453,7 @@ void ui_sign_message_flow(void) { ux_flow_init(0, ux_sign_flow, NULL); } void ui_confirm_single_flow(void) { snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "output #%d", - btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + + context_D.totalOutputs - context_D.remainingOutputs + 1); ux_flow_init(0, ux_confirm_single_flow, NULL); } diff --git a/src/ui_menu_nbgl.c b/src/ui_menu_nbgl.c index 35cca5c0..45a87b12 100644 --- a/src/ui_menu_nbgl.c +++ b/src/ui_menu_nbgl.c @@ -16,11 +16,11 @@ ********************************************************************************/ #ifdef HAVE_NBGL -#include "btchip_display_variables.h" -#include "btchip_internal.h" +#include "display_variables.h" +#include "internal.h" #include "ui.h" -#include "btchip_bagl_extensions.h" +#include "bagl_extensions.h" #include "nbgl_use_case.h" #define NB_INFO_FIELDS 2 diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index 58c7ed26..bc786326 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -18,10 +18,10 @@ #ifdef HAVE_NBGL #include "ui.h" #include "nbgl_use_case.h" -#include "btchip_display_variables.h" -#include "btchip_internal.h" +#include "display_variables.h" +#include "internal.h" -#include "btchip_bagl_extensions.h" +#include "bagl_extensions.h" typedef enum { MESSAGE_TYPE, @@ -55,55 +55,55 @@ static UiContext_t uiContext = {.transaction_prompt_done = 0}; // User action callbacks static void approved_user_action_callback(void) { - if (!btchip_bagl_user_action(1)) { + if (!bagl_user_action(1)) { ui_idle_flow(); } } static void approved_user_action_processing_callback(void) { - if (!btchip_bagl_user_action(1)) { + if (!bagl_user_action(1)) { nbgl_useCaseSpinner("Processing"); } } static void abandon_user_action_callback(void) { - if (!btchip_bagl_user_action(0)) { + if (!bagl_user_action(0)) { ui_idle_flow(); } } static void approved_user_action_message_signing_callback(void) { - btchip_bagl_user_action_message_signing(1); + bagl_user_action_message_signing(1); ui_idle_flow(); } static void abandon_user_action_message_signing_callback(void) { - btchip_bagl_user_action_message_signing(0); + bagl_user_action_message_signing(0); ui_idle_flow(); } static void approved_user_action_display_processing_callback(void) { - btchip_bagl_user_action_display(1); + bagl_user_action_display(1); nbgl_useCaseSpinner("Processing"); } static void approved_user_action_display_callback(void) { - btchip_bagl_user_action_display(1); + bagl_user_action_display(1); ui_idle_flow(); } static void abandon_user_action_display_callback(void) { - btchip_bagl_user_action_display(0); + bagl_user_action_display(0); ui_idle_flow(); } static void approved_user_action_signtx_callback(void) { - btchip_bagl_user_action_signtx(1, 0); + bagl_user_action_signtx(1, 0); ui_idle_flow(); } static void abandon_user_action_signtx_callback(void) { - btchip_bagl_user_action_signtx(0, 0); + bagl_user_action_signtx(0, 0); ui_idle_flow(); } @@ -310,7 +310,7 @@ void ui_confirm_single_flow(void) { ui_transaction_start(ui_confirm_single_flow); } else { snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "#%d", - btchip_context_D.totalOutputs - btchip_context_D.remainingOutputs + + context_D.totalOutputs - context_D.remainingOutputs + 1); uiContext.tagValues[0].item = "Output"; From 2c61ac016167e39ada8225009644358935f1cdb0 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Wed, 27 Mar 2024 11:38:21 +0100 Subject: [PATCH 72/85] Cleaning and standardizing Remove deprecated handlers, only supported mode is wallet U2F is no longer supported set_check_internal_structure_integrity: remove empty function dead code and use functions from SDk standardize, and replace coin_config structure with defines swap: use global variable from standard swap and move to dedicated folder --- Makefile | 252 ++----- TODO.md | 7 - include/apdu_constants.h | 9 - include/base58.h | 30 - include/context.h | 30 - include/helpers.h | 28 - src/apdu_get_coin_version.c | 33 +- src/apdu_get_firmware_version.c | 7 +- src/apdu_get_operation_mode.c | 44 -- src/apdu_get_random.c | 38 - src/apdu_get_trusted_input.c | 18 +- src/apdu_get_wallet_public_key.c | 78 +- src/apdu_hash_input_finalize_full.c | 36 +- src/apdu_hash_input_start.c | 31 +- src/apdu_hash_sign.c | 68 +- src/apdu_set_operation_mode.c | 72 -- src/apdu_setup.c | 42 -- src/apdu_sign_message.c | 27 +- src/apdu_verify_pin.c | 23 - src/base58.c | 141 ---- src/bcd.c | 2 +- src/bip32_path.c | 3 +- src/btchip.c | 495 ++++++++++++- src/context.c | 24 +- src/display_variables.h | 2 + src/filesystem.c | 29 - src/handle_swap_sign_transaction.c | 70 -- src/handle_swap_sign_transaction.h | 13 - src/helpers.c | 112 +-- src/internal.h | 1 - src/main.c | 706 ------------------- src/public_ram_variables.c | 1 - src/public_ram_variables.h | 2 - src/rom_variables.c | 45 -- src/rom_variables.h | 6 - src/secure_value.c | 38 - src/{ => swap}/handle_check_address.c | 57 +- src/{ => swap}/handle_check_address.h | 2 +- src/{ => swap}/handle_get_printable_amount.c | 12 +- src/{ => swap}/handle_get_printable_amount.h | 2 +- src/swap/handle_swap_sign_transaction.c | 96 +++ src/swap/handle_swap_sign_transaction.h | 13 + src/transaction.c | 56 +- src/ui_bagl.c | 71 +- src/ui_menu_nbgl.c | 40 +- src/ui_nbgl.c | 22 +- 46 files changed, 861 insertions(+), 2073 deletions(-) delete mode 100644 TODO.md delete mode 100644 include/base58.h delete mode 100644 src/apdu_get_operation_mode.c delete mode 100644 src/apdu_get_random.c delete mode 100644 src/apdu_set_operation_mode.c delete mode 100644 src/apdu_setup.c delete mode 100644 src/apdu_verify_pin.c delete mode 100644 src/base58.c delete mode 100644 src/filesystem.c delete mode 100644 src/handle_swap_sign_transaction.c delete mode 100644 src/handle_swap_sign_transaction.h delete mode 100644 src/main.c delete mode 100644 src/secure_value.c rename src/{ => swap}/handle_check_address.c (76%) rename src/{ => swap}/handle_check_address.h (58%) rename src/{ => swap}/handle_get_printable_amount.c (59%) rename src/{ => swap}/handle_get_printable_amount.h (58%) create mode 100644 src/swap/handle_swap_sign_transaction.c create mode 100644 src/swap/handle_swap_sign_transaction.h diff --git a/Makefile b/Makefile index 79c9be33..08a0fda0 100644 --- a/Makefile +++ b/Makefile @@ -1,77 +1,115 @@ -#******************************************************************************* -# Ledger App -# (c) 2017 Ledger +# **************************************************************************** +# Ledger App Bitcoin +# (c) 2023 Ledger SAS. # -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -#******************************************************************************* +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# **************************************************************************** ifeq ($(BOLOS_SDK),) $(error Environment variable BOLOS_SDK is not set) endif include $(BOLOS_SDK)/Makefile.defines -APP_PATH = "" -APP_LOAD_PARAMS= --curve secp256k1 $(COMMON_LOAD_PARAMS) +######################################## +# Mandatory configuration # +######################################## +# Name is defined later -APPVERSION_M=2 -APPVERSION_N=3 -APPVERSION_P=0 -APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) -APP_LOAD_FLAGS=--appFlags 0xa50 +# Application version +APPVERSION_M = 2 +APPVERSION_N = 3 +APPVERSION_P = 0 +APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" + +# Application source files +APP_SOURCE_PATH += src + +ICON_NANOS = icons/nanos_app_$(COIN).gif +ICON_NANOX = icons/nanox_app_$(COIN).gif +ICON_NANOSP = icons/nanox_app_$(COIN).gif +ICON_STAX = icons/stax_app_$(COIN).gif + +# Application allowed derivation curves. +CURVE_APP_LOAD_PARAMS = secp256k1 + +# Application allowed derivation paths. +ifeq ($(COIN),$(filter $(COIN), hydra_testnet hydra)) +PATH_APP_LOAD_PARAMS = "44'/609'" +else +PATH_APP_LOAD_PARAMS = "" +endif + +HAVE_APPLICATION_FLAG_DERIVE_MASTER = 1 +HAVE_APPLICATION_FLAG_LIBRARY = 1 + +VARIANT_PARAM = COIN +VARIANT_VALUES = BOL + +# Temporary restriction until we have a Resistance Nano X icon +ifeq ($(TARGET_NAME),TARGET_NANOS) +VARIANT_VALUES = bitcoin_testnet_legacy bitcoin_legacy bitcoin_cash bitcoin_gold litecoin dogecoin dash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte bitcoin_private firo gamecredits zclassic xsn nix lbry ravencoin resistance hydra hydra_testnet xrhodium +else +VARIANT_VALUES = bitcoin_testnet_legacy bitcoin_legacy bitcoin_cash bitcoin_gold litecoin dogecoin dash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte bitcoin_private firo gamecredits zclassic xsn nix lbry ravencoin hydra hydra_testnet xrhodium +endif + +ENABLE_BLUETOOTH = 1 +ENABLE_NBGL_QRCODE = 1 +ENABLE_SWAP = 1 + +ifeq ($(TARGET_NAME),TARGET_STAX) +DEFINES += COIN_ICON=C_$(COIN)_64px +DEFINES += COIN_ICON_BITMAP=C_$(COIN)_64px_bitmap +endif # simplify for tests ifndef COIN COIN=bitcoin_legacy endif +# Enabling DEBUG flag will enable PRINTF and disable optimizations +#DEBUG = 1 + ifeq ($(COIN),bitcoin_testnet_legacy) # Bitcoin testnet DEFINES += BIP44_COIN_TYPE=1 BIP44_COIN_TYPE_2=1 COIN_P2PKH_VERSION=111 COIN_P2SH_VERSION=196 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOIN\" COIN_COINID_NAME=\"Bitcoin\" COIN_COINID_SHORT=\"TEST\" COIN_NATIVE_SEGWIT_PREFIX=\"tb\" COIN_KIND=COIN_KIND_BITCOIN_TESTNET COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Bitcoin Test Legacy" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),bitcoin_legacy) # Bitcoin mainnet DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=0 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOIN\" COIN_COINID_NAME=\"Bitcoin\" COIN_COINID_SHORT=\"BTC\" COIN_NATIVE_SEGWIT_PREFIX=\"bc\" COIN_KIND=COIN_KIND_BITCOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Bitcoin Legacy" -APP_LOAD_PARAMS += --path $(APP_PATH) #LIB and global pin and else ifeq ($(COIN),bitcoin_cash) # Bitcoin cash # Initial fork from Bitcoin, public key access is authorized. Signature is different thanks to the forkId DEFINES += BIP44_COIN_TYPE=145 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=0 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOINCASH\" COIN_COINID_NAME=\"BitcoinCash\" COIN_COINID_SHORT=\"BCH\" COIN_KIND=COIN_KIND_BITCOIN_CASH COIN_FORKID=0 APPNAME ="Bitcoin Cash" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),bitcoin_gold) # Bitcoin Gold # Initial fork from Bitcoin, public key access is authorized. Signature is different thanks to the forkId DEFINES += BIP44_COIN_TYPE=156 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=23 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\\x20Gold\" COIN_COINID_HEADER=\"BITCOINGOLD\" COIN_COINID_NAME=\"BitcoinGold\" COIN_COINID_SHORT=\"BTG\" COIN_KIND=COIN_KIND_BITCOIN_GOLD COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT COIN_FORKID=79 APPNAME ="Bitcoin Gold" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),litecoin) # Litecoin DEFINES += BIP44_COIN_TYPE=2 BIP44_COIN_TYPE_2=2 COIN_P2PKH_VERSION=48 COIN_P2SH_VERSION=50 COIN_FAMILY=1 COIN_COINID=\"Litecoin\" COIN_COINID_HEADER=\"LITECOIN\" COIN_COINID_NAME=\"Litecoin\" COIN_COINID_SHORT=\"LTC\" COIN_NATIVE_SEGWIT_PREFIX=\"ltc\" COIN_KIND=COIN_KIND_LITECOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Litecoin" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),dogecoin) # Doge DEFINES += BIP44_COIN_TYPE=3 BIP44_COIN_TYPE_2=3 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=22 COIN_FAMILY=1 COIN_COINID=\"Dogecoin\" COIN_COINID_HEADER=\"DOGECOIN\" COIN_COINID_NAME=\"Dogecoin\" COIN_COINID_SHORT=\"DOGE\" COIN_KIND=COIN_KIND_DOGE APPNAME ="Dogecoin" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),dash) # Dash DEFINES += BIP44_COIN_TYPE=5 BIP44_COIN_TYPE_2=5 COIN_P2PKH_VERSION=76 COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"DarkCoin\" COIN_COINID_HEADER=\"DASH\" COIN_COINID_NAME=\"Dash\" COIN_COINID_SHORT=\"DASH\" COIN_KIND=COIN_KIND_DASH APPNAME ="Dash" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),zcash) # Zcash (deprecated, code before the NU5 hard fork) $(error the zcash variant is deprecated and no longer functional since the NU5 hard fork) @@ -79,256 +117,98 @@ DEFINES += BIP44_COIN_TYPE=133 BIP44_COIN_TYPE_2=133 COIN_P2PKH_VERSION=7352 C # Switch to Canopy over Heartwood DEFINES += COIN_CONSENSUS_BRANCH_ID=0xE9FF75A6 APPNAME ="Zcash" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),horizen) # Horizen DEFINES += BIP44_COIN_TYPE=121 BIP44_COIN_TYPE_2=121 COIN_P2PKH_VERSION=8329 COIN_P2SH_VERSION=8342 COIN_FAMILY=4 COIN_COINID=\"Horizen\" COIN_COINID_HEADER=\"HORIZEN\" COIN_COINID_NAME=\"Horizen\" COINID=$(COIN) COIN_COINID_SHORT=\"ZEN\" COIN_KIND=COIN_KIND_HORIZEN APPNAME ="Horizen" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),komodo) # Komodo DEFINES += BIP44_COIN_TYPE=141 BIP44_COIN_TYPE_2=141 COIN_P2PKH_VERSION=60 COIN_P2SH_VERSION=85 COIN_FAMILY=1 COIN_COINID=\"Komodo\" COIN_COINID_HEADER=\"KOMODO\" COIN_COINID_NAME=\"Komodo\" COIN_COINID_SHORT=\"KMD\" COIN_KIND=COIN_KIND_KOMODO APPNAME ="Komodo" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),stratis) # Stratis DEFINES += BIP44_COIN_TYPE=105105 BIP44_COIN_TYPE_2=105105 COIN_P2PKH_VERSION=75 COIN_P2SH_VERSION=140 COIN_FAMILY=2 COIN_COINID=\"Stratis\" COIN_COINID_HEADER=\"STRATIS\" COIN_COINID_NAME=\"Stratis\" COIN_COINID_SHORT=\"STRAX\" COIN_KIND=COIN_KIND_STRATIS COIN_FLAGS=FLAG_PEERCOIN_SUPPORT APPNAME ="Stratis" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),xrhodium) #Xrhodium DEFINES += BIP44_COIN_TYPE=10291 BIP44_COIN_TYPE_2=10291 COIN_P2PKH_VERSION=61 COIN_P2SH_VERSION=123 COIN_FAMILY=1 COIN_COINID=\"xrhodium\" COIN_COINID_HEADER=\"XRHODIUM\" COIN_COINID_NAME=\"xRhodium\" COIN_COINID_SHORT=\"XRC\" COIN_KIND=COIN_KIND_XRHODIUM APPNAME ="xRhodium" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),peercoin) # Peercoin DEFINES += BIP44_COIN_TYPE=6 BIP44_COIN_TYPE_2=6 COIN_P2PKH_VERSION=55 COIN_P2SH_VERSION=117 COIN_FAMILY=2 COIN_COINID=\"PPCoin\" COIN_COINID_HEADER=\"PEERCOIN\" COIN_COINID_NAME=\"Peercoin\" COIN_COINID_SHORT=\"PPC\" COIN_KIND=COIN_KIND_PEERCOIN COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT APPNAME ="Peercoin" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),pivx) # PivX # 77 was used in the Chrome apps DEFINES += BIP44_COIN_TYPE=119 BIP44_COIN_TYPE_2=77 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=13 COIN_FAMILY=1 COIN_COINID=\"DarkNet\" COIN_COINID_HEADER=\"PIVX\" COIN_COINID_NAME=\"PivX\" COIN_COINID_SHORT=\"PIVX\" COIN_KIND=COIN_KIND_PIVX APPNAME ="PivX" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),stealth) # Stealth DEFINES += BIP44_COIN_TYPE=125 BIP44_COIN_TYPE_2=125 COIN_P2PKH_VERSION=62 COIN_P2SH_VERSION=85 COIN_FAMILY=4 COIN_COINID=\"Stealth\" COIN_COINID_HEADER=\"STEALTH\" COIN_COINID_NAME=\"Stealth\" COIN_COINID_SHORT=\"XST\" COIN_KIND=COIN_KIND_STEALTH COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT APPNAME ="Stealth" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),viacoin) # Viacoin DEFINES += BIP44_COIN_TYPE=14 BIP44_COIN_TYPE_2=14 COIN_P2PKH_VERSION=71 COIN_P2SH_VERSION=33 COIN_FAMILY=1 COIN_COINID=\"Viacoin\" COIN_COINID_HEADER=\"VIACOIN\" COIN_COINID_NAME=\"Viacoin\" COIN_COINID_SHORT=\"VIA\" COIN_KIND=COIN_KIND_VIACOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Viacoin" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),vertcoin) # Vertcoin # 128 was used in the Chrome apps DEFINES += BIP44_COIN_TYPE=28 BIP44_COIN_TYPE_2=128 COIN_P2PKH_VERSION=71 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Vertcoin\" COIN_COINID_HEADER=\"VERTCOIN\" COIN_COINID_NAME=\"Vertcoin\" COIN_COINID_SHORT=\"VTC\" COIN_NATIVE_SEGWIT_PREFIX=\"vtc\" COIN_KIND=COIN_KIND_VERTCOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Vertcoin" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),digibyte) DEFINES += BIP44_COIN_TYPE=20 BIP44_COIN_TYPE_2=20 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=63 COIN_FAMILY=1 COIN_COINID=\"DigiByte\" COIN_COINID_HEADER=\"DIGIBYTE\" COIN_COINID_NAME=\"DigiByte\" COIN_COINID_SHORT=\"DGB\" COIN_NATIVE_SEGWIT_PREFIX=\"dgb\" COIN_KIND=COIN_KIND_DIGIBYTE COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Digibyte" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),qtum) $(error the qtum variant is deprecated and has been moved to its dedicated repo else ifeq ($(COIN),firo) DEFINES += BIP44_COIN_TYPE=136 BIP44_COIN_TYPE_2=136 COIN_P2PKH_VERSION=82 COIN_P2SH_VERSION=7 COIN_FAMILY=1 COIN_COINID=\"Zcoin\" COIN_COINID_HEADER=\"FIRO\" COIN_COINID_NAME=\"Firo\" COIN_COINID_SHORT=\"FIRO\" COIN_KIND=COIN_KIND_FIRO APPNAME ="Firo" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),bitcoin_private) # Bitcoin Private # Initial fork from Bitcoin, public key access is authorized. Signature is different thanks to the forkId # Note : might need a third lock on ZClassic DEFINES += BIP44_COIN_TYPE=183 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=4901 COIN_P2SH_VERSION=5039 COIN_FAMILY=1 COIN_COINID=\"BPrivate\" COIN_COINID_HEADER=\"BITCOINPRIVATE\" COIN_COINID_NAME=\"BPrivate\" COIN_COINID_SHORT=\"BTCP\" COIN_KIND=COIN_KIND_BITCOIN_PRIVATE COIN_FORKID=42 APPNAME ="Bitcoin Private" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),gamecredits) # GameCredits DEFINES += BIP44_COIN_TYPE=101 BIP44_COIN_TYPE_2=101 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=62 COIN_FAMILY=1 COIN_COINID=\"GameCredits\" COIN_COINID_HEADER=\"GAMECREDITS\" COIN_COINID_NAME=\"GameCredits\" COIN_COINID_SHORT=\"GAME\" COIN_KIND=COIN_KIND_GAMECREDITS COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="GameCredits" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),zclassic) # ZClassic DEFINES += BIP44_COIN_TYPE=147 BIP44_COIN_TYPE_2=147 COIN_P2PKH_VERSION=7352 COIN_P2SH_VERSION=7357 COIN_FAMILY=1 COIN_COINID=\"ZClassic\" COIN_COINID_HEADER=\"ZCLASSIC\" COIN_COINID_NAME=\"ZClassic\" COIN_COINID_SHORT=\"ZCL\" COIN_KIND=COIN_KIND_ZCLASSIC APPNAME ="ZClassic" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),xsn) # XSN mainnet DEFINES += BIP44_COIN_TYPE=384 BIP44_COIN_TYPE_2=384 COIN_P2PKH_VERSION=76 COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"XSN\" COIN_COINID_HEADER=\"XSN\" COIN_COINID_NAME=\"XSN\" COIN_COINID_SHORT=\"XSN\" COIN_NATIVE_SEGWIT_PREFIX=\"xc\" COIN_KIND=COIN_KIND_XSN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="XSN" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),nix) # NIX DEFINES += BIP44_COIN_TYPE=400 BIP44_COIN_TYPE_2=400 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=53 COIN_FAMILY=1 COIN_COINID=\"NIX\" COIN_COINID_HEADER=\"NIX\" COIN_COINID_NAME=\"NIX\" COIN_COINID_SHORT=\"NIX\" COIN_NATIVE_SEGWIT_PREFIX=\"nix\" COIN_KIND=COIN_KIND_NIX COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="NIX" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),lbry) # LBRY DEFINES += BIP44_COIN_TYPE=140 BIP44_COIN_TYPE_2=140 COIN_P2PKH_VERSION=85 COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"LBRY\" COIN_COINID_HEADER=\"LBRY\" COIN_COINID_NAME=\"LBRY\" COIN_COINID_SHORT=\"LBC\" COIN_KIND=COIN_KIND_LBRY APPNAME ="LBRY" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),resistance) # Resistance DEFINES += BIP44_COIN_TYPE=356 BIP44_COIN_TYPE_2=356 COIN_P2PKH_VERSION=7063 COIN_P2SH_VERSION=7068 COIN_FAMILY=1 COIN_COINID=\"Res\" COIN_COINID_HEADER=\"RES\" COIN_COINID_NAME=\"Res\" COIN_COINID_SHORT=\"RES\" COIN_KIND=COIN_KIND_RESISTANCE APPNAME ="Resistance" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),ravencoin) # Ravencoin DEFINES += BIP44_COIN_TYPE=175 BIP44_COIN_TYPE_2=175 COIN_P2PKH_VERSION=60 COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"Ravencoin\" COIN_COINID_HEADER=\"RAVENCOIN\" COIN_COINID_NAME=\"Ravencoin\" COIN_COINID_SHORT=\"RVN\" COIN_KIND=COIN_KIND_RAVENCOIN APPNAME ="Ravencoin" -APP_LOAD_PARAMS += --path $(APP_PATH) else ifeq ($(COIN),hydra_testnet) # Hydra testnet DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=66 COIN_P2SH_VERSION=128 COIN_FAMILY=3 COIN_COINID=\"Hydra\" COIN_COINID_HEADER=\"HYDRA\" COIN_COINID_NAME=\"HYDRA\" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" COIN_KIND=COIN_KIND_HYDRA COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Hydra Test" -APP_LOAD_PARAMS += --path "44'/609'" else ifeq ($(COIN),hydra) # Hydra mainnet DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=40 COIN_P2SH_VERSION=63 COIN_FAMILY=3 COIN_COINID=\"Hydra\" COIN_COINID_HEADER=\"HYDRA\" COIN_COINID_NAME=\"HYDRA\" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" COIN_KIND=COIN_KIND_HYDRA COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Hydra" -APP_LOAD_PARAMS += --path "44'/609'" else ifeq ($(filter clean,$(MAKECMDGOALS)),) $(error Unsupported COIN - use bitcoin_testnet, bitcoin, bitcoin_cash, bitcoin_gold, litecoin, dogecoin, dash, zcash, horizen, komodo, stratis, peercoin, pivx, viacoin, vertcoin, stealth, digibyte, bitcoin_private, firo, gamecredits, zclassic, xsn, nix, lbry, resistance, ravencoin, hydra, hydra_testnet, xrhodium) endif endif -APP_LOAD_PARAMS += $(APP_LOAD_FLAGS) - -ifeq ($(TARGET_NAME),TARGET_NANOS) -ICONNAME=icons/nanos_app_$(COIN).gif -else ifeq ($(TARGET_NAME),TARGET_STAX) -ICONNAME=icons/stax_app_$(COIN).gif -DEFINES += COIN_ICON=C_$(COIN)_64px -DEFINES += COIN_ICON_BITMAP=C_$(COIN)_64px_bitmap -else -ICONNAME=icons/nanox_app_$(COIN).gif -endif - -################ -# Default rule # -################ -all: default - -############ -# Platform # -############ - -DEFINES += OS_IO_SEPROXYHAL IO_SEPROXYHAL_BUFFER_SIZE_B=300 -DEFINES += HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U -DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=4 IO_HID_EP_LENGTH=64 HAVE_USB_APDU -DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P) TCS_LOADER_PATCH_VERSION=0 - -#WEBUSB_URL = www.ledgerwallet.com -#DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=$(shell echo -n $(WEBUSB_URL) | wc -c) WEBUSB_URL=$(shell echo -n $(WEBUSB_URL) | sed -e "s/./\\\'\0\\\',/g") -DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL="" - -DEFINES += APPVERSION=\"$(APPVERSION)\" - -DEFINES += BLAKE_SDK - -ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX)) -DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 -DEFINES += HAVE_BLE_APDU # basic ledger apdu transport over BLE -endif - -ifeq ($(TARGET_NAME),TARGET_STAX) - DEFINES += NBGL_QRCODE - SDK_SOURCE_PATH += qrcode -else - DEFINES += HAVE_BAGL HAVE_UX_FLOW - ifneq ($(TARGET_NAME),TARGET_NANOS) - DEFINES += HAVE_GLO096 - DEFINES += BAGL_WIDTH=128 BAGL_HEIGHT=64 - DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature - DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX - DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX - DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX - endif -endif - -# Enabling debug PRINTF -DEBUG ?= 0 -ifneq ($(DEBUG),0) - ifeq ($(TARGET_NAME),TARGET_NANOS) - DEFINES += HAVE_PRINTF PRINTF=screen_printf - else - DEFINES += HAVE_PRINTF PRINTF=mcu_usb_printf - endif -else - DEFINES += PRINTF\(...\)= -endif - - - -############## -# Compiler # -############## -ifneq ($(BOLOS_ENV),) -$(info BOLOS_ENV=$(BOLOS_ENV)) -CLANGPATH := $(BOLOS_ENV)/clang-arm-fropi/bin/ -GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-5_3-2016q1/bin/ -else -$(info BOLOS_ENV is not set: falling back to CLANGPATH and GCCPATH) -endif -ifeq ($(CLANGPATH),) -$(info CLANGPATH is not set: clang will be used from PATH) -endif -ifeq ($(GCCPATH),) -$(info GCCPATH is not set: arm-none-eabi-* will be used from PATH) -endif - -CC := $(CLANGPATH)clang - -CFLAGS += -Oz -AS := $(GCCPATH)arm-none-eabi-gcc - -LD := $(GCCPATH)arm-none-eabi-gcc -LDFLAGS += -O3 -Os -LDLIBS += -lm -lgcc -lc - -# import rules to compile glyphs(/pone) -include $(BOLOS_SDK)/Makefile.glyphs - -### variables processed by the common makefile.rules of the SDK to grab source files and include dirs -APP_SOURCE_PATH += src - -APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/format.c -APP_SOURCE_FILES += ${BOLOS_SDK}/lib_standard_app/crypto_helpers.c - -SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_u2f -ifneq ($(TARGET_NAME),TARGET_STAX) -SDK_SOURCE_PATH += lib_ux -endif - -ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX)) -SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl -endif - -load: all - python -m ledgerblue.loadApp $(APP_LOAD_PARAMS) - -delete: - python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS) - -# import generic rules from the sdk -include $(BOLOS_SDK)/Makefile.rules - -#add dependency on custom makefile filename -dep/%.d: %.c Makefile - - -# Temporary restriction until we have a Resistance Nano X icon -ifeq ($(TARGET_NAME),TARGET_NANOS) - -listvariants: - @echo VARIANTS COIN bitcoin_testnet_legacy bitcoin_legacy bitcoin_cash bitcoin_gold litecoin dogecoin dash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte bitcoin_private firo gamecredits zclassic xsn nix lbry ravencoin resistance hydra hydra_testnet xrhodium - -else - -listvariants: - @echo VARIANTS COIN bitcoin_testnet_legacy bitcoin_legacy bitcoin_cash bitcoin_gold litecoin dogecoin dash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte bitcoin_private firo gamecredits zclassic xsn nix lbry ravencoin hydra hydra_testnet xrhodium - -endif +include $(BOLOS_SDK)/Makefile.standard_app diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 39fbe3c6..00000000 --- a/TODO.md +++ /dev/null @@ -1,7 +0,0 @@ -# BTC Application TODOs - - - [X] Sign message support - - [X] Altcoins fixes (signing message format, prompts) - - [ ] Support an arbitrary number of TX outputs - - [ ] Support device / PIN locking in next firmware update - diff --git a/include/apdu_constants.h b/include/apdu_constants.h index 34a1441a..1aa127d3 100644 --- a/include/apdu_constants.h +++ b/include/apdu_constants.h @@ -130,23 +130,14 @@ void commit_operation_mode(secu8 operationMode); -unsigned short apdu_setup(void); -unsigned short apdu_verify_pin(void); -unsigned short apdu_get_operation_mode(void); -unsigned short apdu_set_operation_mode(void); unsigned short apdu_get_wallet_public_key(void); unsigned short apdu_get_trusted_input(void); unsigned short apdu_hash_input_start(void); unsigned short apdu_hash_input_finalize(void); unsigned short apdu_hash_sign(void); unsigned short apdu_hash_input_finalize_full(void); -unsigned short apdu_import_private_key(void); -unsigned short apdu_get_public_key(void); -unsigned short apdu_derive_bip32_key(void); -unsigned short apdu_signverify_immediate(void); unsigned short apdu_sign_message(void); -unsigned short apdu_get_random(void); unsigned short apdu_get_firmware_version(void); unsigned short apdu_get_coin_version(void); diff --git a/include/base58.h b/include/base58.h deleted file mode 100644 index 453f8593..00000000 --- a/include/base58.h +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef BASE58_H - -#define BASE58_H - -#include - -int decode_base58(const char *in, size_t length, - unsigned char *out, size_t *outlen); - -int encode_base58(const unsigned char *in, size_t length, - unsigned char *out, size_t *outlen); - -#endif diff --git a/include/context.h b/include/context.h index 90ba37ae..4f23f4db 100644 --- a/include/context.h +++ b/include/context.h @@ -163,12 +163,6 @@ struct context_s { /** (Integrity protected) transaction context */ transaction_context_t transactionContext; - /** Non protected transaction context */ - - /** Last U2F Token streamed by host to attempt pubkey request */ - unsigned char last_token[4]; - unsigned char has_valid_token; - /** Full transaction hash context */ union multi_hash transactionHashFull; /** Authorization transaction hash context */ @@ -241,9 +235,6 @@ struct context_s { unsigned char nExpiryHeight[4]; unsigned char nLockTime[4]; unsigned char sigHashType[4]; - - /*Is swap mode*/ - unsigned char called_from_swap; }; typedef struct context_s context_t; @@ -291,27 +282,6 @@ typedef enum coin_kind_e { COIN_KIND_HYDRA } coin_kind_t; -typedef struct altcoin_config_s { - unsigned int bip44_coin_type; - unsigned int bip44_coin_type2; - unsigned short p2pkh_version; - unsigned short p2sh_version; - unsigned char family; -#ifdef HAVE_NBGL - unsigned char img_raw[1024]; - nbgl_icon_details_t img_nbgl; -#endif // HAVE_NBGL - char coinid[14]; // used coind id for message signature prefix - char name[16]; // for ux displays - char name_short[6]; // for unit in ux displays - char native_segwit_prefix_val[5]; - const char* native_segwit_prefix; // null if no segwit prefix - unsigned int forkid; - unsigned int zcash_consensus_branch_id; - coin_kind_t kind; - unsigned int flags; -} altcoin_config_t; - void context_init(void); #endif diff --git a/include/helpers.h b/include/helpers.h index e60f8d7a..febe122a 100644 --- a/include/helpers.h +++ b/include/helpers.h @@ -40,38 +40,16 @@ unsigned char output_script_is_op_create(unsigned char *buffer, unsigned char output_script_is_op_call(unsigned char *buffer, size_t size); -void sleep16(unsigned short delay); -void sleep32(unsigned long int delayEach, unsigned long int delayRepeat); - -unsigned long int read_u32(unsigned char *buffer, unsigned char be, - unsigned char skipSign); - -void write_u32_be(unsigned char *buffer, unsigned long int value); -void write_u32_le(unsigned char *buffer, unsigned long int value); - -void perform_double_hash(unsigned char *in, unsigned short inlen, - unsigned char *out, - unsigned char hash1Algorithm, - unsigned char hash2Algorithm); - void public_key_hash160(unsigned char *in, unsigned short inlen, unsigned char *out); unsigned short public_key_to_encoded_base58( unsigned char *in, unsigned short inlen, unsigned char *out, unsigned short outlen, unsigned short version, unsigned char alreadyHashed); -unsigned short decode_base58_address(unsigned char *in, - unsigned short inlen, - unsigned char *out, - unsigned short outlen); - unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_path); unsigned char enforce_bip44_coin_type(unsigned char *bip32Path, bool for_pubkey); unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned char max_out_len); -// void set_check_internal_structure_integrity(unsigned char -// setParameter); -#define set_check_internal_structure_integrity(x) void swap_bytes(unsigned char *target, unsigned char *source, unsigned char size); @@ -82,12 +60,6 @@ int sign_finalhash(unsigned char *path, size_t path_len, void transaction_add_output(unsigned char *hash160Address, unsigned char *amount, unsigned char p2sh); -unsigned char rng_u8_modulo(unsigned char modulo); -unsigned char secure_memcmp(const void *buf1, const void *buf2, - unsigned short length); -unsigned char decrease_2fa(void); -void reset_2fa(void); -void reset_token(void); int get_public_key(unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode); #endif diff --git a/src/apdu_get_coin_version.c b/src/apdu_get_coin_version.c index cc754fe4..97e0ac72 100644 --- a/src/apdu_get_coin_version.c +++ b/src/apdu_get_coin_version.c @@ -24,26 +24,19 @@ unsigned short apdu_get_coin_version() { uint8_t offset = 0; - SB_CHECK(N_btchip.bkp.config.operationMode); - if ((SB_GET(N_btchip.bkp.config.operationMode) == - MODE_SETUP_NEEDED) || - (SB_GET(N_btchip.bkp.config.operationMode) == MODE_ISSUER)) { - return SW_CONDITIONS_OF_USE_NOT_SATISFIED; - } - - G_io_apdu_buffer[offset++] = G_coin_config->p2pkh_version >> 8; - G_io_apdu_buffer[offset++] = G_coin_config->p2pkh_version; - G_io_apdu_buffer[offset++] = G_coin_config->p2sh_version >> 8; - G_io_apdu_buffer[offset++] = G_coin_config->p2sh_version; - G_io_apdu_buffer[offset++] = G_coin_config->family; - G_io_apdu_buffer[offset++] = strlen(G_coin_config->coinid); - memmove(G_io_apdu_buffer + offset, G_coin_config->coinid, - strlen(G_coin_config->coinid)); - offset += strlen(G_coin_config->coinid); - G_io_apdu_buffer[offset++] = strlen(G_coin_config->name_short); - memmove(G_io_apdu_buffer + offset, G_coin_config->name_short, - strlen(G_coin_config->name_short)); - offset += strlen(G_coin_config->name_short); + G_io_apdu_buffer[offset++] = COIN_P2PKH_VERSION >> 8; + G_io_apdu_buffer[offset++] = COIN_P2PKH_VERSION; + G_io_apdu_buffer[offset++] = COIN_P2SH_VERSION >> 8; + G_io_apdu_buffer[offset++] = COIN_P2SH_VERSION; + G_io_apdu_buffer[offset++] = COIN_FAMILY; + G_io_apdu_buffer[offset++] = strlen(COIN_COINID); + memmove(G_io_apdu_buffer + offset, COIN_COINID, + strlen(COIN_COINID)); + offset += strlen(COIN_COINID); + G_io_apdu_buffer[offset++] = strlen(COIN_COINID_SHORT); + memmove(G_io_apdu_buffer + offset, COIN_COINID_SHORT, + strlen(COIN_COINID_SHORT)); + offset += strlen(COIN_COINID_SHORT); context_D.outLength = offset; return SW_OK; diff --git a/src/apdu_get_firmware_version.c b/src/apdu_get_firmware_version.c index 48364bb2..b2b90954 100644 --- a/src/apdu_get_firmware_version.c +++ b/src/apdu_get_firmware_version.c @@ -31,12 +31,13 @@ #define ARCH_ID 0x30 // Java Card is 0x60 +#define TCS_LOADER_PATCH_VERSION 0 void get_firmware_version(unsigned char *buffer) { buffer[0] = ARCH_ID; - buffer[1] = LEDGER_MAJOR_VERSION; - buffer[2] = LEDGER_MINOR_VERSION; - buffer[3] = LEDGER_PATCH_VERSION; + buffer[1] = MAJOR_VERSION; + buffer[2] = MINOR_VERSION; + buffer[3] = PATCH_VERSION; buffer[4] = 1; buffer[5] = TCS_LOADER_PATCH_VERSION; } diff --git a/src/apdu_get_operation_mode.c b/src/apdu_get_operation_mode.c deleted file mode 100644 index 13f90fb0..00000000 --- a/src/apdu_get_operation_mode.c +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" -#include "apdu_constants.h" - -#define P1_GET_OPERATION_MODE 0x00 -#define P1_GET_SECOND_FACTOR_MODE 0x01 - -unsigned short apdu_get_operation_mode() { - SB_CHECK(N_btchip.bkp.config.operationMode); - if ((SB_GET(N_btchip.bkp.config.operationMode) == - MODE_SETUP_NEEDED) || - (SB_GET(N_btchip.bkp.config.operationMode) == MODE_ISSUER)) { - return SW_CONDITIONS_OF_USE_NOT_SATISFIED; - } - - switch (G_io_apdu_buffer[ISO_OFFSET_P1]) { - case P1_GET_OPERATION_MODE: - G_io_apdu_buffer[0] = SB_GET(N_btchip.bkp.config.operationMode); - break; - - default: - return SW_INCORRECT_P1_P2; - } - - context_D.outLength = 1; - - return SW_OK; -} diff --git a/src/apdu_get_random.c b/src/apdu_get_random.c deleted file mode 100644 index 0f7d605e..00000000 --- a/src/apdu_get_random.c +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" -#include "apdu_constants.h" - -#define MAX_LENGTH 248 - -unsigned short apdu_get_random() { - unsigned char length = G_io_apdu_buffer[ISO_OFFSET_LC]; - if (length == 0) { - length = MAX_LENGTH; - } - - if (length > MAX_LENGTH) { - return SW_INCORRECT_LENGTH; - } - - cx_rng(G_io_apdu_buffer, length); - - context_D.outLength = length; - - return SW_OK; -} diff --git a/src/apdu_get_trusted_input.c b/src/apdu_get_trusted_input.c index 5aec2411..48fa119a 100644 --- a/src/apdu_get_trusted_input.c +++ b/src/apdu_get_trusted_input.c @@ -17,6 +17,8 @@ #include "internal.h" #include "apdu_constants.h" +#include "lib_standard_app/read.h" +#include "lib_standard_app/write.h" #define GET_TRUSTED_INPUT_P1_FIRST 0x00 #define GET_TRUSTED_INPUT_P1_NEXT 0x80 @@ -26,25 +28,14 @@ unsigned short apdu_get_trusted_input() { unsigned char dataOffset = 0; apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - SB_CHECK(N_btchip.bkp.config.operationMode); - switch (SB_GET(N_btchip.bkp.config.operationMode)) { - case MODE_WALLET: - case MODE_RELAXED_WALLET: - case MODE_SERVER: - break; - default: - return SW_CONDITIONS_OF_USE_NOT_SATISFIED; - } - if (G_io_apdu_buffer[ISO_OFFSET_P1] == GET_TRUSTED_INPUT_P1_FIRST) { // Initialize context_D.transactionTargetInput = - read_u32(G_io_apdu_buffer + ISO_OFFSET_CDATA, 1, 0); + read_u32_be(G_io_apdu_buffer, ISO_OFFSET_CDATA); context_D.transactionContext.transactionState = TRANSACTION_NONE; context_D.trustedInputProcessed = 0; context_D.transactionContext.consumeP2SH = 0; - set_check_internal_structure_integrity(1); dataOffset = 4; context_D.transactionHashOption = TRANSACTION_HASH_FULL; context_D.usingSegwit = 0; @@ -67,7 +58,6 @@ unsigned short apdu_get_trusted_input() { context_D.transactionContext.transactionState = TRANSACTION_NONE; - set_check_internal_structure_integrity(1); if (!context_D.trustedInputProcessed) { // Output was not found return SW_INCORRECT_DATA; @@ -84,7 +74,7 @@ unsigned short apdu_get_trusted_input() { G_io_apdu_buffer[1] = 0x00; cx_hash_sha256(G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32, G_io_apdu_buffer + 4, 32); - write_u32_le(G_io_apdu_buffer + 4 + 32, + write_u32_le(G_io_apdu_buffer, 4 + 32, context_D.transactionTargetInput); memmove(G_io_apdu_buffer + 4 + 32 + 4, context_D.transactionContext.transactionAmount, 8); diff --git a/src/apdu_get_wallet_public_key.c b/src/apdu_get_wallet_public_key.c index 04f9a605..53baced4 100644 --- a/src/apdu_get_wallet_public_key.c +++ b/src/apdu_get_wallet_public_key.c @@ -23,8 +23,10 @@ #include "segwit_addr.h" #include "cashaddr.h" #include "apdu_get_wallet_public_key.h" +#include "lib_standard_app/read.h" +#include "swap.h" -int get_public_key_chain_code(unsigned char* keyPath, size_t keyPath_len, bool uncompressedPublicKeys, unsigned char* publicKey, unsigned char* chainCode) { +int get_public_key_chain_code(unsigned char* keyPath, size_t keyPath_len, unsigned char* publicKey, unsigned char* chainCode) { uint8_t public_key[65]; int keyLength = 0; @@ -32,12 +34,8 @@ int get_public_key_chain_code(unsigned char* keyPath, size_t keyPath_len, bool u return keyLength; } // Then encode it - if (uncompressedPublicKeys) { - keyLength = 65; - } else { - compress_public_key_value(public_key); - keyLength = 33; - } + compress_public_key_value(public_key); + keyLength = 33; memmove(publicKey, public_key, sizeof(public_key)); @@ -46,19 +44,14 @@ int get_public_key_chain_code(unsigned char* keyPath, size_t keyPath_len, bool u unsigned short apdu_get_wallet_public_key() { unsigned char keyLength; - unsigned char uncompressedPublicKeys = - ((N_btchip.bkp.config.options & OPTION_UNCOMPRESSED_KEYS) != 0); - uint32_t request_token; unsigned char chainCode[32]; uint8_t is_derivation_path_unusual = 0; bool display = (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_DISPLAY); - bool display_request_token = N_btchip.pubKeyRequestRestriction && (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_REQUEST_TOKEN) && G_io_apdu_media == IO_APDU_MEDIA_U2F; - bool require_user_approval = N_btchip.pubKeyRequestRestriction && !(display_request_token || display) && G_io_apdu_media == IO_APDU_MEDIA_U2F; bool segwit = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_SEGWIT); bool nativeSegwit = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NATIVE_SEGWIT); bool cashAddr = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_CASHADDR); - if (display && context_D.called_from_swap) { + if (display && G_called_from_swap) { return SW_INCORRECT_DATA; } switch (G_io_apdu_buffer[ISO_OFFSET_P1]) { @@ -72,7 +65,7 @@ unsigned short apdu_get_wallet_public_key() { switch (G_io_apdu_buffer[ISO_OFFSET_P2]) { case P2_NATIVE_SEGWIT: - if (!(G_coin_config->native_segwit_prefix)) { + if (!(COIN_NATIVE_SEGWIT_PREFIX)) { return SW_INCORRECT_P1_P2; } __attribute__((fallthrough)); @@ -80,7 +73,7 @@ unsigned short apdu_get_wallet_public_key() { case P2_SEGWIT: break; case P2_CASHADDR: - if (G_coin_config->kind != COIN_KIND_BITCOIN_CASH) { + if (COIN_KIND != COIN_KIND_BITCOIN_CASH) { return SW_INCORRECT_P1_P2; } break; @@ -95,31 +88,10 @@ unsigned short apdu_get_wallet_public_key() { is_derivation_path_unusual = set_key_path_to_display(G_io_apdu_buffer + ISO_OFFSET_CDATA); } - if(display_request_token){ - uint8_t request_token_offset = ISO_OFFSET_CDATA + G_io_apdu_buffer[ISO_OFFSET_CDATA]*4 + 1; - request_token = read_u32(G_io_apdu_buffer + request_token_offset, true, false); - } - - SB_CHECK(N_btchip.bkp.config.operationMode); - switch (SB_GET(N_btchip.bkp.config.operationMode)) { - case MODE_WALLET: - case MODE_RELAXED_WALLET: - case MODE_SERVER: - break; - default: - return SW_CONDITIONS_OF_USE_NOT_SATISFIED; - } - - if (os_global_pin_is_validated() != BOLOS_UX_OK) { - return SW_SECURITY_STATUS_NOT_SATISFIED; - } - - PRINTF("pin ok\n"); - unsigned char bip44_enforced = enforce_bip44_coin_type(G_io_apdu_buffer + ISO_OFFSET_CDATA, true); G_io_apdu_buffer[0] = 65; - keyLength = get_public_key_chain_code(G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH, uncompressedPublicKeys, G_io_apdu_buffer + 1, chainCode); + keyLength = get_public_key_chain_code(G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH, G_io_apdu_buffer + 1, chainCode); if (keyLength == 0) { return SW_TECHNICAL_PROBLEM; @@ -138,7 +110,7 @@ unsigned short apdu_get_wallet_public_key() { keyLength, // INLEN G_io_apdu_buffer + 67, // OUT 150, // MAXOUTLEN - G_coin_config->p2pkh_version, 0); + COIN_P2PKH_VERSION, 0); } else { uint8_t tmp[22]; tmp[0] = 0x00; @@ -153,12 +125,12 @@ unsigned short apdu_get_wallet_public_key() { 22, // INLEN G_io_apdu_buffer + 67, // OUT 150, // MAXOUTLEN - G_coin_config->p2sh_version, 0); + COIN_P2SH_VERSION, 0); } else { - if (G_coin_config->native_segwit_prefix) { + if (COIN_NATIVE_SEGWIT_PREFIX) { keyLength = segwit_addr_encode( (char *)(G_io_apdu_buffer + 67), - (char *)PIC(G_coin_config->native_segwit_prefix), 0, tmp + 2, 20); + (char *)PIC(COIN_NATIVE_SEGWIT_PREFIX), 0, tmp + 2, 20); if (keyLength == 1) { keyLength = strlen((char *)(G_io_apdu_buffer + 67)); } @@ -167,10 +139,8 @@ unsigned short apdu_get_wallet_public_key() { } G_io_apdu_buffer[66] = keyLength; PRINTF("Length %d\n", keyLength); - if (!uncompressedPublicKeys) { - // Restore for the full key component - G_io_apdu_buffer[1] = 0x04; - } + // Restore for the full key component + G_io_apdu_buffer[1] = 0x04; // output chain code memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, @@ -193,24 +163,6 @@ unsigned short apdu_get_wallet_public_key() { context_D.io_flags |= IO_ASYNCH_REPLY; bagl_display_public_key(is_derivation_path_unusual); } - // If the token requested has already been approved in a previous call, the source is trusted so don't ask for approval again - else if(display_request_token && - (!context_D.has_valid_token || memcmp(&request_token, context_D.last_token, 4))) - { - // disable the has_valid_token flag and store the new token - context_D.has_valid_token = false; - memcpy(context_D.last_token, &request_token, 4); - // Hax, avoid wasting space - snprintf((char *)G_io_apdu_buffer + 200, 9, "%08X", request_token); - G_io_apdu_buffer[200 + 8] = '\0'; - context_D.io_flags |= IO_ASYNCH_REPLY; - bagl_display_token(); - } - else if(require_user_approval) - { - context_D.io_flags |= IO_ASYNCH_REPLY; - bagl_request_pubkey_approval(); - } return SW_OK; } diff --git a/src/apdu_hash_input_finalize_full.c b/src/apdu_hash_input_finalize_full.c index bbc00d90..3e69d334 100644 --- a/src/apdu_hash_input_finalize_full.c +++ b/src/apdu_hash_input_finalize_full.c @@ -23,6 +23,8 @@ #include "bagl_extensions.h" #include "ui.h" #include "lib_standard_app/crypto_helpers.h" +#include "lib_standard_app/read.h" +#include "swap.h" #define FINALIZE_P1_MORE 0x00 #define FINALIZE_P1_LAST 0x80 @@ -39,7 +41,6 @@ void apdu_hash_input_finalize_full_reset(void) { memset(context_D.totalOutputAmount, 0, sizeof(context_D.totalOutputAmount)); context_D.changeOutputFound = 0; - set_check_internal_structure_integrity(1); } static bool check_output_displayable() { @@ -70,10 +71,10 @@ static bool check_output_displayable() { isOpCall = output_script_is_op_call(context_D.currentOutput + 8, sizeof(context_D.currentOutput) - 8); - if (((G_coin_config->kind == COIN_KIND_HYDRA) && + if (((COIN_KIND == COIN_KIND_HYDRA) && !output_script_is_regular(context_D.currentOutput + 8) && !isP2sh && !(nullAmount && isOpReturn) && !isOpCreate && !isOpCall) || - (!(G_coin_config->kind == COIN_KIND_HYDRA) && + (!(COIN_KIND == COIN_KIND_HYDRA) && !output_script_is_regular(context_D.currentOutput + 8) && !isP2sh && !(nullAmount && isOpReturn))) { PRINTF("Error : Unrecognized output script"); @@ -99,7 +100,7 @@ static bool check_output_displayable() { public_key_hash160(changeSegwit, 22, changeSegwit); if (memcmp(context_D.currentOutput + 8 + addressOffset, changeSegwit, 20) == 0) { - if (G_coin_config->flags & FLAG_SEGWIT_CHANGE_SUPPORT) { + if (COIN_FLAGS & FLAG_SEGWIT_CHANGE_SUPPORT) { changeFound = true; } else { // Attempt to avoid fatal failures on Bitcoin Cash @@ -155,7 +156,7 @@ bool handle_output_state() { break; } context_D.totalOutputs = context_D.remainingOutputs = - read_u32(context_D.currentOutput + 1, 0, 0); + read_u32_le(context_D.currentOutput, 1); discardSize = 5; context_D.outputParsingState = OUTPUT_PARSING_OUTPUT; processed = true; @@ -177,8 +178,7 @@ bool handle_output_state() { if (context_D.currentOutputOffset < 9 + 2) { break; } - scriptSize = - read_u32(context_D.currentOutput + 9, 0, 0); + scriptSize = read_u32_le(context_D.currentOutput, 9); discardSize = 3; } else { // Unrealistically large script @@ -227,13 +227,10 @@ int get_pubkey_hash160(unsigned char* keyPath, size_t keyPath_len, unsigned char if (get_public_key(keyPath, keyPath_len, public_key.W, NULL)) { return -1; } - if (((N_btchip.bkp.config.options & - OPTION_UNCOMPRESSED_KEYS) != 0)) { - keyLength = 65; - } else { - compress_public_key_value(public_key.W); - keyLength = 33; - } + + compress_public_key_value(public_key.W); + keyLength = 33; + public_key_hash160( public_key.W, // IN keyLength, // INLEN @@ -272,7 +269,6 @@ unsigned short apdu_hash_input_finalize_full_internal( } // Check state - set_check_internal_structure_integrity(0); if (context_D.transactionContext.transactionState != TRANSACTION_PRESIGN_READY) { sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; @@ -311,7 +307,7 @@ unsigned short apdu_hash_input_finalize_full_internal( // if the bip44 change path provided is not canonical or its index are unsual, ask for user approval if(bip44_derivation_guard(transactionSummary->keyPath, true)) { - if (context_D.called_from_swap) { + if (G_called_from_swap) { PRINTF("In swap mode only standart path is allowed\n"); sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; @@ -459,10 +455,8 @@ unsigned short apdu_hash_input_finalize_full_internal( sizeof(transaction_summary_t)); } - transactionSummary->payToAddressVersion = - G_coin_config->p2pkh_version; - transactionSummary->payToScriptHashVersion = - G_coin_config->p2sh_version; + transactionSummary->payToAddressVersion = COIN_P2PKH_VERSION; + transactionSummary->payToScriptHashVersion = COIN_P2SH_VERSION; // Generate new nonce @@ -487,7 +481,7 @@ unsigned short apdu_hash_input_finalize_full_internal( sizeof(transactionSummary->authorizationHash)); goto return_OK; } else { - if (secure_memcmp( + if (os_secure_memcmp( authorizationHash, transactionSummary->authorizationHash, sizeof(transactionSummary->authorizationHash))) { diff --git a/src/apdu_hash_input_start.c b/src/apdu_hash_input_start.c index 233fddfb..bc315ae5 100644 --- a/src/apdu_hash_input_start.c +++ b/src/apdu_hash_input_start.c @@ -18,6 +18,7 @@ #include "internal.h" #include "apdu_constants.h" #include "bagl_extensions.h" +#include "swap.h" #define P1_FIRST 0x00 #define P1_NEXT 0x80 @@ -43,21 +44,10 @@ unsigned short apdu_hash_input_start() { unsigned char apduLength; apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - SB_CHECK(N_btchip.bkp.config.operationMode); - switch (SB_GET(N_btchip.bkp.config.operationMode)) { - case MODE_WALLET: - case MODE_RELAXED_WALLET: - case MODE_SERVER: - break; - default: - return SW_CONDITIONS_OF_USE_NOT_SATISFIED; - } - if (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_FIRST) { // Initialize context_D.transactionContext.transactionState = TRANSACTION_NONE; - set_check_internal_structure_integrity(1); context_D.transactionHashOption = TRANSACTION_HASH_BOTH; } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != P1_NEXT) { return SW_INCORRECT_P1_P2; @@ -68,8 +58,6 @@ unsigned short apdu_hash_input_start() { (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_CASHADDR) || (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_OVERWINTER) || (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_SAPLING)) { - // context_D.transactionContext.consumeP2SH = - // ((N_btchip.bkp.config.options & OPTION_SKIP_2FA_P2SH) != 0); if (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_FIRST) { unsigned char usingSegwit = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT) || @@ -78,26 +66,16 @@ unsigned short apdu_hash_input_start() { (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_SAPLING); unsigned char usingCashAddr = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_CASHADDR); - // Request PIN validation - // Only request PIN validation (user presence) to start a new - // transaction signing flow. - // Thus allowing for numerous output to be processed in the - // background without - // requiring to disable autolock/autopoweroff - if (!context_D.transactionContext.firstSigned && - os_global_pin_is_validated() != BOLOS_UX_OK) { - return SW_SECURITY_STATUS_NOT_SATISFIED; - } // Master transaction reset context_D.transactionContext.firstSigned = 1; context_D.transactionContext.consumeP2SH = 0; context_D.transactionContext.relaxed = 0; context_D.usingSegwit = usingSegwit; context_D.usingCashAddr = - (G_coin_config->kind == COIN_KIND_BITCOIN_CASH ? usingCashAddr + (COIN_KIND == COIN_KIND_BITCOIN_CASH ? usingCashAddr : 0); context_D.usingOverwinter = 0; - if ((G_coin_config->kind == COIN_KIND_ZCASH) || (G_coin_config->kind == COIN_KIND_KOMODO) || (G_coin_config->kind == COIN_KIND_ZCLASSIC) || (G_coin_config->kind == COIN_KIND_RESISTANCE)) { + if ((COIN_KIND == COIN_KIND_ZCASH) || (COIN_KIND == COIN_KIND_KOMODO) || (COIN_KIND == COIN_KIND_ZCLASSIC) || (COIN_KIND == COIN_KIND_RESISTANCE)) { if (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_OVERWINTER) { context_D.usingOverwinter = ZCASH_USING_OVERWINTER; } @@ -108,7 +86,6 @@ unsigned short apdu_hash_input_start() { } context_D.overwinterSignReady = 0; context_D.segwitParsedOnce = 0; - set_check_internal_structure_integrity(1); // Initialize for screen pairing memset(&context_D.tmpCtx.output, 0, sizeof(context_D.tmpCtx.output)); @@ -130,7 +107,7 @@ unsigned short apdu_hash_input_start() { && IS_INPUT() && !IS_INPUT_TRUSTED()) { - if(context_D.called_from_swap){ + if(G_called_from_swap){ /* There is no point in displaying a warning when the app is signing in silent mode, as its UI is hidden behind the exchange app*/ return SW_SWAP_WITHOUT_TRUSTED_INPUTS; diff --git a/src/apdu_hash_sign.c b/src/apdu_hash_sign.c index a17044f0..9f670031 100644 --- a/src/apdu_hash_sign.c +++ b/src/apdu_hash_sign.c @@ -21,9 +21,16 @@ #include "display_variables.h" #include "ui.h" #include "ledger_assert.h" +#include "lib_standard_app/read.h" +#include "lib_standard_app/write.h" +#include "swap.h" #define SIGHASH_ALL 0x01 +#ifndef COIN_FORKID +#define COIN_FORKID 0 +#endif + unsigned short apdu_hash_sign() { unsigned long int lockTime; uint32_t sighashType; @@ -32,16 +39,6 @@ unsigned short apdu_hash_sign() { unsigned char *parameters = G_io_apdu_buffer + ISO_OFFSET_CDATA; unsigned short sw = SW_TECHNICAL_DETAILS(0xF); - SB_CHECK(N_btchip.bkp.config.operationMode); - switch (SB_GET(N_btchip.bkp.config.operationMode)) { - case MODE_WALLET: - case MODE_RELAXED_WALLET: - case MODE_SERVER: - break; - default: - return SW_CONDITIONS_OF_USE_NOT_SATISFIED; - } - if ((G_io_apdu_buffer[ISO_OFFSET_P1] != 0) || (G_io_apdu_buffer[ISO_OFFSET_P2] != 0)) { return SW_INCORRECT_P1_P2; @@ -51,9 +48,6 @@ unsigned short apdu_hash_sign() { return SW_INCORRECT_LENGTH; } - // Check state - set_check_internal_structure_integrity(0); - // Zcash special - store parameters for later if ((context_D.usingOverwinter) && @@ -64,13 +58,13 @@ unsigned short apdu_hash_sign() { parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; authorizationLength = *(parameters++); parameters += authorizationLength; - lockTime = read_u32(parameters, 1, 0); + lockTime = read_u32_be(parameters, 0); parameters += 4; sighashType = *(parameters++); - expiryHeight = read_u32(parameters, 1, 0); - write_u32_le(context_D.nLockTime, lockTime); - write_u32_le(context_D.sigHashType, sighashType); - write_u32_le(context_D.nExpiryHeight, expiryHeight); + expiryHeight = read_u32_be(parameters, 0); + write_u32_le(context_D.nLockTime, 0, lockTime); + write_u32_le(context_D.sigHashType, 0, sighashType); + write_u32_le(context_D.nExpiryHeight, 0, expiryHeight); context_D.overwinterSignReady = 1; return SW_OK; } @@ -99,34 +93,30 @@ unsigned short apdu_hash_sign() { parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; authorizationLength = *(parameters++); parameters += authorizationLength; - lockTime = read_u32(parameters, 1, 0); + lockTime = read_u32_be(parameters, 0); parameters += 4; sighashType = *(parameters++); context_D.transactionSummary.sighashType = sighashType; - if (((N_btchip.bkp.config.options & - OPTION_FREE_SIGHASHTYPE) == 0)) { // if bitcoin cash OR forkid is set, then use the fork id - if (G_coin_config->kind == COIN_KIND_BITCOIN_CASH || - (G_coin_config->forkid)) { + if (COIN_KIND == COIN_KIND_BITCOIN_CASH || (COIN_FORKID)) { #define SIGHASH_FORKID 0x40 - if (sighashType != (SIGHASH_ALL | SIGHASH_FORKID)) { - sw = SW_INCORRECT_DATA; - goto discardTransaction; - } - sighashType |= (G_coin_config->forkid << 8); - } else { - if (sighashType != SIGHASH_ALL) { - sw = SW_INCORRECT_DATA; - goto discardTransaction; - } + if (sighashType != (SIGHASH_ALL | SIGHASH_FORKID)) { + sw = SW_INCORRECT_DATA; + goto discardTransaction; + } + sighashType |= (COIN_FORKID << 8); + } else { + if (sighashType != SIGHASH_ALL) { + sw = SW_INCORRECT_DATA; + goto discardTransaction; } } // Finalize the hash if (!context_D.usingOverwinter) { - write_u32_le(dataBuffer, lockTime); - write_u32_le(dataBuffer + 4, sighashType); + write_u32_le(dataBuffer, 0, lockTime); + write_u32_le(dataBuffer, 4, sighashType); PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(dataBuffer), dataBuffer); if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, dataBuffer, sizeof(dataBuffer), NULL, 0)) { @@ -144,7 +134,7 @@ unsigned short apdu_hash_sign() { bagl_user_action_signtx(1, 1); } sw = SW_OK; - if (context_D.called_from_swap) { + if (G_called_from_swap) { // if we signed all outputs we should exit, // but only after sending response, so lets raise the // vars.swap_data.should_exit flag and check it on timer later @@ -154,12 +144,9 @@ unsigned short apdu_hash_sign() { } } - // Then discard the transaction and reply - set_check_internal_structure_integrity(1); return sw; discardTransaction: - set_check_internal_structure_integrity(1); context_D.transactionContext.transactionState = TRANSACTION_NONE; return sw; } @@ -188,8 +175,7 @@ void bagl_user_action_signtx(unsigned char confirming, unsigned char direct) { sizeof(context_D.transactionSummary.keyPath), hash, sizeof(hash), G_io_apdu_buffer, &out_len, - ((N_btchip.bkp.config.options & - OPTION_DETERMINISTIC_SIGNATURE) != 0)); + 1); context_D.outLength = G_io_apdu_buffer[1] + 2; G_io_apdu_buffer[context_D.outLength++] = context_D.transactionSummary.sighashType; diff --git a/src/apdu_set_operation_mode.c b/src/apdu_set_operation_mode.c deleted file mode 100644 index 7ab8a27b..00000000 --- a/src/apdu_set_operation_mode.c +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -// TODO BAGL : validate operation mode change - -#include "internal.h" -#include "apdu_constants.h" - -#define P1_DISABLE_KEYCARD 0x00 -#define P1_ENABLE_KEYCARD 0x01 -#define P1_ENABLE_KEYCARD_PERMANENTLY 0x02 - -unsigned short apdu_set_operation_mode() { - unsigned char operationMode; - - if (G_io_apdu_buffer[ISO_OFFSET_LC] != 0x01) { - return SW_INCORRECT_LENGTH; - } - - SB_CHECK(N_btchip.bkp.config.operationMode); - if ((SB_GET(N_btchip.bkp.config.operationMode) == - MODE_SETUP_NEEDED) || - (SB_GET(N_btchip.bkp.config.operationMode) == MODE_ISSUER)) { - return SW_CONDITIONS_OF_USE_NOT_SATISFIED; - } - - if (os_global_pin_is_validated() != BOLOS_UX_OK) { - return SW_SECURITY_STATUS_NOT_SATISFIED; - } - operationMode = G_io_apdu_buffer[ISO_OFFSET_CDATA]; - - if (operationMode == MODE_WALLET) { - } - - if (operationMode == SB_GET(N_btchip.bkp.config.operationMode)) { - return SW_OK; - } - - switch (operationMode) { - case MODE_WALLET: - case MODE_RELAXED_WALLET: - case MODE_SERVER: - case MODE_DEVELOPER: - break; - default: - return SW_INCORRECT_DATA; - } - - SB_CHECK(N_btchip.bkp.config.supportedModes); - if ((SB_GET(N_btchip.bkp.config.supportedModes) & operationMode) == 0) { - return SW_CONDITIONS_OF_USE_NOT_SATISFIED; - } - - // commit new operation - set_operation_mode(operationMode); - - return SW_OK; -} diff --git a/src/apdu_setup.c b/src/apdu_setup.c deleted file mode 100644 index 2e9cb88c..00000000 --- a/src/apdu_setup.c +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" -#include "apdu_constants.h" - -unsigned short apdu_setup() { - return SW_INS_NOT_SUPPORTED; -} - -// Setup with WALLET mode only, deterministic signatures only -void autosetup() { - config_t config; - unsigned char i; - unsigned char tmp[32]; - memset(&config, 0, sizeof(config_t)); - config.options |= OPTION_DETERMINISTIC_SIGNATURE; - config.options |= OPTION_SKIP_2FA_P2SH; // TODO : remove when - // supporting multi output - SB_SET(config.supportedModes, MODE_WALLET); - SB_SET(config.operationMode, MODE_WALLET); - - nvm_write((void *)&N_btchip.bkp.config, &config, sizeof(config)); - cx_rng(tmp, sizeof(tmp)); - nvm_write((void *)&N_btchip.bkp.trustedinput_key, tmp, sizeof(tmp)); - i = 1; - nvm_write((void *)&N_btchip.config_valid, &i, 1); -} diff --git a/src/apdu_sign_message.c b/src/apdu_sign_message.c index 21fa496d..9a5bbc54 100644 --- a/src/apdu_sign_message.c +++ b/src/apdu_sign_message.c @@ -18,6 +18,8 @@ #include "internal.h" #include "apdu_constants.h" #include "bagl_extensions.h" +#include "lib_standard_app/read.h" +#include "swap.h" #define P1_PREPARE 0x00 #define P1_SIGN 0x80 @@ -37,14 +39,8 @@ unsigned char checkBitId(unsigned char *bip32Path) { unsigned char i; unsigned char bip32PathLength = bip32Path[0]; bip32Path++; - /* - if ((bip32PathLength != 0) && (read_u32(bip32Path, 1, 0) == SLIP_13)) - { - return BITID_MULTIPLE; - } - */ for (i = 0; i < bip32PathLength; i++) { - unsigned short account = read_u32(bip32Path, 1, 0); + unsigned short account = read_u32_be(bip32Path, 0); bip32Path += 4; if (account == BITID_DERIVE) { @@ -75,10 +71,6 @@ unsigned short apdu_sign_message_internal() { } } - if (os_global_pin_is_validated() != BOLOS_UX_OK) { - return SW_SECURITY_STATUS_NOT_SATISFIED; - } - if (p1 == P1_PREPARE) { if ((p2 == P2_FIRST) || (p2 == P2_LEGACY)) { unsigned char chunkLength; @@ -91,10 +83,8 @@ unsigned short apdu_sign_message_internal() { sw = SW_INCORRECT_DATA; goto discard; } - context_D.transactionSummary.payToAddressVersion = - G_coin_config->p2pkh_version; - context_D.transactionSummary.payToScriptHashVersion = - G_coin_config->p2sh_version; + context_D.transactionSummary.payToAddressVersion = COIN_P2PKH_VERSION; + context_D.transactionSummary.payToScriptHashVersion = COIN_P2SH_VERSION; memmove( context_D.transactionSummary.keyPath, G_io_apdu_buffer + offset, MAX_BIP32_PATH_LENGTH); @@ -127,7 +117,7 @@ unsigned short apdu_sign_message_internal() { } // Horizen signed message magic header is "Zcash" // See https://github.com/HorizenOfficial/zen/blob/v5.0.0/src/main.cpp#L122 - const char* magicHeader = (G_coin_config->kind != COIN_KIND_HORIZEN) ? G_coin_config->coinid : "Zcash"; + const char* magicHeader = (COIN_KIND != COIN_KIND_HORIZEN) ? COIN_COINID : "Zcash"; chunkLength = strlen(magicHeader) + SIGNMAGIC_LENGTH; if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, @@ -245,7 +235,7 @@ unsigned short apdu_sign_message_internal() { } unsigned short apdu_sign_message() { - if (context_D.called_from_swap) { + if (G_called_from_swap) { return SW_SECURITY_STATUS_NOT_SATISFIED; } unsigned short sw = apdu_sign_message_internal(); @@ -275,8 +265,7 @@ unsigned short compute_hash() { sizeof(context_D.transactionSummary.keyPath), hash, sizeof(hash), // IN G_io_apdu_buffer, &out_len, // OUT - ((N_btchip.bkp.config.options & - OPTION_DETERMINISTIC_SIGNATURE) != 0)); + 1); context_D.outLength = G_io_apdu_buffer[1] + 2; memset(&context_D.transactionSummary, 0, sizeof(transaction_summary_t)); diff --git a/src/apdu_verify_pin.c b/src/apdu_verify_pin.c deleted file mode 100644 index 3d78f8f3..00000000 --- a/src/apdu_verify_pin.c +++ /dev/null @@ -1,23 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" -#include "apdu_constants.h" - -unsigned short apdu_verify_pin() { - return SW_INS_NOT_SUPPORTED; -} diff --git a/src/base58.c b/src/base58.c deleted file mode 100644 index 42e58e02..00000000 --- a/src/base58.c +++ /dev/null @@ -1,141 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" - -#define MAX_DEC_INPUT_SIZE 164 -#define MAX_ENC_INPUT_SIZE 120 - -int decode_base58(const char *in, size_t length, - unsigned char *out, size_t *outlen) { - unsigned char tmp[MAX_DEC_INPUT_SIZE]; - unsigned char buffer[MAX_DEC_INPUT_SIZE] = {0}; - unsigned char i; - unsigned char j; - unsigned char startAt; - unsigned char zeroCount = 0; - if ((length > MAX_DEC_INPUT_SIZE) || (length < 2)) { - return -1; - } - memmove(tmp, in, length); - PRINTF("To decode\n%.*H\n",length,tmp); - for (i = 0; i < length; i++) { - if (in[i] >= sizeof(BASE58TABLE)) { - return -1; - } - tmp[i] = BASE58TABLE[(int)in[i]]; - if (tmp[i] == 0xff) { - return -1; - } - } - while ((zeroCount < length) && (tmp[zeroCount] == 0)) { - ++zeroCount; - } - j = length; - startAt = zeroCount; - while (startAt < length) { - unsigned short remainder = 0; - unsigned char divLoop; - for (divLoop = startAt; divLoop < length; divLoop++) { - unsigned short digit256 = (unsigned short)(tmp[divLoop] & 0xff); - unsigned short tmpDiv = remainder * 58 + digit256; - tmp[divLoop] = (unsigned char)(tmpDiv / 256); - remainder = (tmpDiv % 256); - } - if (tmp[startAt] == 0) { - ++startAt; - } - buffer[--j] = (unsigned char)remainder; - } - while ((j < length) && (buffer[j] == 0)) { - ++j; - } - length = length - (j - zeroCount); - if (*outlen < length) { - PRINTF("Decode overflow %d %d\n", length, *outlen); - return -1; - } - - memmove(out, buffer + j - zeroCount, length); - PRINTF("Decoded\n%.*H\n",length,out); - *outlen = length; - return 0; -} - -int encode_base58(const unsigned char *in, size_t length, - unsigned char *out, size_t *outlen) { - size_t i = 0, j; - size_t startAt, stopAt; - size_t zeroCount = 0; - size_t outputSize; - - if (length > MAX_ENC_INPUT_SIZE) { - return -1; - } - - PRINTF("Length to encode %d\n", length); - PRINTF("To encode\n%.*H\n",length,in); - - while ((zeroCount < length) && (in[zeroCount] == 0)) { - ++zeroCount; - } - - outputSize = (length - zeroCount) * 138 / 100 + 1; - if (*outlen < outputSize) { - *outlen = outputSize; - return -1; - } - memset(out, 0, outputSize); - stopAt = outputSize - 1; - for (startAt = zeroCount; startAt < length; startAt++) { - int carry = in[startAt]; - for (j = outputSize - 1; (int)j >= 0; j--) { - carry += 256 * out[j]; - out[j] = carry % 58; - carry /= 58; - - if (j <= stopAt - 1 && carry == 0) { - break; - } - } - stopAt = j; - } - - j = 0; - while (j < outputSize && out[j] == 0) { - j += 1; - } - - if (*outlen < zeroCount + outputSize - j) { - *outlen = zeroCount + outputSize - j; - return -1; - } - *outlen = zeroCount + outputSize - j; - int distance = zeroCount - j; - if (distance < 0) { - for (i = zeroCount; i < *outlen; ++i) - out[i] = BASE58ALPHABET[out[i - distance]]; - } - else { - for (i = *outlen - 1; (int)i >= 0; --i) - out[i] = BASE58ALPHABET[out[i - distance]]; - } - memset(out, BASE58ALPHABET[0], zeroCount); - // PRINTF("Length encoded %d\n", i); - // PRINTF("Encoded\n%.*H\n",i,out); - return 0; -} diff --git a/src/bcd.c b/src/bcd.c index 9c200d29..a7878d0b 100644 --- a/src/bcd.c +++ b/src/bcd.c @@ -99,5 +99,5 @@ convert_hex_amount_to_displayable_no_globals(unsigned char *amount, unsigned int unsigned char convert_hex_amount_to_displayable(unsigned char *amount) { - return convert_hex_amount_to_displayable_no_globals(amount, G_coin_config->flags, context_D.tmp); + return convert_hex_amount_to_displayable_no_globals(amount, COIN_FLAGS, context_D.tmp); } diff --git a/src/bip32_path.c b/src/bip32_path.c index 4a8d08a0..8be5d787 100644 --- a/src/bip32_path.c +++ b/src/bip32_path.c @@ -1,3 +1,4 @@ +#include "lib_standard_app/read.h" #include "bip32_path.h" #include "helpers.h" @@ -9,7 +10,7 @@ bool parse_serialized_path(bip32_path_t* path, unsigned char* serialized_path, u path->length = serialized_path[0]; serialized_path++; for (int i = 0; i < path->length; i += 1, serialized_path += 4) { - path->path[i] = read_u32(serialized_path, 1, 0); + path->path[i] = read_u32_be(serialized_path, 0); } return true; } diff --git a/src/btchip.c b/src/btchip.c index d815e739..2d65d16f 100644 --- a/src/btchip.c +++ b/src/btchip.c @@ -14,6 +14,482 @@ * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ +#include "os.h" +#include "cx.h" + +#include "string.h" + +#include "internal.h" + +#include "bagl_extensions.h" + +#include "segwit_addr.h" +#include "cashaddr.h" + +#include "ux.h" +#include "display_variables.h" +#include "swap_lib_calls.h" + +#include "handle_swap_sign_transaction.h" +#include "handle_get_printable_amount.h" +#include "handle_check_address.h" +#include "ui.h" +#include "lib_standard_app/format.h" +#include "read.h" +#include "write.h" +#include "bip32.h" +#include "swap.h" + +unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { + switch (channel & ~(IO_FLAGS)) { + case CHANNEL_KEYBOARD: + break; + + // multiplexed io exchange over a SPI channel and TLV encapsulated protocol + case CHANNEL_SPI: + if (tx_len) { + io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); + + if (channel & IO_RESET_AFTER_REPLIED) { + reset(); + } + return 0; // nothing received from the master so far (it's a tx + // transaction) + } else { + return io_seproxyhal_spi_recv(G_io_apdu_buffer, + sizeof(G_io_apdu_buffer), 0); + } + + default: + THROW(INVALID_PARAMETER); + } + return 0; +} + +unsigned char io_event(unsigned char channel) { + UNUSED(channel); + // nothing done with the event, throw an error on the transport layer if + // needed + + // can't have more than one tag in the reply, not supported yet. + switch (G_io_seproxyhal_spi_buffer[0]) { +#ifdef HAVE_NBGL + case SEPROXYHAL_TAG_FINGER_EVENT: + UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); + break; +#endif // HAVE_NBGL + + case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: +#ifdef HAVE_BAGL + UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); +#endif // HAVE_BAGL + break; + + case SEPROXYHAL_TAG_STATUS_EVENT: + if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && + !(U4BE(G_io_seproxyhal_spi_buffer, 3) & + SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { + THROW(EXCEPTION_IO_RESET); + } + __attribute__((fallthrough)); + default: + UX_DEFAULT_EVENT(); + break; + + case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: +#ifdef HAVE_BAGL + UX_DISPLAYED_EVENT({}); +#endif // HAVE_BAGL +#ifdef HAVE_NBGL + UX_DEFAULT_EVENT(); +#endif // HAVE_NBGL + break; + + case SEPROXYHAL_TAG_TICKER_EVENT: + // TODO: found less hacky way to exit library after sending response + // this mechanism is used for Swap/Exchange functionality + // when application is in silent mode, and should return to caller, + // after responding some APDUs + UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {}); + break; + } + + // close the event if not done previously (by a display or whatever) + if (!io_seproxyhal_spi_is_status_sent()) { + io_seproxyhal_general_status(); + } + + // command has been processed, DO NOT reset the current APDU transport + return 1; +} + +uint8_t check_fee_swap() { + unsigned char fees[8]; + unsigned char borrow; + + borrow = transaction_amount_sub_be( + fees, context_D.transactionContext.transactionAmount, + context_D.totalOutputAmount); + if ((borrow != 0) || (memcmp(fees, vars.swap_data.fees, 8) != 0)) + return 0; + context_D.transactionContext.firstSigned = 0; + + if (context_D.usingSegwit && !context_D.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context_D.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + } else { + context_D.transactionContext.transactionState = + TRANSACTION_SIGN_READY; + } + context_D.sw = 0x9000; + context_D.outLength = 0; + G_io_apdu_buffer[context_D.outLength++] = 0x90; + G_io_apdu_buffer[context_D.outLength++] = 0x00; + + return 1; +} + +uint8_t prepare_fees(void) { + if (context_D.transactionContext.relaxed) { + memmove(vars.tmp.feesAmount, "UNKNOWN", 7); + vars.tmp.feesAmount[7] = '\0'; + } else { + unsigned char fees[8]; + unsigned short textSize; + unsigned char borrow; + + borrow = transaction_amount_sub_be( + fees, context_D.transactionContext.transactionAmount, + context_D.totalOutputAmount); + if (borrow && COIN_KIND == COIN_KIND_KOMODO) { + memmove(vars.tmp.feesAmount, "REWARD", 6); + vars.tmp.feesAmount[6] = '\0'; + } + else { + if (borrow) { + PRINTF("Error : Fees not consistent"); + goto error; + } + memmove(vars.tmp.feesAmount, COIN_COINID_SHORT, + strlen(COIN_COINID_SHORT)); + vars.tmp.feesAmount[strlen(COIN_COINID_SHORT)] = ' '; + context_D.tmp = + (unsigned char *)(vars.tmp.feesAmount + + strlen(COIN_COINID_SHORT) + 1); + textSize = convert_hex_amount_to_displayable(fees); + vars.tmp.feesAmount[textSize + strlen(COIN_COINID_SHORT) + 1] = + '\0'; + } + } + return 1; +error: + return 0; +} + +#define OMNI_ASSETID 1 +#define MAIDSAFE_ASSETID 3 +#define USDT_ASSETID 31 + +void get_address_from_output_script(unsigned char* script, int script_size, char* out, int out_size) { + if (output_script_is_op_return(script)) { + strncpy(out, "OP_RETURN", out_size); + return; + } + if ((COIN_KIND == COIN_KIND_HYDRA) && + output_script_is_op_create(script, script_size)) { + strncpy(out, "OP_CREATE", out_size); + return; + } + if ((COIN_KIND == COIN_KIND_HYDRA) && + output_script_is_op_call(script, script_size)) { + strncpy(out, "OP_CALL", out_size); + return; + } + if (output_script_is_native_witness(script)) { + if (COIN_NATIVE_SEGWIT_PREFIX) { + segwit_addr_encode( + out, (char *)PIC(COIN_NATIVE_SEGWIT_PREFIX), 0, + script + OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET, + script[OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET - 1]); + } + return; + } + unsigned char versionSize; + unsigned char address[22]; + unsigned short textSize; + int addressOffset = 3; + unsigned short version = COIN_P2SH_VERSION; + + if (output_script_is_regular(script)) { + addressOffset = 4; + version = COIN_P2PKH_VERSION; + } + + if (version > 255) { + versionSize = 2; + address[0] = (version >> 8); + address[1] = version; + } else { + versionSize = 1; + address[0] = version; + } + memmove(address + versionSize, script + addressOffset, 20); + + // Prepare address + if (context_D.usingCashAddr) { + cashaddr_encode( + address + versionSize, 20, (uint8_t *)out, out_size, + (version == COIN_P2SH_VERSION + ? CASHADDR_P2SH + : CASHADDR_P2PKH)); + } else { + textSize = public_key_to_encoded_base58( + address, 20 + versionSize, (unsigned char *)out, + out_size, version, 1); + out[textSize] = '\0'; + } +} + +uint8_t prepare_single_output(void) { + // TODO : special display for OP_RETURN + unsigned char amount[8]; + unsigned int offset = 0; + unsigned short textSize; + char tmp[80] = {0}; + + swap_bytes(amount, context_D.currentOutput + offset, 8); + offset += 8; + + get_address_from_output_script(context_D.currentOutput + offset, sizeof(context_D.currentOutput) - offset, tmp, sizeof(tmp)); + strncpy(vars.tmp.fullAddress, tmp, sizeof(vars.tmp.fullAddress) - 1); + + // Prepare amount + + // Handle Omni simple send + if ((context_D.currentOutput[offset + 2] == 0x14) && + (memcmp(context_D.currentOutput + offset + 3, "omni", 4) == 0) && + (memcmp(context_D.currentOutput + offset + 3 + 4, "\0\0\0\0", 4) == 0)) { + uint8_t headerLength; + uint32_t omniAssetId = read_u32_be(context_D.currentOutput, offset + 3 + 4 + 4); + switch(omniAssetId) { + case OMNI_ASSETID: + strcpy(vars.tmp.fullAmount, "OMNI "); + break; + case USDT_ASSETID: + strcpy(vars.tmp.fullAmount, "USDT "); + break; + case MAIDSAFE_ASSETID: + strcpy(vars.tmp.fullAmount, "MAID "); + break; + default: + snprintf(vars.tmp.fullAmount, sizeof(vars.tmp.fullAmount), "OMNI asset %d ", omniAssetId); + break; + } + headerLength = strlen(vars.tmp.fullAmount); + context_D.tmp = (uint8_t *)vars.tmp.fullAmount + headerLength; + textSize = convert_hex_amount_to_displayable(context_D.currentOutput + offset + 3 + 4 + 4 + 4); + vars.tmp.fullAmount[textSize + headerLength] = '\0'; + } + else { + memmove(vars.tmp.fullAmount, COIN_COINID_SHORT, + strlen(COIN_COINID_SHORT)); + vars.tmp.fullAmount[strlen(COIN_COINID_SHORT)] = ' '; + context_D.tmp = + (unsigned char *)(vars.tmp.fullAmount + + strlen(COIN_COINID_SHORT) + 1); + textSize = convert_hex_amount_to_displayable(amount); + vars.tmp.fullAmount[textSize + strlen(COIN_COINID_SHORT) + 1] = + '\0'; + } + + return 1; +} + +uint8_t prepare_message_signature(void) { + uint8_t buffer[32]; + + if (cx_hash_no_throw(&context_D.transactionHashAuthorization.header, CX_LAST, + (uint8_t*)vars.tmp.fullAmount, 0, buffer, 32)) { + return 0; + } + + format_hex((const uint8_t*) buffer, sizeof(buffer), vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress)); + + return 1; +} + + +extern bool handle_output_state(void); +extern void apdu_hash_input_finalize_full_reset(void); + +// Analog of bagl_confirm_single_output to work +// in silent mode, when called from SWAP app +unsigned int silent_confirm_single_output() { + char tmp[80] = {0}; + unsigned char amount[8]; + while (true) { + // in swap operation we can only have 1 "external" output + if (vars.swap_data.was_address_checked) { + PRINTF("Address was already checked\n"); + return 0; + } + vars.swap_data.was_address_checked = 1; + // check amount + swap_bytes(amount, context_D.currentOutput, 8); + if (memcmp(amount, vars.swap_data.amount, 8) != 0) { + PRINTF("Amount not matched\n"); + return 0; + } + get_address_from_output_script(context_D.currentOutput + 8, sizeof(context_D.currentOutput) - 8, tmp, sizeof(tmp)); + if (strcmp(tmp, vars.swap_data.destination_address) != 0) { + PRINTF("Address not matched\n"); + return 0; + } + + // Check if all inputs have been confirmed + + if (context_D.outputParsingState == + OUTPUT_PARSING_OUTPUT) { + context_D.remainingOutputs--; + if (context_D.remainingOutputs == 0) + break; + } + + memmove(context_D.currentOutput, + context_D.currentOutput + + context_D.discardSize, + context_D.currentOutputOffset - + context_D.discardSize); + context_D.currentOutputOffset -= context_D.discardSize; + context_D.io_flags &= ~IO_ASYNCH_REPLY; + while (handle_output_state() && + (!(context_D.io_flags & IO_ASYNCH_REPLY))) + ; + if (!(context_D.io_flags & IO_ASYNCH_REPLY)) { + // Out of data to process, wait for the next call + break; + } + } + + if ((context_D.outputParsingState == OUTPUT_PARSING_OUTPUT) && + (context_D.remainingOutputs == 0)) { + context_D.outputParsingState = OUTPUT_FINALIZE_TX; + // check fees + unsigned char fees[8]; + + if ((transaction_amount_sub_be(fees, + context_D.transactionContext.transactionAmount, + context_D.totalOutputAmount) != 0) || + (memcmp(fees, vars.swap_data.fees, 8) != 0)) { + PRINTF("Fees is not matched\n"); + return 0; + } + } + + if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { + context_D.transactionContext.firstSigned = 0; + + if (context_D.usingSegwit && + !context_D.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context_D.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context_D.transactionContext.transactionState = + TRANSACTION_NONE; + } else { + context_D.transactionContext.transactionState = + TRANSACTION_SIGN_READY; + } + } + if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { + // we've finished the processing of the input + apdu_hash_input_finalize_full_reset(); + } + + return 1; +} + +unsigned int bagl_confirm_single_output(void) { + if (G_called_from_swap) { + return silent_confirm_single_output(); + } + if (!prepare_single_output()) { + return 0; + } + + ui_confirm_single_flow(); + return 1; +} + +unsigned int bagl_finalize_tx(void) { + if (G_called_from_swap) { + return check_fee_swap(); + } + + if (!prepare_fees()) { + return 0; + } + + ui_finalize_flow(); + return 1; +} + +void bagl_confirm_message_signature(void) { + if (!prepare_message_signature()) { + return; + } + + ui_sign_message_flow(); +} + +uint8_t set_key_path_to_display(unsigned char* keyPath) { + bip32_print_path(keyPath, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); + return bip44_derivation_guard(keyPath, false); +} + +void bagl_display_public_key(uint8_t is_derivation_path_unusual) { + // append a white space at the end of the address to avoid glitch on nano S + strlcat((char *)G_io_apdu_buffer + 200, " ", sizeof(G_io_apdu_buffer) - 200); + + if (is_derivation_path_unusual) { + ui_display_public_with_warning_flow(); + } + else { + ui_display_public_flow(); + } +} + +void bagl_display_token(void) +{ + ui_display_token_flow(); +} + +void bagl_request_pubkey_approval(void) +{ + ui_request_pubkey_approval_flow(); +} + +void bagl_request_change_path_approval(unsigned char* change_path) +{ + + bip32_print_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); + ui_request_change_path_approval_flow(); +} + +void bagl_request_sign_path_approval(unsigned char* change_path) +{ + bip32_print_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); + ui_request_sign_path_approval_flow(); +} + +void bagl_request_segwit_input_approval(void) +{ + ui_request_segwit_input_approval_flow(); +} + #include "os.h" @@ -39,13 +515,6 @@ void app_dispatch(void) { context_D.outLength = 0; context_D.io_flags = 0; - // If halted, then notify - SB_CHECK(context_D.halted); - if (SB_GET(context_D.halted)) { - context_D.sw = SW_TECHNICAL_PROBLEM; - goto sendSW; - } - cla = G_io_apdu_buffer[ISO_OFFSET_CLA]; ins = G_io_apdu_buffer[ISO_OFFSET_INS]; for (dispatched = 0; dispatched < DISPATCHER_APDUS; dispatched++) { @@ -78,7 +547,7 @@ void app_dispatch(void) { #endif // IO_APP_ACTIVITY sendSW: - if (context_D.called_from_swap) { + if (G_called_from_swap) { context_D.io_flags &= ~IO_ASYNCH_REPLY; if(context_D.sw != SW_OK) { vars.swap_data.should_exit = 1; @@ -94,6 +563,10 @@ void app_dispatch(void) { } void app_main(void) { + context_init(); + + ui_idle_flow(); + memset(G_io_apdu_buffer, 0, 255); // paranoia // Process the incoming APDUs @@ -105,7 +578,7 @@ void app_main(void) { // memset(G_io_apdu_buffer, 0, 255); // paranoia - if (context_D.called_from_swap && vars.swap_data.should_exit) { + if (G_called_from_swap && vars.swap_data.should_exit) { context_D.io_flags |= IO_RETURN_AFTER_TX; } @@ -115,8 +588,8 @@ void app_main(void) { // use the previous outlength as the reply context_D.outLength); - if (context_D.called_from_swap && vars.swap_data.should_exit) { - finalize_exchange_sign_transaction(context_D.sw == SW_OK); + if (G_called_from_swap && vars.swap_data.should_exit) { + swap_finalize_exchange_sign_transaction(context_D.sw == SW_OK); } PRINTF("New APDU received:\n%.*H\n", context_D.inLength, G_io_apdu_buffer); diff --git a/src/context.c b/src/context.c index bb176cf6..3ff49151 100644 --- a/src/context.c +++ b/src/context.c @@ -16,6 +16,7 @@ ********************************************************************************/ #include "internal.h" +#include "swap.h" void autosetup(void); @@ -26,32 +27,11 @@ void context_init() { PRINTF("Context init\n"); PRINTF("Backup size %d\n", sizeof(N_btchip.bkp)); memset(&context_D, 0, sizeof(context_D)); - SB_SET(context_D.halted, 0); - context_D.called_from_swap = 0; + G_called_from_swap = 0; context_D.currentOutputOffset = 0; context_D.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; memset(context_D.totalOutputAmount, 0, sizeof(context_D.totalOutputAmount)); context_D.changeOutputFound = 0; context_D.segwitWarningSeen = 0; - - if (N_btchip.config_valid != 0x01) { - autosetup(); - } - - if (!N_btchip.config_valid) { - unsigned char defaultMode; - PRINTF("No configuration found\n"); - defaultMode = MODE_SETUP_NEEDED; - - set_operation_mode(defaultMode); - } else { - SB_CHECK(N_btchip.bkp.config.operationMode); - } - if (!N_btchip.storageInitialized) { - unsigned char initialized = 1, denied=1; - - nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &denied, 1); - nvm_write((void *)&N_btchip.storageInitialized, &initialized, 1); - } } diff --git a/src/display_variables.h b/src/display_variables.h index a7655cc1..c0ac6f8f 100644 --- a/src/display_variables.h +++ b/src/display_variables.h @@ -1,6 +1,7 @@ #ifndef _DISPLAY_VARIABLES_H_ #define _DISPLAY_VARIABLES_H_ +#include "os.h" // A path contains 10 elements max, which max length in ascii is 1 whitespace + 10 char + optional quote "'" + "/" + \0" #define MAX_DERIV_PATH_ASCII_LENGTH 1 + 10*(10+2) + 1 #define MAX_CHAR_PER_LINE 25 @@ -12,6 +13,7 @@ typedef struct swap_data_s { // number of already signed input in the transaction, to compare with // totalNumberOfInputs and exit properly int alreadySignedInputs; + int initialized; unsigned char amount[8]; unsigned char fees[8]; char destination_address[65]; diff --git a/src/filesystem.c b/src/filesystem.c deleted file mode 100644 index 11a12efe..00000000 --- a/src/filesystem.c +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" - -#include "public_ram_variables.h" - -void set_operation_mode(unsigned char operationMode) { - secu8 opMode; - SB_SET(opMode, operationMode); - - // only modify operation mode - nvm_write((void *)&N_btchip.bkp.config.operationMode, &opMode, - sizeof(opMode)); -} diff --git a/src/handle_swap_sign_transaction.c b/src/handle_swap_sign_transaction.c deleted file mode 100644 index 9cfe9473..00000000 --- a/src/handle_swap_sign_transaction.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "handle_swap_sign_transaction.h" -#include "os_io_seproxyhal.h" -#include "public_ram_variables.h" -#include "display_variables.h" -#include "context.h" -#include "usbd_core.h" -#include "ux.h" - -#ifdef HAVE_NBGL -#include "nbgl_use_case.h" -#endif - -// Save the BSS address where we will write the return value when finished -static uint8_t *G_swap_sign_return_value_address; - -bool copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params) { - // first copy parameters to stack, and then to global data. - // We need this "trick" as the input data position can overlap with btc-app globals - swap_data_t stack_data; - memset(&stack_data, 0, sizeof(stack_data)); - strncpy(stack_data.destination_address, sign_transaction_params->destination_address, sizeof(stack_data.destination_address) - 1); - if ((stack_data.destination_address[sizeof(stack_data.destination_address) - 1] != '\0') || - (sign_transaction_params->amount_length > 8) || - (sign_transaction_params->fee_amount_length > 8)) { - return false; - } - // store amount as big endian in 8 bytes, so the passed data should be alligned to right - // input {0xEE, 0x00, 0xFF} should be stored like {0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x00, 0xFF} - memcpy(stack_data.amount + 8 - sign_transaction_params->amount_length, sign_transaction_params->amount, sign_transaction_params->amount_length); - memcpy(stack_data.fees + 8 - sign_transaction_params->fee_amount_length, sign_transaction_params->fee_amount, sign_transaction_params->fee_amount_length); - - // Erase values inherited from Exchange app - os_explicit_zero_BSS_segment(); - - // Keep the address at which we'll reply the signing status - G_swap_sign_return_value_address = &sign_transaction_params->result; - - // Copy from stack back to global data segment - memcpy(&vars.swap_data, &stack_data, sizeof(stack_data)); - return true; -} - -void handle_swap_sign_transaction(altcoin_config_t *config) { - G_coin_config = config; - context_init(); - context_D.called_from_swap = 1; - io_seproxyhal_init(); - UX_INIT(); -#ifdef HAVE_NBGL - nbgl_useCaseSpinner("Signing"); -#endif // HAVE_BAGL - USB_power(0); - USB_power(1); - //ui_idle(); - PRINTF("USB power ON/OFF\n"); -#ifdef TARGET_NANOX - // grab the current plane mode setting - G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); -#endif // TARGET_NANOX -#ifdef HAVE_BLE - BLE_power(0, NULL); - BLE_power(1, "Nano X"); -#endif // HAVE_BLE - app_main(); -} - -void __attribute__((noreturn)) finalize_exchange_sign_transaction(bool is_success) { - *G_swap_sign_return_value_address = is_success; - os_lib_end(); -} diff --git a/src/handle_swap_sign_transaction.h b/src/handle_swap_sign_transaction.h deleted file mode 100644 index c66caacc..00000000 --- a/src/handle_swap_sign_transaction.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _HANDLE_SWAP_SIGN_TRANSACTION_H_ -#define _HANDLE_SWAP_SIGN_TRANSACTION_H_ - -#include "swap_lib_calls.h" -#include "context.h" - -bool copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params); - -void handle_swap_sign_transaction(altcoin_config_t *config); - -void __attribute__((noreturn)) finalize_exchange_sign_transaction(bool is_success); - -#endif // _HANDLE_SWAP_SIGN_TRANSACTION_H_ diff --git a/src/helpers.c b/src/helpers.c index fa9c5976..605acb06 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -18,6 +18,8 @@ #include "internal.h" #include "apdu_constants.h" #include "lib_standard_app/crypto_helpers.h" +#include "lib_standard_app/read.h" +#include "lib_standard_app/base58.h" #include "bip32_path.h" #include "ledger_assert.h" @@ -62,7 +64,7 @@ const unsigned char ZEN_OUTPUT_SCRIPT_POST[] = { }; // BIP0115 Replay Protection unsigned char output_script_is_regular(unsigned char *buffer) { - if (G_coin_config->native_segwit_prefix) { + if (COIN_NATIVE_SEGWIT_PREFIX) { if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, @@ -77,7 +79,7 @@ unsigned char output_script_is_regular(unsigned char *buffer) { sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { return 1; } - if (G_coin_config->kind == COIN_KIND_HORIZEN) { + if (COIN_KIND == COIN_KIND_HORIZEN) { if ((memcmp(buffer, ZEN_OUTPUT_SCRIPT_PRE, sizeof(ZEN_OUTPUT_SCRIPT_PRE)) == 0) && (memcmp(buffer + sizeof(ZEN_OUTPUT_SCRIPT_PRE) + 20, @@ -98,7 +100,7 @@ unsigned char output_script_is_p2sh(unsigned char *buffer) { sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { return 1; } - if (G_coin_config->kind == COIN_KIND_HORIZEN) { + if (COIN_KIND == COIN_KIND_HORIZEN) { if ((memcmp(buffer, ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && (memcmp(buffer + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, @@ -111,7 +113,7 @@ unsigned char output_script_is_p2sh(unsigned char *buffer) { } unsigned char output_script_is_native_witness(unsigned char *buffer) { - if (G_coin_config->native_segwit_prefix) { + if (COIN_NATIVE_SEGWIT_PREFIX) { if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, @@ -123,7 +125,7 @@ unsigned char output_script_is_native_witness(unsigned char *buffer) { } unsigned char output_script_is_op_return(unsigned char *buffer) { - if (G_coin_config->kind == COIN_KIND_BITCOIN_CASH) { + if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { return ((buffer[1] == 0x6A) || ((buffer[1] == 0x00) && (buffer[2] == 0x6A))); } else { @@ -151,64 +153,6 @@ unsigned char output_script_is_op_call(unsigned char *buffer, return output_script_is_op_create_or_call(buffer, size, 0xC2); } -unsigned char rng_u8_modulo(unsigned char modulo) { - unsigned int rng_max = 256 % modulo; - unsigned int rng_limit = 256 - rng_max; - unsigned char candidate; - while ((candidate = cx_rng_u8()) > rng_limit) - ; - return (candidate % modulo); -} - -unsigned char secure_memcmp(const void *buf1, const void *buf2, - unsigned short length) { - unsigned char error = 0; - while (length--) { - error |= ((unsigned char *)buf1)[length] ^ - ((unsigned char *)buf2)[length]; - } - if (length != 0xffff) { - return 1; - } - return error; -} - -unsigned long int read_u32(unsigned char *buffer, unsigned char be, - unsigned char skipSign) { - unsigned char i; - unsigned long int result = 0; - unsigned char shiftValue = (be ? 24 : 0); - for (i = 0; i < 4; i++) { - unsigned char x = (unsigned char)buffer[i]; - if ((i == 0) && skipSign) { - x &= 0x7f; - } - result += ((unsigned long int)x) << shiftValue; - if (be) { - shiftValue -= 8; - } else { - shiftValue += 8; - } - } - return result; -} - -void write_u32_be(unsigned char *buffer, unsigned long int value) { - buffer[0] = ((value >> 24) & 0xff); - buffer[1] = ((value >> 16) & 0xff); - buffer[2] = ((value >> 8) & 0xff); - buffer[3] = (value & 0xff); -} - -void write_u32_le(unsigned char *buffer, unsigned long int value) { - buffer[0] = (value & 0xff); - buffer[1] = ((value >> 8) & 0xff); - buffer[2] = ((value >> 16) & 0xff); - buffer[3] = ((value >> 24) & 0xff); -} - - - void public_key_hash160(unsigned char *in, unsigned short inlen, unsigned char *out) { cx_ripemd160_t riprip; @@ -252,8 +196,8 @@ unsigned short public_key_to_encoded_base58( compute_checksum(tmpBuffer, 20 + versionSize, tmpBuffer + 20 + versionSize); - outputLen = outlen; - if (encode_base58(tmpBuffer, 24 + versionSize, out, &outputLen) < 0) { + outputLen = base58_encode(tmpBuffer, 24 + versionSize, (char *)out, outlen); + if (outputLen < 0) { THROW(EXCEPTION); } return outputLen; @@ -267,30 +211,6 @@ void swap_bytes(unsigned char *target, unsigned char *source, } } -unsigned short decode_base58_address(unsigned char *in, - unsigned short inlen, - unsigned char *out, - unsigned short outlen) { - unsigned char hashBuffer[32]; - size_t outputLen = outlen; - if (decode_base58((char *)in, inlen, out, &outputLen) < 0) { - THROW(EXCEPTION); - } - outlen = outputLen; - - // Compute hash to verify address - cx_hash_sha256(out, outlen - 4, hashBuffer, 32); - - cx_hash_sha256(hashBuffer, 32, hashBuffer, 32); - - if (memcmp(out + outlen - 4, hashBuffer, 4)) { - PRINTF("Hash checksum mismatch\n%.*H\n",sizeof(hashBuffer),hashBuffer); - THROW(INVALID_CHECKSUM); - } - - return outlen; -} - /* Checks if the values of a derivation path are within "normal" (arbitrary) ranges: Account < 100, change == 1 or 0, address index < 50000 @@ -314,9 +234,9 @@ unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_pa } // If the coin type doesn't match, return a warning - if ((G_coin_config->bip44_coin_type != 0) && - (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != G_coin_config->bip44_coin_type) && - ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != G_coin_config->bip44_coin_type2))) { + if ((BIP44_COIN_TYPE != 0) && + (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != BIP44_COIN_TYPE) && + ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != BIP44_COIN_TYPE_2))) { return 1; } @@ -337,7 +257,7 @@ Returns 0 if the path is non compliant, or 1 if compliant unsigned char enforce_bip44_coin_type(unsigned char *bip32Path, bool for_pubkey) { bip32_path_t bip32PathInt; // No enforcement required - if (G_coin_config->bip44_coin_type == 0) { + if (BIP44_COIN_TYPE == 0) { return 1; } // Path is too short - always require a user validation if signing @@ -356,8 +276,8 @@ unsigned char enforce_bip44_coin_type(unsigned char *bip32Path, bool for_pubkey) return for_pubkey; } - if (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == G_coin_config->bip44_coin_type) || - ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == G_coin_config->bip44_coin_type2)) { + if (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == BIP44_COIN_TYPE) || + ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == BIP44_COIN_TYPE_2)) { // Valid BIP 44 path return 1; } @@ -382,7 +302,7 @@ unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned cha out[0] = ' '; offset=1; for (i = 0; i < bip32PathLength; i++) { - current_level = read_u32(bip32Path, 1, 0); + current_level = read_u32_be(bip32Path, 0); hardened = (bool)(current_level & 0x80000000); if(hardened) { //remove hardening flag diff --git a/src/internal.h b/src/internal.h index eeb7ff7e..1b84471e 100644 --- a/src/internal.h +++ b/src/internal.h @@ -22,7 +22,6 @@ #include "public_ram_variables.h" #include "rom_variables.h" #include "filesystem.h" -#include "base58.h" #include "bcd.h" #include "ecc.h" #include "helpers.h" diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 9454ccbe..00000000 --- a/src/main.c +++ /dev/null @@ -1,706 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#include "os.h" -#include "cx.h" - -#include "string.h" - -#include "internal.h" - -#include "bagl_extensions.h" - -#include "segwit_addr.h" -#include "cashaddr.h" - -#include "ux.h" -#include "display_variables.h" -#include "swap_lib_calls.h" - -#include "swap_lib_calls.h" -#include "handle_swap_sign_transaction.h" -#include "handle_get_printable_amount.h" -#include "handle_check_address.h" -#include "ui.h" -#include "lib_standard_app/format.h" - -#define __NAME3(a, b, c) a##b##c -#define NAME3(a, b, c) __NAME3(a, b, c) - -unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; -bolos_ux_params_t G_ux_params; -ux_state_t G_ux; - -unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { - switch (channel & ~(IO_FLAGS)) { - case CHANNEL_KEYBOARD: - break; - - // multiplexed io exchange over a SPI channel and TLV encapsulated protocol - case CHANNEL_SPI: - if (tx_len) { - io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); - - if (channel & IO_RESET_AFTER_REPLIED) { - reset(); - } - return 0; // nothing received from the master so far (it's a tx - // transaction) - } else { - return io_seproxyhal_spi_recv(G_io_apdu_buffer, - sizeof(G_io_apdu_buffer), 0); - } - - default: - THROW(INVALID_PARAMETER); - } - return 0; -} - -unsigned char io_event(unsigned char channel) { - UNUSED(channel); - // nothing done with the event, throw an error on the transport layer if - // needed - - // can't have more than one tag in the reply, not supported yet. - switch (G_io_seproxyhal_spi_buffer[0]) { -#ifdef HAVE_NBGL - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; -#endif // HAVE_NBGL - - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: -#ifdef HAVE_BAGL - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); -#endif // HAVE_BAGL - break; - - case SEPROXYHAL_TAG_STATUS_EVENT: - if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && - !(U4BE(G_io_seproxyhal_spi_buffer, 3) & - SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { - THROW(EXCEPTION_IO_RESET); - } - __attribute__((fallthrough)); - default: - UX_DEFAULT_EVENT(); - break; - - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: -#ifdef HAVE_BAGL - UX_DISPLAYED_EVENT({}); -#endif // HAVE_BAGL -#ifdef HAVE_NBGL - UX_DEFAULT_EVENT(); -#endif // HAVE_NBGL - break; - - case SEPROXYHAL_TAG_TICKER_EVENT: - // TODO: found less hacky way to exit library after sending response - // this mechanism is used for Swap/Exchange functionality - // when application is in silent mode, and should return to caller, - // after responding some APDUs - UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {}); - break; - } - - // close the event if not done previously (by a display or whatever) - if (!io_seproxyhal_spi_is_status_sent()) { - io_seproxyhal_general_status(); - } - - // command has been processed, DO NOT reset the current APDU transport - return 1; -} - -uint8_t check_fee_swap() { - unsigned char fees[8]; - unsigned char borrow; - - borrow = transaction_amount_sub_be( - fees, context_D.transactionContext.transactionAmount, - context_D.totalOutputAmount); - if ((borrow != 0) || (memcmp(fees, vars.swap_data.fees, 8) != 0)) - return 0; - context_D.transactionContext.firstSigned = 0; - - if (context_D.usingSegwit && !context_D.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context_D.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - } else { - context_D.transactionContext.transactionState = - TRANSACTION_SIGN_READY; - } - context_D.sw = 0x9000; - context_D.outLength = 0; - G_io_apdu_buffer[context_D.outLength++] = 0x90; - G_io_apdu_buffer[context_D.outLength++] = 0x00; - - return 1; -} - -uint8_t prepare_fees() { - if (context_D.transactionContext.relaxed) { - memmove(vars.tmp.feesAmount, "UNKNOWN", 7); - vars.tmp.feesAmount[7] = '\0'; - } else { - unsigned char fees[8]; - unsigned short textSize; - unsigned char borrow; - - borrow = transaction_amount_sub_be( - fees, context_D.transactionContext.transactionAmount, - context_D.totalOutputAmount); - if (borrow && G_coin_config->kind == COIN_KIND_KOMODO) { - memmove(vars.tmp.feesAmount, "REWARD", 6); - vars.tmp.feesAmount[6] = '\0'; - } - else { - if (borrow) { - PRINTF("Error : Fees not consistent"); - goto error; - } - memmove(vars.tmp.feesAmount, G_coin_config->name_short, - strlen(G_coin_config->name_short)); - vars.tmp.feesAmount[strlen(G_coin_config->name_short)] = ' '; - context_D.tmp = - (unsigned char *)(vars.tmp.feesAmount + - strlen(G_coin_config->name_short) + 1); - textSize = convert_hex_amount_to_displayable(fees); - vars.tmp.feesAmount[textSize + strlen(G_coin_config->name_short) + 1] = - '\0'; - } - } - return 1; -error: - return 0; -} - -#define OMNI_ASSETID 1 -#define MAIDSAFE_ASSETID 3 -#define USDT_ASSETID 31 - -void get_address_from_output_script(unsigned char* script, int script_size, char* out, int out_size) { - if (output_script_is_op_return(script)) { - strncpy(out, "OP_RETURN", out_size); - return; - } - if ((G_coin_config->kind == COIN_KIND_HYDRA) && - output_script_is_op_create(script, script_size)) { - strncpy(out, "OP_CREATE", out_size); - return; - } - if ((G_coin_config->kind == COIN_KIND_HYDRA) && - output_script_is_op_call(script, script_size)) { - strncpy(out, "OP_CALL", out_size); - return; - } - if (output_script_is_native_witness(script)) { - if (G_coin_config->native_segwit_prefix) { - segwit_addr_encode( - out, (char *)PIC(G_coin_config->native_segwit_prefix), 0, - script + OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET, - script[OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET - 1]); - } - return; - } - unsigned char versionSize; - unsigned char address[22]; - unsigned short textSize; - int addressOffset = 3; - unsigned short version = G_coin_config->p2sh_version; - - if (output_script_is_regular(script)) { - addressOffset = 4; - version = G_coin_config->p2pkh_version; - } - - if (version > 255) { - versionSize = 2; - address[0] = (version >> 8); - address[1] = version; - } else { - versionSize = 1; - address[0] = version; - } - memmove(address + versionSize, script + addressOffset, 20); - - // Prepare address - if (context_D.usingCashAddr) { - cashaddr_encode( - address + versionSize, 20, (uint8_t *)out, out_size, - (version == G_coin_config->p2sh_version - ? CASHADDR_P2SH - : CASHADDR_P2PKH)); - } else { - textSize = public_key_to_encoded_base58( - address, 20 + versionSize, (unsigned char *)out, - out_size, version, 1); - out[textSize] = '\0'; - } -} - -uint8_t prepare_single_output() { - // TODO : special display for OP_RETURN - unsigned char amount[8]; - unsigned int offset = 0; - unsigned short textSize; - char tmp[80] = {0}; - - swap_bytes(amount, context_D.currentOutput + offset, 8); - offset += 8; - - get_address_from_output_script(context_D.currentOutput + offset, sizeof(context_D.currentOutput) - offset, tmp, sizeof(tmp)); - strncpy(vars.tmp.fullAddress, tmp, sizeof(vars.tmp.fullAddress) - 1); - - // Prepare amount - - // Handle Omni simple send - if ((context_D.currentOutput[offset + 2] == 0x14) && - (memcmp(context_D.currentOutput + offset + 3, "omni", 4) == 0) && - (memcmp(context_D.currentOutput + offset + 3 + 4, "\0\0\0\0", 4) == 0)) { - uint8_t headerLength; - uint32_t omniAssetId = read_u32(context_D.currentOutput + offset + 3 + 4 + 4, 1, 0); - switch(omniAssetId) { - case OMNI_ASSETID: - strcpy(vars.tmp.fullAmount, "OMNI "); - break; - case USDT_ASSETID: - strcpy(vars.tmp.fullAmount, "USDT "); - break; - case MAIDSAFE_ASSETID: - strcpy(vars.tmp.fullAmount, "MAID "); - break; - default: - snprintf(vars.tmp.fullAmount, sizeof(vars.tmp.fullAmount), "OMNI asset %d ", omniAssetId); - break; - } - headerLength = strlen(vars.tmp.fullAmount); - context_D.tmp = (uint8_t *)vars.tmp.fullAmount + headerLength; - textSize = convert_hex_amount_to_displayable(context_D.currentOutput + offset + 3 + 4 + 4 + 4); - vars.tmp.fullAmount[textSize + headerLength] = '\0'; - } - else { - memmove(vars.tmp.fullAmount, G_coin_config->name_short, - strlen(G_coin_config->name_short)); - vars.tmp.fullAmount[strlen(G_coin_config->name_short)] = ' '; - context_D.tmp = - (unsigned char *)(vars.tmp.fullAmount + - strlen(G_coin_config->name_short) + 1); - textSize = convert_hex_amount_to_displayable(amount); - vars.tmp.fullAmount[textSize + strlen(G_coin_config->name_short) + 1] = - '\0'; - } - - return 1; -} - -uint8_t prepare_message_signature() { - uint8_t buffer[32]; - - if (cx_hash_no_throw(&context_D.transactionHashAuthorization.header, CX_LAST, - (uint8_t*)vars.tmp.fullAmount, 0, buffer, 32)) { - return 0; - } - - format_hex((const uint8_t*) buffer, sizeof(buffer), vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress)); - - return 1; -} - - -extern bool handle_output_state(); -extern void apdu_hash_input_finalize_full_reset(void); - -// Analog of bagl_confirm_single_output to work -// in silent mode, when called from SWAP app -unsigned int silent_confirm_single_output() { - char tmp[80] = {0}; - unsigned char amount[8]; - while (true) { - // in swap operation we can only have 1 "external" output - if (vars.swap_data.was_address_checked) { - PRINTF("Address was already checked\n"); - return 0; - } - vars.swap_data.was_address_checked = 1; - // check amount - swap_bytes(amount, context_D.currentOutput, 8); - if (memcmp(amount, vars.swap_data.amount, 8) != 0) { - PRINTF("Amount not matched\n"); - return 0; - } - get_address_from_output_script(context_D.currentOutput + 8, sizeof(context_D.currentOutput) - 8, tmp, sizeof(tmp)); - if (strcmp(tmp, vars.swap_data.destination_address) != 0) { - PRINTF("Address not matched\n"); - return 0; - } - - // Check if all inputs have been confirmed - - if (context_D.outputParsingState == - OUTPUT_PARSING_OUTPUT) { - context_D.remainingOutputs--; - if (context_D.remainingOutputs == 0) - break; - } - - memmove(context_D.currentOutput, - context_D.currentOutput + - context_D.discardSize, - context_D.currentOutputOffset - - context_D.discardSize); - context_D.currentOutputOffset -= context_D.discardSize; - context_D.io_flags &= ~IO_ASYNCH_REPLY; - while (handle_output_state() && - (!(context_D.io_flags & IO_ASYNCH_REPLY))) - ; - if (!(context_D.io_flags & IO_ASYNCH_REPLY)) { - // Out of data to process, wait for the next call - break; - } - } - - if ((context_D.outputParsingState == OUTPUT_PARSING_OUTPUT) && - (context_D.remainingOutputs == 0)) { - context_D.outputParsingState = OUTPUT_FINALIZE_TX; - // check fees - unsigned char fees[8]; - - if ((transaction_amount_sub_be(fees, - context_D.transactionContext.transactionAmount, - context_D.totalOutputAmount) != 0) || - (memcmp(fees, vars.swap_data.fees, 8) != 0)) { - PRINTF("Fees is not matched\n"); - return 0; - } - } - - if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { - context_D.transactionContext.firstSigned = 0; - - if (context_D.usingSegwit && - !context_D.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context_D.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - } else { - context_D.transactionContext.transactionState = - TRANSACTION_SIGN_READY; - } - } - if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { - // we've finished the processing of the input - apdu_hash_input_finalize_full_reset(); - } - - return 1; -} - -unsigned int bagl_confirm_single_output() { - if (context_D.called_from_swap) { - return silent_confirm_single_output(); - } - if (!prepare_single_output()) { - return 0; - } - - ui_confirm_single_flow(); - return 1; -} - -unsigned int bagl_finalize_tx() { - if (context_D.called_from_swap) { - return check_fee_swap(); - } - - if (!prepare_fees()) { - return 0; - } - - ui_finalize_flow(); - return 1; -} - -void bagl_confirm_message_signature() { - if (!prepare_message_signature()) { - return; - } - - ui_sign_message_flow(); -} - -uint8_t set_key_path_to_display(unsigned char* keyPath) { - bip32_print_path(keyPath, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); - return bip44_derivation_guard(keyPath, false); -} - -void bagl_display_public_key(uint8_t is_derivation_path_unusual) { - // append a white space at the end of the address to avoid glitch on nano S - strlcat((char *)G_io_apdu_buffer + 200, " ", sizeof(G_io_apdu_buffer) - 200); - - if (is_derivation_path_unusual) { - ui_display_public_with_warning_flow(); - } - else { - ui_display_public_flow(); - } -} - -void bagl_display_token() -{ - ui_display_token_flow(); -} - -void bagl_request_pubkey_approval() -{ - ui_request_pubkey_approval_flow(); -} - -void bagl_request_change_path_approval(unsigned char* change_path) -{ - bip32_print_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); - ui_request_change_path_approval_flow(); -} - -void bagl_request_sign_path_approval(unsigned char* change_path) -{ - bip32_print_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); - ui_request_sign_path_approval_flow(); -} - -void bagl_request_segwit_input_approval() -{ - ui_request_segwit_input_approval_flow(); -} - - - -void app_exit(void) { - BEGIN_TRY_L(exit) { - TRY_L(exit) { - os_sched_exit(-1); - } - FINALLY_L(exit) { - } - } - END_TRY_L(exit); -} - -void init_coin_config(altcoin_config_t *coin_config) { - memset(coin_config, 0, sizeof(altcoin_config_t)); - coin_config->bip44_coin_type = BIP44_COIN_TYPE; - coin_config->bip44_coin_type2 = BIP44_COIN_TYPE_2; - coin_config->p2pkh_version = COIN_P2PKH_VERSION; - coin_config->p2sh_version = COIN_P2SH_VERSION; - coin_config->family = COIN_FAMILY; - strcpy(coin_config->coinid, COIN_COINID); - strcpy(coin_config->name, COIN_COINID_NAME); - strcpy(coin_config->name_short, COIN_COINID_SHORT); -#ifdef HAVE_NBGL - memcpy(coin_config->img_raw, &COIN_ICON_BITMAP, sizeof(coin_config->img_raw)); - memcpy(&coin_config->img_nbgl, &COIN_ICON, sizeof(nbgl_icon_details_t)); - coin_config->img_nbgl.bitmap = coin_config->img_raw; -#endif // HAVE_NBGL -#ifdef COIN_NATIVE_SEGWIT_PREFIX - strcpy(coin_config->native_segwit_prefix_val, COIN_NATIVE_SEGWIT_PREFIX); - coin_config->native_segwit_prefix = coin_config->native_segwit_prefix_val; -#else - coin_config->native_segwit_prefix = 0; -#endif // #ifdef COIN_NATIVE_SEGWIT_PREFIX -#ifdef COIN_FORKID - coin_config->forkid = COIN_FORKID; -#endif // COIN_FORKID -#ifdef COIN_CONSENSUS_BRANCH_ID - coin_config->zcash_consensus_branch_id = COIN_CONSENSUS_BRANCH_ID; -#endif // COIN_CONSENSUS_BRANCH_ID -#ifdef COIN_FLAGS - coin_config->flags = COIN_FLAGS; -#endif // COIN_FLAGS - coin_config->kind = COIN_KIND; -} - -void coin_main(altcoin_config_t *coin_config) { - altcoin_config_t config; - if (coin_config == NULL) { - init_coin_config(&config); - G_coin_config = &config; - } else { - G_coin_config = coin_config; - } - - for (;;) { - // Initialize the UX system - UX_INIT(); - - BEGIN_TRY { - TRY { - io_seproxyhal_init(); - -#ifdef TARGET_NANOX - // grab the current plane mode setting - G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); -#endif // TARGET_NANOX - - context_init(); - - USB_power(0); - USB_power(1); - - ui_idle_flow(); - -#ifdef HAVE_BLE - BLE_power(0, NULL); - BLE_power(1, NULL); -#endif // HAVE_BLE - - app_main(); - } - CATCH(EXCEPTION_IO_RESET) { - // reset IO and UX - CLOSE_TRY; - continue; - } - CATCH_ALL { - CLOSE_TRY; - break; - } - FINALLY { - } - } - END_TRY; - } - app_exit(); -} - -static void library_main_helper(libargs_t *args) { - PRINTF("Inside a library \n"); - switch (args->command) { - case CHECK_ADDRESS: - // ensure result is zero if an exception is thrown - args->check_address->result = 0; - args->check_address->result = - handle_check_address(args->check_address, args->coin_config); - break; - case SIGN_TRANSACTION: - if (copy_transaction_parameters(args->create_transaction)) { - // never returns - handle_swap_sign_transaction(args->coin_config); - } - break; - case GET_PRINTABLE_AMOUNT: - handle_get_printable_amount(args->get_printable_amount, args->coin_config); - break; - default: - break; - } -} - -void library_main(libargs_t *args) { - altcoin_config_t coin_config; - if (args->coin_config == NULL) { - init_coin_config(&coin_config); - args->coin_config = &coin_config; - } - bool end = false; - /* This loop ensures that library_main_helper and os_lib_end are called - * within a try context, even if an exception is thrown */ - while (1) { - BEGIN_TRY { - TRY { - if (!end) { - library_main_helper(args); - } - os_lib_end(); - } - FINALLY { - end = true; - } - } - END_TRY; - } -} - -__attribute__((section(".boot"))) int main(int arg0) { -#ifdef USE_LIB_BITCOIN - BEGIN_TRY { - TRY { - unsigned int libcall_params[5]; - altcoin_config_t coin_config; - init_coin_config(&coin_config); - PRINTF("Hello from litecoin\n"); - // delegate to bitcoin app/lib - libcall_params[0] = "Bitcoin Legacy"; - libcall_params[1] = 0x100; - libcall_params[2] = RUN_APPLICATION; - libcall_params[3] = &coin_config; - libcall_params[4] = 0; - if (arg0) { - // call as a library - libcall_params[2] = ((unsigned int *)arg0)[1]; - libcall_params[4] = ((unsigned int *)arg0)[3]; // library arguments - os_lib_call(&libcall_params); - ((unsigned int *)arg0)[0] = libcall_params[1]; - os_lib_end(); - } - else { - // launch coin application - os_lib_call(&libcall_params); - } - } - FINALLY {} - } - END_TRY; - // no return -#else - // exit critical section - __asm volatile("cpsie i"); - - // ensure exception will work as planned - os_boot(); - - if (!arg0) { - // Bitcoin application launched from dashboard - coin_main(NULL); - return 0; - } - libargs_t *args = (libargs_t *) arg0; - if (args->id != 0x100) { - app_exit(); - return 0; - } - switch (args->command) { - case RUN_APPLICATION: - // coin application launched from dashboard - if (args->coin_config == NULL) - app_exit(); - else - coin_main(args->coin_config); - break; - default: - // called as bitcoin or altcoin library - library_main(args); - } -#endif // USE_LIB_BITCOIN - return 0; -} diff --git a/src/public_ram_variables.c b/src/public_ram_variables.c index 8537e3b3..a0acc359 100644 --- a/src/public_ram_variables.c +++ b/src/public_ram_variables.c @@ -19,4 +19,3 @@ context_t context_D; -altcoin_config_t *G_coin_config; \ No newline at end of file diff --git a/src/public_ram_variables.h b/src/public_ram_variables.h index de0cfe55..3251c5da 100644 --- a/src/public_ram_variables.h +++ b/src/public_ram_variables.h @@ -25,6 +25,4 @@ extern context_t context_D; -extern altcoin_config_t *G_coin_config; - #endif /* _PUBLIC_RAM_VARIABLES_H_ */ diff --git a/src/rom_variables.c b/src/rom_variables.c index daee33d1..375e3d86 100644 --- a/src/rom_variables.c +++ b/src/rom_variables.c @@ -18,34 +18,9 @@ #include "internal.h" #include "apdu_constants.h" -unsigned char const HEXDIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - -unsigned char const BASE58TABLE[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0x10, 0xff, 0x11, 0x12, 0x13, 0x14, 0x15, 0xff, 0x16, 0x17, 0x18, 0x19, - 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0xff, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff}; - -unsigned char const BASE58ALPHABET[] = { - '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', - 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; - unsigned char const SIGNMAGIC[] = {' ', 'S', 'i', 'g', 'n', 'e', 'd', ' ', 'M', 'e', 's', 's', 'a', 'g', 'e', ':', '\n'}; -unsigned char const TWOPOWER[] = {0x01, 0x02, 0x04, 0x08, - 0x10, 0x20, 0x40, 0x80}; - unsigned char const OVERWINTER_PARAM_PREVOUTS[16] = { 'Z', 'c', 'a', 's', 'h', 'P', 'r', 'e', 'v', 'o', 'u', 't', 'H', 'a', 's', 'h' }; unsigned char const OVERWINTER_PARAM_SEQUENCE[16] = { 'Z', 'c', 'a', 's', 'h', 'S', 'e', 'q', 'u', 'e', 'n', 'c', 'H', 'a', 's', 'h' }; unsigned char const OVERWINTER_PARAM_OUTPUTS[16] = { 'Z', 'c', 'a', 's', 'h', 'O', 'u', 't', 'p', 'u', 't', 's', 'H', 'a', 's', 'h' }; @@ -53,65 +28,45 @@ unsigned char const OVERWINTER_PARAM_SIGHASH[16] = { 'Z', 'c', 'a', 's', 'h', 'S unsigned char const OVERWINTER_NO_JOINSPLITS[32] = { 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 }; unsigned char const DISPATCHER_CLA[] = { - CLA, // apdu_setup, - CLA, // apdu_verify_pin, - CLA, // apdu_get_operation_mode, - CLA, // apdu_set_operation_mode, CLA, // apdu_get_wallet_public_key, CLA, // apdu_get_trusted_input, CLA, // apdu_hash_input_start, CLA, // apdu_hash_sign, CLA, // apdu_hash_input_finalize_full, CLA, // apdu_sign_message, - CLA, // apdu_get_random, CLA, // apdu_get_firmware_version, CLA, // apdu_get_coin_version }; unsigned char const DISPATCHER_INS[] = { - INS_SETUP, // apdu_setup, - INS_VERIFY_PIN, // apdu_verify_pin, - INS_GET_OPERATION_MODE, // apdu_get_operation_mode, - INS_SET_OPERATION_MODE, // apdu_set_operation_mode, INS_GET_WALLET_PUBLIC_KEY, // apdu_get_wallet_public_key, INS_GET_TRUSTED_INPUT, // apdu_get_trusted_input, INS_HASH_INPUT_START, // apdu_hash_input_start, INS_HASH_SIGN, // apdu_hash_sign, INS_HASH_INPUT_FINALIZE_FULL, // apdu_hash_input_finalize_full, INS_SIGN_MESSAGE, // apdu_sign_message, - INS_GET_RANDOM, // apdu_get_random, INS_GET_FIRMWARE_VERSION, // apdu_get_firmware_version, INS_GET_COIN_VER, // apdu_get_coin_version }; unsigned char const DISPATCHER_DATA_IN[] = { - 1, // apdu_setup, - 1, // apdu_verify_pin, - 0, // apdu_get_operation_mode, - 1, // apdu_set_operation_mode, 1, // apdu_get_wallet_public_key, 1, // apdu_get_trusted_input, 1, // apdu_hash_input_start, 1, // apdu_hash_sign, 1, // apdu_hash_input_finalize_full, 1, // apdu_sign_message, - 0, // apdu_get_random, 0, // apdu_get_firmware_version, 0, // apdu_get_coin_version }; apduProcessingFunction const DISPATCHER_FUNCTIONS[] = { - apdu_setup, - apdu_verify_pin, - apdu_get_operation_mode, - apdu_set_operation_mode, apdu_get_wallet_public_key, apdu_get_trusted_input, apdu_hash_input_start, apdu_hash_sign, apdu_hash_input_finalize_full, apdu_sign_message, - apdu_get_random, apdu_get_firmware_version, apdu_get_coin_version, }; diff --git a/src/rom_variables.h b/src/rom_variables.h index ef9cde4a..82d5fa89 100644 --- a/src/rom_variables.h +++ b/src/rom_variables.h @@ -22,10 +22,6 @@ #define SIGNMAGIC_LENGTH 17 -extern unsigned char const HEXDIGITS[16]; -extern unsigned char const BASE58TABLE[128]; -extern unsigned char const BASE58ALPHABET[58]; - extern unsigned char const SIGNMAGIC[SIGNMAGIC_LENGTH]; extern unsigned char const OVERWINTER_PARAM_PREVOUTS[16]; @@ -36,8 +32,6 @@ extern unsigned char const OVERWINTER_NO_JOINSPLITS[32]; #define HDKEY_VERSION_LENGTH 4 -extern unsigned char const TWOPOWER[8]; - #define APDU_DEBUG_LENGTH 0 #define APDU_NFCPAYMENT_LENGTH 0 diff --git a/src/secure_value.c b/src/secure_value.c deleted file mode 100644 index 03ca4c1b..00000000 --- a/src/secure_value.c +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" - -void sbSet(secu8 *target, unsigned char source) { - *target = (((unsigned char)~source) << 8) + source; -} - -void sbCheck(secu8 source) { - if (((source >> 8) & 0xff) != (unsigned char)(~(source & 0xff))) { - reset(); - } -} - -void ssSet(secu16 *target, unsigned short source) { - *target = (((unsigned long int)((unsigned short)~source)) << 16) + source; -} - -void ssCheck(secu16 source) { - if (((source >> 16) & 0xffff) != (unsigned short)(~(source & 0xffff))) { - reset(); - } -} diff --git a/src/handle_check_address.c b/src/swap/handle_check_address.c similarity index 76% rename from src/handle_check_address.c rename to src/swap/handle_check_address.c index e993dacf..1fd13dec 100644 --- a/src/handle_check_address.c +++ b/src/swap/handle_check_address.c @@ -82,44 +82,63 @@ bool get_address_from_compressed_public_key( return true; } -static int os_strcmp(const char* s1, const char* s2) { - size_t size = strlen(s1) + 1; - return memcmp(s1, s2, size); -} +void swap_handle_check_address(check_address_parameters_t* params) { + PRINTF("Inside swap_handle_check_address\n"); + params->result = 0; + + if (params->address_parameters == NULL) { + PRINTF("derivation path expected\n"); + return; + } + + if (params->address_to_check == NULL) { + PRINTF("Address to check expected\n"); + return; + } + PRINTF("Address to check %s\n", params->address_to_check); + + if (params->extra_id_to_check == NULL) { + PRINTF("extra_id_to_check expected\n"); + return; + } else if (params->extra_id_to_check[0] != '\0') { + PRINTF("extra_id_to_check expected empty, not '%s'\n", params->extra_id_to_check); + return; + } -int handle_check_address(check_address_parameters_t* params, altcoin_config_t* coin_config) { - unsigned char compressed_public_key[33]; - PRINTF("Params on the address %d\n",(unsigned int)params); - PRINTF("Address to check %s\n",params->address_to_check); - PRINTF("Inside handle_check_address\n"); if (params->address_to_check == 0) { PRINTF("Address to check == 0\n"); - return 0; + return; } + + unsigned char compressed_public_key[33]; if (!derive_compressed_public_key( params->address_parameters + 1, params->address_parameters_length - 1, compressed_public_key, sizeof(compressed_public_key))) { - return 0; + PRINTF("Failed to derive public key\n"); + return; } char address[51]; if (!get_address_from_compressed_public_key( params->address_parameters[0], compressed_public_key, - coin_config->p2pkh_version, - coin_config->p2sh_version, - coin_config->native_segwit_prefix, + COIN_P2PKH_VERSION, + COIN_P2SH_VERSION, + COIN_NATIVE_SEGWIT_PREFIX, address, sizeof(address))) { PRINTF("Can't create address from given public key\n"); - return 0; + return; } - if (os_strcmp(address,params->address_to_check) != 0) { - PRINTF("Addresses don't match\n"); - return 0; + if (strcmp(params->address_to_check, address) != 0) { + PRINTF("Address %s != %s\n", params->address_to_check, address); + return; } + PRINTF("Addresses match\n"); - return 1; + + params->result = 1; + return; } \ No newline at end of file diff --git a/src/handle_check_address.h b/src/swap/handle_check_address.h similarity index 58% rename from src/handle_check_address.h rename to src/swap/handle_check_address.h index d45ed63d..01d8e138 100644 --- a/src/handle_check_address.h +++ b/src/swap/handle_check_address.h @@ -4,6 +4,6 @@ #include "swap_lib_calls.h" #include "context.h" -int handle_check_address(check_address_parameters_t* check_address_params, altcoin_config_t* coin_config); +void swap_handle_check_address(check_address_parameters_t* check_address_params); #endif // _HANDLE_CHECK_ADDRESS_H_ \ No newline at end of file diff --git a/src/handle_get_printable_amount.c b/src/swap/handle_get_printable_amount.c similarity index 59% rename from src/handle_get_printable_amount.c rename to src/swap/handle_get_printable_amount.c index 5af59581..8f9d8fd7 100644 --- a/src/handle_get_printable_amount.c +++ b/src/swap/handle_get_printable_amount.c @@ -2,20 +2,20 @@ #include "bcd.h" #include -int handle_get_printable_amount( get_printable_amount_parameters_t* params, altcoin_config_t *config) { +void swap_handle_get_printable_amount(get_printable_amount_parameters_t* params) { params->printable_amount[0] = 0; if (params->amount_length > 8) { PRINTF("Amount is too big"); - return 0; + return; } unsigned char amount[8]; memset(amount, 0, 8); memcpy(amount + (8 - params->amount_length), params->amount, params->amount_length); - unsigned char coin_name_length = strlen(config->name_short); - memmove(params->printable_amount, config->name_short, coin_name_length); + unsigned char coin_name_length = strlen(COIN_COINID_SHORT); + memmove(params->printable_amount, COIN_COINID_SHORT, coin_name_length); params->printable_amount[coin_name_length] = ' '; - int res_length = convert_hex_amount_to_displayable_no_globals(amount, config->flags, (uint8_t *)params->printable_amount + coin_name_length + 1); + int res_length = convert_hex_amount_to_displayable_no_globals(amount, COIN_FLAGS, (uint8_t *)params->printable_amount + coin_name_length + 1); params->printable_amount[res_length + coin_name_length + 1] = '\0'; - return 1; + return; } \ No newline at end of file diff --git a/src/handle_get_printable_amount.h b/src/swap/handle_get_printable_amount.h similarity index 58% rename from src/handle_get_printable_amount.h rename to src/swap/handle_get_printable_amount.h index f6beb7e0..f47d46e0 100644 --- a/src/handle_get_printable_amount.h +++ b/src/swap/handle_get_printable_amount.h @@ -4,6 +4,6 @@ #include "swap_lib_calls.h" #include "context.h" -int handle_get_printable_amount(get_printable_amount_parameters_t* get_printable_amount_params, altcoin_config_t *config); +void swap_handle_get_printable_amount(get_printable_amount_parameters_t* get_printable_amount_params); #endif // _HANDLE_GET_PRINTABLE_AMOUNT_H_ \ No newline at end of file diff --git a/src/swap/handle_swap_sign_transaction.c b/src/swap/handle_swap_sign_transaction.c new file mode 100644 index 00000000..c29af60c --- /dev/null +++ b/src/swap/handle_swap_sign_transaction.c @@ -0,0 +1,96 @@ +#include "handle_swap_sign_transaction.h" +#include "os_io_seproxyhal.h" +#include "public_ram_variables.h" +#include "display_variables.h" +#include "context.h" +#include "usbd_core.h" +#include "ux.h" + +#ifdef HAVE_NBGL +#include "nbgl_use_case.h" +#endif + +#include "swap.h" + +// Save the BSS address where we will write the return value when finished +static uint8_t *G_swap_sign_return_value_address; + +bool swap_copy_transaction_parameters(create_transaction_parameters_t* params) { + PRINTF("Inside swap_copy_transaction_parameters\n"); + + // Ensure no extraid + if (params->destination_address_extra_id == NULL) { + PRINTF("destination_address_extra_id expected\n"); + return false; + } else if (params->destination_address_extra_id[0] != '\0') { + PRINTF("destination_address_extra_id expected empty, not '%s'\n", + params->destination_address_extra_id); + return false; + } + + // We need this "trick" as the input data position can overlap with app globals + // and also because we want to memset the whole bss segment as it is not done + // when an app is called as a lib. + // This is necessary as many part of the code expect bss variables to + // initialized at 0. + swap_data_t swap_validated; + memset(&swap_validated, 0, sizeof(swap_validated)); + + // Save recipient + strlcpy(swap_validated.destination_address, + params->destination_address, + sizeof(swap_validated.destination_address)); + if (swap_validated.destination_address[sizeof(swap_validated.destination_address) - 1] != '\0') { + return false; + } + + // store amount as big endian in 8 bytes, so the passed data should be alligned to right + // input {0xEE, 0x00, 0xFF} should be stored like {0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x00, 0xFF} + memcpy(swap_validated.amount + 8 - params->amount_length, params->amount, params->amount_length); + memcpy(swap_validated.fees + 8 - params->fee_amount_length, params->fee_amount, params->fee_amount_length); + + // Save amount and fees +// swap_str_to_u64(params->amount, params->amount_length, &swap_validated.amount); +// swap_str_to_u64(params->fee_amount, params->fee_amount_length, &swap_validated.fees); +// + swap_validated.initialized = true; + + // Full reset the global variables + os_explicit_zero_BSS_segment(); + + // Keep the address at which we'll reply the signing status + G_swap_sign_return_value_address = ¶ms->result; + + + // Copy from stack back to global data segment + memcpy(&vars.swap_data, &swap_validated, sizeof(swap_validated)); + swap_validated.initialized = true; + return true; +} + +void swap_handle_swap_sign_transaction(void) { + context_init(); + io_seproxyhal_init(); + UX_INIT(); +#ifdef HAVE_NBGL + nbgl_useCaseSpinner("Signing"); +#endif // HAVE_BAGL + USB_power(0); + USB_power(1); + //ui_idle(); + PRINTF("USB power ON/OFF\n"); +#ifdef TARGET_NANOX + // grab the current plane mode setting + G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); +#endif // TARGET_NANOX +#ifdef HAVE_BLE + BLE_power(0, NULL); + BLE_power(1, "Nano X"); +#endif // HAVE_BLE + app_main(); +} + +void __attribute__((noreturn)) swap_finalize_exchange_sign_transaction(bool is_success) { + *G_swap_sign_return_value_address = is_success; + os_lib_end(); +} diff --git a/src/swap/handle_swap_sign_transaction.h b/src/swap/handle_swap_sign_transaction.h new file mode 100644 index 00000000..7203d065 --- /dev/null +++ b/src/swap/handle_swap_sign_transaction.h @@ -0,0 +1,13 @@ +#ifndef _HANDLE_SWAP_SIGN_TRANSACTION_H_ +#define _HANDLE_SWAP_SIGN_TRANSACTION_H_ + +#include "swap_lib_calls.h" +#include "context.h" + +bool swap_copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params); + +void swap_handle_swap_sign_transaction(void); + +void __attribute__((noreturn)) swap_finalize_exchange_sign_transaction(bool is_success); + +#endif // _HANDLE_SWAP_SIGN_TRANSACTION_H_ diff --git a/src/transaction.c b/src/transaction.c index 5a381306..2806d623 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -19,17 +19,24 @@ #include "apdu_constants.h" #include "display_variables.h" #include "ledger_assert.h" +#include "lib_standard_app/read.h" +#include "lib_standard_app/write.h" +#include "swap.h" + +#ifndef COIN_CONSENSUS_BRANCH_ID +#define COIN_CONSENSUS_BRANCH_ID 0 +#endif #define CONSENSUS_BRANCH_ID_OVERWINTER 0x5ba81b19 #define CONSENSUS_BRANCH_ID_SAPLING 0x76b809bb #define CONSENSUS_BRANCH_ID_ZCLASSIC 0x930b540d // Check if fOverwintered flag is set and if nVersion is >= 0x03 -#define TRUSTED_INPUT_OVERWINTER ( (G_coin_config->kind == COIN_KIND_ZCASH || \ - G_coin_config->kind == COIN_KIND_ZCLASSIC || \ - G_coin_config->kind == COIN_KIND_KOMODO) && \ - (read_u32(context_D.transactionVersion, 0, 0) & (1<<31)) && \ - (read_u32(context_D.transactionVersion, 0, 0) ^ (1<<31)) >= 0x03 \ +#define TRUSTED_INPUT_OVERWINTER ( (COIN_KIND == COIN_KIND_ZCASH || \ + COIN_KIND == COIN_KIND_ZCLASSIC || \ + COIN_KIND == COIN_KIND_KOMODO) && \ + (read_u32_le(context_D.transactionVersion, 0) & (1<<31)) && \ + (read_u32_le(context_D.transactionVersion, 0) ^ (1<<31)) >= 0x03 \ ) #define DEBUG_LONG "%d" @@ -131,8 +138,7 @@ unsigned long int transaction_get_varint(void) { unsigned long int result; transaction_offset_increase(1); check_transaction_available(4); - result = - read_u32(context_D.transactionBufferPointer, 0, 0); + result = read_u32_le(context_D.transactionBufferPointer, 0); transaction_offset_increase(4); return result; } else { @@ -145,7 +151,6 @@ unsigned long int transaction_get_varint(void) { void transaction_parse(unsigned char parseMode) { unsigned char optionP2SHSkip2FA = ((N_btchip.bkp.config.options & OPTION_SKIP_2FA_P2SH) != 0); - set_check_internal_structure_integrity(0); BEGIN_TRY { TRY { for (;;) { @@ -168,13 +173,13 @@ void transaction_parse(unsigned char parseMode) { if (context_D.segwitParsedOnce) { uint8_t parameters[16]; memmove(parameters, OVERWINTER_PARAM_SIGHASH, 16); - if (G_coin_config->kind == COIN_KIND_ZCLASSIC) { - write_u32_le(parameters + 12, CONSENSUS_BRANCH_ID_ZCLASSIC); + if (COIN_KIND == COIN_KIND_ZCLASSIC) { + write_u32_le(parameters, 12, CONSENSUS_BRANCH_ID_ZCLASSIC); } else { - write_u32_le(parameters + 12, + write_u32_le(parameters, 12, context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING ? - (G_coin_config->zcash_consensus_branch_id != 0 ? G_coin_config->zcash_consensus_branch_id : CONSENSUS_BRANCH_ID_SAPLING) : CONSENSUS_BRANCH_ID_OVERWINTER); + (COIN_CONSENSUS_BRANCH_ID != 0 ? COIN_CONSENSUS_BRANCH_ID : CONSENSUS_BRANCH_ID_SAPLING) : CONSENSUS_BRANCH_ID_OVERWINTER); } if (cx_blake2b_init2_no_throw(&context_D.transactionHashFull.blake2b, 256, NULL, 0, parameters, 16)) { goto fail; @@ -313,11 +318,11 @@ void transaction_parse(unsigned char parseMode) { transaction_offset_increase(4); } - if (G_coin_config->flags & FLAG_PEERCOIN_SUPPORT) { - if (((G_coin_config->family == + if (COIN_FLAGS & FLAG_PEERCOIN_SUPPORT) { + if (((COIN_FAMILY == FAMILY_PEERCOIN && (context_D.transactionVersion[0] < 3))) || - ((G_coin_config->family == FAMILY_STEALTH) && + ((COIN_FAMILY == FAMILY_STEALTH) && (context_D.transactionVersion[0] < 2))) { // Timestamp check_transaction_available(4); @@ -330,7 +335,7 @@ void transaction_parse(unsigned char parseMode) { .transactionRemainingInputsOutputs = transaction_get_varint(); PRINTF("Number of inputs : " DEBUG_LONG "\n",context_D.transactionContext.transactionRemainingInputsOutputs); - if (context_D.called_from_swap && parseMode == PARSE_MODE_SIGNATURE) { + if (G_called_from_swap && parseMode == PARSE_MODE_SIGNATURE) { // remember number of inputs to know when to exit from library // we will count number of already signed inputs and compare with this value // As there are a lot of different states in which we can have different number of input @@ -431,7 +436,7 @@ void transaction_parse(unsigned char parseMode) { PRINTF("====> Input HMAC: %.*H\n", 8, context_D.transactionBufferPointer + 2 + trustedInputLength - 8); PRINTF("====> Computed HMAC: %.*H\n", 8, trustedInput); - if (secure_memcmp( + if (os_secure_memcmp( trustedInput, // Contains computed Hmac for now context_D.transactionBufferPointer + 2 + trustedInputLength - 8, @@ -509,20 +514,7 @@ void transaction_parse(unsigned char parseMode) { } // Handle non-segwit inputs (i.e. InputHashStart 1st APDU's P2==00 && data[0]==0x00) else if (!trustedInputFlag) { - // Only authorized in relaxed wallet and server - // modes - SB_CHECK(N_btchip.bkp.config.operationMode); - switch (SB_GET(N_btchip.bkp.config.operationMode)) { - case MODE_WALLET: - if (!optionP2SHSkip2FA) { - PRINTF("Untrusted input not authorized\n"); - goto fail; - } - break; - case MODE_RELAXED_WALLET: - case MODE_SERVER: - break; - default: + if (!optionP2SHSkip2FA) { PRINTF("Untrusted input not authorized\n"); goto fail; } @@ -1002,13 +994,11 @@ void transaction_parse(unsigned char parseMode) { PRINTF("Transaction parse - surprise fail\n"); context_D.transactionContext.transactionState = TRANSACTION_NONE; - set_check_internal_structure_integrity(1); THROW(e); } // before the finally to restore the surrounding context if an exception // is raised during finally FINALLY { - set_check_internal_structure_integrity(1); } } END_TRY; diff --git a/src/ui_bagl.c b/src/ui_bagl.c index 6df29a7f..6c4ee66e 100644 --- a/src/ui_bagl.c +++ b/src/ui_bagl.c @@ -25,11 +25,6 @@ bagl_element_t tmp_element; -void settings_pubkey_export_change(unsigned int enabled) { - nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &enabled, 1); - ui_idle_flow(); -} - static unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { UNUSED(e); // user denied the transaction, tell the USB side @@ -112,83 +107,25 @@ void io_seproxyhal_display(const bagl_element_t *element) { io_seproxyhal_display_default((bagl_element_t *)element); } } -////////////////////////////////////////////////////////////////////////////////////// -// Public keys export submenu: - -const char *const settings_pubkey_export_getter_values[] = { - "Auto Approval", "Manual Approval", "Back"}; - -const char *settings_submenu_getter(unsigned int idx); -void settings_submenu_selector(unsigned int idx); - -const char *const settings_submenu_getter_values[] = { - "Public keys export", - "Back", -}; - -const char *settings_pubkey_export_getter(unsigned int idx) { - if (idx < ARRAYLEN(settings_pubkey_export_getter_values)) { - return settings_pubkey_export_getter_values[idx]; - } - return NULL; -} - -void settings_pubkey_export_selector(unsigned int idx) { - switch (idx) { - case 0: - settings_pubkey_export_change(0); - break; - case 1: - settings_pubkey_export_change(1); - break; - default: - ux_menulist_init(0, settings_submenu_getter, settings_submenu_selector); - } -} - -const char *settings_submenu_getter(unsigned int idx) { - if (idx < ARRAYLEN(settings_submenu_getter_values)) { - return settings_submenu_getter_values[idx]; - } - return NULL; -} - -void settings_submenu_selector(unsigned int idx) { - switch (idx) { - case 0: - ux_menulist_init_select(0, settings_pubkey_export_getter, - settings_pubkey_export_selector, - N_btchip.pubKeyRequestRestriction); - break; - default: - ui_idle_flow(); - } -} +////////////////////////////////////////////////////////////////////// UX_STEP_NOCB(ux_idle_flow_1_step, nn, { "Application", "is ready", }); -UX_STEP_CB(ux_idle_flow_2_step, pb, - ux_menulist_init(0, settings_submenu_getter, - settings_submenu_selector), - { - &C_icon_coggle, - "Settings", - }); -UX_STEP_NOCB(ux_idle_flow_3_step, bn, +UX_STEP_NOCB(ux_idle_flow_2_step, bn, { "Version", APPVERSION, }); -UX_STEP_CB(ux_idle_flow_4_step, pb, os_sched_exit(-1), +UX_STEP_CB(ux_idle_flow_3_step, pb, os_sched_exit(-1), { &C_icon_dashboard_x, "Quit", }); UX_FLOW(ux_idle_flow, &ux_idle_flow_1_step, &ux_idle_flow_2_step, - &ux_idle_flow_3_step, &ux_idle_flow_4_step, FLOW_LOOP); + &ux_idle_flow_3_step, FLOW_LOOP); ////////////////////////////////////////////////////////////////////// UX_STEP_NOCB(ux_sign_flow_1_step, pnn, diff --git a/src/ui_menu_nbgl.c b/src/ui_menu_nbgl.c index 45a87b12..20b865e6 100644 --- a/src/ui_menu_nbgl.c +++ b/src/ui_menu_nbgl.c @@ -25,8 +25,8 @@ #define NB_INFO_FIELDS 2 #define PAGE_START 0 -#define NB_PAGE_SETTING 2 -#define IS_TOUCHABLE false +#define NB_PAGE_SETTING 1 +#define IS_TOUCHABLE true #define NB_SETTINGS_SWITCHES 1 #define SWITCH_PUBLIC_KEY_SET_TOKEN FIRST_USER_TOKEN @@ -35,33 +35,16 @@ static char text[20]; static const char *const infoTypes[] = {"Version", "Developer"}; static const char *const infoContents[] = {APPVERSION, "Ledger"}; -static nbgl_layoutSwitch_t switches[NB_SETTINGS_SWITCHES]; - static void quit_cb(void) { os_sched_exit(-1); } -static void switch_public_key(void) { - uint8_t value = (N_btchip.pubKeyRequestRestriction != 0 ? 0 : 1); - nvm_write((void *)&N_btchip.pubKeyRequestRestriction, &value, 1); -} - static bool settings_navigation_cb(uint8_t page, nbgl_pageContent_t *content) { if (page == 0) { content->type = INFOS_LIST; content->infosList.nbInfos = NB_INFO_FIELDS; content->infosList.infoTypes = (const char **)infoTypes; content->infosList.infoContents = (const char **)infoContents; - } else if (page == 1) { - switches[0].text = "Public key export"; - switches[0].subText = "Auto / manual export mode"; - switches[0].token = SWITCH_PUBLIC_KEY_SET_TOKEN; - switches[0].tuneId = TUNE_TAP_CASUAL; - switches[0].initState = N_btchip.pubKeyRequestRestriction; - - content->type = SWITCHES_LIST; - content->switchesList.nbSwitches = NB_SETTINGS_SWITCHES; - content->switchesList.switches = (nbgl_layoutSwitch_t *)switches; } else { return false; } @@ -70,29 +53,16 @@ static bool settings_navigation_cb(uint8_t page, nbgl_pageContent_t *content) { static void display_settings_menu(void); -static void settings_control_cb(int token, uint8_t index) { - UNUSED(index); - switch (token) { - case SWITCH_PUBLIC_KEY_SET_TOKEN: - switch_public_key(); - break; - - default: - PRINTF("Should not happen !"); - break; - } -} - static void display_settings_menu(void) { - snprintf(text, sizeof(text), "%s settings", G_coin_config->name); + snprintf(text, sizeof(text), "%s settings", COIN_COINID_NAME); nbgl_useCaseSettings(text, PAGE_START, NB_PAGE_SETTING, IS_TOUCHABLE, ui_idle_flow, settings_navigation_cb, - settings_control_cb); + NULL); } void ui_idle_flow(void) { - nbgl_useCaseHome(G_coin_config->name, &G_coin_config->img_nbgl, NULL, true, + nbgl_useCaseHome(COIN_COINID_NAME, &COIN_ICON, NULL, true, display_settings_menu, quit_cb); } #endif // HAVE_NBGL diff --git a/src/ui_nbgl.c b/src/ui_nbgl.c index bc786326..ee41f795 100644 --- a/src/ui_nbgl.c +++ b/src/ui_nbgl.c @@ -187,7 +187,7 @@ static void transaction_fee_callback(int token, uint8_t index) { (void) index; if (token) { releaseContext(); - snprintf(text, sizeof(text), "Sign transaction\nto send %s?", G_coin_config->name); + snprintf(text, sizeof(text), "Sign transaction\nto send %s?", COIN_COINID_NAME); nbgl_pageNavigationInfo_t info = {.activePage = 0, .nbPages = 0, .navType = NAV_WITH_TAP, @@ -200,7 +200,7 @@ static void transaction_fee_callback(int token, uint8_t index) { .tuneId = TUNE_TAP_CASUAL}; nbgl_pageContent_t content = {.type = INFO_LONG_PRESS, - .infoLongPress.icon = &G_coin_config->img_nbgl, + .infoLongPress.icon = &COIN_ICON, .infoLongPress.text = text, .infoLongPress.longPressText = "Hold to sign", .infoLongPress.longPressToken = CONFIRM_TOKEN, @@ -225,7 +225,7 @@ static void continue_review(flow_type_t type) { uiContext.tagValueList.pairs = uiContext.tagValues; uiContext.tagValueList.nbPairs = uiContext.nbPairs; - uiContext.infoLongPress.icon = &G_coin_config->img_nbgl; + uiContext.infoLongPress.icon = &COIN_ICON; uiContext.infoLongPress.longPressText = "Hold to sign"; uiContext.infoLongPress.longPressToken = 1; uiContext.infoLongPress.tuneId = TUNE_TAP_CASUAL; @@ -252,14 +252,14 @@ static void continue_message_review(void) { static void ui_start(void (*cb)(void), flow_type_t type) { switch (type) { case MESSAGE_TYPE: - nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, "Review\nmessage", NULL, + nbgl_useCaseReviewStart(&COIN_ICON, "Review\nmessage", NULL, "Cancel", continue_message_review, prompt_cancel_message); break; case TRANSACTION_TYPE: - snprintf(text, sizeof(text), "Review transaction\nto send %s", G_coin_config->name); - nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, text, NULL, + snprintf(text, sizeof(text), "Review transaction\nto send %s", COIN_COINID_NAME); + nbgl_useCaseReviewStart(&COIN_ICON, text, NULL, "Cancel", cb, prompt_cancel_transaction); break; } @@ -417,7 +417,7 @@ void ui_request_pubkey_approval_flow(void) { ui_transaction_start(ui_request_pubkey_approval_flow); } else { - nbgl_useCaseChoice(&G_coin_config->img_nbgl, "Export public key", NULL, + nbgl_useCaseChoice(&COIN_ICON, "Export public key", NULL, "Approve", "Reject", transaction_review_callback); } } @@ -449,7 +449,7 @@ void ui_display_token_flow(void) { uiContext.abandon_status = "Token\nrejected"; uiContext.approved_status = "TOKEN\nCONFIRMED"; - nbgl_useCaseChoice(&G_coin_config->img_nbgl, "Confirm token", + nbgl_useCaseChoice(&COIN_ICON, "Confirm token", (char *)G_io_apdu_buffer + 200, "Approve", "Reject", status_callback); } @@ -467,14 +467,14 @@ static void warn_unusual_derivation_path(void) { } static void prompt_public_key(bool warning) { - snprintf(text, sizeof(text), "Verify %s\naddress", G_coin_config->name); + snprintf(text, sizeof(text), "Verify %s\naddress", COIN_COINID_NAME); if (warning) { - nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, text, NULL, + nbgl_useCaseReviewStart(&COIN_ICON, text, NULL, "Cancel", warn_unusual_derivation_path, abandon_status); } else { - nbgl_useCaseReviewStart(&G_coin_config->img_nbgl, text, NULL, + nbgl_useCaseReviewStart(&COIN_ICON, text, NULL, "Cancel", display_pubkey_callback, abandon_status); } } From a91ced4cc7fe85307dd9e622874720ff5b5ac523 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 2 Feb 2024 11:57:14 +0100 Subject: [PATCH 73/85] Remove throw, use standard app layout, clean, and move to its own lib --- .../workflows/build_and_functional_tests.yml | 33 + .github/workflows/ci-workflow.yml | 98 --- Makefile | 442 +++++++++--- glyphs/icon_back.gif | Bin 74 -> 0 bytes glyphs/icon_certificate.gif | Bin 1127 -> 0 bytes glyphs/icon_coggle.gif | Bin 1122 -> 0 bytes glyphs/icon_crossmark.gif | Bin 1125 -> 0 bytes glyphs/icon_dashboard.gif | Bin 1127 -> 0 bytes glyphs/icon_dashboard_x.gif | Bin 1120 -> 0 bytes glyphs/icon_down.gif | Bin 1100 -> 0 bytes glyphs/icon_eye.gif | Bin 1124 -> 0 bytes glyphs/icon_left.gif | Bin 1101 -> 0 bytes glyphs/icon_right.gif | Bin 1100 -> 0 bytes glyphs/icon_up.gif | Bin 1100 -> 0 bytes glyphs/icon_validate_14.gif | Bin 1119 -> 0 bytes glyphs/icon_warning.gif | Bin 1124 -> 0 bytes include/apdu_constants.h | 145 ---- include/config.h | 28 - include/filesystem.h | 86 --- include/secure_value.h | 50 -- include/swap_lib_calls.h | 81 --- lib-app-bitcoin/Makefile | 141 ++++ lib-app-bitcoin/apdu/apdu_constants.h | 60 ++ lib-app-bitcoin/apdu/dispatcher.c | 117 ++++ lib-app-bitcoin/apdu/dispatcher.h | 14 + lib-app-bitcoin/app_main.c | 72 ++ {src => lib-app-bitcoin}/context.c | 25 +- {include => lib-app-bitcoin}/context.h | 33 +- lib-app-bitcoin/customizable_helpers.c | 151 ++++ .../customizable_helpers.h | 19 +- lib-app-bitcoin/customizable_ui.c | 117 ++++ .../customizable_ui.h | 11 +- lib-app-bitcoin/display_utils.c | 132 ++++ lib-app-bitcoin/display_utils.h | 24 + {src => lib-app-bitcoin}/display_variables.c | 0 .../filesystem.h | 26 +- {include => lib-app-bitcoin}/filesystem_tx.h | 7 +- .../handler/get_coin_version.c | 46 +- .../handler/get_firmware_version.c | 47 +- .../handler/get_trusted_input.c | 69 +- .../handler/get_wallet_public_key.c | 111 +-- .../handler/hash_input_finalize_full.c | 661 ++++++++++++++++++ lib-app-bitcoin/handler/hash_input_start.c | 136 ++++ lib-app-bitcoin/handler/hash_sign.c | 192 +++++ lib-app-bitcoin/handler/sign_message.c | 279 ++++++++ lib-app-bitcoin/helpers.c | 232 ++++++ {include => lib-app-bitcoin}/helpers.h | 36 +- .../swap/handle_check_address.c | 19 +- .../swap/handle_check_address.h | 1 - .../swap/handle_get_printable_amount.c | 20 + .../swap/handle_get_printable_amount.h | 0 .../swap/handle_swap_sign_transaction.c | 23 - .../swap/handle_swap_sign_transaction.h | 3 - {src => lib-app-bitcoin}/transaction.c | 629 +++++++---------- .../btchip.h => lib-app-bitcoin/transaction.h | 23 +- .../ui}/display_variables.h | 10 +- .../ui/extensions.h | 36 +- lib-app-bitcoin/ui/main_ui.c | 311 ++++++++ {src => lib-app-bitcoin/ui}/ui.h | 0 {src => lib-app-bitcoin/ui}/ui_bagl.c | 27 +- {src => lib-app-bitcoin/ui}/ui_menu_nbgl.c | 3 +- {src => lib-app-bitcoin/ui}/ui_nbgl.c | 32 +- lib-app-bitcoin/utils/be_operations.c | 42 ++ .../utils/be_operations.h | 20 +- {src => lib-app-bitcoin/utils}/cashaddr.c | 0 {src => lib-app-bitcoin/utils}/cashaddr.h | 1 + {src => lib-app-bitcoin/utils}/segwit_addr.c | 0 {src => lib-app-bitcoin/utils}/segwit_addr.h | 0 src/apdu_get_wallet_public_key.h | 13 - src/apdu_hash_input_finalize_full.c | 647 ----------------- src/apdu_hash_input_start.c | 128 ---- src/apdu_hash_sign.c | 196 ------ src/apdu_sign_message.c | 290 -------- src/bcd.c | 103 --- src/bip32_path.c | 16 - src/bip32_path.h | 16 - src/btchip.c | 606 ---------------- src/ecc.c | 22 - src/helpers.c | 407 ----------- src/internal.h | 30 - src/nvram.c | 22 - src/public_ram_variables.c | 21 - src/rom_variables.c | 72 -- src/rom_variables.h | 64 -- src/swap/handle_get_printable_amount.c | 21 - 85 files changed, 3628 insertions(+), 3967 deletions(-) create mode 100644 .github/workflows/build_and_functional_tests.yml delete mode 100644 .github/workflows/ci-workflow.yml delete mode 100644 glyphs/icon_back.gif delete mode 100644 glyphs/icon_certificate.gif delete mode 100644 glyphs/icon_coggle.gif delete mode 100644 glyphs/icon_crossmark.gif delete mode 100644 glyphs/icon_dashboard.gif delete mode 100644 glyphs/icon_dashboard_x.gif delete mode 100644 glyphs/icon_down.gif delete mode 100644 glyphs/icon_eye.gif delete mode 100644 glyphs/icon_left.gif delete mode 100644 glyphs/icon_right.gif delete mode 100644 glyphs/icon_up.gif delete mode 100644 glyphs/icon_validate_14.gif delete mode 100644 glyphs/icon_warning.gif delete mode 100644 include/apdu_constants.h delete mode 100644 include/config.h delete mode 100644 include/filesystem.h delete mode 100644 include/secure_value.h delete mode 100644 include/swap_lib_calls.h create mode 100644 lib-app-bitcoin/Makefile create mode 100644 lib-app-bitcoin/apdu/apdu_constants.h create mode 100644 lib-app-bitcoin/apdu/dispatcher.c create mode 100644 lib-app-bitcoin/apdu/dispatcher.h create mode 100644 lib-app-bitcoin/app_main.c rename {src => lib-app-bitcoin}/context.c (65%) rename {include => lib-app-bitcoin}/context.h (91%) create mode 100644 lib-app-bitcoin/customizable_helpers.c rename include/bcd.h => lib-app-bitcoin/customizable_helpers.h (58%) create mode 100644 lib-app-bitcoin/customizable_ui.c rename include/ecc.h => lib-app-bitcoin/customizable_ui.h (82%) create mode 100644 lib-app-bitcoin/display_utils.c create mode 100644 lib-app-bitcoin/display_utils.h rename {src => lib-app-bitcoin}/display_variables.c (100%) rename src/public_ram_variables.h => lib-app-bitcoin/filesystem.h (65%) rename {include => lib-app-bitcoin}/filesystem_tx.h (97%) rename src/apdu_get_coin_version.c => lib-app-bitcoin/handler/get_coin_version.c (53%) rename src/apdu_get_firmware_version.c => lib-app-bitcoin/handler/get_firmware_version.c (52%) rename src/apdu_get_trusted_input.c => lib-app-bitcoin/handler/get_trusted_input.c (51%) rename src/apdu_get_wallet_public_key.c => lib-app-bitcoin/handler/get_wallet_public_key.c (62%) create mode 100644 lib-app-bitcoin/handler/hash_input_finalize_full.c create mode 100644 lib-app-bitcoin/handler/hash_input_start.c create mode 100644 lib-app-bitcoin/handler/hash_sign.c create mode 100644 lib-app-bitcoin/handler/sign_message.c create mode 100644 lib-app-bitcoin/helpers.c rename {include => lib-app-bitcoin}/helpers.h (55%) rename {src => lib-app-bitcoin}/swap/handle_check_address.c (93%) rename {src => lib-app-bitcoin}/swap/handle_check_address.h (91%) create mode 100644 lib-app-bitcoin/swap/handle_get_printable_amount.c rename {src => lib-app-bitcoin}/swap/handle_get_printable_amount.h (100%) rename {src => lib-app-bitcoin}/swap/handle_swap_sign_transaction.c (83%) rename {src => lib-app-bitcoin}/swap/handle_swap_sign_transaction.h (83%) rename {src => lib-app-bitcoin}/transaction.c (57%) rename include/btchip.h => lib-app-bitcoin/transaction.h (67%) rename {src => lib-app-bitcoin/ui}/display_variables.h (87%) rename src/bagl_extensions.h => lib-app-bitcoin/ui/extensions.h (57%) create mode 100644 lib-app-bitcoin/ui/main_ui.c rename {src => lib-app-bitcoin/ui}/ui.h (100%) rename {src => lib-app-bitcoin/ui}/ui_bagl.c (97%) rename {src => lib-app-bitcoin/ui}/ui_menu_nbgl.c (97%) rename {src => lib-app-bitcoin/ui}/ui_nbgl.c (96%) create mode 100644 lib-app-bitcoin/utils/be_operations.c rename src/transaction.h => lib-app-bitcoin/utils/be_operations.h (71%) rename {src => lib-app-bitcoin/utils}/cashaddr.c (100%) rename {src => lib-app-bitcoin/utils}/cashaddr.h (98%) rename {src => lib-app-bitcoin/utils}/segwit_addr.c (100%) rename {src => lib-app-bitcoin/utils}/segwit_addr.h (100%) delete mode 100644 src/apdu_get_wallet_public_key.h delete mode 100644 src/apdu_hash_input_finalize_full.c delete mode 100644 src/apdu_hash_input_start.c delete mode 100644 src/apdu_hash_sign.c delete mode 100644 src/apdu_sign_message.c delete mode 100644 src/bcd.c delete mode 100644 src/bip32_path.c delete mode 100644 src/bip32_path.h delete mode 100644 src/btchip.c delete mode 100644 src/ecc.c delete mode 100644 src/helpers.c delete mode 100644 src/internal.h delete mode 100644 src/nvram.c delete mode 100644 src/public_ram_variables.c delete mode 100644 src/rom_variables.c delete mode 100644 src/rom_variables.h delete mode 100644 src/swap/handle_get_printable_amount.c diff --git a/.github/workflows/build_and_functional_tests.yml b/.github/workflows/build_and_functional_tests.yml new file mode 100644 index 00000000..927806a0 --- /dev/null +++ b/.github/workflows/build_and_functional_tests.yml @@ -0,0 +1,33 @@ +name: Build and run functional tests using ragger through reusable workflow + +# This workflow will build the app and then run functional tests using the Ragger framework upon Speculos emulation. +# It calls a reusable workflow developed by Ledger's internal developer team to build the application and upload the +# resulting binaries. +# It then calls another reusable workflow to run the Ragger tests on the compiled application binary. +# +# While this workflow is optional, having functional testing on your application is mandatory and this workflow and +# tooling environment is meant to be easy to use and adapt after forking your application + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + build_application: + name: Build application using the reusable workflow + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1 + with: + upload_app_binaries_artifact: "compiled_app_binaries" + flags: "COIN=bitcoin_testnet_legacy" + + ragger_tests: + name: Run ragger tests using the reusable workflow + needs: build_application + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_ragger_tests.yml@v1 + with: + download_app_binaries_artifact: "compiled_app_binaries" diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml deleted file mode 100644 index 6fd8555c..00000000 --- a/.github/workflows/ci-workflow.yml +++ /dev/null @@ -1,98 +0,0 @@ -name: CI - -on: - workflow_dispatch: - push: - branches: - - master - pull_request: - branches: - - master - - -jobs: - job_build: - name: Compilation - strategy: - matrix: - include: - - model: nanos - SDK: "$NANOS_SDK" - - model: nanox - SDK: "$NANOX_SDK" - - model: nanosp - SDK: "$NANOSP_SDK" - - model: stax - SDK: "$STAX_SDK" - - runs-on: ubuntu-latest - - container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest - - steps: - - name: Clone - uses: actions/checkout@v2 - - - name: Build - run: | - make BOLOS_SDK=${{ matrix.SDK }} && mv bin/ bitcoin-bin/ - make clean - make COIN=bitcoin_testnet_legacy BOLOS_SDK=${{ matrix.SDK }} && mv bin/ bitcoin-testnet-bin/ - - - name: Upload Bitcoin app binary - uses: actions/upload-artifact@v2 - with: - name: bitcoin-app-${{ matrix.model }} - path: bitcoin-bin - - - name: Upload Bitcoin Testnet app binary - uses: actions/upload-artifact@v2 - with: - name: bitcoin-testnet-app-${{ matrix.model }} - path: bitcoin-testnet-bin - - job_test: - name: Tests - strategy: - matrix: - include: - - model: nanos - - model: nanox - - model: nanosp - - model: stax - - needs: job_build - runs-on: ubuntu-latest - - container: - image: ghcr.io/ledgerhq/speculos:latest - ports: - - 1234:1234 - - 9999:9999 - - 40000:40000 - - 41000:41000 - - 42000:42000 - - 43000:43000 - options: --entrypoint /bin/bash - - steps: - - name: Clone - uses: actions/checkout@v2 - - - name: Download Bitcoin app binary - uses: actions/download-artifact@v2 - with: - name: bitcoin-app-${{matrix.model}} - path: tests/bitcoin-bin - - - name: Download Bitcoin Testnet app binary - uses: actions/download-artifact@v2 - with: - name: bitcoin-testnet-app-${{ matrix.model }} - path: tests/bitcoin-testnet-bin - - - name: Run tests - run: | - cd tests && pip install -r requirements.txt && SPECULOS=/speculos/speculos.py pytest --model=${{ matrix.model }} - diff --git a/Makefile b/Makefile index 08a0fda0..707c4e1b 100644 --- a/Makefile +++ b/Makefile @@ -15,61 +15,20 @@ # limitations under the License. # **************************************************************************** -ifeq ($(BOLOS_SDK),) -$(error Environment variable BOLOS_SDK is not set) -endif -include $(BOLOS_SDK)/Makefile.defines - ######################################## # Mandatory configuration # ######################################## -# Name is defined later # Application version APPVERSION_M = 2 -APPVERSION_N = 3 +APPVERSION_N = 4 APPVERSION_P = 0 -APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" - -# Application source files -APP_SOURCE_PATH += src - -ICON_NANOS = icons/nanos_app_$(COIN).gif -ICON_NANOX = icons/nanox_app_$(COIN).gif -ICON_NANOSP = icons/nanox_app_$(COIN).gif -ICON_STAX = icons/stax_app_$(COIN).gif - -# Application allowed derivation curves. -CURVE_APP_LOAD_PARAMS = secp256k1 -# Application allowed derivation paths. -ifeq ($(COIN),$(filter $(COIN), hydra_testnet hydra)) -PATH_APP_LOAD_PARAMS = "44'/609'" -else -PATH_APP_LOAD_PARAMS = "" -endif - -HAVE_APPLICATION_FLAG_DERIVE_MASTER = 1 -HAVE_APPLICATION_FLAG_LIBRARY = 1 - -VARIANT_PARAM = COIN -VARIANT_VALUES = BOL - -# Temporary restriction until we have a Resistance Nano X icon -ifeq ($(TARGET_NAME),TARGET_NANOS) -VARIANT_VALUES = bitcoin_testnet_legacy bitcoin_legacy bitcoin_cash bitcoin_gold litecoin dogecoin dash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte bitcoin_private firo gamecredits zclassic xsn nix lbry ravencoin resistance hydra hydra_testnet xrhodium -else VARIANT_VALUES = bitcoin_testnet_legacy bitcoin_legacy bitcoin_cash bitcoin_gold litecoin dogecoin dash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte bitcoin_private firo gamecredits zclassic xsn nix lbry ravencoin hydra hydra_testnet xrhodium -endif - -ENABLE_BLUETOOTH = 1 -ENABLE_NBGL_QRCODE = 1 -ENABLE_SWAP = 1 -ifeq ($(TARGET_NAME),TARGET_STAX) -DEFINES += COIN_ICON=C_$(COIN)_64px -DEFINES += COIN_ICON_BITMAP=C_$(COIN)_64px_bitmap -endif +# Application source files +# There is no additional sources for bitcoin +#APP_SOURCE_PATH += src/ # simplify for tests ifndef COIN @@ -80,135 +39,450 @@ endif #DEBUG = 1 ifeq ($(COIN),bitcoin_testnet_legacy) -# Bitcoin testnet -DEFINES += BIP44_COIN_TYPE=1 BIP44_COIN_TYPE_2=1 COIN_P2PKH_VERSION=111 COIN_P2SH_VERSION=196 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOIN\" COIN_COINID_NAME=\"Bitcoin\" COIN_COINID_SHORT=\"TEST\" COIN_NATIVE_SEGWIT_PREFIX=\"tb\" COIN_KIND=COIN_KIND_BITCOIN_TESTNET COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=1 +BIP44_COIN_TYPE_2=1 +COIN_P2PKH_VERSION=111 +COIN_P2SH_VERSION=196 +COIN_FAMILY=1 +COIN_COINID=\"Bitcoin\" +COIN_COINID_HEADER=\"BITCOIN\" +COIN_COINID_NAME=\"Bitcoin\" +COIN_COINID_SHORT=\"TEST\" +COIN_NATIVE_SEGWIT_PREFIX=\"tb\" +COIN_KIND=COIN_KIND_BITCOIN_TESTNET +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Bitcoin Test Legacy" + else ifeq ($(COIN),bitcoin_legacy) -# Bitcoin mainnet -DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=0 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOIN\" COIN_COINID_NAME=\"Bitcoin\" COIN_COINID_SHORT=\"BTC\" COIN_NATIVE_SEGWIT_PREFIX=\"bc\" COIN_KIND=COIN_KIND_BITCOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +# Horizen +BIP44_COIN_TYPE=0 +BIP44_COIN_TYPE_2=0 +COIN_P2PKH_VERSION=0 +COIN_P2SH_VERSION=5 +COIN_FAMILY=1 +COIN_COINID=\"Bitcoin\" +COIN_COINID_HEADER=\"BITCOIN\" +COIN_COINID_NAME=\"Bitcoin\" +COIN_COINID_SHORT=\"BTC\" +COIN_NATIVE_SEGWIT_PREFIX=\"bc\" +COIN_KIND=COIN_KIND_BITCOIN +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Bitcoin Legacy" -#LIB and global pin and + else ifeq ($(COIN),bitcoin_cash) # Bitcoin cash # Initial fork from Bitcoin, public key access is authorized. Signature is different thanks to the forkId -DEFINES += BIP44_COIN_TYPE=145 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=0 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOINCASH\" COIN_COINID_NAME=\"BitcoinCash\" COIN_COINID_SHORT=\"BCH\" COIN_KIND=COIN_KIND_BITCOIN_CASH COIN_FORKID=0 +BIP44_COIN_TYPE=145 +BIP44_COIN_TYPE_2=0 +COIN_P2PKH_VERSION=0 +COIN_P2SH_VERSION=5 +COIN_FAMILY=1 +COIN_COINID=\"Bitcoin\" +COIN_COINID_HEADER=\"BITCOINCASH\" +COIN_COINID_NAME=\"BitcoinCash\" +COIN_COINID_SHORT=\"BCH\" +COIN_KIND=COIN_KIND_BITCOIN_CASH +COIN_FORKID=0 APPNAME ="Bitcoin Cash" + else ifeq ($(COIN),bitcoin_gold) # Bitcoin Gold # Initial fork from Bitcoin, public key access is authorized. Signature is different thanks to the forkId -DEFINES += BIP44_COIN_TYPE=156 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=23 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\\x20Gold\" COIN_COINID_HEADER=\"BITCOINGOLD\" COIN_COINID_NAME=\"BitcoinGold\" COIN_COINID_SHORT=\"BTG\" COIN_KIND=COIN_KIND_BITCOIN_GOLD COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT COIN_FORKID=79 +BIP44_COIN_TYPE=156 +BIP44_COIN_TYPE_2=0 +COIN_P2PKH_VERSION=38 +COIN_P2SH_VERSION=23 +COIN_FAMILY=1 +COIN_COINID=\"Bitcoin\\x20Gold\" +COIN_COINID_HEADER=\"BITCOINGOLD\" +COIN_COINID_NAME=\"BitcoinGold\" +COIN_COINID_SHORT=\"BTG\" +COIN_KIND=COIN_KIND_BITCOIN_GOLD +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +COIN_FORKID=79 APPNAME ="Bitcoin Gold" + else ifeq ($(COIN),litecoin) # Litecoin -DEFINES += BIP44_COIN_TYPE=2 BIP44_COIN_TYPE_2=2 COIN_P2PKH_VERSION=48 COIN_P2SH_VERSION=50 COIN_FAMILY=1 COIN_COINID=\"Litecoin\" COIN_COINID_HEADER=\"LITECOIN\" COIN_COINID_NAME=\"Litecoin\" COIN_COINID_SHORT=\"LTC\" COIN_NATIVE_SEGWIT_PREFIX=\"ltc\" COIN_KIND=COIN_KIND_LITECOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=2 +BIP44_COIN_TYPE_2=2 +COIN_P2PKH_VERSION=48 +COIN_P2SH_VERSION=50 +COIN_FAMILY=1 +COIN_COINID=\"Litecoin\" +COIN_COINID_HEADER=\"LITECOIN\" +COIN_COINID_NAME=\"Litecoin\" +COIN_COINID_SHORT=\"LTC\" +COIN_NATIVE_SEGWIT_PREFIX=\"ltc\" +COIN_KIND=COIN_KIND_LITECOIN +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Litecoin" + else ifeq ($(COIN),dogecoin) # Doge -DEFINES += BIP44_COIN_TYPE=3 BIP44_COIN_TYPE_2=3 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=22 COIN_FAMILY=1 COIN_COINID=\"Dogecoin\" COIN_COINID_HEADER=\"DOGECOIN\" COIN_COINID_NAME=\"Dogecoin\" COIN_COINID_SHORT=\"DOGE\" COIN_KIND=COIN_KIND_DOGE +BIP44_COIN_TYPE=3 +BIP44_COIN_TYPE_2=3 +COIN_P2PKH_VERSION=30 +COIN_P2SH_VERSION=22 +COIN_FAMILY=1 +COIN_COINID=\"Dogecoin\" +COIN_COINID_HEADER=\"DOGECOIN\" +COIN_COINID_NAME=\"Dogecoin\" +COIN_COINID_SHORT=\"DOGE\" +COIN_KIND=COIN_KIND_DOGE APPNAME ="Dogecoin" + else ifeq ($(COIN),dash) # Dash -DEFINES += BIP44_COIN_TYPE=5 BIP44_COIN_TYPE_2=5 COIN_P2PKH_VERSION=76 COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"DarkCoin\" COIN_COINID_HEADER=\"DASH\" COIN_COINID_NAME=\"Dash\" COIN_COINID_SHORT=\"DASH\" COIN_KIND=COIN_KIND_DASH +BIP44_COIN_TYPE=5 +BIP44_COIN_TYPE_2=5 +COIN_P2PKH_VERSION=76 +COIN_P2SH_VERSION=16 +COIN_FAMILY=1 +COIN_COINID=\"DarkCoin\" +COIN_COINID_HEADER=\"DASH\" +COIN_COINID_NAME=\"Dash\" +COIN_COINID_SHORT=\"DASH\" +COIN_KIND=COIN_KIND_DASH APPNAME ="Dash" + else ifeq ($(COIN),zcash) # Zcash (deprecated, code before the NU5 hard fork) $(error the zcash variant is deprecated and no longer functional since the NU5 hard fork) -DEFINES += BIP44_COIN_TYPE=133 BIP44_COIN_TYPE_2=133 COIN_P2PKH_VERSION=7352 COIN_P2SH_VERSION=7357 COIN_FAMILY=1 COIN_COINID=\"Zcash\" COIN_COINID_HEADER=\"ZCASH\" COIN_COINID_NAME=\"Zcash\" COIN_COINID_SHORT=\"ZEC\" COIN_KIND=COIN_KIND_ZCASH +BIP44_COIN_TYPE=133 +BIP44_COIN_TYPE_2=133 +COIN_P2PKH_VERSION=7352 +COIN_P2SH_VERSION=7357 +COIN_FAMILY=1 +COIN_COINID=\"Zcash\" +COIN_COINID_HEADER=\"ZCASH\" +COIN_COINID_NAME=\"Zcash\" +COIN_COINID_SHORT=\"ZEC\" +COIN_KIND=COIN_KIND_ZCASH # Switch to Canopy over Heartwood -DEFINES += COIN_CONSENSUS_BRANCH_ID=0xE9FF75A6 +BRANCH_ID=0xE9FF75A6 APPNAME ="Zcash" + else ifeq ($(COIN),horizen) # Horizen -DEFINES += BIP44_COIN_TYPE=121 BIP44_COIN_TYPE_2=121 COIN_P2PKH_VERSION=8329 COIN_P2SH_VERSION=8342 COIN_FAMILY=4 COIN_COINID=\"Horizen\" COIN_COINID_HEADER=\"HORIZEN\" COIN_COINID_NAME=\"Horizen\" COINID=$(COIN) COIN_COINID_SHORT=\"ZEN\" COIN_KIND=COIN_KIND_HORIZEN +BIP44_COIN_TYPE=121 +BIP44_COIN_TYPE_2=121 +COIN_P2PKH_VERSION=8329 +COIN_P2SH_VERSION=8342 +COIN_FAMILY=4 +COIN_COINID=\"Horizen\" +COIN_COINID_HEADER=\"HORIZEN\" +COIN_COINID_NAME=\"Horizen\" +COIN_COINID_SHORT=\"ZEN\" +COIN_KIND=COIN_KIND_HORIZEN APPNAME ="Horizen" + else ifeq ($(COIN),komodo) # Komodo -DEFINES += BIP44_COIN_TYPE=141 BIP44_COIN_TYPE_2=141 COIN_P2PKH_VERSION=60 COIN_P2SH_VERSION=85 COIN_FAMILY=1 COIN_COINID=\"Komodo\" COIN_COINID_HEADER=\"KOMODO\" COIN_COINID_NAME=\"Komodo\" COIN_COINID_SHORT=\"KMD\" COIN_KIND=COIN_KIND_KOMODO +BIP44_COIN_TYPE=141 +BIP44_COIN_TYPE_2=141 +COIN_P2PKH_VERSION=60 +COIN_P2SH_VERSION=85 +COIN_FAMILY=1 +COIN_COINID=\"Komodo\" +COIN_COINID_HEADER=\"KOMODO\" +COIN_COINID_NAME=\"Komodo\" +COIN_COINID_SHORT=\"KMD\" +COIN_KIND=COIN_KIND_KOMODO APPNAME ="Komodo" + else ifeq ($(COIN),stratis) # Stratis -DEFINES += BIP44_COIN_TYPE=105105 BIP44_COIN_TYPE_2=105105 COIN_P2PKH_VERSION=75 COIN_P2SH_VERSION=140 COIN_FAMILY=2 COIN_COINID=\"Stratis\" COIN_COINID_HEADER=\"STRATIS\" COIN_COINID_NAME=\"Stratis\" COIN_COINID_SHORT=\"STRAX\" COIN_KIND=COIN_KIND_STRATIS COIN_FLAGS=FLAG_PEERCOIN_SUPPORT +BIP44_COIN_TYPE=105105 +BIP44_COIN_TYPE_2=105105 +COIN_P2PKH_VERSION=75 +COIN_P2SH_VERSION=140 +COIN_FAMILY=2 +COIN_COINID=\"Stratis\" +COIN_COINID_HEADER=\"STRATIS\" +COIN_COINID_NAME=\"Stratis\" +COIN_COINID_SHORT=\"STRAX\" +COIN_KIND=COIN_KIND_STRATIS +COIN_FLAGS=FLAG_PEERCOIN_SUPPORT APPNAME ="Stratis" + else ifeq ($(COIN),xrhodium) #Xrhodium -DEFINES += BIP44_COIN_TYPE=10291 BIP44_COIN_TYPE_2=10291 COIN_P2PKH_VERSION=61 COIN_P2SH_VERSION=123 COIN_FAMILY=1 COIN_COINID=\"xrhodium\" COIN_COINID_HEADER=\"XRHODIUM\" COIN_COINID_NAME=\"xRhodium\" COIN_COINID_SHORT=\"XRC\" COIN_KIND=COIN_KIND_XRHODIUM +BIP44_COIN_TYPE=10291 +BIP44_COIN_TYPE_2=10291 +COIN_P2PKH_VERSION=61 +COIN_P2SH_VERSION=123 +COIN_FAMILY=1 +COIN_COINID=\"xrhodium\" +COIN_COINID_HEADER=\"XRHODIUM\" +COIN_COINID_NAME=\"xRhodium\" +COIN_COINID_SHORT=\"XRC\" +COIN_KIND=COIN_KIND_XRHODIUM APPNAME ="xRhodium" + else ifeq ($(COIN),peercoin) # Peercoin -DEFINES += BIP44_COIN_TYPE=6 BIP44_COIN_TYPE_2=6 COIN_P2PKH_VERSION=55 COIN_P2SH_VERSION=117 COIN_FAMILY=2 COIN_COINID=\"PPCoin\" COIN_COINID_HEADER=\"PEERCOIN\" COIN_COINID_NAME=\"Peercoin\" COIN_COINID_SHORT=\"PPC\" COIN_KIND=COIN_KIND_PEERCOIN COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT +BIP44_COIN_TYPE=6 +BIP44_COIN_TYPE_2=6 +COIN_P2PKH_VERSION=55 +COIN_P2SH_VERSION=117 +COIN_FAMILY=2 +COIN_COINID=\"PPCoin\" +COIN_COINID_HEADER=\"PEERCOIN\" +COIN_COINID_NAME=\"Peercoin\" +COIN_COINID_SHORT=\"PPC\" +COIN_KIND=COIN_KIND_PEERCOIN +COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT APPNAME ="Peercoin" + else ifeq ($(COIN),pivx) # PivX # 77 was used in the Chrome apps -DEFINES += BIP44_COIN_TYPE=119 BIP44_COIN_TYPE_2=77 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=13 COIN_FAMILY=1 COIN_COINID=\"DarkNet\" COIN_COINID_HEADER=\"PIVX\" COIN_COINID_NAME=\"PivX\" COIN_COINID_SHORT=\"PIVX\" COIN_KIND=COIN_KIND_PIVX +BIP44_COIN_TYPE=119 +BIP44_COIN_TYPE_2=77 +COIN_P2PKH_VERSION=30 +COIN_P2SH_VERSION=13 +COIN_FAMILY=1 +COIN_COINID=\"DarkNet\" +COIN_COINID_HEADER=\"PIVX\" +COIN_COINID_NAME=\"PivX\" +COIN_COINID_SHORT=\"PIVX\" +COIN_KIND=COIN_KIND_PIVX APPNAME ="PivX" + else ifeq ($(COIN),stealth) # Stealth -DEFINES += BIP44_COIN_TYPE=125 BIP44_COIN_TYPE_2=125 COIN_P2PKH_VERSION=62 COIN_P2SH_VERSION=85 COIN_FAMILY=4 COIN_COINID=\"Stealth\" COIN_COINID_HEADER=\"STEALTH\" COIN_COINID_NAME=\"Stealth\" COIN_COINID_SHORT=\"XST\" COIN_KIND=COIN_KIND_STEALTH COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT +BIP44_COIN_TYPE=125 +BIP44_COIN_TYPE_2=125 +COIN_P2PKH_VERSION=62 +COIN_P2SH_VERSION=85 +COIN_FAMILY=4 +COIN_COINID=\"Stealth\" +COIN_COINID_HEADER=\"STEALTH\" +COIN_COINID_NAME=\"Stealth\" +COIN_COINID_SHORT=\"XST\" +COIN_KIND=COIN_KIND_STEALTH +COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT APPNAME ="Stealth" + else ifeq ($(COIN),viacoin) # Viacoin -DEFINES += BIP44_COIN_TYPE=14 BIP44_COIN_TYPE_2=14 COIN_P2PKH_VERSION=71 COIN_P2SH_VERSION=33 COIN_FAMILY=1 COIN_COINID=\"Viacoin\" COIN_COINID_HEADER=\"VIACOIN\" COIN_COINID_NAME=\"Viacoin\" COIN_COINID_SHORT=\"VIA\" COIN_KIND=COIN_KIND_VIACOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=14 +BIP44_COIN_TYPE_2=14 +COIN_P2PKH_VERSION=71 +COIN_P2SH_VERSION=33 +COIN_FAMILY=1 +COIN_COINID=\"Viacoin\" +COIN_COINID_HEADER=\"VIACOIN\" +COIN_COINID_NAME=\"Viacoin\" +COIN_COINID_SHORT=\"VIA\" +COIN_KIND=COIN_KIND_VIACOIN +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Viacoin" + else ifeq ($(COIN),vertcoin) # Vertcoin # 128 was used in the Chrome apps -DEFINES += BIP44_COIN_TYPE=28 BIP44_COIN_TYPE_2=128 COIN_P2PKH_VERSION=71 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Vertcoin\" COIN_COINID_HEADER=\"VERTCOIN\" COIN_COINID_NAME=\"Vertcoin\" COIN_COINID_SHORT=\"VTC\" COIN_NATIVE_SEGWIT_PREFIX=\"vtc\" COIN_KIND=COIN_KIND_VERTCOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=28 +BIP44_COIN_TYPE_2=128 +COIN_P2PKH_VERSION=71 +COIN_P2SH_VERSION=5 +COIN_FAMILY=1 +COIN_COINID=\"Vertcoin\" +COIN_COINID_HEADER=\"VERTCOIN\" +COIN_COINID_NAME=\"Vertcoin\" +COIN_COINID_SHORT=\"VTC\" +COIN_NATIVE_SEGWIT_PREFIX=\"vtc\" +COIN_KIND=COIN_KIND_VERTCOIN +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Vertcoin" + else ifeq ($(COIN),digibyte) -DEFINES += BIP44_COIN_TYPE=20 BIP44_COIN_TYPE_2=20 COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=63 COIN_FAMILY=1 COIN_COINID=\"DigiByte\" COIN_COINID_HEADER=\"DIGIBYTE\" COIN_COINID_NAME=\"DigiByte\" COIN_COINID_SHORT=\"DGB\" COIN_NATIVE_SEGWIT_PREFIX=\"dgb\" COIN_KIND=COIN_KIND_DIGIBYTE COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=20 +BIP44_COIN_TYPE_2=20 +COIN_P2PKH_VERSION=30 +COIN_P2SH_VERSION=63 +COIN_FAMILY=1 +COIN_COINID=\"DigiByte\" +COIN_COINID_HEADER=\"DIGIBYTE\" +COIN_COINID_NAME=\"DigiByte\" +COIN_COINID_SHORT=\"DGB\" +COIN_NATIVE_SEGWIT_PREFIX=\"dgb\" +COIN_KIND=COIN_KIND_DIGIBYTE +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Digibyte" + else ifeq ($(COIN),qtum) -$(error the qtum variant is deprecated and has been moved to its dedicated repo +$(error the qtum variant is deprecated and has been moved to its dedicated repo) else ifeq ($(COIN),firo) -DEFINES += BIP44_COIN_TYPE=136 BIP44_COIN_TYPE_2=136 COIN_P2PKH_VERSION=82 COIN_P2SH_VERSION=7 COIN_FAMILY=1 COIN_COINID=\"Zcoin\" COIN_COINID_HEADER=\"FIRO\" COIN_COINID_NAME=\"Firo\" COIN_COINID_SHORT=\"FIRO\" COIN_KIND=COIN_KIND_FIRO +BIP44_COIN_TYPE=136 +BIP44_COIN_TYPE_2=136 +COIN_P2PKH_VERSION=82 +COIN_P2SH_VERSION=7 +COIN_FAMILY=1 +COIN_COINID=\"Zcoin\" +COIN_COINID_HEADER=\"FIRO\" +COIN_COINID_NAME=\"Firo\" +COIN_COINID_SHORT=\"FIRO\" +COIN_KIND=COIN_KIND_FIRO APPNAME ="Firo" + else ifeq ($(COIN),bitcoin_private) # Bitcoin Private # Initial fork from Bitcoin, public key access is authorized. Signature is different thanks to the forkId # Note : might need a third lock on ZClassic -DEFINES += BIP44_COIN_TYPE=183 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=4901 COIN_P2SH_VERSION=5039 COIN_FAMILY=1 COIN_COINID=\"BPrivate\" COIN_COINID_HEADER=\"BITCOINPRIVATE\" COIN_COINID_NAME=\"BPrivate\" COIN_COINID_SHORT=\"BTCP\" COIN_KIND=COIN_KIND_BITCOIN_PRIVATE COIN_FORKID=42 +BIP44_COIN_TYPE=183 +BIP44_COIN_TYPE_2=0 +COIN_P2PKH_VERSION=4901 +COIN_P2SH_VERSION=5039 +COIN_FAMILY=1 +COIN_COINID=\"BPrivate\" +COIN_COINID_HEADER=\"BITCOINPRIVATE\" +COIN_COINID_NAME=\"BPrivate\" +COIN_COINID_SHORT=\"BTCP\" +COIN_KIND=COIN_KIND_BITCOIN_PRIVATE +COIN_FORKID=42 APPNAME ="Bitcoin Private" + else ifeq ($(COIN),gamecredits) # GameCredits -DEFINES += BIP44_COIN_TYPE=101 BIP44_COIN_TYPE_2=101 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=62 COIN_FAMILY=1 COIN_COINID=\"GameCredits\" COIN_COINID_HEADER=\"GAMECREDITS\" COIN_COINID_NAME=\"GameCredits\" COIN_COINID_SHORT=\"GAME\" COIN_KIND=COIN_KIND_GAMECREDITS COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=101 +BIP44_COIN_TYPE_2=101 +COIN_P2PKH_VERSION=38 +COIN_P2SH_VERSION=62 +COIN_FAMILY=1 +COIN_COINID=\"GameCredits\" +COIN_COINID_HEADER=\"GAMECREDITS\" +COIN_COINID_NAME=\"GameCredits\" +COIN_COINID_SHORT=\"GAME\" +COIN_KIND=COIN_KIND_GAMECREDITS +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="GameCredits" + else ifeq ($(COIN),zclassic) # ZClassic -DEFINES += BIP44_COIN_TYPE=147 BIP44_COIN_TYPE_2=147 COIN_P2PKH_VERSION=7352 COIN_P2SH_VERSION=7357 COIN_FAMILY=1 COIN_COINID=\"ZClassic\" COIN_COINID_HEADER=\"ZCLASSIC\" COIN_COINID_NAME=\"ZClassic\" COIN_COINID_SHORT=\"ZCL\" COIN_KIND=COIN_KIND_ZCLASSIC +BIP44_COIN_TYPE=147 +BIP44_COIN_TYPE_2=147 +COIN_P2PKH_VERSION=7352 +COIN_P2SH_VERSION=7357 +COIN_FAMILY=1 +COIN_COINID=\"ZClassic\" +COIN_COINID_HEADER=\"ZCLASSIC\" +COIN_COINID_NAME=\"ZClassic\" +COIN_COINID_SHORT=\"ZCL\" +COIN_KIND=COIN_KIND_ZCLASSIC APPNAME ="ZClassic" + else ifeq ($(COIN),xsn) # XSN mainnet -DEFINES += BIP44_COIN_TYPE=384 BIP44_COIN_TYPE_2=384 COIN_P2PKH_VERSION=76 COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"XSN\" COIN_COINID_HEADER=\"XSN\" COIN_COINID_NAME=\"XSN\" COIN_COINID_SHORT=\"XSN\" COIN_NATIVE_SEGWIT_PREFIX=\"xc\" COIN_KIND=COIN_KIND_XSN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=384 +BIP44_COIN_TYPE_2=384 +COIN_P2PKH_VERSION=76 +COIN_P2SH_VERSION=16 +COIN_FAMILY=1 +COIN_COINID=\"XSN\" +COIN_COINID_HEADER=\"XSN\" +COIN_COINID_NAME=\"XSN\" +COIN_COINID_SHORT=\"XSN\" +COIN_NATIVE_SEGWIT_PREFIX=\"xc\" +COIN_KIND=COIN_KIND_XSN +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="XSN" + else ifeq ($(COIN),nix) # NIX -DEFINES += BIP44_COIN_TYPE=400 BIP44_COIN_TYPE_2=400 COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=53 COIN_FAMILY=1 COIN_COINID=\"NIX\" COIN_COINID_HEADER=\"NIX\" COIN_COINID_NAME=\"NIX\" COIN_COINID_SHORT=\"NIX\" COIN_NATIVE_SEGWIT_PREFIX=\"nix\" COIN_KIND=COIN_KIND_NIX COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=400 +BIP44_COIN_TYPE_2=400 +COIN_P2PKH_VERSION=38 +COIN_P2SH_VERSION=53 +COIN_FAMILY=1 +COIN_COINID=\"NIX\" +COIN_COINID_HEADER=\"NIX\" +COIN_COINID_NAME=\"NIX\" +COIN_COINID_SHORT=\"NIX\" +COIN_NATIVE_SEGWIT_PREFIX=\"nix\" +COIN_KIND=COIN_KIND_NIX +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="NIX" + else ifeq ($(COIN),lbry) # LBRY -DEFINES += BIP44_COIN_TYPE=140 BIP44_COIN_TYPE_2=140 COIN_P2PKH_VERSION=85 COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"LBRY\" COIN_COINID_HEADER=\"LBRY\" COIN_COINID_NAME=\"LBRY\" COIN_COINID_SHORT=\"LBC\" COIN_KIND=COIN_KIND_LBRY +BIP44_COIN_TYPE=140 +BIP44_COIN_TYPE_2=140 +COIN_P2PKH_VERSION=85 +COIN_P2SH_VERSION=122 +COIN_FAMILY=1 +COIN_COINID=\"LBRY\" +COIN_COINID_HEADER=\"LBRY\" +COIN_COINID_NAME=\"LBRY\" +COIN_COINID_SHORT=\"LBC\" +COIN_KIND=COIN_KIND_LBRY APPNAME ="LBRY" + else ifeq ($(COIN),resistance) # Resistance -DEFINES += BIP44_COIN_TYPE=356 BIP44_COIN_TYPE_2=356 COIN_P2PKH_VERSION=7063 COIN_P2SH_VERSION=7068 COIN_FAMILY=1 COIN_COINID=\"Res\" COIN_COINID_HEADER=\"RES\" COIN_COINID_NAME=\"Res\" COIN_COINID_SHORT=\"RES\" COIN_KIND=COIN_KIND_RESISTANCE +BIP44_COIN_TYPE=356 +BIP44_COIN_TYPE_2=356 +COIN_P2PKH_VERSION=7063 +COIN_P2SH_VERSION=7068 +COIN_FAMILY=1 +COIN_COINID=\"Res\" +COIN_COINID_HEADER=\"RES\" +COIN_COINID_NAME=\"Res\" +COIN_COINID_SHORT=\"RES\" +COIN_KIND=COIN_KIND_RESISTANCE APPNAME ="Resistance" + else ifeq ($(COIN),ravencoin) # Ravencoin -DEFINES += BIP44_COIN_TYPE=175 BIP44_COIN_TYPE_2=175 COIN_P2PKH_VERSION=60 COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"Ravencoin\" COIN_COINID_HEADER=\"RAVENCOIN\" COIN_COINID_NAME=\"Ravencoin\" COIN_COINID_SHORT=\"RVN\" COIN_KIND=COIN_KIND_RAVENCOIN +BIP44_COIN_TYPE=175 +BIP44_COIN_TYPE_2=175 +COIN_P2PKH_VERSION=60 +COIN_P2SH_VERSION=122 +COIN_FAMILY=1 +COIN_COINID=\"Ravencoin\" +COIN_COINID_HEADER=\"RAVENCOIN\" +COIN_COINID_NAME=\"Ravencoin\" +COIN_COINID_SHORT=\"RVN\" +COIN_KIND=COIN_KIND_RAVENCOIN APPNAME ="Ravencoin" + else ifeq ($(COIN),hydra_testnet) # Hydra testnet -DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=66 COIN_P2SH_VERSION=128 COIN_FAMILY=3 COIN_COINID=\"Hydra\" COIN_COINID_HEADER=\"HYDRA\" COIN_COINID_NAME=\"HYDRA\" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" COIN_KIND=COIN_KIND_HYDRA COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=0 +BIP44_COIN_TYPE_2=0 +COIN_P2PKH_VERSION=66 +COIN_P2SH_VERSION=128 +COIN_FAMILY=3 +COIN_COINID=\"Hydra\" +COIN_COINID_HEADER=\"HYDRA\" +COIN_COINID_NAME=\"HYDRA\" +COIN_COINID_SHORT=\"HYDRA\" +COIN_NATIVE_SEGWIT_PREFIX=\"hc\" +COIN_KIND=COIN_KIND_HYDRA +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Hydra Test" +APP_LOAD_PARAMS += --path "44'/609'" + else ifeq ($(COIN),hydra) # Hydra mainnet -DEFINES += BIP44_COIN_TYPE=0 BIP44_COIN_TYPE_2=0 COIN_P2PKH_VERSION=40 COIN_P2SH_VERSION=63 COIN_FAMILY=3 COIN_COINID=\"Hydra\" COIN_COINID_HEADER=\"HYDRA\" COIN_COINID_NAME=\"HYDRA\" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" COIN_KIND=COIN_KIND_HYDRA COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT +BIP44_COIN_TYPE=0 +BIP44_COIN_TYPE_2=0 +COIN_P2PKH_VERSION=40 +COIN_P2SH_VERSION=63 +COIN_FAMILY=3 +COIN_COINID=\"Hydra\" +COIN_COINID_HEADER=\"HYDRA\" +COIN_COINID_NAME=\"HYDRA\" +COIN_COINID_SHORT=\"HYDRA\" +COIN_NATIVE_SEGWIT_PREFIX=\"hc\" +COIN_KIND=COIN_KIND_HYDRA +COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT APPNAME ="Hydra" -else -ifeq ($(filter clean,$(MAKECMDGOALS)),) -$(error Unsupported COIN - use bitcoin_testnet, bitcoin, bitcoin_cash, bitcoin_gold, litecoin, dogecoin, dash, zcash, horizen, komodo, stratis, peercoin, pivx, viacoin, vertcoin, stealth, digibyte, bitcoin_private, firo, gamecredits, zclassic, xsn, nix, lbry, resistance, ravencoin, hydra, hydra_testnet, xrhodium) -endif +APP_LOAD_PARAMS += --path "44'/609'" + +else ifeq ($(filter clean,$(MAKECMDGOALS)),) +$(error Unsupported COIN - use $(VARIANT_VALUES)) endif -include $(BOLOS_SDK)/Makefile.standard_app +include lib-app-bitcoin/Makefile diff --git a/glyphs/icon_back.gif b/glyphs/icon_back.gif deleted file mode 100644 index f52f795da28e27d098cf4222443496bdcadc469f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74 zcmZ?wbhEHbVQa)3&1F1^Z_deej9OTpfN$I&r>Q U9j8%m#uB?}l~q~FW~>a>0M33DMF0Q* diff --git a/glyphs/icon_certificate.gif b/glyphs/icon_certificate.gif deleted file mode 100644 index 389215460af8a0c4276cfd0f273f633fd4bc1d9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1127 zcmZ?wbhEHbTBRz;GCL~=}}db8eHWUl3bOYY?-2DZ>L~WVFlEiTau_y zk(-lOY*k^al$esAlxhWJ=cbk<>MJRLRg`4gDmj8A6e4^B6rA&mQWZ?~%yg3tO$-#w zE%gk|3`|T7brg&Y49)coO!W=SbPWux3@ogS3>Bb2$vOKg>t6#hd!kXryZHLq9?>>0h}{9OHt!~%UoJp+)3AU@44@b$&7G&dKl z8WTK@=NlI zGx7@*oSi{IW}%?ro0y!L2NcundS0ve;2nVDkcBDn?CDb84(0(J>RYYJ|cxZu>Q4|Iz@dR#+9fXN3W2}!lU z^a>*tT}-@bnN{ORL|_ix|4e)aOj^Jh<=Jbv`> z!To!8@7%t1^TzdSSFc>Ybn(LZb7#+-K6UcM@nc7i96ogL!2W%E_w3%abI0~=Teoc9 zv~k1wb!*qGUbS+?@?}exEMBy5!Tfo1=ggipbH?;(Q>RRxG;um zQ)5GYU2RQuRb@qaS!qdeQDH%TUT#iyR%S+eT53viQer}UTx?8qRAfYWSZGLaP+)++ zpRbR%m#2rjn=3F>93AZKY;CNqEG^8TBRz;GCL~=}}db8eHWUl3bOYY?-2DZ>L~WVFlEiTau_y zk(-lOY*k^al$esAlxhWJ=cbk<>MJRLRg`4gDmj8A6e4^B6rA&mQWZ?~%yg3tO$-#w zE%gk|3`|T7brg&Y49)coO!W=SbPWux3@ogS3>Bb2$vOKg>t6#hd!kXryZHLq9?>>0h}{9OHt!~%UoJp+)3AU@44@b$&7G&dKl z8WTK@=NlI zGx7@*oSi{IW}%?ro0y!L2NcundS0ve;2nVDkc?&xgc z?Br~0Xy|I;WN7Z}+RFGwpWEr5aq z7{EoDWvMA{Mftf3V1HX>BDn?CDP~xm0(J>RYYJ|c0Nswo8z8;pypFj>Y-TyC9NX-ML_99@iX8ix}@1Nhle*XCW?dzA%pFVzg|Mt!6S1(^YfA;jr z<3|r4+`o7C&h1+_Z(P52^~&W-7cZPYclONbQzuUxKX&xU;X?-x?BBO{&+c72cWmFb zb<5^W8#k<9w|33yRV!C4U$%6~;zbJ=%%3-R&g@w;XH1_qb;{&P6DRcd_4agkb#}D3 zwYD@jH8#}O)z(y3RaTUjm6jA26&B>@<>q8(WoD$OrKTh&B__nj#l}QOMMi{&g@yzN z1qS&0`TBT!d3w0Jxw<$zIXc+e+1glJSz4HznVJ|I85-#8>FQ`}X=7 at#z-J%D-2PnAUS$$x|S7?Yd|N25SH;I*tSY diff --git a/glyphs/icon_crossmark.gif b/glyphs/icon_crossmark.gif deleted file mode 100644 index c30bfe40efbce6cdc99fa21262ecfe1d97a6d955..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1125 zcmZ?wbhEHbTBRz;GCL~=}}db8eHWUl3bOYY?-2DZ>L~WVFlEiTau_y zk(-lOY*k^al$esAlxhWJ=cbk<>MJRLRg`4gDmj8A6e4^B6rA&mQWZ?~%yg3tO$-#w zE%gk|3`|T7brg&Y49)coO!W=SbPWux3@ogS3>Bb2$vOKg>t6#hd!kXryZHLq9?>>0h}{9OHt!~%UoJp+)3AU@44@b$&7G&dKl z8WTK@=NlI zGx7@*oSi{IW}%?ro0y!L2NcundS0ve;2nVDkc1gKc z?Br}_Xy|I;WN7Z}BDn?CDUMj30(J>RYYJ|cIN{W*4|Iz@dR#+9fXN3W2}!lU z^a>*tT}-@bnN{ORL|_ix|4e)aOj^Jh<=Jbv`> z!To!8@7%t1^TzdSSFc>Ybn(LZb7#+-K6UcM@nc7i96ogL!2W%E_w3%abI0~=Teoc9 zv~k1wb!*qGUbS+?@?}exEMBy5!Tfo1=ggipbH?;(Q>RRxG;um zQ)5GYU2RQuRb@qaS!qdeQDH%TUT#iyR%S+eT53viQer}UTx?8qRAfYWSZGLaP+)++ zpRbR%m#2rjn=3GW93AZKY;CNqEG^8TBRz;GCL~=}}db8eHWUl3bOYY?-2DZ>L~WVFlEiTau_y zk(-lOY*k^al$esAlxhWJ=cbk<>MJRLRg`4gDmj8A6e4^B6rA&mQWZ?~%yg3t%*++c zE%gjd&CN~Bbrg&Y3{CY7jP;ETbd8LyObo0{j1-_i$vOKg>t6#hd!kXryZHLq9?>>0h}{9OHt!~%UoJp+)3AU@44@b$&7G&dKl z8WTK@=NlI zGx7@*oSnfzrl8@Qn4Fmh6x0N3^7Xay%quQQ%u7!7bg@+e8l#t)nPO#ZX69z#WbSBe zV&-aS=xS!+E!JC-_6+#rr9MwximL5uLPz!1)2QuBbRy$G1B8UO$L`{(zspFh5T`}*bcrw{Mny?yig)yo&ppFMr@ z_|d}$_wU`kbNklK8`rO0y>j`|#S7=pojr5<)X5Xaj~zX7_|U-v`}ghLvwPRh9ox5U z-LiSp#trM&tzENv)yfsimn~hgc+tWI^XJW-Gkey|8PlgtoicgS#0mXjScm6wKdgMl@;Y>r6t8hg$4O}xjETcnHlM6sVT`xi3#y>u`$t6krClxp&`LR zfdT%0zCPYwo*wRQt}f0_jt=&Awl>yQmKNq_rY6Qlh6eh2x;olgni}eAsw&D#iVE^_ zvNFsv}Ud^BZD;nHr$ZY diff --git a/glyphs/icon_dashboard_x.gif b/glyphs/icon_dashboard_x.gif deleted file mode 100644 index 6e508aa7b9fcb4ac264dfdf94c43586b33654fbe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1120 zcmZ?wbhEHbTBRz;GCL~=}}db8eHWUl3bOYY?-2DZ>L~WVFlEiTau_y zk(-lOY*k^al$esAlxhWJ=cbk<>MJRLRg`4gDmj8A6e4^B6rA&mQWZ?~%yg3tO$-#w zE%gk|3`|T7brg&Y49)coO!W=SbPWux3@ogS3>Bb2$vOKg>t6#hd!kXryZHLq9?>>0h}{9OHt!~%UoJp+)3AU@44@b$&7G&dKl z8WTK@=NlI zGx7@*oSi{IW}%?ro0y!L2NcundS0ve;2nVDkcBDn?CDMnbG0(J>RYYJ|c7~|Bd4|Iz@dR#+9fXN3W2}!lU z^a>*tT}-@bnN{ORL|_ix|4e)aOj^Jh<=Jbv`> z!To!8@7%t1^TzdSSFc>Ybn(LZb7#+-K6UcM@nc7i96ogL!2W%E_w3%abI0~=Teoc9 zv~k1wb!*qGUbS+?@?}exEMBy5!Tfo1=ggipbH?;(Q>RRxG;um zQ)5GYU2RQuRb@qaS!qdeQDH%TUT#iyR%S+eT53viQer}UTx?8qRAfYWSZGLaP+)++ zpRbR%m#2rjo2!enlcR&Zovn?vm8FHbnW>4fk)eUUp019zmZpZfnyQMjlA?mVoUDwr zl%#~Xn5c-bke~oRA1@CNHy0-dI~ywtGZP~NgAS;G0F@dHOwv95D_1kr%xMl<7bScw UBmHcwzd@(l%^r;-n^+mF0T@kc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*btCX0MpOk6^Wap-qB64UF}T4Rno+txOE8OpFwuK*`RgC?(A*$i)q66_97Elu=SrV5P5L zUS6(Ou9shwu5V~*X{m2uq;F)T3sj(6T$u;-oo-&SvJ%j-AOl=di<65o3raHc^Aw8G ztP+#*OG|8(lob9$J&;=fH#M(V59}GeYG-AXPsowK%`DC^;3VTp46jft7PnYGO%#QAmD%4lD=*GV)9Ei!<^I z6r7#GL8hSLo0y!L2NcundS0ve;2nVDi`Y;NgdWMu4QWZ>pz zXy|I@XlQBVYUE;UXz6Nc_}|je8K&7KKe;qFHLnDwIR&BF8LAmYFGwpWEr5aq7{EoD zWvMA{Mftf3V1HX>!rg-I6icj50lNgEH3i8fKwls^#1W@feV|kH(V`kA1WZ04CM4AY z(t84%^TORUA=Po(!~qs&z(JU`qar2$B!L7a`@1}1N-;w-Lrew&K=vgZQZhY z)5ZeMTG_VdAT{+S(zE>X{jm6Nr?&Zaj`McQIQehVWA};$o%uI|73_73^0#s@+FtPL0rFC}Ia4}c|0Jk%O AU;qFB diff --git a/glyphs/icon_eye.gif b/glyphs/icon_eye.gif deleted file mode 100644 index a2bd5a42c6494c166ab902b67b494d544bbdde03..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1124 zcmZ?wbhEHbTBRz;GCL~=}}db8eHWUl3bOYY?-2DZ>L~WVFlEiTau_y zk(-lOY*k^al$esAlxhWJ=cbk<>MJRLRg`4gDmj8A6e4^B6rA&mQWZ?~%yg3tO$-#w zE%gk|3`|T7brg&Y49)coO!W=SbPWux3@ogS3>Bb2$vOKg>t6#hd!kXryZHLq9?>>0h}{9OHt!~%UoJp+)3AU@44@b$&7G&dKl z8WTK@=NlI zGx7@*oSi{IW}%?ro0y!L2NcundS0ve;2nVDkcY+&YMU~25@ z?Br}_Xy|I;WN7Z}BDn?CDb84(0(J>RYYJ|cxZu>Q4|Iz@dR#+9fXN3W2}!lU z^a>*tT}-@bnN{ORL|_ix|4e)aOj^Jh<=Jbv`> z!To!8@7%t1^TzdSSFc>Ybn(LZb7#+-K6UcM@nc7i96ogL!2W%E_w3%abI0~=Teoc9 zv~k1wb!*qGUbS+?@?}exEMBy5!Tfo1=ggipbH?;(Q>RRxG;um zQ)5GYU2RQuRb@qaS!qdeQDH%TUT#iyR%S+eT53viQer}UTx?8qRAfYWSZGLaP+)++ zpRbR%m#2rjn=3F>93AZKY;CNqEG^8a@oyW*W@LJs26R0d``LApigX diff --git a/glyphs/icon_left.gif b/glyphs/icon_left.gif deleted file mode 100644 index 524226ba11247d9c5f797801400fd630071a049a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1101 zcmZ?wbhEHbWMN=u_`m=H|NsA2{K*1lD*orL$SqJvNi0bO(*Nx%3KEmEQ%e+*Qqwc@ zY?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*btCX0MpOk6^Wap-qB64UF}T4Rno+txOE8OpFwuK*`RgC?(A*$i)q66_97Elu=SrV5P5L zUS6(Ou9shwu5V~*X{m2uq;F)T3sj(6T$u;-oo-&SvJ%j-AOl=di<65o3raHc^Aw8G ztP+#*OG|8(lob9$J&;=fH#M(V59}GeYG-AXPsowK%`DC^;3VTp46jft7PnYGO%#QAmD%4lD=*GV)9Ei!<^I z6r7#GL8hSLo0y!L2NcundS0ve;2nVDkcY~W;U?r3IeWZ>*# zXy|I@XlQBVYUE;UXz6Nc_}|je8K&7KKe;qFHLnDwIR&BF45}GLFGwpWEr5aq7{EoD zWvMA{Mftf3V1HX>!rg-I6l1JT0lNgEH3i8fKwls^!~~~SeV|kH(V`kA1WZ04CM4AY z(t84%^TORUA=Po(!~qs&z(JU`qar2$B!L7a`@1}1N-;w-Lrew&K=vgZQZhY z)5ZeMTG_VdAT{+S(zE>X{jm6Nr?&Zaj`McQIQehVWA};$o%uI|73_73^0#s@+FmbdLb7tJW=fuch4FGsN BgIfRq diff --git a/glyphs/icon_right.gif b/glyphs/icon_right.gif deleted file mode 100644 index 15ff3cf5994421fbd6e7d593aae8e438310f33ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1100 zcmZ?wbhEHbWMN=u_`m=H|NsA2{K*1lD*orL$SqJvNi0bO(*Nx%3KEmEQ%e+*Qqwc@ zY?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*btCX0MpOk6^Wap-qB64UF}T4Rno+txOE8OpFwuK*`RgC?(A*$i)q66_97Elu=SrV5P5L zUS6(Ou9shwu5V~*X{m2uq;F)T3sj(6T$u;-oo-&SvJ%j-AOl=di<65o3raHc^Aw8G ztP+#*OG|8(lob9$J&;=fH#M(V59}GeYG-AXPsowK%`DC^;3VTp46jft7PnYGO%#QAmD%4lD=*GV)9Ei!<^I z6r7#GL8hSLo0y!L2NcundS0ve;2nVDkcY~W;U?r3IcWZ>*# zXy|I@XlQBVYUE;UXz6Nc_}|je8K&7KKe;qFHLnDwIR&BF2&x%HFGwpWEr5aq7{EoD zWvMA{Mftf3V1HX>!rg-A6jL{>P64|FqBRA{B|u*wIm7^`R(+sT^wFXkCIn1AASNW$ z0@Eju15Nk;OB7P`fT_I*n5-H9|NHyr_phHnzJL4r<@2Wx@87+B^ZM1x7tfzPee(Fx z!w2{8-Mw@B*3BE&uU)-z`O?J;=g*xzbNbZD6UUDoJ#zTa!2|pE?cK9`*UlZ=w{6|B zdDF%X>({MavwGFa70Z_`U9x!5!Ugl^&7CuQ*322xr%jzQdD6rQ{e8VX-Cdm>?QN|s z%}tFB^>wv1)m4=h1nAc$w`R`@o}*+(NU2R;bEa6!9jrm z{(inb-d>&_?ryFw&Q6XF_I9>5)>f7l=4PfQ#zuw)`g*!L+FF_#>T0Sg%1Vj~@^Z2= z(o&KV;$osA!a{-q{CvDTJltHI9PDhYEX+)d3=BG;5&~3eFfg(6@U>OF>g8gv1_1YR Bf|mdQ diff --git a/glyphs/icon_up.gif b/glyphs/icon_up.gif deleted file mode 100644 index 4e13c064f7605feb2e6e04a48a3133e5c95912cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1100 zcmZ?wbhEHbWM^Pu_`m=H|NsA2{K*1lD*orL$SqJvNi0bO(*Nx%3KEmEQ%e+*Qqwc@ zY?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*btCX0MpOk6^Wap-qB64UF}T4Rno+txOE8OpFwuK*`RgC?(A*$i)q66_97Elu=SrV5P5L zUS6(Ou9shwu5V~*X{m2uq;F)T3sj(6T$u;-oo-&SvJ%j-AOl=di<65o3raHc^Aw8G ztP+#*OG|8(lob9$J&;=fH#M(V59}GeYG-AXPsowK%`DC^;3VTp46jft7PnYGO%#QAmD%4lD=*GV)9Ei!<^I z6r7#GL8hSLo0y!L2NcundS0ve;2nVDi`Y;NgdWMu4SWZ>pz zXy|I@XlQBVYUE;UXz6Nc_}|je8K&7KKe;qFHLnDwIR&oS!~m)pMK4GzC@p}31Q@_Y znPsUdZbkXI3SfU*Wy0Np?i3fSP64|FqBRA{B|u*w9AfN>Q>#AEDf(zp4HE(;9}p9g zYJuq!$bqK&|0N2kdBD_O1WeY9|Ns5{^ZVD&AK$-y{qp(KhxhN^zIpxX<%{Rfo<4c} z=;4F=_wL@gee33p>({PcxqRv3h4bgmo;iK$#u35cm<%;FYmM&SmXyJnS^XAT(J!|HS>C>i8nLKIYg#NzXp6;&Bj`p_J zmgc6$hWfhNn(C^`it@73lH#Jmg8aPPob0U3jP$hBl;otug!s7FnCPg;i14t`kl>)e z0DnJUA8#*D4|g|L7iT9&2YWkP8*3{|3v)A56JsMo1ARSR9c?X54RtkD6=fww1$jAH z8EGj=32`w|5n&-g0e(JS9v*HkP7Zc9Ru*O^Mg|5QPzeDlH5i!KTar5~xYlqnSOWmI C)q;Qk diff --git a/glyphs/icon_validate_14.gif b/glyphs/icon_validate_14.gif deleted file mode 100644 index 0ceb67ebeaa261c6c2f3236a030222a56682acef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1119 zcmZ?wbhEHbTBRz;GCL~=}}db8eHWUl3bOYY?-2DZ>L~WVFlEiTau_y zk(-lOY*k^al$esAlxhWJ=cbk<>MJRLRg`4gDmj8A6e4^B6rA&mQWZ?~%yg3tO$-#w zE%gk|3`|T7brg&Y49)coO!W=SbPWux3@ogS3>Bb2$vOKg>t6#hd!kXryZHLq9?>>0h}{9OHt!~%UoJp+)3AU@44@b$&7G&dKl z8WTK@=NlI zGx7@*oSi{IW}%?ro0y!L2NcundS0ve;2nVDkcY+&YMU}|FI z?Br}_Xy|I;WN7Z}BDn?CDF#@b0(J>RYYJ|c7~<5c4|Iz@dR#+9fXN3W2}!lU z^a>*tT}-@bnN{ORL|_ix|4e)aOj^Jh<=Jbv`> z!To!8@7%t1^TzdSSFc>Ybn(LZb7#+-K6UcM@nc7i96ogL!2W%E_w3%abI0~=Teoc9 zv~k1wb!*qGUbS+?@?}exEMBy5!Tfo1=ggipbH?;(Q>RRxG;um zQ)5GYU2RQuRb@qaS!qdeQDH%TUT#iyR%S+eT53viQer}UTx?8qRAfYWSZGLaP+)++ zpRbR%m#2rjo2!enlcR&Zovn?vm8FHbnW>4fk)eUUp019zmZpZfnyQMjlA?mVoUDwr zl%#~Xn5c-bke~oRA1@CNHy0-dI~ywtGZP~NgAS;G0F@dHOj14lD^K5Lh-vufSS)Ni TJ3YQs>Z|6G5HGD@1_o;Y_R@=% diff --git a/glyphs/icon_warning.gif b/glyphs/icon_warning.gif deleted file mode 100644 index a3ee4bfcb4f7ea78f6f369fce3b991fbeee66486..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1124 zcmZ?wbhEHbTBRz;GCL~=}}db8eHWUl3bOYY?-2DZ>L~WVFlEiTau_y zk(-lOY*k^al$esAlxhWJ=cbk<>MJRLRg`4gDmj8A6e4^B6rA&mQWZ?~%yg3tO$-#w zE%gk|3`|T7brg&Y49)coO!W=SbPWux3@ogS3>Bb2$vOKg>t6#hd!kXryZHLq9?>>0h}{9OHt!~%UoJp+)3AU@44@b$&7G&dKl z8WTK@=NlI zGx7@*oSi{IW}%?ro0y!L2NcundS0ve;2nVDkcWNu>U>SSc> z?Br}_Xy|I;WN7Z}BDn?CDTY{`0(J>RYYJ|c7~#~b4|Iz@dR#+9fXN3W2}!lU z^a>*tT}-@bnN{ORL|_ix|4e)aOj^Jh<=Jbv`> z!To!8@7%t1^TzdSSFc>Ybn(LZb7#+-K6UcM@nc7i96ogL!2W%E_w3%abI0~=Teoc9 zv~k1wb!*qGUbS+?@?}exEMBy5!Tfo1=ggipbH?;(Q>RRxG;um zQ)5GYU2RQuRb@qaS!qdeQDH%TUT#iyR%S+eT53viQer}UTx?8qRAfYWSZGLaP+)++ zpRbR%m#2rjo2!enlcR&Zovn?vm8FHbnW>4fk)eUUp019zmZpZfnyQMjlA?mVoUDwr zl%#~Xn5c-bke~oRA1@CNHy0-dI~ywtGZP~NgAS;G0F@dHO!7VbGZ|LB5ok6viPo$w Z_kJrmS;FsG#f&Fq>mJ+;^JHYO1^_=}k2C-P diff --git a/include/apdu_constants.h b/include/apdu_constants.h deleted file mode 100644 index 1aa127d3..00000000 --- a/include/apdu_constants.h +++ /dev/null @@ -1,145 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef APDU_CONSTANTS_H - -#define APDU_CONSTANTS_H - -#define CLA 0xE0 -#define ADM_CLA 0xD0 -#define NFCPAYMENT_CLA 0xF0 - -#define INS_SETUP 0x20 -#define INS_VERIFY_PIN 0x22 -#define INS_GET_OPERATION_MODE 0x24 -#define INS_SET_OPERATION_MODE 0x26 -#define INS_SET_KEYBOARD_CFG 0x28 -#define INS_GET_WALLET_PUBLIC_KEY 0x40 -#define INS_GET_TRUSTED_INPUT 0x42 -#define INS_HASH_INPUT_START 0x44 -#define INS_HASH_INPUT_FINALIZE 0x46 -#define INS_HASH_SIGN 0x48 -#define INS_HASH_INPUT_FINALIZE_FULL 0x4A -#define INS_GET_INTERNAL_CHAIN_INDEX 0x4C -#define INS_SIGN_MESSAGE 0x4E -#define INS_GET_TRANSACTION_LIMIT 0xA0 -#define INS_SET_TRANSACTION_LIMIT 0xA2 -#define INS_IMPORT_PRIVATE_KEY 0xB0 -#define INS_GET_PUBLIC_KEY 0xB2 -#define INS_DERIVE_BIP32_KEY 0xB4 -#define INS_SIGNVERIFY_IMMEDIATE 0xB6 -#define INS_GET_RANDOM 0xC0 -#define INS_GET_ATTESTATION 0xC2 -#define INS_GET_FIRMWARE_VERSION 0xC4 -#define INS_COMPOSE_MOFN_ADDRESS 0xC6 -#define INS_GET_POS_SEED 0xCA -#define INS_DEBUG 0xD0 - -#define INS_ADM_INIT_KEYS 0x20 -#define INS_ADM_INIT_ATTESTATION 0x22 -#define INS_ADM_GET_UPDATE_ID 0x24 -#define INS_ADM_SET_KEYCARD_SEED 0x26 -#define INS_ADM_FIRMWARE_UPDATE 0x42 - -#define INS_SET_USER_KEYCARD 0x10 -#define INS_SETUP_SECURE_SCREEN 0x12 -#define INS_SET_ALTERNATE_COIN_VER 0x14 -#define INS_GET_COIN_VER 0x16 - -#define INS_STORE_TRUST_ROOT_BIP70 0x30 -#define INS_CREATE_CERTIFICATE_BIP70 0x32 -#define INS_CREATE_PAYMENT_REQ_BIP70 0x34 -#define INS_PROCESS_CERTIFICATE_BIP70 0x36 -#define INS_PARSE_PAYMENT_REQ_BIP70 0x38 -#define INS_HASH_INPUT_FINALIZE_BIP70 0x3A -#define INS_ADM_SET_ROOT_BIP70 0x28 -#define INS_ADM_SET_BIP39_SHUFFLE 0x2A - -#define INS_NFCPAYMENT_SET_CONFIG 0x20 -#define INS_NFCPAYMENT_GET_CONFIG 0x22 -#define INS_NFCPAYMENT_STORE_UTXO 0x40 -#define INS_NFCPAYMENT_STORE_SCRIPT 0x42 -#define INS_NFCPAYMENT_GET_UTXO 0x44 -#define INS_NFCPAYMENT_DELETE_UTXO 0x46 -#define INS_NFCPAYMENT_GET_PAYMENT_TX 0x50 -#define INS_NFCPAYMENT_GET_LAST_TX 0x52 -#define INS_NFCPAYMENT_CONFIRM_TX 0x54 -#define INS_NFCPAYMENT_CONFIRM_CHANGE 0x56 -#define INS_NFCPAYMENT_GET_LAST_STAT 0x58 -#define INS_NFCPAYMENT_GET_DATA 0xC0 - -#define SW_PIN_REMAINING_ATTEMPTS 0x63C0 -#define SW_INCORRECT_LENGTH 0x6700 -#define SW_COMMAND_INCOMPATIBLE_FILE_STRUCTURE 0x6981 -#define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 -#define SW_CONDITIONS_OF_USE_NOT_SATISFIED 0x6985 -#define SW_INCORRECT_DATA 0x6A80 -#define SW_NOT_ENOUGH_MEMORY_SPACE 0x6A84 -#define SW_REFERENCED_DATA_NOT_FOUND 0x6A88 -#define SW_FILE_ALREADY_EXISTS 0x6A89 -#define SW_SWAP_WITHOUT_TRUSTED_INPUTS 0x6A8A -#define SW_INCORRECT_P1_P2 0x6B00 -#define SW_INS_NOT_SUPPORTED 0x6D00 -#define SW_CLA_NOT_SUPPORTED 0x6E00 -#define SW_TECHNICAL_PROBLEM 0x6F00 -#define SW_OK 0x9000 -#define SW_MEMORY_PROBLEM 0x9240 -#define SW_NO_EF_SELECTED 0x9400 -#define SW_INVALID_OFFSET 0x9402 -#define SW_FILE_NOT_FOUND 0x9404 -#define SW_INCONSISTENT_FILE 0x9408 -#define SW_ALGORITHM_NOT_SUPPORTED 0x9484 -#define SW_INVALID_KCV 0x9485 -#define SW_CODE_NOT_INITIALIZED 0x9802 -#define SW_ACCESS_CONDITION_NOT_FULFILLED 0x9804 -#define SW_CONTRADICTION_SECRET_CODE_STATUS 0x9808 -#define SW_CONTRADICTION_INVALIDATION 0x9810 -#define SW_CODE_BLOCKED 0x9840 -#define SW_MAX_VALUE_REACHED 0x9850 -#define SW_GP_AUTH_FAILED 0x6300 -#define SW_LICENSING 0x6F42 -#define SW_HALTED 0x6FAA -#define SW_APP_HALTED SW_CONDITIONS_OF_USE_NOT_SATISFIED - -#define ISO_OFFSET_CLA 0x00 -#define ISO_OFFSET_INS 0x01 -#define ISO_OFFSET_P1 0x02 -#define ISO_OFFSET_P2 0x03 -#define ISO_OFFSET_LC 0x04 -#define ISO_OFFSET_CDATA 0x05 - -#define BITID_DERIVE 0xB11D -#define BITID_DERIVE_MULTIPLE 0xB11E - -#include "os.h" -#include "secure_value.h" - -void commit_operation_mode(secu8 operationMode); - -unsigned short apdu_get_wallet_public_key(void); -unsigned short apdu_get_trusted_input(void); -unsigned short apdu_hash_input_start(void); -unsigned short apdu_hash_input_finalize(void); -unsigned short apdu_hash_sign(void); -unsigned short apdu_hash_input_finalize_full(void); -unsigned short apdu_sign_message(void); - -unsigned short apdu_get_firmware_version(void); - -unsigned short apdu_get_coin_version(void); - -#endif diff --git a/include/config.h b/include/config.h deleted file mode 100644 index dac4e214..00000000 --- a/include/config.h +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef CONFIG_H - -#define CONFIG_H - -//#define DISABLE_SECURE_VALUE - -#define VERBOSE_6F - -#define os_crc cx_crc16 - -#endif diff --git a/include/filesystem.h b/include/filesystem.h deleted file mode 100644 index fe994dc9..00000000 --- a/include/filesystem.h +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef FS_H - -#define FS_H - -#include "os.h" -#include "config.h" -#include "context.h" -#include "filesystem_tx.h" - -enum supported_modes_e { - SUPPORTED_MODE_WALLET = 0x01, - SUPPORTED_MODE_RELAXED_WALLET = 0x02, - SUPPORTED_MODE_SERVER = 0x04, - SUPPORTED_MODE_DEVELOPER = 0x08 -}; - -enum family_e { - FAMILY_BITCOIN = 0x01, - FAMILY_PEERCOIN = 0x02, - FAMILY_STEALTH = 0x04 -}; - -struct config_s { - secu8 supportedModes; - secu8 operationMode; - unsigned char options; - // unsigned short payToAddressVersion; - // unsigned short payToScriptHashVersion; - // unsigned char coinFamily; - // /** Current Coin ID */ - // unsigned char coinId[MAX_COIN_ID]; - // /** Current short Coin ID */ - // unsigned char shortCoinId[MAX_SHORT_COIN_ID]; - // /** Current Coin ID length */ - // unsigned char coinIdLength; - // /** Current short Coin ID length */ - // unsigned char shortCoinIdLength; -}; -typedef struct config_s config_t; - -typedef struct backup_area_s { - config_t config; - uint8_t trustedinput_key[32]; -} backup_area_t; - -typedef struct storage_s { - unsigned char storageInitialized; - - unsigned char config_valid; - backup_area_t bkp; - - unsigned char fidoTransport; - - uint8_t pubKeyRequestRestriction; - -} storage_t; - -// the global nvram memory variable -#if 0 -extern storage_t N_real; -#define N_btchip (*(storage_t *)PIC(&N_real)) -#else -extern storage_t const N_real; -#define N_btchip (*(volatile storage_t *)PIC(&N_real)) -#endif - -void set_operation_mode(unsigned char operationMode); - -#endif diff --git a/include/secure_value.h b/include/secure_value.h deleted file mode 100644 index 8052084a..00000000 --- a/include/secure_value.h +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef SECURE_VALUE_H - -#define SECURE_VALUE_H - -#include "os.h" - -typedef unsigned short secu8; -typedef unsigned long int secu16; - -void sbSet(secu8 *target, unsigned char source); -void sbCheck(secu8 source); -void ssSet(secu16 *target, unsigned short source); -void ssCheck(secu16 source); - -#define SB_GET(x) ((unsigned char)x) - -#define SB_SET(x, y) sbSet(&x, y); - -#define SB_CHECK(x) sbCheck(x); - -#define SS_GET(x) ((unsigned short)x) - -#define SS_SET(x, y) ssSet(&x, y); - -#define SS_CHECK(x) ssCheck(x); - -#define SSEC_DEF(x) unsigned char x = 0; -#define SSEC_INC(x) x++; -#define SSEC_CHECK(x, value) \ - if (x != value) \ - reset(); - -#endif diff --git a/include/swap_lib_calls.h b/include/swap_lib_calls.h deleted file mode 100644 index 806e5f09..00000000 --- a/include/swap_lib_calls.h +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once - -/* This file is the shared API between Exchange and the apps started in Library mode for Exchange - * - * DO NOT MODIFY THIS FILE IN APPLICATIONS OTHER THAN EXCHANGE - * On modification in Exchange, forward the changes to all applications supporting Exchange - */ - -#include "stdbool.h" -#include "stdint.h" -#include "context.h" - -#define RUN_APPLICATION 1 - -#define SIGN_TRANSACTION 2 - -#define CHECK_ADDRESS 3 - -#define GET_PRINTABLE_AMOUNT 4 - -/* - * Amounts are stored as bytes, with a max size of 16 (see protobuf - * specifications). Max 16B integer is 340282366920938463463374607431768211455 - * in decimal, which is a 32-long char string. - * The printable amount also contains spaces, the ticker symbol (with variable - * size, up to 12 in Ethereum for instance) and a terminating null byte, so 50 - * bytes total should be a fair maximum. - */ -#define MAX_PRINTABLE_AMOUNT_SIZE 50 - -// structure that should be send to specific coin application to get address -typedef struct check_address_parameters_s { - // IN - uint8_t *coin_configuration; - uint8_t coin_configuration_length; - // serialized path, segwit, version prefix, hash used, dictionary etc. - // fields and serialization format depends on specific coin app - uint8_t *address_parameters; - uint8_t address_parameters_length; - char *address_to_check; - char *extra_id_to_check; - // OUT - int result; -} check_address_parameters_t; - -// structure that should be send to specific coin application to get printable amount -typedef struct get_printable_amount_parameters_s { - // IN - uint8_t *coin_configuration; - uint8_t coin_configuration_length; - uint8_t *amount; - uint8_t amount_length; - bool is_fee; - // OUT - char printable_amount[MAX_PRINTABLE_AMOUNT_SIZE]; -} get_printable_amount_parameters_t; - -typedef struct create_transaction_parameters_s { - // IN - uint8_t *coin_configuration; - uint8_t coin_configuration_length; - uint8_t *amount; - uint8_t amount_length; - uint8_t *fee_amount; - uint8_t fee_amount_length; - char *destination_address; - char *destination_address_extra_id; - // OUT - uint8_t result; -} create_transaction_parameters_t; - -typedef struct libargs_s { - unsigned int id; - unsigned int command; - altcoin_config_t *coin_config; - union { - check_address_parameters_t *check_address; - create_transaction_parameters_t *create_transaction; - get_printable_amount_parameters_t *get_printable_amount; - }; -} libargs_t; diff --git a/lib-app-bitcoin/Makefile b/lib-app-bitcoin/Makefile new file mode 100644 index 00000000..829f84d9 --- /dev/null +++ b/lib-app-bitcoin/Makefile @@ -0,0 +1,141 @@ +# **************************************************************************** +# Ledger App Bitcoin +# (c) 2023 Ledger SAS. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# **************************************************************************** + +ifeq ($(BOLOS_SDK),) +$(error Environment variable BOLOS_SDK is not set) +endif +include $(BOLOS_SDK)/Makefile.defines + +######################################## +# Mandatory configuration # +######################################## +# Name is defined later + +ifeq ($(APPVERSION_M),) +$(error APPVERSION_M must be defined) +endif +ifeq ($(APPVERSION_N),) +$(error APPVERSION_N must be defined) +endif +ifeq ($(APPVERSION_P),) +$(error APPVERSION_P must be defined) +endif + +APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" + +APP_SOURCE_PATH += lib-app-bitcoin/ + +ICON_NANOS = icons/nanos_app_$(COIN).gif +ICON_NANOX = icons/nanox_app_$(COIN).gif +ICON_NANOSP = icons/nanox_app_$(COIN).gif +ICON_STAX = icons/stax_app_$(COIN).gif + +ifeq ($(TARGET_NAME),TARGET_STAX) +DEFINES += COIN_ICON=C_$(COIN)_64px +DEFINES += COIN_ICON_BITMAP=C_$(COIN)_64px_bitmap +endif + +# Application allowed derivation curves. +CURVE_APP_LOAD_PARAMS ?= secp256k1 + +# Application allowed derivation paths. +# Currently there is no path restriction +PATH_APP_LOAD_PARAMS ?= "" + +HAVE_APPLICATION_FLAG_DERIVE_MASTER = 1 +HAVE_APPLICATION_FLAG_LIBRARY = 1 + +VARIANT_PARAM = COIN + +ENABLE_BLUETOOTH = 1 +ENABLE_NBGL_QRCODE = 1 +ENABLE_SWAP = 1 + +ifndef BIP44_COIN_TYPE +$(error BIP44_COIN_TYPE must be defined) +endif + +ifndef BIP44_COIN_TYPE_2 +$(error BIP44_COIN_TYPE_2 must be defined) +endif + +ifndef COIN_P2PKH_VERSION +$(error COIN_P2PKH_VERSION must be defined) +endif + +ifndef COIN_P2SH_VERSION +$(error COIN_P2SH_VERSION must be defined) +endif + +ifndef COIN_FAMILY +$(error COIN_FAMILY must be defined) +endif + +ifndef COIN_COINID +$(error COIN_COINID must be defined) +endif + +ifndef COIN_COINID_HEADER +$(error COIN_COINID_HEADER must be defined) +endif + +ifndef COIN_COINID_NAME +$(error COIN_COINID_NAME must be defined) +endif + +ifndef COIN_COINID_SHORT +$(error COIN_COINID_SHORT must be defined) +endif + +ifndef COIN_NATIVE_SEGWIT_PREFIX +$(info COIN_NATIVE_SEGWIT_PREFIX automatically set to 0) +COIN_NATIVE_SEGWIT_PREFIX=0 +endif + +ifndef COIN_KIND +$(error COIN_KIND must be defined) +endif + +ifndef COIN_FLAGS +$(info COIN_FLAGS automatically set to 0) +COIN_FLAGS=0 +endif + +ifndef COIN_FORKID +$(info COIN_FORKID automatically set to 0) +COIN_FORKID=0 +endif + +ifeq ($(APPNAME),) +$(error APPNAME must be defined) +endif + +DEFINES +=BIP44_COIN_TYPE=$(BIP44_COIN_TYPE) +DEFINES +=BIP44_COIN_TYPE_2=$(BIP44_COIN_TYPE_2) +DEFINES +=COIN_P2PKH_VERSION=$(COIN_P2PKH_VERSION) +DEFINES +=COIN_P2SH_VERSION=$(COIN_P2SH_VERSION) +DEFINES +=COIN_FAMILY=$(COIN_FAMILY) +DEFINES +=COIN_COINID=$(COIN_COINID) +DEFINES +=COIN_COINID_HEADER=$(COIN_COINID_HEADER) +DEFINES +=COIN_COINID_NAME=$(COIN_COINID_NAME) +DEFINES +=COIN_COINID_SHORT=$(COIN_COINID_SHORT) +DEFINES +=COIN_NATIVE_SEGWIT_PREFIX=$(COIN_NATIVE_SEGWIT_PREFIX) +DEFINES +=COIN_KIND=$(COIN_KIND) +DEFINES +=COIN_FLAGS=$(COIN_FLAGS) +DEFINES +=COIN_FORKID=$(COIN_FORKID) + +include $(BOLOS_SDK)/Makefile.standard_app diff --git a/lib-app-bitcoin/apdu/apdu_constants.h b/lib-app-bitcoin/apdu/apdu_constants.h new file mode 100644 index 00000000..f5265425 --- /dev/null +++ b/lib-app-bitcoin/apdu/apdu_constants.h @@ -0,0 +1,60 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#pragma once + +#include "os.h" +#include "buffer.h" +#include "macros.h" + +#define CLA 0xE0 + +#define INS_GET_WALLET_PUBLIC_KEY 0x40 +#define INS_GET_TRUSTED_INPUT 0x42 +#define INS_HASH_INPUT_START 0x44 +#define INS_HASH_SIGN 0x48 +#define INS_HASH_INPUT_FINALIZE_FULL 0x4A +#define INS_SIGN_MESSAGE 0x4E +#define INS_GET_FIRMWARE_VERSION 0xC4 +#define INS_GET_COIN_VER 0x16 + +#define SW_INCORRECT_LENGTH 0x6700 +#define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 +#define SW_CONDITIONS_OF_USE_NOT_SATISFIED 0x6985 +#define SW_INCORRECT_DATA 0x6A80 +#define SW_SWAP_WITHOUT_TRUSTED_INPUTS 0x6A8A +#define SW_INCORRECT_P1_P2 0x6B00 +#define SW_INS_NOT_SUPPORTED 0x6D00 +#define SW_CLA_NOT_SUPPORTED 0x6E00 +#define SW_TECHNICAL_PROBLEM 0x6F00 +#define SW_TECHNICAL_PROBLEM_2 0x6F0F +#define SW_OK 0x9000 + +#define BITID_DERIVE 0xB11D +#define BITID_DERIVE_MULTIPLE 0xB11E + +#define ZCASH_USING_OVERWINTER 0x01 +#define ZCASH_USING_OVERWINTER_SAPLING 0x02 + +unsigned short handler_sign_message(buffer_t* buffer, uint8_t p1, uint8_t p2); +unsigned short handler_hash_sign(buffer_t* buffer, uint8_t p1, uint8_t p2); +unsigned short handler_hash_input_start(buffer_t* buffer, uint8_t p1, uint8_t p2); +unsigned short handler_hash_input_finalize_full(buffer_t* buffer, uint8_t p1, uint8_t p2); +unsigned short handler_get_wallet_public_key(buffer_t* buffer, uint8_t p1, uint8_t p2); +unsigned short handler_get_trusted_input(buffer_t* buffer, uint8_t p1, uint8_t p2); +unsigned short handler_get_firmware_version(void); +unsigned short handler_get_coin_version(void); + diff --git a/lib-app-bitcoin/apdu/dispatcher.c b/lib-app-bitcoin/apdu/dispatcher.c new file mode 100644 index 00000000..7e2c6c0e --- /dev/null +++ b/lib-app-bitcoin/apdu/dispatcher.c @@ -0,0 +1,117 @@ +/***************************************************************************** + * Ledger App Boilerplate. + * (c) 2020 Ledger SAS. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *****************************************************************************/ + +#include +#include + +#include "buffer.h" +#include "io.h" +#include "ledger_assert.h" + +#include "dispatcher.h" +#include "apdu_constants.h" + +int apdu_dispatcher(const command_t *cmd) { + LEDGER_ASSERT(cmd != NULL, "NULL cmd"); + + if (cmd->cla != CLA) { + return io_send_sw(SW_CLA_NOT_SUPPORTED); + } + + buffer_t buf = {0}; + + switch (cmd->ins) { + case INS_GET_WALLET_PUBLIC_KEY: + PRINTF("Get wallet public key\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_get_wallet_public_key(&buf, cmd->p1, cmd->p2); + + case INS_GET_TRUSTED_INPUT: + PRINTF("Get trusted input\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_get_trusted_input(&buf, cmd->p1, cmd->p2); + + case INS_HASH_INPUT_START: + PRINTF("Hash input start\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_hash_input_start(&buf, cmd->p1, cmd->p2); + + case INS_HASH_SIGN: + PRINTF("Hash sign\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_hash_sign(&buf, cmd->p1, cmd->p2); + + case INS_HASH_INPUT_FINALIZE_FULL: + PRINTF("Hash input finalize full\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_hash_input_finalize_full(&buf, cmd->p1, cmd->p2); + + case INS_SIGN_MESSAGE: + PRINTF("Sign message\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_sign_message(&buf, cmd->p1, cmd->p2); + + case INS_GET_FIRMWARE_VERSION: + PRINTF("Get firmware version\n"); + + return handler_get_firmware_version(); + + case INS_GET_COIN_VER: + PRINTF("Get coin version\n"); + + return handler_get_coin_version(); + + default: + PRINTF("Instruction not supported\n"); + return io_send_sw(SW_INS_NOT_SUPPORTED); + } +} diff --git a/lib-app-bitcoin/apdu/dispatcher.h b/lib-app-bitcoin/apdu/dispatcher.h new file mode 100644 index 00000000..36e1f60c --- /dev/null +++ b/lib-app-bitcoin/apdu/dispatcher.h @@ -0,0 +1,14 @@ +#pragma once + +#include "parser.h" + +/** + * Dispatch APDU command received to the right handler. + * + * @param[in] cmd + * Structured APDU command (CLA, INS, P1, P2, Lc, Command data). + * + * @return zero or positive integer if success, negative integer otherwise. + * + */ +int apdu_dispatcher(const command_t *cmd); diff --git a/lib-app-bitcoin/app_main.c b/lib-app-bitcoin/app_main.c new file mode 100644 index 00000000..c2f9a62b --- /dev/null +++ b/lib-app-bitcoin/app_main.c @@ -0,0 +1,72 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#include "swap.h" +#include "io.h" + +#include "context.h" +#include "apdu_constants.h" +#include "dispatcher.h" +#include "ui.h" + + +void app_main(void) { + // Structured APDU command + command_t cmd; + + io_init(); + + if (!G_called_from_swap) { + ui_idle_flow(); + } + + context_init(); + + for (;;) { + // Length of APDU command received in G_io_apdu_buffer + int input_len = 0; + + // Receive command bytes in G_io_apdu_buffer + if ((input_len = io_recv_command()) < 0) { + PRINTF("=> io_recv_command failure\n"); + return; + } + + // Parse APDU command from G_io_apdu_buffer + if (!apdu_parser(&cmd, G_io_apdu_buffer, input_len)) { + PRINTF("=> /!\\ BAD LENGTH: %.*H\n", input_len, G_io_apdu_buffer); + io_send_sw(SW_INCORRECT_LENGTH); + continue; + } + + PRINTF("=> CLA=%02X | INS=%02X | P1=%02X | P2=%02X | Lc=%02X | CData=%.*H\n", + cmd.cla, + cmd.ins, + cmd.p1, + cmd.p2, + cmd.lc, + cmd.lc, + cmd.data); + + context.outLength = 0; + + // Dispatch structured APDU command to handler + if (apdu_dispatcher(&cmd) < 0) { + PRINTF("=> apdu_dispatcher failure\n"); + return; + } + } +} diff --git a/src/context.c b/lib-app-bitcoin/context.c similarity index 65% rename from src/context.c rename to lib-app-bitcoin/context.c index 3ff49151..2cf6da40 100644 --- a/src/context.c +++ b/lib-app-bitcoin/context.c @@ -15,23 +15,24 @@ * limitations under the License. ********************************************************************************/ -#include "internal.h" -#include "swap.h" +#include "context.h" +#include "filesystem.h" -void autosetup(void); +context_t context; +storage_t const N_real; /** * Initialize the application context on boot */ void context_init() { PRINTF("Context init\n"); - PRINTF("Backup size %d\n", sizeof(N_btchip.bkp)); - memset(&context_D, 0, sizeof(context_D)); - G_called_from_swap = 0; - context_D.currentOutputOffset = 0; - context_D.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; - memset(context_D.totalOutputAmount, 0, - sizeof(context_D.totalOutputAmount)); - context_D.changeOutputFound = 0; - context_D.segwitWarningSeen = 0; + PRINTF("Backup size %d\n", sizeof(g_nvram_data.bkp)); + memset(&context, 0, sizeof(context)); + context.currentOutputOffset = 0; + context.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; + memset(context.totalOutputAmount, 0, + sizeof(context.totalOutputAmount)); + context.changeOutputFound = 0; + context.segwitWarningSeen = 0; } + diff --git a/include/context.h b/lib-app-bitcoin/context.h similarity index 91% rename from include/context.h rename to lib-app-bitcoin/context.h index 4f23f4db..48a4aa1a 100644 --- a/include/context.h +++ b/lib-app-bitcoin/context.h @@ -15,13 +15,10 @@ * limitations under the License. ********************************************************************************/ -#ifndef CONTEXT_H - -#define CONTEXT_H +#pragma once #include "os.h" #include "cx.h" -#include "secure_value.h" #include "filesystem_tx.h" #ifdef HAVE_NBGL #include "nbgl_types.h" @@ -33,27 +30,6 @@ #define MAX_SHORT_COIN_ID 5 #define MAGIC_TRUSTED_INPUT 0x32 -#define MAGIC_DEV_KEY 0x01 - -#define ZCASH_USING_OVERWINTER 0x01 -#define ZCASH_USING_OVERWINTER_SAPLING 0x02 - -enum modes_e { - MODE_ISSUER = 0x00, - MODE_SETUP_NEEDED = 0xff, - MODE_WALLET = 0x01, - MODE_RELAXED_WALLET = 0x02, - MODE_SERVER = 0x04, - MODE_DEVELOPER = 0x08, -}; - -enum options_e { - OPTION_UNCOMPRESSED_KEYS = 0x01, - OPTION_DETERMINISTIC_SIGNATURE = 0x02, - OPTION_FREE_SIGHASHTYPE = 0x04, - OPTION_SKIP_2FA_P2SH = 0x08, - OPTION_ALLOW_ARBITRARY_CHANGE = 0x10 -}; /** * Current state of an untrusted transaction hashing @@ -156,8 +132,6 @@ struct tmp_output_s { typedef struct tmp_output_s tmp_output_t; struct context_s { - /** Flag if dongle has been halted */ - secu8 halted; /** Index of the output to convert into a trusted input in a transaction */ unsigned long int trustedInputIndex; /** (Integrity protected) transaction context */ @@ -200,9 +174,6 @@ struct context_s { /** Length of the outgoing command */ unsigned short outLength; - /** IO flags to reply with at the end of an APDU handler */ - unsigned char io_flags; - /** Status Word of the response */ unsigned short sw; @@ -284,4 +255,4 @@ typedef enum coin_kind_e { void context_init(void); -#endif +extern context_t context; diff --git a/lib-app-bitcoin/customizable_helpers.c b/lib-app-bitcoin/customizable_helpers.c new file mode 100644 index 00000000..78e70a39 --- /dev/null +++ b/lib-app-bitcoin/customizable_helpers.c @@ -0,0 +1,151 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#include "macros.h" + +#include "context.h" +#include "customizable_helpers.h" + +const unsigned char TRANSACTION_OUTPUT_SCRIPT_PRE[] = { + 0x19, 0x76, 0xA9, + 0x14}; // script length, OP_DUP, OP_HASH160, address length +const unsigned char TRANSACTION_OUTPUT_SCRIPT_POST[] = { + 0x88, 0xAC}; // OP_EQUALVERIFY, OP_CHECKSIG + +const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { + 0x17, 0xA9, 0x14}; // script length, OP_HASH160, address length +const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL + +const unsigned char ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { + 0x3D, 0xA9, + 0x14}; // script length, OP_HASH160, address length + +const unsigned char ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = { + 0x87, // OP_EQUAL + 0x20, 0x9E, 0xC9, 0x84, 0x5A, 0xCB, 0x02, 0xFA, 0XB2, 0X4E, + 0x1C, 0x03, 0x68, 0xB3, 0xB5, 0x17, 0xC1, 0xA4, 0x48, 0x8F, + 0xBA, 0x97, 0xF0, 0xE3, 0x45, 0x9A, 0xC0, 0x53, 0xEA, 0x01, + 0x00, 0x00, 0x00, // ParamHash + 0x03, // Push 3 bytes to stack to make ParamHeight line up properly + 0xC0, 0x1F, 0x02, // ParamHeight (139200) -> hex -> endianness swapped + 0xB4}; // OP_CHECKBLOCKATHEIGHT + +const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE[] = {0x16, 0x00, 0x14}; +const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE[] = {0x22, 0x00, 0x20}; + +const unsigned char ZEN_OUTPUT_SCRIPT_PRE[] = { + 0x3F, 0x76, 0xA9, + 0x14}; // script length, OP_DUP, OP_HASH160, address length +const unsigned char ZEN_OUTPUT_SCRIPT_POST[] = { + 0x88, 0xAC, // OP_EQUALVERIFY, OP_CHECKSIG + 0x20, 0x9e, 0xc9, 0x84, 0x5a, 0xcb, 0x02, 0xfa, 0xb2, 0x4e, 0x1c, 0x03, + 0x68, 0xb3, 0xb5, 0x17, 0xc1, 0xa4, 0x48, 0x8f, 0xba, 0x97, 0xf0, 0xe3, + 0x45, 0x9a, 0xc0, 0x53, 0xea, 0x01, 0x00, 0x00, 0x00, // ParamHash + 0x03, // Push 3 bytes to stack to make ParamHeight line up properly + 0xc0, 0x1f, 0x02, // ParamHeight (139200) -> hex -> endianness swapped + 0xb4 // OP_CHECKBLOCKATHEIGHT +}; // BIP0115 Replay Protection + +WEAK unsigned char output_script_is_regular(unsigned char *buffer) { + if (COIN_NATIVE_SEGWIT_PREFIX) { + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || + (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { + return 1; + } + } + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) && + (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, + TRANSACTION_OUTPUT_SCRIPT_POST, + sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { + return 1; + } + if (COIN_KIND == COIN_KIND_HORIZEN) { + if ((memcmp(buffer, ZEN_OUTPUT_SCRIPT_PRE, + sizeof(ZEN_OUTPUT_SCRIPT_PRE)) == 0) && + (memcmp(buffer + sizeof(ZEN_OUTPUT_SCRIPT_PRE) + 20, + ZEN_OUTPUT_SCRIPT_POST, + sizeof(ZEN_OUTPUT_SCRIPT_POST)) == 0)) { + return 1; + } + } + + return 0; +} + +WEAK unsigned char output_script_is_p2sh(unsigned char *buffer) { + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && + (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, + TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { + return 1; + } + if (COIN_KIND == COIN_KIND_HORIZEN) { + if ((memcmp(buffer, ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && + (memcmp(buffer + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, + ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { + return 1; + } + } + return 0; +} + +WEAK unsigned char output_script_is_native_witness(unsigned char *buffer) { + if (COIN_NATIVE_SEGWIT_PREFIX) { + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || + (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { + return 1; + } + } + return 0; +} + +WEAK unsigned char output_script_is_op_return(unsigned char *buffer) { + if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { + return ((buffer[1] == 0x6A) || ((buffer[1] == 0x00) && (buffer[2] == 0x6A))); + } + else { + return (buffer[1] == 0x6A); + } +} + +WEAK unsigned char output_script_is_op_create_or_call(unsigned char *buffer, + size_t size, + unsigned char value) { + return (!output_script_is_regular(buffer) && + !output_script_is_p2sh(buffer) && + !output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && + (buffer[0] < size) && + (buffer[buffer[0]] == value)); +} + +WEAK unsigned char output_script_is_op_create(unsigned char *buffer, + size_t size) { + return output_script_is_op_create_or_call(buffer, size, 0xC1); +} + +WEAK unsigned char output_script_is_op_call(unsigned char *buffer, + size_t size) { + return output_script_is_op_create_or_call(buffer, size, 0xC2); +} + diff --git a/include/bcd.h b/lib-app-bitcoin/customizable_helpers.h similarity index 58% rename from include/bcd.h rename to lib-app-bitcoin/customizable_helpers.h index 42eb41ff..ab7ac1c9 100644 --- a/include/bcd.h +++ b/lib-app-bitcoin/customizable_helpers.h @@ -15,14 +15,17 @@ * limitations under the License. ********************************************************************************/ -#ifndef BCD_H +#pragma once -#define BCD_H +#include "os.h" +#include "cx.h" -unsigned char -convert_hex_amount_to_displayable_no_globals(unsigned char *amount, unsigned int config_flag, unsigned char* out); +unsigned char output_script_is_regular(unsigned char *buffer); +unsigned char output_script_is_p2sh(unsigned char *buffer); +unsigned char output_script_is_op_return(unsigned char *buffer); +unsigned char output_script_is_native_witness(unsigned char *buffer); +unsigned char output_script_is_op_create(unsigned char *buffer, + size_t size); +unsigned char output_script_is_op_call(unsigned char *buffer, + size_t size); -unsigned char -convert_hex_amount_to_displayable(unsigned char *amount); - -#endif diff --git a/lib-app-bitcoin/customizable_ui.c b/lib-app-bitcoin/customizable_ui.c new file mode 100644 index 00000000..8a10da47 --- /dev/null +++ b/lib-app-bitcoin/customizable_ui.c @@ -0,0 +1,117 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#include "customizable_ui.h" +#include "customizable_helpers.h" +#include "helpers.h" +#include "context.h" +#include "display_variables.h" +#include "segwit_addr.h" +#include "cashaddr.h" +#include "be_operations.h" +#include "display_utils.h" +#include "read.h" + + +WEAK void get_address_from_output_script(unsigned char* script, int script_size, char* out, int out_size) { + if (output_script_is_op_return(script)) { + strncpy(out, "OP_RETURN", out_size); + return; + } + if ((COIN_KIND == COIN_KIND_HYDRA) && + output_script_is_op_create(script, script_size)) { + strncpy(out, "OP_CREATE", out_size); + return; + } + if ((COIN_KIND == COIN_KIND_HYDRA) && + output_script_is_op_call(script, script_size)) { + strncpy(out, "OP_CALL", out_size); + return; + } + if (output_script_is_native_witness(script)) { + if (COIN_NATIVE_SEGWIT_PREFIX) { + segwit_addr_encode( + out, (char *)PIC(COIN_NATIVE_SEGWIT_PREFIX), 0, + script + OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET, + script[OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET - 1]); + } + return; + } + unsigned char versionSize; + unsigned char address[22]; + unsigned short textSize; + int addressOffset = 3; + unsigned short version = COIN_P2SH_VERSION; + + if (output_script_is_regular(script)) { + addressOffset = 4; + version = COIN_P2PKH_VERSION; + } + + if (version > 255) { + versionSize = 2; + address[0] = (version >> 8); + address[1] = version; + } else { + versionSize = 1; + address[0] = version; + } + memmove(address + versionSize, script + addressOffset, 20); + + // Prepare address + if (context.usingCashAddr) { + cashaddr_encode( + address + versionSize, 20, (uint8_t *)out, out_size, + (version == COIN_P2SH_VERSION + ? CASHADDR_P2SH + : CASHADDR_P2PKH)); + } else { + textSize = public_key_to_encoded_base58( + address, 20 + versionSize, (unsigned char *)out, + out_size, version, 1); + out[textSize] = '\0'; + } +} + +WEAK uint8_t prepare_fees(void) { + if (context.transactionContext.relaxed) { + memmove(vars.tmp.feesAmount, "UNKNOWN", 7); + vars.tmp.feesAmount[7] = '\0'; + } else { + unsigned char fees[8]; + unsigned char borrow; + + borrow = transaction_amount_sub_be( + fees, context.transactionContext.transactionAmount, + context.totalOutputAmount); + if (borrow && COIN_KIND == COIN_KIND_KOMODO) { + memmove(vars.tmp.feesAmount, "REWARD", 6); + vars.tmp.feesAmount[6] = '\0'; + } + else { + if (borrow) { + PRINTF("Error : Fees not consistent"); + goto error; + } + format_sats_amount(COIN_COINID_SHORT, + (uint64_t)read_u64_be(fees, 0), // Cast prevents weird compilo bug + vars.tmp.feesAmount); + } + } + return 1; +error: + return 0; +} diff --git a/include/ecc.h b/lib-app-bitcoin/customizable_ui.h similarity index 82% rename from include/ecc.h rename to lib-app-bitcoin/customizable_ui.h index 4a07074d..75649c2b 100644 --- a/include/ecc.h +++ b/lib-app-bitcoin/customizable_ui.h @@ -14,13 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ - -#ifndef ECC_H - -#define ECC_H - +#pragma once #include "os.h" +#include "macros.h" -void compress_public_key_value(unsigned char *value); +void get_address_from_output_script(unsigned char* script, int script_size, char* out, int out_size); -#endif +uint8_t prepare_fees(void); diff --git a/lib-app-bitcoin/display_utils.c b/lib-app-bitcoin/display_utils.c new file mode 100644 index 00000000..4bfae3f5 --- /dev/null +++ b/lib-app-bitcoin/display_utils.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include "ledger_assert.h" +#include "read.h" +#include "filesystem_tx.h" + +#include "./display_utils.h" + +// Division and modulus operators over uint64_t causes the inclusion of the __udivmoddi4 and other +// library functions that occupy more than 400 bytes. Since performance is not critical and division +// by 10 is sufficient, we avoid it with a binary search instead. +static uint64_t div10(uint64_t n) { + if (n < 10) return 0; // special case needed to make sure that n - 10 is safe + + // Since low, mid and high are always <= UINT64_MAX / 10, there is no risk of overflow + uint64_t low = 0; + uint64_t high = UINT64_MAX / 10; + + while (true) { + uint64_t mid = (low + high) / 2; + + // the result equals mid if and only if mid * 10 <= n < mid * 10 + 10 + // care is taken to make sure overflows and underflows are impossible + if (mid * 10 > n - 10 && n >= mid * 10) { + return mid; + } else if (n < mid * 10) { + high = mid - 1; + } else /* n >= 10 * mid + 10 */ { + low = mid + 1; + } + } +} + +static uint64_t div100000000(uint64_t n) { + uint64_t res = n; + for (int i = 0; i < 8; i++) res = div10(res); + return res; +} + +static size_t n_digits(uint64_t number) { + size_t count = 0; + do { + count++; + + // HACK: avoid __udivmoddi4 + // number /= 10; + + number = div10(number); + } while (number != 0); + return count; +} + +void format_sats_amount(const char *coin_name, + uint64_t amount, + char out[static MAX_AMOUNT_LENGTH + 1]) { + size_t coin_name_len = strlen(coin_name); + strncpy(out, coin_name, MAX_AMOUNT_LENGTH + 1); + out[coin_name_len] = ' '; + + char *amount_str = out + coin_name_len + 1; + + // HACK: avoid __udivmoddi4 + // uint64_t integral_part = amount / 100000000; + // uint32_t fractional_part = (uint32_t) (amount % 100000000); + uint64_t integral_part = div100000000(amount); + uint32_t fractional_part = (uint32_t) (amount - integral_part * 100000000); + + // format the integral part, starting from the least significant digit + size_t integral_part_digit_count = n_digits(integral_part); + for (unsigned int i = 0; i < integral_part_digit_count; i++) { + // HACK: avoid __udivmoddi4 + // amount_str[integral_part_digit_count - 1 - i] = '0' + (integral_part % 10); + // integral_part /= 10; + + uint64_t tmp_quotient = div10(integral_part); + char tmp_remainder = (char) (integral_part - 10 * tmp_quotient); + amount_str[integral_part_digit_count - 1 - i] = '0' + tmp_remainder; + integral_part = tmp_quotient; + } + + if (fractional_part == 0) { + amount_str[integral_part_digit_count] = '\0'; + } else { + // format the fractional part (exactly 8 digits, possibly with trailing zeros) + amount_str[integral_part_digit_count] = '.'; + char *fract_part_str = amount_str + integral_part_digit_count + 1; + snprintf(fract_part_str, 8 + 1, "%08u", fractional_part); + + // drop trailing zeros + for (int i = 7; i > 0 && fract_part_str[i] == '0'; i--) { + fract_part_str[i] = '\0'; + } + } +} + +unsigned char format_path(const unsigned char *bip32Path, char* out, unsigned char max_out_len) { + + unsigned char bip32PathLength; + unsigned char i, offset; + unsigned int current_level; + bool hardened; + + bip32PathLength = bip32Path[0]; + + LEDGER_ASSERT(bip32PathLength <= MAX_BIP32_PATH, "Wrong path len: %d", bip32PathLength); + + bip32Path++; + out[0] = ' '; + offset=1; + for (i = 0; i < bip32PathLength; i++) { + current_level = read_u32_be(bip32Path, 0); + hardened = (bool)(current_level & 0x80000000); + if(hardened) { + //remove hardening flag + current_level ^= 0x80000000; + } + bip32Path += 4; + snprintf(out+offset, max_out_len-offset, "%u", current_level); + offset = strnlen(out, max_out_len); + LEDGER_ASSERT(offset < max_out_len - 2, "OVERFLOW"); + if(hardened) out[offset++] = '\''; + + out[offset++] = '/'; + out[offset] = '\0'; + } + // remove last '/' + out[offset-1] = '\0'; + + return offset -1; +} + diff --git a/lib-app-bitcoin/display_utils.h b/lib-app-bitcoin/display_utils.h new file mode 100644 index 00000000..f5f28ba7 --- /dev/null +++ b/lib-app-bitcoin/display_utils.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +// up to 5 chars for ticker, 1 space, up to 20 digits (20 = digits of 2^64), + 1 decimal separator +#define MAX_AMOUNT_LENGTH (5 + 1 + 20 + 1) + +/** + * Converts a 64-bits unsigned integer into a decimal rapresentation, where the `amount` is a + * multiple of 1/100_000_000th. Trailing decimal zeros are not appended (and no decimal point is + * present if the `amount` is a multiple of 100_000_000). The resulting string is prefixed with a + * ticker name (up to 5 characters long), followed by a space. + * + * @param coin_name a zero-terminated ticker name, at most 5 characterso long (not including the + * terminating 0) + * @param amount the amount to format + * @param out the output array which must be at least MAX_AMOUNT_LENGTH + 1 bytes long + */ +void format_sats_amount(const char *coin_name, + uint64_t amount, + char out[static MAX_AMOUNT_LENGTH + 1]); + +unsigned char format_path(const unsigned char *bip32Path, char* out, unsigned char max_out_len); + diff --git a/src/display_variables.c b/lib-app-bitcoin/display_variables.c similarity index 100% rename from src/display_variables.c rename to lib-app-bitcoin/display_variables.c diff --git a/src/public_ram_variables.h b/lib-app-bitcoin/filesystem.h similarity index 65% rename from src/public_ram_variables.h rename to lib-app-bitcoin/filesystem.h index 3251c5da..fd615b04 100644 --- a/src/public_ram_variables.h +++ b/lib-app-bitcoin/filesystem.h @@ -15,14 +15,26 @@ * limitations under the License. ********************************************************************************/ -#ifndef _PUBLIC_RAM_VARIABLES_H_ -#define _PUBLIC_RAM_VARIABLES_H_ +#pragma once -#include "config.h" - -#include "secure_value.h" +#include "os.h" #include "context.h" +#include "filesystem_tx.h" + +enum family_e { + FAMILY_BITCOIN = 0x01, + FAMILY_PEERCOIN = 0x02, + FAMILY_STEALTH = 0x04 +}; + +typedef struct backup_area_s { + uint8_t trustedinput_key[32]; +} backup_area_t; -extern context_t context_D; +typedef struct storage_s { + backup_area_t bkp; +} storage_t; -#endif /* _PUBLIC_RAM_VARIABLES_H_ */ +// the global nvram memory variable +extern storage_t const N_real; +#define g_nvram_data (*(volatile storage_t *)PIC(&N_real)) diff --git a/include/filesystem_tx.h b/lib-app-bitcoin/filesystem_tx.h similarity index 97% rename from include/filesystem_tx.h rename to lib-app-bitcoin/filesystem_tx.h index e9f13f84..8a413c08 100644 --- a/include/filesystem_tx.h +++ b/lib-app-bitcoin/filesystem_tx.h @@ -15,10 +15,7 @@ * limitations under the License. ********************************************************************************/ -#ifndef FS_TX_H - -#define FS_TX_H - +#pragma once #include "os.h" #define MAX_BIP32_PATH 10 @@ -43,5 +40,3 @@ struct transaction_summary_s { unsigned char sighashType; }; typedef struct transaction_summary_s transaction_summary_t; - -#endif diff --git a/src/apdu_get_coin_version.c b/lib-app-bitcoin/handler/get_coin_version.c similarity index 53% rename from src/apdu_get_coin_version.c rename to lib-app-bitcoin/handler/get_coin_version.c index 97e0ac72..6b2aebf9 100644 --- a/src/apdu_get_coin_version.c +++ b/lib-app-bitcoin/handler/get_coin_version.c @@ -15,29 +15,35 @@ * limitations under the License. ********************************************************************************/ -#include "internal.h" -#include "apdu_constants.h" +#include "io.h" +#include "write.h" -#define P1_VERSION_ONLY 0x00 -#define P1_VERSION_COINID 0x01 +#include "context.h" +#include "apdu_constants.h" -unsigned short apdu_get_coin_version() { +WEAK unsigned short handler_get_coin_version(void) { uint8_t offset = 0; + size_t string_size; + + write_u16_be(G_io_apdu_buffer, offset, COIN_P2PKH_VERSION); + offset += 2; + + write_u16_be(G_io_apdu_buffer, offset, COIN_P2SH_VERSION); + offset += 2; - G_io_apdu_buffer[offset++] = COIN_P2PKH_VERSION >> 8; - G_io_apdu_buffer[offset++] = COIN_P2PKH_VERSION; - G_io_apdu_buffer[offset++] = COIN_P2SH_VERSION >> 8; - G_io_apdu_buffer[offset++] = COIN_P2SH_VERSION; G_io_apdu_buffer[offset++] = COIN_FAMILY; - G_io_apdu_buffer[offset++] = strlen(COIN_COINID); - memmove(G_io_apdu_buffer + offset, COIN_COINID, - strlen(COIN_COINID)); - offset += strlen(COIN_COINID); - G_io_apdu_buffer[offset++] = strlen(COIN_COINID_SHORT); - memmove(G_io_apdu_buffer + offset, COIN_COINID_SHORT, - strlen(COIN_COINID_SHORT)); - offset += strlen(COIN_COINID_SHORT); - context_D.outLength = offset; - - return SW_OK; + + string_size = strlen(COIN_COINID); + G_io_apdu_buffer[offset++] = string_size; + memmove(G_io_apdu_buffer + offset, COIN_COINID, string_size); + offset += string_size; + + string_size = strlen(COIN_COINID_SHORT); + G_io_apdu_buffer[offset++] = string_size; + memmove(G_io_apdu_buffer + offset, COIN_COINID_SHORT, string_size); + offset += string_size; + + context.outLength = offset; + + return io_send_response_pointer(G_io_apdu_buffer, offset, SW_OK); } diff --git a/src/apdu_get_firmware_version.c b/lib-app-bitcoin/handler/get_firmware_version.c similarity index 52% rename from src/apdu_get_firmware_version.c rename to lib-app-bitcoin/handler/get_firmware_version.c index b2b90954..6f11725a 100644 --- a/src/apdu_get_firmware_version.c +++ b/lib-app-bitcoin/handler/get_firmware_version.c @@ -14,52 +14,37 @@ * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ +#include "io.h" -#include "internal.h" +#include "context.h" #include "apdu_constants.h" -#define FEATURES_COMPRESSED_KEYS 0x01 #define FEATURES_SELF_SCREEN_BUTTONS 0x02 -#define FEATURES_EXTERNAL_SCREEN_BUTTONS 0x04 #define FEATURES_NFC 0x08 #define FEATURES_BLE 0x10 -#define FEATURES_TEE 0x20 #define MODE_SETUP 0x01 #define MODE_OPERATION 0x02 +#define FEATURES (FEATURES_NFC | FEATURES_BLE | FEATURES_SELF_SCREEN_BUTTONS) +#define MODE (MODE_SETUP | MODE_OPERATION) + #define ARCH_ID 0x30 -// Java Card is 0x60 #define TCS_LOADER_PATCH_VERSION 0 -void get_firmware_version(unsigned char *buffer) { - buffer[0] = ARCH_ID; - buffer[1] = MAJOR_VERSION; - buffer[2] = MINOR_VERSION; - buffer[3] = PATCH_VERSION; - buffer[4] = 1; - buffer[5] = TCS_LOADER_PATCH_VERSION; -} - -unsigned short apdu_get_firmware_version() { - G_io_apdu_buffer[0] = - (((N_btchip.bkp.config.options & OPTION_UNCOMPRESSED_KEYS) != 0) - ? 0x00 - : 0x01); - - G_io_apdu_buffer[0] |= FEATURES_NFC; - G_io_apdu_buffer[0] |= FEATURES_BLE; - - G_io_apdu_buffer[0] |= FEATURES_SELF_SCREEN_BUTTONS; - - get_firmware_version(G_io_apdu_buffer + 1); +WEAK unsigned short handler_get_firmware_version() { - G_io_apdu_buffer[7] = 0x00; - G_io_apdu_buffer[7] |= MODE_SETUP; - G_io_apdu_buffer[7] |= MODE_OPERATION; + G_io_apdu_buffer[0] = FEATURES; + G_io_apdu_buffer[1] = ARCH_ID; + G_io_apdu_buffer[2] = MAJOR_VERSION; + G_io_apdu_buffer[3] = MINOR_VERSION; + G_io_apdu_buffer[4] = PATCH_VERSION; + G_io_apdu_buffer[5] = 1; + G_io_apdu_buffer[6] = TCS_LOADER_PATCH_VERSION; + G_io_apdu_buffer[7] = MODE; - context_D.outLength = 0x08; + context.outLength = 0x08; - return SW_OK; + return io_send_response_pointer(G_io_apdu_buffer, 0x08, SW_OK); } diff --git a/src/apdu_get_trusted_input.c b/lib-app-bitcoin/handler/get_trusted_input.c similarity index 51% rename from src/apdu_get_trusted_input.c rename to lib-app-bitcoin/handler/get_trusted_input.c index 48fa119a..6925b36b 100644 --- a/src/apdu_get_trusted_input.c +++ b/lib-app-bitcoin/handler/get_trusted_input.c @@ -14,58 +14,59 @@ * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ - -#include "internal.h" -#include "apdu_constants.h" #include "lib_standard_app/read.h" #include "lib_standard_app/write.h" +#include "io.h" + +#include "context.h" +#include "filesystem.h" +#include "transaction.h" +#include "apdu_constants.h" #define GET_TRUSTED_INPUT_P1_FIRST 0x00 #define GET_TRUSTED_INPUT_P1_NEXT 0x80 -unsigned short apdu_get_trusted_input() { - unsigned char apduLength; +WEAK unsigned short handler_get_trusted_input(buffer_t* buffer, uint8_t p1, uint8_t p2) { unsigned char dataOffset = 0; - apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - if (G_io_apdu_buffer[ISO_OFFSET_P1] == GET_TRUSTED_INPUT_P1_FIRST) { + if (p1 == GET_TRUSTED_INPUT_P1_FIRST) { // Initialize - context_D.transactionTargetInput = - read_u32_be(G_io_apdu_buffer, ISO_OFFSET_CDATA); - context_D.transactionContext.transactionState = + context.transactionTargetInput = + read_u32_be(buffer->ptr, 0); + context.transactionContext.transactionState = TRANSACTION_NONE; - context_D.trustedInputProcessed = 0; - context_D.transactionContext.consumeP2SH = 0; + context.trustedInputProcessed = 0; + context.transactionContext.consumeP2SH = 0; dataOffset = 4; - context_D.transactionHashOption = TRANSACTION_HASH_FULL; - context_D.usingSegwit = 0; - context_D.usingOverwinter = 0; - } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != GET_TRUSTED_INPUT_P1_NEXT) { - return SW_INCORRECT_P1_P2; + context.transactionHashOption = TRANSACTION_HASH_FULL; + context.usingSegwit = 0; + context.usingOverwinter = 0; + } else if (p1 != GET_TRUSTED_INPUT_P1_NEXT) { + return io_send_sw(SW_INCORRECT_P1_P2); } - if (G_io_apdu_buffer[ISO_OFFSET_P2] != 0x00) { - return SW_INCORRECT_P1_P2; + if (p2 != 0x00) { + return io_send_sw(SW_INCORRECT_P1_P2); } - context_D.transactionBufferPointer = - G_io_apdu_buffer + ISO_OFFSET_CDATA + dataOffset; - context_D.transactionDataRemaining = apduLength - dataOffset; + + context.transactionBufferPointer = (uint8_t* ) buffer->ptr + dataOffset; + context.transactionDataRemaining = buffer->size - dataOffset; transaction_parse(PARSE_MODE_TRUSTED_INPUT); - if (context_D.transactionContext.transactionState == + if (context.transactionContext.transactionState == TRANSACTION_PARSED) { - context_D.transactionContext.transactionState = + context.transactionContext.transactionState = TRANSACTION_NONE; - if (!context_D.trustedInputProcessed) { + if (!context.trustedInputProcessed) { // Output was not found - return SW_INCORRECT_DATA; + return io_send_sw(SW_INCORRECT_DATA); } - if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, CX_LAST, + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, CX_LAST, NULL, 0, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32)) { - return SW_TECHNICAL_PROBLEM; + return io_send_sw(SW_TECHNICAL_PROBLEM); } // Otherwise prepare @@ -75,14 +76,14 @@ unsigned short apdu_get_trusted_input() { cx_hash_sha256(G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32, G_io_apdu_buffer + 4, 32); write_u32_le(G_io_apdu_buffer, 4 + 32, - context_D.transactionTargetInput); + context.transactionTargetInput); memmove(G_io_apdu_buffer + 4 + 32 + 4, - context_D.transactionContext.transactionAmount, 8); + context.transactionContext.transactionAmount, 8); - cx_hmac_sha256((uint8_t *)N_btchip.bkp.trustedinput_key, - sizeof(N_btchip.bkp.trustedinput_key), G_io_apdu_buffer, + cx_hmac_sha256((uint8_t *)g_nvram_data.bkp.trustedinput_key, + sizeof(g_nvram_data.bkp.trustedinput_key), G_io_apdu_buffer, TRUSTED_INPUT_SIZE, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32); - context_D.outLength = TRUSTED_INPUT_TOTAL_SIZE; + context.outLength = TRUSTED_INPUT_TOTAL_SIZE; } - return SW_OK; + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); } diff --git a/src/apdu_get_wallet_public_key.c b/lib-app-bitcoin/handler/get_wallet_public_key.c similarity index 62% rename from src/apdu_get_wallet_public_key.c rename to lib-app-bitcoin/handler/get_wallet_public_key.c index 53baced4..d376bda6 100644 --- a/src/apdu_get_wallet_public_key.c +++ b/lib-app-bitcoin/handler/get_wallet_public_key.c @@ -15,18 +15,28 @@ * limitations under the License. ********************************************************************************/ -#include "internal.h" +#include "context.h" +#include "helpers.h" #include "apdu_constants.h" -#include "bagl_extensions.h" +#include "extensions.h" #include "segwit_addr.h" #include "cashaddr.h" -#include "apdu_get_wallet_public_key.h" #include "lib_standard_app/read.h" #include "swap.h" +#include "io.h" -int get_public_key_chain_code(unsigned char* keyPath, size_t keyPath_len, unsigned char* publicKey, unsigned char* chainCode) { +#define P1_NO_DISPLAY 0x00 +#define P1_DISPLAY 0x01 +#define P1_REQUEST_TOKEN 0x02 + +#define P2_LEGACY 0x00 +#define P2_SEGWIT 0x01 +#define P2_NATIVE_SEGWIT 0x02 +#define P2_CASHADDR 0x03 + +static int get_public_key_chain_code(const unsigned char* keyPath, size_t keyPath_len, unsigned char* publicKey, unsigned char* chainCode) { uint8_t public_key[65]; int keyLength = 0; @@ -42,59 +52,57 @@ int get_public_key_chain_code(unsigned char* keyPath, size_t keyPath_len, unsign return keyLength; } -unsigned short apdu_get_wallet_public_key() { +WEAK unsigned short handler_get_wallet_public_key(buffer_t* buffer, uint8_t p1, uint8_t p2) { unsigned char keyLength; unsigned char chainCode[32]; uint8_t is_derivation_path_unusual = 0; - bool display = (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_DISPLAY); - bool segwit = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_SEGWIT); - bool nativeSegwit = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NATIVE_SEGWIT); - bool cashAddr = (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_CASHADDR); + bool display = (p1 == P1_DISPLAY); + bool segwit = (p2 == P2_SEGWIT); + bool nativeSegwit = (p2 == P2_NATIVE_SEGWIT); + bool cashAddr = (p2 == P2_CASHADDR); + if (display && G_called_from_swap) { - return SW_INCORRECT_DATA; + PRINTF("Refused INS when in SWAP mode\n"); + return io_send_sw(SW_INS_NOT_SUPPORTED); } - switch (G_io_apdu_buffer[ISO_OFFSET_P1]) { - case P1_NO_DISPLAY: - case P1_DISPLAY: - case P1_REQUEST_TOKEN: - break; - default: - return SW_INCORRECT_P1_P2; + + if (p1 != P1_NO_DISPLAY && p1 != P1_DISPLAY) { + PRINTF("Wrong P1 value\n"); + return io_send_sw(SW_INCORRECT_P1_P2); } - switch (G_io_apdu_buffer[ISO_OFFSET_P2]) { - case P2_NATIVE_SEGWIT: - if (!(COIN_NATIVE_SEGWIT_PREFIX)) { - return SW_INCORRECT_P1_P2; - } - __attribute__((fallthrough)); - case P2_LEGACY: - case P2_SEGWIT: - break; - case P2_CASHADDR: - if (COIN_KIND != COIN_KIND_BITCOIN_CASH) { - return SW_INCORRECT_P1_P2; - } - break; - default: - return SW_INCORRECT_P1_P2; + if (p2 == P2_NATIVE_SEGWIT && !COIN_NATIVE_SEGWIT_PREFIX) { + PRINTF("Wrong P2 value\n"); + return io_send_sw(SW_INCORRECT_P1_P2); } - if (G_io_apdu_buffer[ISO_OFFSET_LC] < 0x01) { - return SW_INCORRECT_LENGTH; + if (p2 == P2_CASHADDR && COIN_KIND != COIN_KIND_BITCOIN_CASH) { + PRINTF("Wrong P2 value\n"); + return io_send_sw(SW_INCORRECT_P1_P2); } + + if (p2 != P2_NATIVE_SEGWIT && p2 != P2_LEGACY && p2 != P2_SEGWIT && p2 != P2_CASHADDR) { + PRINTF("Wrong P2 value\n"); + return io_send_sw(SW_INCORRECT_P1_P2); + } + + if (buffer->size < 0x01) { + PRINTF("Wrong size\n"); + return io_send_sw(SW_INCORRECT_LENGTH); + } + if (display) { - is_derivation_path_unusual = set_key_path_to_display(G_io_apdu_buffer + ISO_OFFSET_CDATA); + is_derivation_path_unusual = set_key_path_to_display(buffer->ptr); } - unsigned char bip44_enforced = enforce_bip44_coin_type(G_io_apdu_buffer + ISO_OFFSET_CDATA, true); + unsigned char bip44_enforced = enforce_bip44_coin_type(buffer->ptr, true); G_io_apdu_buffer[0] = 65; - keyLength = get_public_key_chain_code(G_io_apdu_buffer + ISO_OFFSET_CDATA, MAX_BIP32_PATH_LENGTH, G_io_apdu_buffer + 1, chainCode); + keyLength = get_public_key_chain_code(buffer->ptr, MAX_BIP32_PATH_LENGTH, G_io_apdu_buffer + 1, chainCode); if (keyLength == 0) { - return SW_TECHNICAL_PROBLEM; + return io_send_sw(SW_TECHNICAL_PROBLEM); } if (cashAddr) { @@ -145,7 +153,7 @@ unsigned short apdu_get_wallet_public_key() { // output chain code memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, sizeof(chainCode)); - context_D.outLength = 1 + 65 + 1 + keyLength + sizeof(chainCode); + context.outLength = 1 + 65 + 1 + keyLength + sizeof(chainCode); // privacy : force display the address if the path isn't standard // and could reveal another fork holdings according to BIP 44 rules @@ -155,31 +163,24 @@ unsigned short apdu_get_wallet_public_key() { if (display) { if (keyLength > 50) { - return SW_INCORRECT_DATA; + return io_send_sw(SW_INCORRECT_DATA); } // Hax, avoid wasting space memmove(G_io_apdu_buffer + 200, G_io_apdu_buffer + 67, keyLength); G_io_apdu_buffer[200 + keyLength] = '\0'; - context_D.io_flags |= IO_ASYNCH_REPLY; - bagl_display_public_key(is_derivation_path_unusual); + display_public_key(is_derivation_path_unusual); + return 0; } - - return SW_OK; + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); } -void bagl_user_action_display(unsigned char confirming) { - unsigned short sw = SW_OK; +int user_action_display(unsigned char confirming) { // confirm and finish the apdu exchange //spaghetti if (confirming) { - context_D.outLength -= - 2; // status was already set by the last call + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); } else { - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - context_D.outLength = 0; + context.outLength = 0; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); } - G_io_apdu_buffer[context_D.outLength++] = sw >> 8; - G_io_apdu_buffer[context_D.outLength++] = sw; - - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, context_D.outLength); } diff --git a/lib-app-bitcoin/handler/hash_input_finalize_full.c b/lib-app-bitcoin/handler/hash_input_finalize_full.c new file mode 100644 index 00000000..8fc61a9d --- /dev/null +++ b/lib-app-bitcoin/handler/hash_input_finalize_full.c @@ -0,0 +1,661 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +// TODO Trustlet, BAGL : process each output separately. +// review nvm_write policy + +#include "crypto_helpers.h" +#include "read.h" +#include "swap.h" +#include "io.h" + +#include "context.h" +#include "helpers.h" +#include "customizable_helpers.h" +#include "apdu_constants.h" +#include "extensions.h" +#include "ui.h" +#include "be_operations.h" + +#define FINALIZE_P1_MORE 0x00 +#define FINALIZE_P1_LAST 0x80 +#define FINALIZE_P1_CHANGEINFO 0xFF + +#define FINALIZE_P2_DEFAULT 0x00 + +#define FLAG_SIGNATURE 0x01 +#define FLAG_CHANGE_VALIDATED 0x80 + +void hash_input_finalize_full_reset(void) { + context.currentOutputOffset = 0; + context.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; + memset(context.totalOutputAmount, 0, + sizeof(context.totalOutputAmount)); + context.changeOutputFound = 0; +} + +static int check_output_displayable(bool* displayable) { + *displayable = true; + unsigned char amount[8], isOpReturn, isP2sh, isNativeSegwit, j, + nullAmount = 1; + + for (j = 0; j < 8; j++) { + if (context.currentOutput[j] != 0) { + nullAmount = 0; + break; + } + } + if (!nullAmount) { + swap_bytes(amount, context.currentOutput, 8); + transaction_amount_add_be(context.totalOutputAmount, + context.totalOutputAmount, amount); + } + isOpReturn = + output_script_is_op_return(context.currentOutput + 8); + isP2sh = output_script_is_p2sh(context.currentOutput + 8); + isNativeSegwit = output_script_is_native_witness( + context.currentOutput + 8); +#ifndef __clang_analyzer__ + unsigned char isOpCreate = + output_script_is_op_create(context.currentOutput + 8, + sizeof(context.currentOutput) - 8); + unsigned char isOpCall = + output_script_is_op_call(context.currentOutput + 8, + sizeof(context.currentOutput) - 8); + if (((COIN_KIND == COIN_KIND_HYDRA) && + !output_script_is_regular(context.currentOutput + 8) && + !isP2sh && !(nullAmount && isOpReturn) && !isOpCreate && !isOpCall) || + (!(COIN_KIND == COIN_KIND_HYDRA) && + !output_script_is_regular(context.currentOutput + 8) && + !isP2sh && !(nullAmount && isOpReturn))) { + PRINTF("Error : Unrecognized output script"); + return -1; + } +#endif + if (context.tmpCtx.output.changeInitialized && !isOpReturn) { + bool changeFound = false; + unsigned char addressOffset = + (isNativeSegwit ? OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET + : isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH + : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); + if (!isP2sh && + memcmp(context.currentOutput + 8 + addressOffset, + context.tmpCtx.output.changeAddress, + 20) == 0) { + changeFound = true; + } else if (isP2sh && context.usingSegwit) { + unsigned char changeSegwit[22]; + changeSegwit[0] = 0x00; + changeSegwit[1] = 0x14; + memmove(changeSegwit + 2, + context.tmpCtx.output.changeAddress, 20); + public_key_hash160(changeSegwit, 22, changeSegwit); + if (memcmp(context.currentOutput + 8 + addressOffset, + changeSegwit, 20) == 0) { + if (COIN_FLAGS & FLAG_SEGWIT_CHANGE_SUPPORT) { + changeFound = true; + } else { + // Attempt to avoid fatal failures on Bitcoin Cash + PRINTF("Error : Non spendable Segwit change"); + return -1; + } + } + } + if (changeFound) { + if (context.changeOutputFound) { + PRINTF("Error : Multiple change output found"); + return -1; + } + context.changeOutputFound = true; + *displayable = false; + } + } + return 0; +} + +int handle_output_state(unsigned int* processed) { + uint32_t discardSize = 0; + context.discardSize = 0; + *processed = 0; + switch (context.outputParsingState) { + case OUTPUT_PARSING_NUMBER_OUTPUTS: { + context.totalOutputs = 0; + if (context.currentOutputOffset < 1) { + break; + } + if (context.currentOutput[0] < 0xFD) { + context.totalOutputs = context.remainingOutputs = + context.currentOutput[0]; + discardSize = 1; + context.outputParsingState = OUTPUT_PARSING_OUTPUT; + *processed = 1; + break; + } + if (context.currentOutput[0] == 0xFD) { + if (context.currentOutputOffset < 3) { + break; + } + context.totalOutputs = context.remainingOutputs = + (context.currentOutput[2] << 8) | + context.currentOutput[1]; + discardSize = 3; + context.outputParsingState = OUTPUT_PARSING_OUTPUT; + *processed = 1; + break; + } else if (context.currentOutput[0] == 0xFE) { + if (context.currentOutputOffset < 5) { + break; + } + context.totalOutputs = context.remainingOutputs = + read_u32_le(context.currentOutput, 1); + discardSize = 5; + context.outputParsingState = OUTPUT_PARSING_OUTPUT; + *processed = 1; + break; + } else { + return -1; + } + } break; + + case OUTPUT_PARSING_OUTPUT: { + unsigned int scriptSize = 0; + if (context.currentOutputOffset < 9) { + break; + } + if (context.currentOutput[8] < 0xFD) { + scriptSize = context.currentOutput[8]; + discardSize = 1; + } else if (context.currentOutput[8] == 0xFD) { + if (context.currentOutputOffset < 9 + 2) { + break; + } + scriptSize = read_u32_le(context.currentOutput, 9); + discardSize = 3; + } else { + // Unrealistically large script + return -1; + } + if (context.currentOutputOffset < + 8 + discardSize + scriptSize) { + discardSize = 0; + break; + } + + *processed = 1; + + discardSize += 8 + scriptSize; + + bool displayable; + if (check_output_displayable(&displayable)) { + return -1; + } + + if (displayable) { + // The output can be processed by the UI + + context.discardSize = discardSize; + discardSize = 0; + *processed = 2; + } else { + context.remainingOutputs--; + } + } break; + + default: + return -1; + } + + if (discardSize != 0) { + memmove(context.currentOutput, + context.currentOutput + discardSize, + context.currentOutputOffset - discardSize); + context.currentOutputOffset -= discardSize; + } + + return 0; +} + +// out should be 32 bytes, even only 20 bytes is significant for output +int get_pubkey_hash160(unsigned char* keyPath, size_t keyPath_len, unsigned char* out) { + cx_ecfp_public_key_t public_key; + if (get_public_key(keyPath, keyPath_len, public_key.W, NULL)) { + return -1; + } + compress_public_key_value(public_key.W); + + public_key_hash160( + public_key.W, // IN + 33, // INLEN + out // OUT + ); + return 0; +} + +static unsigned short hash_input_finalize_full_internal(transaction_summary_t *transactionSummary, buffer_t* buffer, uint8_t p1, uint8_t p2, bool *async) { + unsigned char authorizationHash[32]; + unsigned short sw = SW_OK; + unsigned char *target = G_io_apdu_buffer; + unsigned char hashOffset = 0; + + (void) p2; + + if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && + (p1 != FINALIZE_P1_CHANGEINFO)) { + return SW_INCORRECT_P1_P2; + } + + // See if there is a hashing offset + if (context.usingSegwit && + (context.tmpCtx.output.multipleOutput == 0)) { + unsigned char firstByte = buffer->ptr[0]; + if (firstByte < 0xfd) { + hashOffset = 1; + } else if (firstByte == 0xfd) { + hashOffset = 3; + } else if (firstByte == 0xfe) { + hashOffset = 5; + } + } + + // Check state + if (context.transactionContext.transactionState != + TRANSACTION_PRESIGN_READY) { + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } + + if (p1 == FINALIZE_P1_CHANGEINFO) { + if (!context.transactionContext.firstSigned) { + // Already validated, should be prevented on the client side + return SW_OK; + } + if (!context.tmpCtx.output.changeAccepted) { + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } + memset(transactionSummary, 0, + sizeof(transaction_summary_t)); + if (buffer->ptr[0] == 0x00) { + // Called with no change path, abort, should be prevented on + // the client side + return SW_OK; + } + memmove(transactionSummary->keyPath, + buffer->ptr, + MAX_BIP32_PATH_LENGTH); + + if (get_pubkey_hash160(transactionSummary->keyPath, sizeof(transactionSummary->keyPath), context.tmpCtx.output.changeAddress)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + PRINTF("Change address = %.*H\n", 20, context.tmpCtx.output.changeAddress); + + context.tmpCtx.output.changeInitialized = 1; + context.tmpCtx.output.changeAccepted = 0; + + // if the bip44 change path provided is not canonical or its index are unsual, ask for user approval + if(bip44_derivation_guard(transactionSummary->keyPath, true)) { + if (G_called_from_swap) { + PRINTF("In swap mode only standart path is allowed\n"); + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } + *async = true; + context.outputParsingState = BIP44_CHANGE_PATH_VALIDATION; + request_change_path_approval(transactionSummary->keyPath); + } + + return SW_OK; + } + + // Always update the transaction & authorization hashes with the + // given data + // For SegWit, this has been reset to hold hashOutputs + if (!context.segwitParsedOnce) { + if ((int)(buffer->size - hashOffset) < 0) { + sw = SW_INCORRECT_DATA; + goto discardTransaction; + } + if (context.usingOverwinter) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, buffer->ptr + hashOffset, buffer->size - hashOffset, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + } + else { + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", buffer->size - hashOffset, buffer->ptr + hashOffset); + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + buffer->ptr + hashOffset, + buffer->size - hashOffset, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + } + } + + if (context.transactionContext.firstSigned) { + if ((context.currentOutputOffset + buffer->size) > + sizeof(context.currentOutput)) { + PRINTF("Output is too long to be checked\n"); + sw = SW_INCORRECT_DATA; + goto discardTransaction; + } + memmove(context.currentOutput + + context.currentOutputOffset, + buffer->ptr, buffer->size); + context.currentOutputOffset += buffer->size; + + unsigned int processed = 1; + while (processed == 1) { + if (handle_output_state(&processed)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + } + + if (processed == 2) { + *async = true; + } + // Finalize the TX if necessary + + if ((context.remainingOutputs == 0) && + (!*async)) { + *async = true; + context.outputParsingState = + OUTPUT_FINALIZE_TX; + } + } + + if (p1 == FINALIZE_P1_MORE) { + if (!context.usingSegwit) { + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", buffer->size, buffer->ptr); + if (cx_hash_no_throw( + &context.transactionHashAuthorization.header, + 0, buffer->ptr, buffer->size, + NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + } + G_io_apdu_buffer[0] = 0x00; + context.outLength = 1; + context.tmpCtx.output.multipleOutput = 1; + return SW_OK; + } + + if (!context.usingSegwit) { + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", buffer->size, buffer->ptr); + if (cx_hash_no_throw(&context.transactionHashAuthorization.header, + CX_LAST, buffer->ptr, + buffer->size, authorizationHash, 32)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + } + + if (context.usingSegwit) { + if (!context.segwitParsedOnce) { + if (context.usingOverwinter) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, CX_LAST, context.segwit.cache.hashedOutputs, 0, context.segwit.cache.hashedOutputs, 32)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + } + else { + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, + CX_LAST, + context.segwit.cache.hashedOutputs, 0, + context.segwit.cache.hashedOutputs, 32)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, + CX_LAST, + context.segwit.cache.hashedOutputs, + sizeof(context.segwit.cache.hashedOutputs), + context.segwit.cache.hashedOutputs, 32)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + } + PRINTF("hashOutputs\n%.*H\n",32,context.segwit.cache.hashedOutputs); + if (cx_hash_no_throw( + &context.transactionHashAuthorization.header, + CX_LAST, G_io_apdu_buffer, 0, authorizationHash, 32)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); + } else { + if (cx_hash_no_throw( + &context.transactionHashAuthorization.header, + CX_LAST, + (unsigned char *)&context.segwit.cache, + sizeof(context.segwit.cache), + authorizationHash, 32)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); + } + } + + if (context.transactionContext.firstSigned) { + if (!context.tmpCtx.output.changeInitialized) { + memset(transactionSummary, 0, + sizeof(transaction_summary_t)); + } + + transactionSummary->payToAddressVersion = COIN_P2PKH_VERSION; + transactionSummary->payToScriptHashVersion = COIN_P2SH_VERSION; + + // Generate new nonce + + cx_rng(transactionSummary->transactionNonce, 8); + } + + G_io_apdu_buffer[0] = 0x00; + target++; + + *target = 0x00; + target++; + + context.outLength = (target - G_io_apdu_buffer); + + // Check that the input being signed is part of the same + // transaction, otherwise abort + // (this is done to keep the transaction counter limit per session + // synchronized) + if (context.transactionContext.firstSigned) { + memmove(transactionSummary->authorizationHash, + authorizationHash, + sizeof(transactionSummary->authorizationHash)); + return SW_OK; + } else { + if (os_secure_memcmp( + authorizationHash, + transactionSummary->authorizationHash, + sizeof(transactionSummary->authorizationHash))) { + PRINTF("Authorization hash not matching, aborting\n"); + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } + + if (context.usingSegwit && + !context.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context.transactionContext.transactionState = + TRANSACTION_NONE; + } else { + context.transactionContext.transactionState = + TRANSACTION_SIGN_READY; + } + hash_input_finalize_full_reset(); + return SW_OK; + } + +discardTransaction: + hash_input_finalize_full_reset(); + ui_transaction_error(); + context.transactionContext.transactionState = + TRANSACTION_NONE; + context.outLength = 0; + + memmove(G_io_apdu_buffer, context.currentOutput, + context.currentOutputOffset); + context.outLength = context.currentOutputOffset; + return sw; +} + +unsigned short handler_hash_input_finalize_full(buffer_t* buffer, uint8_t p1, uint8_t p2) { + bool is_async = false; + PRINTF("state=%d\n", context.outputParsingState); + unsigned short sw = hash_input_finalize_full_internal( + &context.transactionSummary, buffer, p1, p2, &is_async); + + if (is_async) { + // if the UI reject the processing of the request, then reply + // immediately + int status; + if(context.outputParsingState == BIP44_CHANGE_PATH_VALIDATION) { + context.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; + return 0; + } + else if (context.outputParsingState == OUTPUT_FINALIZE_TX) { + status = finalize_tx(); + } + else { + status = confirm_single_output(); + } + if (status == 0) { + ui_transaction_error(); + context.transactionContext.transactionState = + TRANSACTION_NONE; + context.outLength = 0; + sw = SW_INCORRECT_DATA; + return io_send_sw(sw); + } + else if (status == 2) { + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); + } + return 0; + } + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); +} + +unsigned char user_action(unsigned char confirming) { + unsigned short sw = SW_OK; + + // confirm and finish the apdu exchange //spaghetti + + if (confirming) { + // Check if all inputs have been confirmed + + if (context.outputParsingState == + OUTPUT_PARSING_OUTPUT) { + context.remainingOutputs--; + } + + while (context.remainingOutputs != 0) { + memmove(context.currentOutput, + context.currentOutput + + context.discardSize, + context.currentOutputOffset - + context.discardSize); + context.currentOutputOffset -= + context.discardSize; + unsigned int processed = 1; + while (processed == 1) { + if (handle_output_state(&processed)) { + context.transactionContext.transactionState = + TRANSACTION_NONE; + sw = SW_INCORRECT_DATA; + break; + } + } + + if (processed == 2) { + if (!confirm_single_output()) { + context.transactionContext.transactionState = + TRANSACTION_NONE; + sw = SW_INCORRECT_DATA; + break; + } else { + // Let the UI play + return 1; + } + } else { + // Out of data to process, wait for the next call + break; + } + } + + if ((context.outputParsingState == + OUTPUT_PARSING_OUTPUT) && + (context.remainingOutputs == 0)) { + context.outputParsingState = OUTPUT_FINALIZE_TX; + if (!finalize_tx()) { + context.outputParsingState = + OUTPUT_PARSING_NONE; + context.transactionContext.transactionState = + TRANSACTION_NONE; + sw = SW_INCORRECT_DATA; + } else { + // Let the UI play + return 1; + } + } + + if (context.outputParsingState == + OUTPUT_FINALIZE_TX) { + context.transactionContext.firstSigned = 0; + + if (context.usingSegwit && + !context.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context.transactionContext.transactionState = + TRANSACTION_NONE; + } else { + context.transactionContext.transactionState = + TRANSACTION_SIGN_READY; + } + } + } else { + // Discard transaction + context.transactionContext.transactionState = + TRANSACTION_NONE; + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + context.outLength = 0; + } + + if ((context.outputParsingState == OUTPUT_FINALIZE_TX) || + (sw != SW_OK)) { + + // we've finished the processing of the input + hash_input_finalize_full_reset(); + } + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); + +} diff --git a/lib-app-bitcoin/handler/hash_input_start.c b/lib-app-bitcoin/handler/hash_input_start.c new file mode 100644 index 00000000..274418a9 --- /dev/null +++ b/lib-app-bitcoin/handler/hash_input_start.c @@ -0,0 +1,136 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include "io.h" + +#include "context.h" +#include "transaction.h" +#include "apdu_constants.h" +#include "extensions.h" +#include "swap.h" + +#define P1_FIRST 0x00 +#define P1_NEXT 0x80 +#define P2_NEW 0x00 +#define P2_NEW_SEGWIT 0x02 +#define P2_NEW_SEGWIT_CASHADDR 0x03 +#define P2_NEW_SEGWIT_OVERWINTER 0x04 +#define P2_NEW_SEGWIT_SAPLING 0x05 +#define P2_CONTINUE 0x80 + +#define IS_INPUT() \ + (buffer->size - 1 > 8 \ + && buffer->size - 1 <= TRUSTED_INPUT_TOTAL_SIZE + 2 \ + && buffer->ptr[0] <= 0x02) \ + +#define IS_INPUT_TRUSTED() \ + (buffer->ptr[0] == 0x01 \ + && buffer->ptr[1] == TRUSTED_INPUT_TOTAL_SIZE \ + && buffer->ptr[2] == MAGIC_TRUSTED_INPUT \ + && buffer->ptr[3] == 0x00) + +WEAK unsigned short handler_hash_input_start(buffer_t* buffer, uint8_t p1, uint8_t p2) { + if (p1 == P1_FIRST) { + // Initialize + context.transactionContext.transactionState = + TRANSACTION_NONE; + context.transactionHashOption = TRANSACTION_HASH_BOTH; + } else if (p1 != P1_NEXT) { + return io_send_sw(SW_INCORRECT_P1_P2); + } + + if ((p2 == P2_NEW) || + (p2 == P2_NEW_SEGWIT) || + (p2 == P2_NEW_SEGWIT_CASHADDR) || + (p2 == P2_NEW_SEGWIT_OVERWINTER) || + (p2 == P2_NEW_SEGWIT_SAPLING)) { + if (p1 == P1_FIRST) { + unsigned char usingSegwit = + (p2 == P2_NEW_SEGWIT) || + (p2 == P2_NEW_SEGWIT_CASHADDR) || + (p2 == P2_NEW_SEGWIT_OVERWINTER) || + (p2 == P2_NEW_SEGWIT_SAPLING); + // Master transaction reset + context.transactionContext.firstSigned = 1; + context.transactionContext.consumeP2SH = 0; + context.transactionContext.relaxed = 0; + context.usingSegwit = usingSegwit; + + if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { + unsigned char usingCashAddr = (p2 == P2_NEW_SEGWIT_CASHADDR); + context.usingCashAddr = usingCashAddr; + } + else { + context.usingCashAddr = 0; + } + + context.usingOverwinter = 0; + if ((COIN_KIND == COIN_KIND_ZCASH) || (COIN_KIND == COIN_KIND_KOMODO) || (COIN_KIND == COIN_KIND_ZCLASSIC) || (COIN_KIND == COIN_KIND_RESISTANCE)) { + if (p2 == P2_NEW_SEGWIT_OVERWINTER) { + context.usingOverwinter = ZCASH_USING_OVERWINTER; + } + else + if (p2 == P2_NEW_SEGWIT_SAPLING) { + context.usingOverwinter = ZCASH_USING_OVERWINTER_SAPLING; + } + } + context.overwinterSignReady = 0; + context.segwitParsedOnce = 0; + // Initialize for screen pairing + memset(&context.tmpCtx.output, 0, + sizeof(context.tmpCtx.output)); + context.tmpCtx.output.changeAccepted = 1; + // Reset segwitWarningSeen flag to prevent displaying the warning for each + // segwit input when coontinuing from a previous session (P2=0x80) + context.segwitWarningSeen = 0; + } + } else if (p2 != P2_CONTINUE) { + return io_send_sw(SW_INCORRECT_P1_P2); + } + + // In segwit mode, warn user one time only to update its client wallet... + if (context.usingSegwit + && !context.segwitWarningSeen + && (p1 == P1_NEXT) + && (p2 != P2_CONTINUE) + // ...if input is not passed as a TrustedInput + && IS_INPUT() + && !IS_INPUT_TRUSTED()) + { + if(G_called_from_swap){ + /* There is no point in displaying a warning when the app is signing + in silent mode, as its UI is hidden behind the exchange app*/ + return io_send_sw(SW_SWAP_WITHOUT_TRUSTED_INPUTS); + } + context.segwitWarningSeen = 1; + request_segwit_input_approval(); + // Start parsing of the 1st chunk + context.transactionBufferPointer = (uint8_t*) buffer->ptr; + context.transactionDataRemaining = buffer->size; + + transaction_parse(PARSE_MODE_SIGNATURE); + return 0; + } + + // Start parsing of the 1st chunk + context.transactionBufferPointer = (uint8_t*) buffer->ptr; + context.transactionDataRemaining = buffer->size; + + transaction_parse(PARSE_MODE_SIGNATURE); + + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); +} diff --git a/lib-app-bitcoin/handler/hash_sign.c b/lib-app-bitcoin/handler/hash_sign.c new file mode 100644 index 00000000..c4496660 --- /dev/null +++ b/lib-app-bitcoin/handler/hash_sign.c @@ -0,0 +1,192 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include "macros.h" +#include "io.h" +#include "ledger_assert.h" +#include "read.h" +#include "write.h" +#include "swap.h" + +#include "context.h" +#include "helpers.h" +#include "apdu_constants.h" +#include "extensions.h" +#include "display_variables.h" +#include "ui.h" + +#define SIGHASH_ALL 0x01 + +#ifndef COIN_FORKID +#define COIN_FORKID 0 +#endif + +WEAK unsigned short handler_hash_sign(buffer_t* buffer, uint8_t p1, uint8_t p2) { + unsigned long int lockTime; + uint32_t sighashType; + unsigned char dataBuffer[8]; + unsigned char authorizationLength; + unsigned char *parameters = (uint8_t*)buffer->ptr; + + if ((p1 != 0) || (p2 != 0)) { + return io_send_sw(SW_INCORRECT_P1_P2); + } + +#define HASH_LENGTH 1 + 1 + 4 + 1 + if (buffer->size < HASH_LENGTH) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + // Zcash special - store parameters for later + + if ((context.usingOverwinter) && + (!context.overwinterSignReady) && + (context.segwitParsedOnce) && + (context.transactionContext.transactionState == TRANSACTION_NONE)) { + unsigned long int expiryHeight; + parameters += (4 * buffer->ptr[0]) + 1; + authorizationLength = *(parameters++); + parameters += authorizationLength; + lockTime = read_u32_be(parameters, 0); + parameters += 4; + sighashType = *(parameters++); + expiryHeight = read_u32_be(parameters, 0); + write_u32_le(context.nLockTime, 0, lockTime); + write_u32_le(context.sigHashType, 0, sighashType); + write_u32_le(context.nExpiryHeight, 0, expiryHeight); + context.overwinterSignReady = 1; + return io_send_sw(SW_OK); + } + + if (context.transactionContext.transactionState != + TRANSACTION_SIGN_READY) { + PRINTF("Invalid transaction state %d\n", context.transactionContext.transactionState); + context.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); + } + + if (context.usingOverwinter && !context.overwinterSignReady) { + PRINTF("Overwinter not ready to sign\n"); + context.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); + } + + // Read parameters + if (buffer->ptr[0] > MAX_BIP32_PATH) { + context.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_INCORRECT_DATA); + } + memmove(context.transactionSummary.keyPath, + buffer->ptr, + MAX_BIP32_PATH_LENGTH); + parameters += (4 * buffer->ptr[0]) + 1; + authorizationLength = *(parameters++); + parameters += authorizationLength; + lockTime = read_u32_be(parameters, 0); + parameters += 4; + sighashType = *(parameters++); + context.transactionSummary.sighashType = sighashType; + + // if bitcoin cash OR forkid is set, then use the fork id + if ((COIN_KIND == COIN_KIND_BITCOIN_CASH) || + (COIN_FORKID)) { +#define SIGHASH_FORKID 0x40 + if (sighashType != (SIGHASH_ALL | SIGHASH_FORKID)) { + context.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_INCORRECT_DATA); + } + sighashType |= (COIN_FORKID << 8); + + } else { + if (sighashType != SIGHASH_ALL) { + context.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_INCORRECT_DATA); + } + } + + // Finalize the hash + if (!context.usingOverwinter) { + write_u32_le(dataBuffer, 0, lockTime); + write_u32_le(dataBuffer, 4, sighashType); + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(dataBuffer), dataBuffer); + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + dataBuffer, sizeof(dataBuffer), NULL, 0)) { + context.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_INCORRECT_DATA); + } + } + + // Check if the path needs to be enforced + if (!enforce_bip44_coin_type(context.transactionSummary.keyPath, false)) { + request_sign_path_approval(context.transactionSummary.keyPath); + } + else { + // Sign immediately + user_action_signtx(1, 0); + } + if (G_called_from_swap) { + // if we signed all outputs we should exit, + // but only after sending response, so lets raise the + // vars.swap_data.should_exit flag and check it on timer later + vars.swap_data.alreadySignedInputs++; + if (vars.swap_data.alreadySignedInputs >= vars.swap_data.totalNumberOfInputs) { + vars.swap_data.should_exit = 1; + } + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); + } + return 0; +} + +int user_action_signtx(unsigned char confirming, unsigned char direct) { + // confirm and finish the apdu exchange //spaghetti + if (confirming) { + unsigned char hash[32]; + if (context.usingOverwinter) { + LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashFull.blake2b.header, CX_LAST, hash, 0, hash, 32) == CX_OK, "Hash Failed"); + } + else { + LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashFull.sha256.header, CX_LAST, + hash, 0, hash, 32) == CX_OK, "Hash Failed"); + PRINTF("Hash1\n%.*H\n", sizeof(hash), hash); + + // Rehash + cx_hash_sha256(hash, sizeof(hash), hash, 32); + } + PRINTF("Hash2\n%.*H\n", sizeof(hash), hash); + // Sign + size_t out_len = sizeof(G_io_apdu_buffer); + sign_finalhash( + context.transactionSummary.keyPath, + sizeof(context.transactionSummary.keyPath), + hash, sizeof(hash), + G_io_apdu_buffer, &out_len); + + context.outLength = G_io_apdu_buffer[1] + 2; + G_io_apdu_buffer[context.outLength++] = context.transactionSummary.sighashType; + ui_transaction_finish(); + + } else { + context.outLength = 0; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); + } + + if (!direct) { + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); + } + return 0; +} + diff --git a/lib-app-bitcoin/handler/sign_message.c b/lib-app-bitcoin/handler/sign_message.c new file mode 100644 index 00000000..01a6a332 --- /dev/null +++ b/lib-app-bitcoin/handler/sign_message.c @@ -0,0 +1,279 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include "context.h" +#include "helpers.h" +#include "apdu_constants.h" +#include "extensions.h" +#include "lib_standard_app/read.h" +#include "swap.h" +#include "io.h" + +#define P1_PREPARE 0x00 +#define P1_SIGN 0x80 +#define P2_LEGACY 0x00 +#define P2_FIRST 0x01 +#define P2_OTHER 0x80 + +#define BITID_NONE 0 +#define BITID_POWERCYCLE 1 +#define BITID_MULTIPLE 2 + +unsigned char const SIGNMAGIC[] = {' ', 'S', 'i', 'g', 'n', 'e', 'd', ' ', 'M', + 'e', 's', 's', 'a', 'g', 'e', ':', '\n'}; + +// TODO : support longer messages +unsigned char message_check_bit_id(unsigned char *bip32Path) { + unsigned char i; + unsigned char bip32PathLength = bip32Path[0]; + bip32Path++; + for (i = 0; i < bip32PathLength; i++) { + unsigned short account = read_u32_be(bip32Path, 0); + bip32Path += 4; + + if (account == BITID_DERIVE) { + return BITID_POWERCYCLE; + } + if (account == BITID_DERIVE_MULTIPLE) { + return BITID_MULTIPLE; + } + } + return BITID_NONE; +} + +unsigned short message_compute_hash(void) { + unsigned char hash[32]; + unsigned short sw = SW_OK; + + context.outLength = 0; + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, CX_LAST, hash, + 0, hash, 32)) { + goto discard; + } + + if (cx_hash_sha256(hash, sizeof(hash), hash, 32) == 0) { + goto discard; + } + + size_t out_len = 100; + sign_finalhash( + context.transactionSummary.keyPath, + sizeof(context.transactionSummary.keyPath), + hash, sizeof(hash), // IN + G_io_apdu_buffer, &out_len); // OUT + context.outLength = G_io_apdu_buffer[1] + 2; + memset(&context.transactionSummary, 0, + sizeof(transaction_summary_t)); + return sw; + + discard: + sw = SW_TECHNICAL_PROBLEM_2; + return sw; +} + + +static unsigned short sign_message_internal(buffer_t* buffer, uint8_t p1, uint8_t p2) { + unsigned short sw = SW_OK; + unsigned char apduLength = buffer->size; + unsigned short offset = 0; + + if ((p1 != P1_PREPARE) && (p1 != P1_SIGN)) { + return io_send_sw(SW_INCORRECT_P1_P2); + } + if (p1 == P1_PREPARE) { + if ((p2 != P2_FIRST) && (p2 != P2_OTHER) && (p2 != P2_LEGACY)) { + return io_send_sw(SW_INCORRECT_P1_P2); + } + } + + if (p1 == P1_PREPARE) { + if ((p2 == P2_FIRST) || (p2 == P2_LEGACY)) { + unsigned char chunkLength; + unsigned char messageLength[3]; + unsigned char messageLengthSize; + memset(&context.transactionSummary, 0, + sizeof(transaction_summary_t)); + if (buffer->ptr[0] > MAX_BIP32_PATH) { + PRINTF("Invalid path\n"); + sw = SW_INCORRECT_DATA; + goto discard; + } + context.transactionSummary.payToAddressVersion = COIN_P2PKH_VERSION; + context.transactionSummary.payToScriptHashVersion = COIN_P2SH_VERSION; + memmove( + context.transactionSummary.keyPath, + buffer->ptr, MAX_BIP32_PATH_LENGTH); + offset += (4 * buffer->ptr[0]) + 1; + if (p2 == P2_LEGACY) { + context.transactionSummary.messageLength = + buffer->ptr[offset]; + offset++; + } else { + context.transactionSummary.messageLength = + (buffer->ptr[offset] << 8) | + (buffer->ptr[offset + 1]); + offset += 2; + } + if (context.transactionSummary.messageLength == + 0) { + PRINTF("Null message length\n"); + sw = SW_INCORRECT_DATA; + goto discard; + } + context.hashedMessageLength = 0; + + // Horizen signed message magic header is "Zcash" + // See https://github.com/HorizenOfficial/zen/blob/v5.0.0/src/main.cpp#L122 + const char* magicHeader = (COIN_KIND != COIN_KIND_HORIZEN) ? COIN_COINID : "Zcash"; + + cx_sha256_init_no_throw(&context.transactionHashFull.sha256); + cx_sha256_init_no_throw(&context.transactionHashAuthorization); + + chunkLength = + strlen(magicHeader) + sizeof(SIGNMAGIC); + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + &chunkLength, 1, NULL, 0)) { + goto discard; + } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + (uint8_t *)magicHeader, + strlen(magicHeader), NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + (unsigned char *)SIGNMAGIC, sizeof(SIGNMAGIC), NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + if (context.transactionSummary.messageLength < + 0xfd) { + messageLength[0] = + context.transactionSummary.messageLength; + messageLengthSize = 1; + } else { + messageLength[0] = 0xfd; + messageLength[1] = + (context.transactionSummary.messageLength & + 0xff); + messageLength[2] = ((context.transactionSummary + .messageLength >> + 8) & + 0xff); + messageLengthSize = 3; + } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + messageLength, messageLengthSize, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + chunkLength = apduLength - offset; + if ((context.hashedMessageLength + chunkLength) > + context.transactionSummary.messageLength) { + PRINTF("Invalid data length\n"); + sw = SW_INCORRECT_DATA; + goto discard; + } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + buffer->ptr + offset, chunkLength, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + if (cx_hash_no_throw( + &context.transactionHashAuthorization.header, + 0, buffer->ptr + offset, chunkLength, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + context.hashedMessageLength += chunkLength; + G_io_apdu_buffer[0] = 0x00; + if (context.hashedMessageLength == + context.transactionSummary.messageLength) { + G_io_apdu_buffer[1] = 0x00; + context.outLength = 2; + } else { + context.outLength = 1; + } + } else { + if ((context.hashedMessageLength + apduLength) > + context.transactionSummary.messageLength) { + PRINTF("Invalid data length\n"); + sw = SW_INCORRECT_DATA; + goto discard; + } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + buffer->ptr + offset, apduLength, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + if (cx_hash_no_throw( + &context.transactionHashAuthorization.header, + 0, buffer->ptr + offset, apduLength, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + context.hashedMessageLength += apduLength; + G_io_apdu_buffer[0] = 0x00; + if (context.hashedMessageLength == + context.transactionSummary.messageLength) { + G_io_apdu_buffer[1] = 0x00; + context.outLength = 2; + } else { + context.outLength = 1; + } + } + } else { + if ((context.transactionSummary.messageLength == 0) || + (context.hashedMessageLength != + context.transactionSummary.messageLength)) { + PRINTF("Invalid length to sign\n"); + sw = SW_INCORRECT_DATA; + goto discard; + } + if (message_check_bit_id(context.transactionSummary.keyPath) != BITID_NONE) { + sw = message_compute_hash(); + } else { + confirm_message_signature(); + return 0; + } + } + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); + + discard : + memset(&context.transactionSummary, 0, + sizeof(transaction_summary_t)); + return io_send_sw(sw); +} + +WEAK unsigned short handler_sign_message(buffer_t* buffer, uint8_t p1, uint8_t p2) { + if (G_called_from_swap) { + return io_send_sw(SW_SECURITY_STATUS_NOT_SATISFIED); + } + + return sign_message_internal(buffer, p1, p2); +} + +int user_action_message_signing(unsigned char confirming) { + unsigned short sw; + if (confirming) { + sw = message_compute_hash(); + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); + } else { + context.outLength = 0; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); + } +} diff --git a/lib-app-bitcoin/helpers.c b/lib-app-bitcoin/helpers.c new file mode 100644 index 00000000..ba200359 --- /dev/null +++ b/lib-app-bitcoin/helpers.c @@ -0,0 +1,232 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +#include "lib_standard_app/crypto_helpers.h" +#include "lib_standard_app/bip32.h" +#include "ledger_assert.h" +#include "io.h" +#include "base58.h" +#include "read.h" + +#include "context.h" +#include "helpers.h" + +void public_key_hash160(unsigned char *in, unsigned short inlen, + unsigned char out[static CX_RIPEMD160_SIZE]) { + unsigned char buffer[CX_SHA256_SIZE]; + cx_hash_sha256(in, inlen, buffer, sizeof(buffer)); + cx_ripemd160_hash(buffer, sizeof(buffer), out); +} + +static void compute_checksum(unsigned char *in, unsigned short inlen, + unsigned char output[static 4]) { + unsigned char checksumBuffer[32]; + cx_hash_sha256(in, inlen, checksumBuffer, 32); + cx_hash_sha256(checksumBuffer, 32, checksumBuffer, 32); + + PRINTF("Checksum\n%.*H\n",4,checksumBuffer); + memmove(output, checksumBuffer, 4); +} + +unsigned short public_key_to_encoded_base58( + unsigned char *in, unsigned short inlen, unsigned char *out, + unsigned short outlen, unsigned short version, + unsigned char alreadyHashed) { + unsigned char tmpBuffer[34]; + + unsigned char versionSize = (version > 255 ? 2 : 1); + short outputLen; + + if (!alreadyHashed) { + PRINTF("To hash\n%.*H\n",inlen,in); + public_key_hash160(in, inlen, tmpBuffer + versionSize); + PRINTF("Hash160\n%.*H\n",20,(tmpBuffer + versionSize)); + if (version > 255) { + tmpBuffer[0] = (version >> 8); + tmpBuffer[1] = version; + } else { + tmpBuffer[0] = version; + } + } else { + memmove(tmpBuffer, in, 20 + versionSize); + } + + compute_checksum(tmpBuffer, 20 + versionSize, tmpBuffer + 20 + versionSize); + + outputLen = base58_encode(tmpBuffer, 24 + versionSize, (char *)out, outlen); + LEDGER_ASSERT(outputLen >= 0, "Error encoding public key"); + + return outputLen; +} + +void swap_bytes(unsigned char *target, unsigned char *source, + unsigned char size) { + unsigned char i; + for (i = 0; i < size; i++) { + target[i] = source[size - 1 - i]; + } +} + +/* +Checks if the values of a derivation path are within "normal" (arbitrary) ranges: +Account < 100, change == 1 or 0, address index < 50000 +Returns 1 if the path is unusual, or not compliant with BIP44*/ +unsigned char bip44_derivation_guard(const unsigned char *bip32Path, bool is_change_path) { + unsigned char path_len; + bip32_path_t bip32PathInt; + + path_len = bip32Path[0]; + if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { + return 1; + } + + // If the path length is not compliant with BIP44 or if the purpose don't match regular usage, return a warning + if(path_len != BIP44_PATH_LEN || + ((bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 44 && + (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 49 && + (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 84)) { + return 1; + } + + // If the coin type doesn't match, return a warning + if ((BIP44_COIN_TYPE != 0) && + (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != BIP44_COIN_TYPE) && + ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != BIP44_COIN_TYPE_2))) { + return 1; + } + + // If the account or address index is very high or if the change isn't 1, return a warning + if((bip32PathInt.path[BIP44_ACCOUNT_OFFSET]^0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || + bip32PathInt.path[BIP44_CHANGE_OFFSET] != is_change_path?1:0 || + bip32PathInt.path[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { + return 1; + } + + return 0; +} + +/* +Only enforce the structure or coin type for consumed UTXOs or a public address +Returns 0 if the path is non compliant, or 1 if compliant +*/ +unsigned char enforce_bip44_coin_type(const unsigned char *bip32Path, bool for_pubkey) { + bip32_path_t bip32PathInt; + // No enforcement required + if (BIP44_COIN_TYPE == 0) { + return 1; + } + // Path is too short - always require a user validation if signing + if (bip32Path[0] < 2) { + return for_pubkey; + } + + if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { + return 1; + } + + // Path is not compliant with BIP 44 or derivatives - valid if not signing + if (!(((bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 44 || + (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 49 || + (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 84))) { + return for_pubkey; + } + + if (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == BIP44_COIN_TYPE) || + ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == BIP44_COIN_TYPE_2)) { + // Valid BIP 44 path + return 1; + } + // Everything else needs a user validation + return 0; +} + +int sign_finalhash(unsigned char* path, size_t path_len, unsigned char *in, unsigned short inlen, + unsigned char *out, size_t* outlen) { + + unsigned int info = 0; + + io_seproxyhal_io_heartbeat(); + + bip32_path_t bip32Path; + bip32Path.length = path[0]; + + if (!parse_serialized_path(&bip32Path, path, path_len)) { + return -1; + } + + if (bip32_derive_ecdsa_sign_hash_256( + CX_CURVE_SECP256K1, + bip32Path.path, + bip32Path.length, + CX_LAST | CX_RND_RFC6979, + CX_SHA256, + in, + inlen, + out, + outlen, + &info) != CX_OK) { + return -1; + } + + // Store information about the parity of the 'y' coordinate + if (info & CX_ECCINFO_PARITY_ODD) { + out[0] |= 0x01; + } + + io_seproxyhal_io_heartbeat(); + return 0; +} + +int get_public_key(const unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode) { + + bip32_path_t bip32Path; + + if (!parse_serialized_path(&bip32Path, keyPath, keyPath_len)) { + return -1; + } + + if (bip32_derive_get_pubkey_256( + CX_CURVE_SECP256K1, + bip32Path.path, + bip32Path.length, + raw_pubkey, + chainCode, + CX_SHA512) != CX_OK) + { + return -1; + } + + return 0; +} + +void compress_public_key_value(unsigned char *value) { + bool odd = (value[64] & 1); + value[0] = odd ? 0x03 : 0x02; +} + +bool parse_serialized_path(bip32_path_t* path, const unsigned char* serialized_path, unsigned char serialized_path_length) { + if (serialized_path_length < 1 || + serialized_path[0] > MAX_BIP32_PATH || + serialized_path[0] * 4 + 1 > serialized_path_length) + return false; + path->length = serialized_path[0]; + serialized_path++; + for (int i = 0; i < path->length; i += 1, serialized_path += 4) { + path->path[i] = read_u32_be(serialized_path, 0); + } + return true; +} diff --git a/include/helpers.h b/lib-app-bitcoin/helpers.h similarity index 55% rename from include/helpers.h rename to lib-app-bitcoin/helpers.h index febe122a..88314f74 100644 --- a/include/helpers.h +++ b/lib-app-bitcoin/helpers.h @@ -15,13 +15,12 @@ * limitations under the License. ********************************************************************************/ -#ifndef HELPERS_H - -#define HELPERS_H +#pragma once #include "os.h" #include "cx.h" #include "stdbool.h" +#include "filesystem_tx.h" #define OUTPUT_SCRIPT_REGULAR_PRE_LENGTH 4 #define OUTPUT_SCRIPT_REGULAR_POST_LENGTH 2 @@ -30,36 +29,29 @@ #define OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET 3 -unsigned char output_script_is_regular(unsigned char *buffer); -unsigned char output_script_is_p2sh(unsigned char *buffer); -unsigned char output_script_is_op_return(unsigned char *buffer); -unsigned char output_script_is_native_witness(unsigned char *buffer); - -unsigned char output_script_is_op_create(unsigned char *buffer, - size_t size); -unsigned char output_script_is_op_call(unsigned char *buffer, - size_t size); +typedef struct bip32_path { + unsigned char length; + unsigned int path[MAX_BIP32_PATH]; +} bip32_path_t; void public_key_hash160(unsigned char *in, unsigned short inlen, - unsigned char *out); + unsigned char out [static CX_RIPEMD160_SIZE]); unsigned short public_key_to_encoded_base58( unsigned char *in, unsigned short inlen, unsigned char *out, unsigned short outlen, unsigned short version, unsigned char alreadyHashed); -unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_path); -unsigned char enforce_bip44_coin_type(unsigned char *bip32Path, bool for_pubkey); -unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned char max_out_len); +unsigned char bip44_derivation_guard(const unsigned char *bip32Path, bool is_change_path); +unsigned char enforce_bip44_coin_type(const unsigned char *bip32Path, bool for_pubkey); void swap_bytes(unsigned char *target, unsigned char *source, unsigned char size); int sign_finalhash(unsigned char *path, size_t path_len, unsigned char *in, unsigned short inlen, - unsigned char *out, size_t* outlen, - unsigned char rfc6979); + unsigned char *out, size_t* outlen); + +int get_public_key(const unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode); -void transaction_add_output(unsigned char *hash160Address, - unsigned char *amount, unsigned char p2sh); -int get_public_key(unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode); +void compress_public_key_value(unsigned char *value); -#endif +bool parse_serialized_path(bip32_path_t* path, const unsigned char* serialized_path, unsigned char serialized_path_length); diff --git a/src/swap/handle_check_address.c b/lib-app-bitcoin/swap/handle_check_address.c similarity index 93% rename from src/swap/handle_check_address.c rename to lib-app-bitcoin/swap/handle_check_address.c index 1fd13dec..95e6d166 100644 --- a/src/swap/handle_check_address.c +++ b/lib-app-bitcoin/swap/handle_check_address.c @@ -1,14 +1,19 @@ #include "handle_check_address.h" -#include "os.h" #include "helpers.h" -#include "bip32_path.h" -#include "ecc.h" -#include "apdu_get_wallet_public_key.h" +#include "context.h" #include "cashaddr.h" #include "segwit_addr.h" -#include -bool derive_compressed_public_key( +#define P1_NO_DISPLAY 0x00 +#define P1_DISPLAY 0x01 +#define P1_REQUEST_TOKEN 0x02 + +#define P2_LEGACY 0x00 +#define P2_SEGWIT 0x01 +#define P2_NATIVE_SEGWIT 0x02 +#define P2_CASHADDR 0x03 + +static bool derive_compressed_public_key( unsigned char* serialized_path, unsigned char serialized_path_length, unsigned char* public_key, unsigned char public_key_length) { UNUSED(public_key_length); @@ -23,7 +28,7 @@ bool derive_compressed_public_key( return true; } -bool get_address_from_compressed_public_key( +static bool get_address_from_compressed_public_key( unsigned char format, unsigned char* compressed_pub_key, unsigned short payToAddressVersion, diff --git a/src/swap/handle_check_address.h b/lib-app-bitcoin/swap/handle_check_address.h similarity index 91% rename from src/swap/handle_check_address.h rename to lib-app-bitcoin/swap/handle_check_address.h index 01d8e138..2e5eaa54 100644 --- a/src/swap/handle_check_address.h +++ b/lib-app-bitcoin/swap/handle_check_address.h @@ -2,7 +2,6 @@ #define _HANDLE_CHECK_ADDRESS_H_ #include "swap_lib_calls.h" -#include "context.h" void swap_handle_check_address(check_address_parameters_t* check_address_params); diff --git a/lib-app-bitcoin/swap/handle_get_printable_amount.c b/lib-app-bitcoin/swap/handle_get_printable_amount.c new file mode 100644 index 00000000..d801bfab --- /dev/null +++ b/lib-app-bitcoin/swap/handle_get_printable_amount.c @@ -0,0 +1,20 @@ +#include "read.h" + +#include "handle_get_printable_amount.h" +#include "display_utils.h" + +void swap_handle_get_printable_amount(get_printable_amount_parameters_t* params) { + params->printable_amount[0] = 0; + if (params->amount_length > 8) { + PRINTF("Amount is too big"); + return; + } + unsigned char amount[8]; + memset(amount, 0, 8); + memcpy(amount + (8 - params->amount_length), params->amount, params->amount_length); + + format_sats_amount(COIN_COINID_SHORT, + (uint64_t)(read_u64_be(amount, 0)), // Cast prevents weird compilo bug + params->printable_amount); + return; +} \ No newline at end of file diff --git a/src/swap/handle_get_printable_amount.h b/lib-app-bitcoin/swap/handle_get_printable_amount.h similarity index 100% rename from src/swap/handle_get_printable_amount.h rename to lib-app-bitcoin/swap/handle_get_printable_amount.h diff --git a/src/swap/handle_swap_sign_transaction.c b/lib-app-bitcoin/swap/handle_swap_sign_transaction.c similarity index 83% rename from src/swap/handle_swap_sign_transaction.c rename to lib-app-bitcoin/swap/handle_swap_sign_transaction.c index c29af60c..9452ef94 100644 --- a/src/swap/handle_swap_sign_transaction.c +++ b/lib-app-bitcoin/swap/handle_swap_sign_transaction.c @@ -1,6 +1,5 @@ #include "handle_swap_sign_transaction.h" #include "os_io_seproxyhal.h" -#include "public_ram_variables.h" #include "display_variables.h" #include "context.h" #include "usbd_core.h" @@ -68,28 +67,6 @@ bool swap_copy_transaction_parameters(create_transaction_parameters_t* params) { return true; } -void swap_handle_swap_sign_transaction(void) { - context_init(); - io_seproxyhal_init(); - UX_INIT(); -#ifdef HAVE_NBGL - nbgl_useCaseSpinner("Signing"); -#endif // HAVE_BAGL - USB_power(0); - USB_power(1); - //ui_idle(); - PRINTF("USB power ON/OFF\n"); -#ifdef TARGET_NANOX - // grab the current plane mode setting - G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); -#endif // TARGET_NANOX -#ifdef HAVE_BLE - BLE_power(0, NULL); - BLE_power(1, "Nano X"); -#endif // HAVE_BLE - app_main(); -} - void __attribute__((noreturn)) swap_finalize_exchange_sign_transaction(bool is_success) { *G_swap_sign_return_value_address = is_success; os_lib_end(); diff --git a/src/swap/handle_swap_sign_transaction.h b/lib-app-bitcoin/swap/handle_swap_sign_transaction.h similarity index 83% rename from src/swap/handle_swap_sign_transaction.h rename to lib-app-bitcoin/swap/handle_swap_sign_transaction.h index 7203d065..a9e2914c 100644 --- a/src/swap/handle_swap_sign_transaction.h +++ b/lib-app-bitcoin/swap/handle_swap_sign_transaction.h @@ -2,12 +2,9 @@ #define _HANDLE_SWAP_SIGN_TRANSACTION_H_ #include "swap_lib_calls.h" -#include "context.h" bool swap_copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params); -void swap_handle_swap_sign_transaction(void); - void __attribute__((noreturn)) swap_finalize_exchange_sign_transaction(bool is_success); #endif // _HANDLE_SWAP_SIGN_TRANSACTION_H_ diff --git a/src/transaction.c b/lib-app-bitcoin/transaction.c similarity index 57% rename from src/transaction.c rename to lib-app-bitcoin/transaction.c index 2806d623..ab59b215 100644 --- a/src/transaction.c +++ b/lib-app-bitcoin/transaction.c @@ -15,14 +15,19 @@ * limitations under the License. ********************************************************************************/ -#include "internal.h" -#include "apdu_constants.h" -#include "display_variables.h" #include "ledger_assert.h" #include "lib_standard_app/read.h" #include "lib_standard_app/write.h" #include "swap.h" +#include "apdu_constants.h" +#include "display_variables.h" +#include "be_operations.h" +#include "transaction.h" +#include "context.h" +#include "filesystem.h" +#include "helpers.h" + #ifndef COIN_CONSENSUS_BRANCH_ID #define COIN_CONSENSUS_BRANCH_ID 0 #endif @@ -31,95 +36,57 @@ #define CONSENSUS_BRANCH_ID_SAPLING 0x76b809bb #define CONSENSUS_BRANCH_ID_ZCLASSIC 0x930b540d +unsigned char const OVERWINTER_PARAM_PREVOUTS[16] = { 'Z', 'c', 'a', 's', 'h', 'P', 'r', 'e', 'v', 'o', 'u', 't', 'H', 'a', 's', 'h' }; +unsigned char const OVERWINTER_PARAM_SEQUENCE[16] = { 'Z', 'c', 'a', 's', 'h', 'S', 'e', 'q', 'u', 'e', 'n', 'c', 'H', 'a', 's', 'h' }; +unsigned char const OVERWINTER_PARAM_OUTPUTS[16] = { 'Z', 'c', 'a', 's', 'h', 'O', 'u', 't', 'p', 'u', 't', 's', 'H', 'a', 's', 'h' }; +unsigned char const OVERWINTER_PARAM_SIGHASH[16] = { 'Z', 'c', 'a', 's', 'h', 'S', 'i', 'g', 'H', 'a', 's', 'h', 0, 0, 0, 0 }; +unsigned char const OVERWINTER_NO_JOINSPLITS[32] = { 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 }; + // Check if fOverwintered flag is set and if nVersion is >= 0x03 #define TRUSTED_INPUT_OVERWINTER ( (COIN_KIND == COIN_KIND_ZCASH || \ COIN_KIND == COIN_KIND_ZCLASSIC || \ COIN_KIND == COIN_KIND_KOMODO) && \ - (read_u32_le(context_D.transactionVersion, 0) & (1<<31)) && \ - (read_u32_le(context_D.transactionVersion, 0) ^ (1<<31)) >= 0x03 \ + (read_u32_le(context.transactionVersion, 0) & (1<<31)) && \ + (read_u32_le(context.transactionVersion, 0) ^ (1<<31)) >= 0x03 \ ) -#define DEBUG_LONG "%d" - -void check_transaction_available(unsigned char x) { - if (context_D.transactionDataRemaining < x) { - PRINTF("Check transaction available failed %d < %d\n", context_D.transactionDataRemaining, x); - THROW(EXCEPTION); - } +static void check_transaction_available(unsigned char x) { + LEDGER_ASSERT(context.transactionDataRemaining >= x, "Check transaction available failed %d < %d\n", context.transactionDataRemaining, x); } #define OP_HASH160 0xA9 #define OP_EQUAL 0x87 #define OP_CHECKMULTISIG 0xAE -unsigned char transaction_amount_add_be(unsigned char *target, - unsigned char *a, - unsigned char *b) { - unsigned char carry = 0; - unsigned char i; - for (i = 0; i < 8; i++) { - unsigned short val = a[8 - 1 - i] + b[8 - 1 - i] + (carry ? 1 : 0); - carry = (val > 255); - target[8 - 1 - i] = (val & 255); - } - return carry; -} - -unsigned char transaction_amount_sub_be(unsigned char *target, - unsigned char *a, - unsigned char *b) { - unsigned char borrow = 0; - unsigned char i; - for (i = 0; i < 8; i++) { - unsigned short tmpA = a[8 - 1 - i]; - unsigned short tmpB = b[8 - 1 - i]; - if (borrow) { - if (tmpA <= tmpB) { - tmpA += (255 + 1) - 1; - } else { - borrow = 0; - tmpA--; - } - } - if (tmpA < tmpB) { - borrow = 1; - tmpA += 255 + 1; - } - target[8 - 1 - i] = (unsigned char)(tmpA - tmpB); - } - - return borrow; -} - -void transaction_offset(unsigned char value) { - if ((context_D.transactionHashOption & TRANSACTION_HASH_FULL) != 0) { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", value, context_D.transactionBufferPointer); - if (context_D.usingOverwinter) { - LEDGER_ASSERT(cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); +static void transaction_offset(unsigned char value) { + if ((context.transactionHashOption & TRANSACTION_HASH_FULL) != 0) { + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", value, context.transactionBufferPointer); + if (context.usingOverwinter) { + LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); } else { - LEDGER_ASSERT(cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, - context_D.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); + LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + context.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); } } - if ((context_D.transactionHashOption & + if ((context.transactionHashOption & TRANSACTION_HASH_AUTHORIZATION) != 0) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", value, context_D.transactionBufferPointer); - LEDGER_ASSERT(cx_hash_no_throw(&context_D.transactionHashAuthorization.header, 0, - context_D.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", value, context.transactionBufferPointer); + LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashAuthorization.header, 0, + context.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); } } -void transaction_offset_increase(unsigned char value) { +static void transaction_offset_increase(unsigned char value) { transaction_offset(value); - context_D.transactionBufferPointer += value; - context_D.transactionDataRemaining -= value; + context.transactionBufferPointer += value; + context.transactionDataRemaining -= value; } -unsigned long int transaction_get_varint(void) { +static unsigned long int transaction_get_varint(void) { unsigned char firstByte; check_transaction_available(1); - firstByte = *context_D.transactionBufferPointer; + firstByte = *context.transactionBufferPointer; if (firstByte < 0xFD) { transaction_offset_increase(1); return firstByte; @@ -128,8 +95,8 @@ unsigned long int transaction_get_varint(void) { transaction_offset_increase(1); check_transaction_available(2); result = - (unsigned long int)(*context_D.transactionBufferPointer) | - ((unsigned long int)(*(context_D.transactionBufferPointer + + (unsigned long int)(*context.transactionBufferPointer) | + ((unsigned long int)(*(context.transactionBufferPointer + 1)) << 8); transaction_offset_increase(2); @@ -138,39 +105,34 @@ unsigned long int transaction_get_varint(void) { unsigned long int result; transaction_offset_increase(1); check_transaction_available(4); - result = read_u32_le(context_D.transactionBufferPointer, 0); + result = read_u32_le(context.transactionBufferPointer, 0); transaction_offset_increase(4); return result; } else { - PRINTF("Varint parsing failed\n"); - THROW(INVALID_PARAMETER); - return 0; + LEDGER_ASSERT(false, "Varint parsing failed"); + __builtin_unreachable(); } } void transaction_parse(unsigned char parseMode) { - unsigned char optionP2SHSkip2FA = - ((N_btchip.bkp.config.options & OPTION_SKIP_2FA_P2SH) != 0); - BEGIN_TRY { - TRY { for (;;) { - switch (context_D.transactionContext.transactionState) { + switch (context.transactionContext.transactionState) { case TRANSACTION_NONE: { PRINTF("Init transaction parser\n"); // Reset transaction state - context_D.transactionContext + context.transactionContext .transactionRemainingInputsOutputs = 0; - context_D.transactionContext + context.transactionContext .transactionCurrentInputOutput = 0; - context_D.transactionContext.scriptRemaining = 0; + context.transactionContext.scriptRemaining = 0; memset( - context_D.transactionContext.transactionAmount, - 0, sizeof(context_D.transactionContext + context.transactionContext.transactionAmount, + 0, sizeof(context.transactionContext .transactionAmount)); // TODO : transactionControlFid // Reset hashes - if (context_D.usingOverwinter) { - if (context_D.segwitParsedOnce) { + if (context.usingOverwinter) { + if (context.segwitParsedOnce) { uint8_t parameters[16]; memmove(parameters, OVERWINTER_PARAM_SIGHASH, 16); if (COIN_KIND == COIN_KIND_ZCLASSIC) { @@ -178,124 +140,124 @@ void transaction_parse(unsigned char parseMode) { } else { write_u32_le(parameters, 12, - context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING ? + context.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING ? (COIN_CONSENSUS_BRANCH_ID != 0 ? COIN_CONSENSUS_BRANCH_ID : CONSENSUS_BRANCH_ID_SAPLING) : CONSENSUS_BRANCH_ID_OVERWINTER); } - if (cx_blake2b_init2_no_throw(&context_D.transactionHashFull.blake2b, 256, NULL, 0, parameters, 16)) { + if (cx_blake2b_init2_no_throw(&context.transactionHashFull.blake2b, 256, NULL, 0, parameters, 16)) { goto fail; } } } else { - if (cx_sha256_init_no_throw(&context_D.transactionHashFull.sha256)) { + if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { goto fail; } } if (cx_sha256_init_no_throw( - &context_D.transactionHashAuthorization)) { + &context.transactionHashAuthorization)) { goto fail; } - if (context_D.usingSegwit) { - context_D.transactionHashOption = 0; - if (!context_D.segwitParsedOnce) { - if (context_D.usingOverwinter) { - if (cx_blake2b_init2_no_throw(&context_D.segwit.hash.hashPrevouts.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_PREVOUTS, 16)) { + if (context.usingSegwit) { + context.transactionHashOption = 0; + if (!context.segwitParsedOnce) { + if (context.usingOverwinter) { + if (cx_blake2b_init2_no_throw(&context.segwit.hash.hashPrevouts.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_PREVOUTS, 16)) { goto fail; } - if (cx_blake2b_init2_no_throw(&context_D.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_SEQUENCE, 16)) { + if (cx_blake2b_init2_no_throw(&context.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_SEQUENCE, 16)) { goto fail; } } else { if (cx_sha256_init_no_throw( - &context_D.segwit.hash.hashPrevouts.sha256)) { + &context.segwit.hash.hashPrevouts.sha256)) { goto fail; } } } else { PRINTF("Resume SegWit hash\n"); - PRINTF("SEGWIT Version\n%.*H\n",sizeof(context_D.transactionVersion),context_D.transactionVersion); - PRINTF("SEGWIT HashedPrevouts\n%.*H\n",sizeof(context_D.segwit.cache.hashedPrevouts),context_D.segwit.cache.hashedPrevouts); - PRINTF("SEGWIT HashedSequence\n%.*H\n",sizeof(context_D.segwit.cache.hashedSequence),context_D.segwit.cache.hashedSequence); - if (context_D.usingOverwinter) { - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.transactionVersion, sizeof(context_D.transactionVersion), NULL, 0)) { + PRINTF("SEGWIT Version\n%.*H\n",sizeof(context.transactionVersion),context.transactionVersion); + PRINTF("SEGWIT HashedPrevouts\n%.*H\n",sizeof(context.segwit.cache.hashedPrevouts),context.segwit.cache.hashedPrevouts); + PRINTF("SEGWIT HashedSequence\n%.*H\n",sizeof(context.segwit.cache.hashedSequence),context.segwit.cache.hashedSequence); + if (context.usingOverwinter) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.transactionVersion, sizeof(context.transactionVersion), NULL, 0)) { goto fail; } - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.nVersionGroupId, sizeof(context_D.nVersionGroupId), NULL, 0)) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.nVersionGroupId, sizeof(context.nVersionGroupId), NULL, 0)) { goto fail; } - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.segwit.cache.hashedPrevouts, sizeof(context_D.segwit.cache.hashedPrevouts), NULL, 0)) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.segwit.cache.hashedPrevouts, sizeof(context.segwit.cache.hashedPrevouts), NULL, 0)) { goto fail; } - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.segwit.cache.hashedSequence, sizeof(context_D.segwit.cache.hashedSequence), NULL, 0)) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.segwit.cache.hashedSequence, sizeof(context.segwit.cache.hashedSequence), NULL, 0)) { goto fail; } - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.segwit.cache.hashedOutputs, sizeof(context_D.segwit.cache.hashedOutputs), NULL, 0)) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.segwit.cache.hashedOutputs, sizeof(context.segwit.cache.hashedOutputs), NULL, 0)) { goto fail; } - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { goto fail; } - if (context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { // sapling hashShieldedSpend) + if (context.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { // sapling hashShieldedSpend) goto fail; } - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { // sapling hashShieldedOutputs + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { // sapling hashShieldedOutputs goto fail; } } - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.nLockTime, sizeof(context_D.nLockTime), NULL, 0)) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.nLockTime, sizeof(context.nLockTime), NULL, 0)) { goto fail; } - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.nExpiryHeight, sizeof(context_D.nExpiryHeight), NULL, 0)) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.nExpiryHeight, sizeof(context.nExpiryHeight), NULL, 0)) { goto fail; } - if (context_D.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { + if (context.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { unsigned char valueBalance[8]; memset(valueBalance, 0, sizeof(valueBalance)); - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, valueBalance, sizeof(valueBalance), NULL, 0)) { // sapling valueBalance + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, valueBalance, sizeof(valueBalance), NULL, 0)) { // sapling valueBalance goto fail; } } - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.sigHashType, sizeof(context_D.sigHashType), NULL, 0)) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.sigHashType, sizeof(context.sigHashType), NULL, 0)) { goto fail; } } else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context_D.transactionVersion), context_D.transactionVersion); + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context.transactionVersion), context.transactionVersion); if (cx_hash_no_throw( - &context_D.transactionHashFull.sha256.header, 0, - context_D.transactionVersion, - sizeof(context_D.transactionVersion), + &context.transactionHashFull.sha256.header, 0, + context.transactionVersion, + sizeof(context.transactionVersion), NULL, 0)) { goto fail; } - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context_D.segwit.cache.hashedPrevouts), context_D.segwit.cache.hashedPrevouts); + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context.segwit.cache.hashedPrevouts), context.segwit.cache.hashedPrevouts); if (cx_hash_no_throw( - &context_D.transactionHashFull.sha256.header, 0, - context_D.segwit.cache.hashedPrevouts, - sizeof(context_D.segwit.cache + &context.transactionHashFull.sha256.header, 0, + context.segwit.cache.hashedPrevouts, + sizeof(context.segwit.cache .hashedPrevouts), NULL, 0)) { goto fail; } - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context_D.segwit.cache.hashedSequence), context_D.segwit.cache.hashedSequence); + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context.segwit.cache.hashedSequence), context.segwit.cache.hashedSequence); if (cx_hash_no_throw( - &context_D.transactionHashFull.sha256.header, 0, - context_D.segwit.cache.hashedSequence, - sizeof(context_D.segwit.cache + &context.transactionHashFull.sha256.header, 0, + context.segwit.cache.hashedSequence, + sizeof(context.segwit.cache .hashedSequence), NULL, 0)) { goto fail; } - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", sizeof(context_D.segwit.cache), (unsigned char *)&context_D.segwit.cache); - if (cx_hash_no_throw(&context_D + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", sizeof(context.segwit.cache), (unsigned char *)&context.segwit.cache); + if (cx_hash_no_throw(&context .transactionHashAuthorization.header, 0, - (unsigned char *)&context_D + (unsigned char *)&context .segwit.cache, - sizeof(context_D.segwit.cache), + sizeof(context.segwit.cache), NULL, 0)) { goto fail; } @@ -305,25 +267,25 @@ void transaction_parse(unsigned char parseMode) { // Parse the beginning of the transaction // Version check_transaction_available(4); - memmove(context_D.transactionVersion, - context_D.transactionBufferPointer, 4); + memmove(context.transactionVersion, + context.transactionBufferPointer, 4); transaction_offset_increase(4); - if (context_D.usingOverwinter || + if (context.usingOverwinter || TRUSTED_INPUT_OVERWINTER) { // nVersionGroupId check_transaction_available(4); - memmove(context_D.nVersionGroupId, - context_D.transactionBufferPointer, 4); + memmove(context.nVersionGroupId, + context.transactionBufferPointer, 4); transaction_offset_increase(4); } if (COIN_FLAGS & FLAG_PEERCOIN_SUPPORT) { if (((COIN_FAMILY == FAMILY_PEERCOIN && - (context_D.transactionVersion[0] < 3))) || + (context.transactionVersion[0] < 3))) || ((COIN_FAMILY == FAMILY_STEALTH) && - (context_D.transactionVersion[0] < 2))) { + (context.transactionVersion[0] < 2))) { // Timestamp check_transaction_available(4); transaction_offset_increase(4); @@ -331,10 +293,10 @@ void transaction_parse(unsigned char parseMode) { } // Number of inputs - context_D.transactionContext + context.transactionContext .transactionRemainingInputsOutputs = transaction_get_varint(); - PRINTF("Number of inputs : " DEBUG_LONG "\n",context_D.transactionContext.transactionRemainingInputsOutputs); + PRINTF("Number of inputs : %d\n", context.transactionContext.transactionRemainingInputsOutputs); if (G_called_from_swap && parseMode == PARSE_MODE_SIGNATURE) { // remember number of inputs to know when to exit from library // we will count number of already signed inputs and compare with this value @@ -342,13 +304,13 @@ void transaction_parse(unsigned char parseMode) { // (when for ex. we sign segregated witness) if (vars.swap_data.totalNumberOfInputs == 0) { vars.swap_data.totalNumberOfInputs = - context_D.transactionContext.transactionRemainingInputsOutputs; + context.transactionContext.transactionRemainingInputsOutputs; } // Reseting the flag, because we should check address ones for each input vars.swap_data.was_address_checked = 0; } // Ready to proceed - context_D.transactionContext.transactionState = + context.transactionContext.transactionState = TRANSACTION_DEFINED_WAIT_INPUT; __attribute__((fallthrough)); @@ -357,14 +319,14 @@ void transaction_parse(unsigned char parseMode) { case TRANSACTION_DEFINED_WAIT_INPUT: { unsigned char trustedInputFlag = 1; PRINTF("Process input\n"); - if (context_D.transactionContext + if (context.transactionContext .transactionRemainingInputsOutputs == 0) { // No more inputs to hash, move forward - context_D.transactionContext.transactionState = + context.transactionContext.transactionState = TRANSACTION_INPUT_HASHING_DONE; continue; } - if (context_D.transactionDataRemaining < 1) { + if (context.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } @@ -382,23 +344,23 @@ void transaction_parse(unsigned char parseMode) { // Expect the trusted input flag and trusted input length check_transaction_available(2); - switch (*context_D.transactionBufferPointer) { + switch (*context.transactionBufferPointer) { case 0: - if (context_D.usingSegwit) { + if (context.usingSegwit) { PRINTF("Non trusted input used in segwit mode\n"); goto fail; } trustedInputFlag = 0; break; case 1: - if (context_D.usingSegwit) { + if (context.usingSegwit) { // Segwit inputs can be passed as TrustedInput also PRINTF("Trusted input used in segwit mode\n"); } trustedInputFlag = 1; break; case 2: - if (!context_D.usingSegwit) { + if (!context.usingSegwit) { PRINTF("Segwit input not used in segwit mode\n"); goto fail; } @@ -408,18 +370,10 @@ void transaction_parse(unsigned char parseMode) { PRINTF("Invalid trusted input flag\n"); goto fail; } - /* - trustedInputLength = - *(context_D.transactionBufferPointer + 1); - if (trustedInputLength > sizeof(trustedInput)) { - PRINTF("Trusted input too long\n"); - goto fail; - } - */ // Check TrustedInput (TI) integrity, be it a non-segwit TI or a segwit TI if (trustedInputFlag) { trustedInputLength = *( - context_D.transactionBufferPointer + 1); + context.transactionBufferPointer + 1); if ((trustedInputLength > sizeof(trustedInput)) || (trustedInputLength < 8)) { PRINTF("Invalid trusted input size\n"); @@ -429,16 +383,16 @@ void transaction_parse(unsigned char parseMode) { check_transaction_available(2 + trustedInputLength); // Check TrustedInput Hmac cx_hmac_sha256( - (uint8_t *)N_btchip.bkp.trustedinput_key, - sizeof(N_btchip.bkp.trustedinput_key), - context_D.transactionBufferPointer + 2, + (uint8_t *)g_nvram_data.bkp.trustedinput_key, + sizeof(g_nvram_data.bkp.trustedinput_key), + context.transactionBufferPointer + 2, trustedInputLength - 8, trustedInput, trustedInputLength); - PRINTF("====> Input HMAC: %.*H\n", 8, context_D.transactionBufferPointer + 2 + trustedInputLength - 8); + PRINTF("====> Input HMAC: %.*H\n", 8, context.transactionBufferPointer + 2 + trustedInputLength - 8); PRINTF("====> Computed HMAC: %.*H\n", 8, trustedInput); if (os_secure_memcmp( trustedInput, // Contains computed Hmac for now - context_D.transactionBufferPointer + + context.transactionBufferPointer + 2 + trustedInputLength - 8, 8) != 0) { PRINTF("Invalid signature\n"); @@ -447,34 +401,34 @@ void transaction_parse(unsigned char parseMode) { // Hmac is valid. If TrustedInput contains a segwit input, update data pointer & length // to fake the parser into believing a normal segwit input was received. Do not use // transaction_offset_increase() here as it could update the hash being computed. - if (context_D.usingSegwit) { + if (context.usingSegwit) { // Overwrite the no longer needed HMAC's 1st byte w/ the input script length byte. - *(context_D.transactionBufferPointer + 1 + TRUSTED_INPUT_SIZE + 1) = - *(context_D.transactionBufferPointer + 1 + TRUSTED_INPUT_TOTAL_SIZE + 1); + *(context.transactionBufferPointer + 1 + TRUSTED_INPUT_SIZE + 1) = + *(context.transactionBufferPointer + 1 + TRUSTED_INPUT_TOTAL_SIZE + 1); // Set tx data pointer on TI header's (i.e. 0x38||0x32||0x00||Nonce (2B)) last byte // before prevout tx hash. Also remove HMAC size from remaining data length. - context_D.transactionBufferPointer += 5; - context_D.transactionDataRemaining -= (5+8); + context.transactionBufferPointer += 5; + context.transactionDataRemaining -= (5+8); } } // Handle pure segwit inputs, whether trusted or not (i.e. InputHashStart 1st APDU's P2==02 // & data[0]=={0x01, 0x02}) - if (context_D.usingSegwit) { + if (context.usingSegwit) { transaction_offset_increase(1); // Set tx pointer on 1st byte of hash check_transaction_available( 36); // prevout : 32 hash + 4 index - if (!context_D.segwitParsedOnce) { - if (context_D.usingOverwinter) { - if (cx_hash_no_throw(&context_D.segwit.hash.hashPrevouts.blake2b.header, 0, context_D.transactionBufferPointer, 36, NULL, 0)) { + if (!context.segwitParsedOnce) { + if (context.usingOverwinter) { + if (cx_hash_no_throw(&context.segwit.hash.hashPrevouts.blake2b.header, 0, context.transactionBufferPointer, 36, NULL, 0)) { goto fail; } } else { if (cx_hash_no_throw( - &context_D.segwit.hash.hashPrevouts + &context.segwit.hash.hashPrevouts .sha256.header, 0, - context_D.transactionBufferPointer, + context.transactionBufferPointer, 36, NULL, 0)) { goto fail; } @@ -483,58 +437,45 @@ void transaction_parse(unsigned char parseMode) { check_transaction_available(8); // update amount swap_bytes( amount, - context_D.transactionBufferPointer, + context.transactionBufferPointer, 8); if (transaction_amount_add_be( - context_D.transactionContext + context.transactionContext .transactionAmount, - context_D.transactionContext + context.transactionContext .transactionAmount, amount)) { PRINTF("Overflow\n"); goto fail; } - PRINTF("Adding amount\n%.*H\n",8,context_D.transactionBufferPointer); - PRINTF("New amount\n%.*H\n",8,context_D.transactionContext.transactionAmount); + PRINTF("Adding amount\n%.*H\n",8,context.transactionBufferPointer); + PRINTF("New amount\n%.*H\n",8,context.transactionContext.transactionAmount); transaction_offset_increase(8); } else { - context_D.transactionHashOption = + context.transactionHashOption = TRANSACTION_HASH_FULL; transaction_offset_increase(36); - context_D.transactionHashOption = 0; + context.transactionHashOption = 0; check_transaction_available(8); // save amount memmove( - context_D.inputValue, - context_D.transactionBufferPointer, + context.inputValue, + context.transactionBufferPointer, 8); transaction_offset_increase(8); - context_D.transactionHashOption = + context.transactionHashOption = TRANSACTION_HASH_FULL; } } // Handle non-segwit inputs (i.e. InputHashStart 1st APDU's P2==00 && data[0]==0x00) else if (!trustedInputFlag) { - if (!optionP2SHSkip2FA) { - PRINTF("Untrusted input not authorized\n"); - goto fail; - } - context_D.transactionBufferPointer++; - context_D.transactionDataRemaining--; - check_transaction_available( - 36); // prevout : 32 hash + 4 index - transaction_offset_increase(36); - PRINTF("Marking relaxed input\n"); - context_D.transactionContext.relaxed = 1; - /* - PRINTF("Clearing P2SH consumption\n"); - context_D.transactionContext.consumeP2SH = 0; - */ + PRINTF("Untrusted input not authorized\n"); + goto fail; } // Handle non-segwit TrustedInput (i.e. InputHashStart 1st APDU's P2==00 & data[0]==0x01) - else if (trustedInputFlag && !context_D.usingSegwit) { + else if (trustedInputFlag && !context.usingSegwit) { memmove( trustedInput, - context_D.transactionBufferPointer + 2, + context.transactionBufferPointer + 2, trustedInputLength - 8); if (trustedInput[0] != MAGIC_TRUSTED_INPUT) { PRINTF("Failed to verify trusted input signature\n"); @@ -542,33 +483,24 @@ void transaction_parse(unsigned char parseMode) { } // Update the hash with prevout data savePointer = - context_D.transactionBufferPointer; - /* - // Check if a P2SH script is used - if ((trustedInput[1] & FLAG_TRUSTED_INPUT_P2SH) == - 0) { - PRINTF("Clearing P2SH consumption\n"); - context_D.transactionContext.consumeP2SH = - 0; - } - */ - context_D.transactionBufferPointer = + context.transactionBufferPointer; + context.transactionBufferPointer = trustedInput + 4; - PRINTF("Trusted input hash\n%.*H\n",36,context_D.transactionBufferPointer); + PRINTF("Trusted input hash\n%.*H\n",36,context.transactionBufferPointer); transaction_offset(36); - context_D.transactionBufferPointer = + context.transactionBufferPointer = savePointer + (2 + trustedInputLength); - context_D.transactionDataRemaining -= + context.transactionDataRemaining -= (2 + trustedInputLength); // Update the amount swap_bytes(amount, trustedInput + 40, 8); if (transaction_amount_add_be( - context_D.transactionContext + context.transactionContext .transactionAmount, - context_D.transactionContext + context.transactionContext .transactionAmount, amount)) { PRINTF("Overflow\n"); @@ -576,90 +508,85 @@ void transaction_parse(unsigned char parseMode) { } PRINTF("Adding amount\n%.*H\n",8,(trustedInput + 40)); - PRINTF("New amount\n%.*H\n",8,context_D.transactionContext.transactionAmount); + PRINTF("New amount\n%.*H\n",8,context.transactionContext.transactionAmount); } - if (!context_D.usingSegwit) { + if (!context.usingSegwit) { // Do not include the input script length + value in // the authentication hash - context_D.transactionHashOption = + context.transactionHashOption = TRANSACTION_HASH_FULL; } } // Read the script length - context_D.transactionContext.scriptRemaining = + context.transactionContext.scriptRemaining = transaction_get_varint(); - PRINTF("Script to read " DEBUG_LONG "\n",context_D.transactionContext.scriptRemaining); + PRINTF("Script to read %d\n", context.transactionContext.scriptRemaining); if ((parseMode == PARSE_MODE_SIGNATURE) && - !trustedInputFlag && !context_D.usingSegwit) { + !trustedInputFlag && !context.usingSegwit) { // Only proceeds if this is not to be signed - so length // should be null - if (context_D.transactionContext + if (context.transactionContext .scriptRemaining != 0) { PRINTF("Request to sign relaxed input\n"); - if (!optionP2SHSkip2FA) { - goto fail; - } + goto fail; } } // Move on - context_D.transactionContext.transactionState = + context.transactionContext.transactionState = TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; __attribute__((fallthrough)); } case TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { unsigned char dataAvailable; - PRINTF("Process input script, remaining " DEBUG_LONG "\n",context_D.transactionContext.scriptRemaining); - if (context_D.transactionDataRemaining < 1) { + PRINTF("Process input script, remaining %d\n", context.transactionContext.scriptRemaining); + if (context.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } // Scan for P2SH consumption - huge shortcut, but fine // enough // Also usable in SegWit mode - if (context_D.transactionContext.scriptRemaining == + if (context.transactionContext.scriptRemaining == 1) { - if (*context_D.transactionBufferPointer == + if (*context.transactionBufferPointer == OP_CHECKMULTISIG) { - if (optionP2SHSkip2FA) { - PRINTF("Marking P2SH consumption\n"); - context_D.transactionContext - .consumeP2SH = 1; - } + PRINTF("Marking P2SH consumption\n"); + context.transactionContext.consumeP2SH = 1; } else { // When using the P2SH shortcut, all inputs must use // P2SH PRINTF("Disabling P2SH consumption\n"); - context_D.transactionContext.consumeP2SH = 0; + context.transactionContext.consumeP2SH = 0; } transaction_offset_increase(1); - context_D.transactionContext.scriptRemaining--; + context.transactionContext.scriptRemaining--; } - if (context_D.transactionContext.scriptRemaining == + if (context.transactionContext.scriptRemaining == 0) { if (parseMode == PARSE_MODE_SIGNATURE) { - if (!context_D.usingSegwit) { + if (!context.usingSegwit) { // Restore dual hash for signature + // authentication - context_D.transactionHashOption = + context.transactionHashOption = TRANSACTION_HASH_BOTH; } else { - if (context_D.segwitParsedOnce) { + if (context.segwitParsedOnce) { // Append the saved value - PRINTF("SEGWIT Add value\n%.*H\n",8,context_D.inputValue); - if (context_D.usingOverwinter) { - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.inputValue, 8, NULL, 0)) { + PRINTF("SEGWIT Add value\n%.*H\n",8,context.inputValue); + if (context.usingOverwinter) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.inputValue, 8, NULL, 0)) { goto fail; } } else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context_D.inputValue), context_D.inputValue); - if (cx_hash_no_throw(&context_D + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context.inputValue), context.inputValue); + if (cx_hash_no_throw(&context .transactionHashFull.sha256.header, - 0, context_D.inputValue, 8, + 0, context.inputValue, 8, NULL, 0)) { goto fail; } @@ -669,19 +596,19 @@ void transaction_parse(unsigned char parseMode) { } // Sequence check_transaction_available(4); - if (context_D.usingSegwit && - !context_D.segwitParsedOnce) { - if (context_D.usingOverwinter) { - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, context_D.transactionBufferPointer, 4, NULL, 0)) { + if (context.usingSegwit && + !context.segwitParsedOnce) { + if (context.usingOverwinter) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.transactionBufferPointer, 4, NULL, 0)) { goto fail; } } else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", 4, context_D.transactionBufferPointer); - if (cx_hash_no_throw(&context_D.transactionHashFull + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", 4, context.transactionBufferPointer); + if (cx_hash_no_throw(&context.transactionHashFull .sha256.header, 0, - context_D.transactionBufferPointer, + context.transactionBufferPointer, 4, NULL, 0)) { goto fail; } @@ -689,29 +616,29 @@ void transaction_parse(unsigned char parseMode) { } transaction_offset_increase(4); // Move to next input - context_D.transactionContext + context.transactionContext .transactionRemainingInputsOutputs--; - context_D.transactionContext + context.transactionContext .transactionCurrentInputOutput++; - context_D.transactionContext.transactionState = + context.transactionContext.transactionState = TRANSACTION_DEFINED_WAIT_INPUT; continue; } // Save the last script byte for the P2SH check dataAvailable = - (context_D.transactionDataRemaining > - context_D.transactionContext + (context.transactionDataRemaining > + context.transactionContext .scriptRemaining - 1 - ? context_D.transactionContext + ? context.transactionContext .scriptRemaining - 1 - : context_D.transactionDataRemaining); + : context.transactionDataRemaining); if (dataAvailable == 0) { goto ok; } transaction_offset_increase(dataAvailable); - context_D.transactionContext.scriptRemaining -= + context.transactionContext.scriptRemaining -= dataAvailable; break; } @@ -719,46 +646,46 @@ void transaction_parse(unsigned char parseMode) { PRINTF("Input hashing done\n"); if (parseMode == PARSE_MODE_SIGNATURE) { // inputs have been prepared, stop the parsing here - if (context_D.usingSegwit && - !context_D.segwitParsedOnce) { + if (context.usingSegwit && + !context.segwitParsedOnce) { unsigned char hashedPrevouts[32]; unsigned char hashedSequence[32]; // Flush the cache - if (context_D.usingOverwinter) { - if (cx_hash_no_throw(&context_D.segwit.hash.hashPrevouts.blake2b.header, CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32)) { + if (context.usingOverwinter) { + if (cx_hash_no_throw(&context.segwit.hash.hashPrevouts.blake2b.header, CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32)) { goto fail; } - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, CX_LAST, hashedSequence, 0, hashedSequence, 32)) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, CX_LAST, hashedSequence, 0, hashedSequence, 32)) { goto fail; } } else { - if (cx_hash_no_throw(&context_D.segwit.hash.hashPrevouts + if (cx_hash_no_throw(&context.segwit.hash.hashPrevouts .sha256.header, CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32)) { goto fail; } if (cx_sha256_init_no_throw( - &context_D.segwit.hash.hashPrevouts.sha256)) { + &context.segwit.hash.hashPrevouts.sha256)) { goto fail; } - if (cx_hash_no_throw(&context_D.segwit.hash.hashPrevouts + if (cx_hash_no_throw(&context.segwit.hash.hashPrevouts .sha256.header, CX_LAST, hashedPrevouts, sizeof(hashedPrevouts), hashedPrevouts, 32)) { goto fail; } - if (cx_hash_no_throw(&context_D.transactionHashFull + if (cx_hash_no_throw(&context.transactionHashFull .sha256.header, CX_LAST, hashedSequence, 0, hashedSequence, 32)) { goto fail; } if (cx_sha256_init_no_throw( - &context_D.transactionHashFull.sha256)) { + &context.transactionHashFull.sha256)) { goto fail; } PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(hashedSequence), hashedSequence); - if (cx_hash_no_throw(&context_D.transactionHashFull + if (cx_hash_no_throw(&context.transactionHashFull .sha256.header, CX_LAST, hashedSequence, sizeof(hashedSequence), hashedSequence, 32)) { @@ -767,153 +694,139 @@ void transaction_parse(unsigned char parseMode) { } memmove( - context_D.segwit.cache.hashedPrevouts, + context.segwit.cache.hashedPrevouts, hashedPrevouts, sizeof(hashedPrevouts)); memmove( - context_D.segwit.cache.hashedSequence, + context.segwit.cache.hashedSequence, hashedSequence, sizeof(hashedSequence)); - PRINTF("hashPrevout\n%.*H\n",32,context_D.segwit.cache.hashedPrevouts); - PRINTF("hashSequence\n%.*H\n",32,context_D.segwit.cache.hashedSequence); + PRINTF("hashPrevout\n%.*H\n",32,context.segwit.cache.hashedPrevouts); + PRINTF("hashSequence\n%.*H\n",32,context.segwit.cache.hashedSequence); } - if (context_D.usingSegwit && - context_D.segwitParsedOnce) { - if (!context_D.usingOverwinter) { - PRINTF("SEGWIT hashedOutputs\n%.*H\n",sizeof(context_D.segwit.cache.hashedOutputs),context_D.segwit.cache.hashedOutputs); + if (context.usingSegwit && + context.segwitParsedOnce) { + if (!context.usingOverwinter) { + PRINTF("SEGWIT hashedOutputs\n%.*H\n",sizeof(context.segwit.cache.hashedOutputs),context.segwit.cache.hashedOutputs); if (cx_hash_no_throw( - &context_D.transactionHashFull.sha256.header, 0, - context_D.segwit.cache.hashedOutputs, - sizeof(context_D.segwit.cache + &context.transactionHashFull.sha256.header, 0, + context.segwit.cache.hashedOutputs, + sizeof(context.segwit.cache .hashedOutputs), NULL, 0)) { goto fail; } } - context_D.transactionContext + context.transactionContext .transactionState = TRANSACTION_SIGN_READY; } else { - context_D.transactionContext + context.transactionContext .transactionState = TRANSACTION_PRESIGN_READY; - if (context_D.usingOverwinter) { - if (cx_blake2b_init2_no_throw(&context_D.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_OUTPUTS, 16)) { + if (context.usingOverwinter) { + if (cx_blake2b_init2_no_throw(&context.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_OUTPUTS, 16)) { goto fail; } } else - if (context_D.usingSegwit) { - if (cx_sha256_init_no_throw(&context_D.transactionHashFull.sha256)) { + if (context.usingSegwit) { + if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { goto fail; } } } continue; } - if (context_D.transactionDataRemaining < 1) { + if (context.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } // Number of outputs - context_D.transactionContext + context.transactionContext .transactionRemainingInputsOutputs = transaction_get_varint(); - context_D.transactionContext + context.transactionContext .transactionCurrentInputOutput = 0; - PRINTF("Number of outputs : " DEBUG_LONG "\n", - context_D.transactionContext.transactionRemainingInputsOutputs); + PRINTF("Number of outputs : %d\n", + context.transactionContext.transactionRemainingInputsOutputs); // Ready to proceed - context_D.transactionContext.transactionState = + context.transactionContext.transactionState = TRANSACTION_DEFINED_WAIT_OUTPUT; __attribute__((fallthrough)); } case TRANSACTION_DEFINED_WAIT_OUTPUT: { - if (context_D.transactionContext + if (context.transactionContext .transactionRemainingInputsOutputs == 0) { // No more outputs to hash, move forward - context_D.transactionContext.transactionState = + context.transactionContext.transactionState = TRANSACTION_OUTPUT_HASHING_DONE; continue; } - if (context_D.transactionDataRemaining < 1) { + if (context.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } // Amount check_transaction_available(8); if ((parseMode == PARSE_MODE_TRUSTED_INPUT) && - (context_D.transactionContext + (context.transactionContext .transactionCurrentInputOutput == - context_D.transactionTargetInput)) { + context.transactionTargetInput)) { // Save the amount - memmove(context_D.transactionContext + memmove(context.transactionContext .transactionAmount, - context_D.transactionBufferPointer, + context.transactionBufferPointer, 8); - context_D.trustedInputProcessed = 1; + context.trustedInputProcessed = 1; } transaction_offset_increase(8); // Read the script length - context_D.transactionContext.scriptRemaining = + context.transactionContext.scriptRemaining = transaction_get_varint(); - PRINTF("Script to read " DEBUG_LONG "\n",context_D.transactionContext.scriptRemaining); + PRINTF("Script to read %d\n", context.transactionContext.scriptRemaining); // Move on - context_D.transactionContext.transactionState = + context.transactionContext.transactionState = TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; __attribute__((fallthrough)); } case TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { unsigned char dataAvailable; - PRINTF("Process output script, remaining " DEBUG_LONG "\n",context_D.transactionContext.scriptRemaining); - /* - // Special check if consuming a P2SH script - if (parseMode == PARSE_MODE_TRUSTED_INPUT) { - // Assume the full input script is sent in a single APDU, - then do the ghetto validation - if ((context_D.transactionBufferPointer[0] == - OP_HASH160) && - (context_D.transactionBufferPointer[context_D.transactionDataRemaining - - 1] == OP_EQUAL)) { - PRINTF("Marking P2SH output\n"); - context_D.transactionContext.consumeP2SH = 1; - } - } - */ - if (context_D.transactionDataRemaining < 1) { + PRINTF("Process output script, remaining %d\n", context.transactionContext.scriptRemaining); + if (context.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } - if (context_D.transactionContext.scriptRemaining == + if (context.transactionContext.scriptRemaining == 0) { // Move to next output - context_D.transactionContext + context.transactionContext .transactionRemainingInputsOutputs--; - context_D.transactionContext + context.transactionContext .transactionCurrentInputOutput++; - context_D.transactionContext.transactionState = + context.transactionContext.transactionState = TRANSACTION_DEFINED_WAIT_OUTPUT; continue; } dataAvailable = - (context_D.transactionDataRemaining > - context_D.transactionContext + (context.transactionDataRemaining > + context.transactionContext .scriptRemaining - ? context_D.transactionContext + ? context.transactionContext .scriptRemaining - : context_D.transactionDataRemaining); + : context.transactionDataRemaining); if (dataAvailable == 0) { goto ok; } transaction_offset_increase(dataAvailable); - context_D.transactionContext.scriptRemaining -= + context.transactionContext.scriptRemaining -= dataAvailable; break; } case TRANSACTION_OUTPUT_HASHING_DONE: { PRINTF("Output hashing done\n"); - if (context_D.transactionDataRemaining < 1) { + if (context.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } @@ -921,17 +834,17 @@ void transaction_parse(unsigned char parseMode) { check_transaction_available(4); transaction_offset_increase(4); - if (context_D.transactionDataRemaining == 0) { - context_D.transactionContext.transactionState = + if (context.transactionDataRemaining == 0) { + context.transactionContext.transactionState = TRANSACTION_PARSED; continue; } else { - context_D.transactionHashOption = 0; - context_D.transactionContext.scriptRemaining = + context.transactionHashOption = 0; + context.transactionContext.scriptRemaining = transaction_get_varint(); - context_D.transactionHashOption = + context.transactionHashOption = TRANSACTION_HASH_FULL; - context_D.transactionContext.transactionState = + context.transactionContext.transactionState = TRANSACTION_PROCESS_EXTRA; continue; } @@ -940,30 +853,30 @@ void transaction_parse(unsigned char parseMode) { case TRANSACTION_PROCESS_EXTRA: { unsigned char dataAvailable; - if (context_D.transactionContext.scriptRemaining == + if (context.transactionContext.scriptRemaining == 0) { - context_D.transactionContext.transactionState = + context.transactionContext.transactionState = TRANSACTION_PARSED; continue; } - if (context_D.transactionDataRemaining < 1) { + if (context.transactionDataRemaining < 1) { // No more data to read, ok goto ok; } dataAvailable = - (context_D.transactionDataRemaining > - context_D.transactionContext + (context.transactionDataRemaining > + context.transactionContext .scriptRemaining - ? context_D.transactionContext + ? context.transactionContext .scriptRemaining - : context_D.transactionDataRemaining); + : context.transactionDataRemaining); if (dataAvailable == 0) { goto ok; } transaction_offset_increase(dataAvailable); - context_D.transactionContext.scriptRemaining -= + context.transactionContext.scriptRemaining -= dataAvailable; break; } @@ -986,20 +899,8 @@ void transaction_parse(unsigned char parseMode) { } fail: - PRINTF("Transaction parse - fail\n"); - THROW(EXCEPTION); - ok : {} - } - CATCH_OTHER(e) { - PRINTF("Transaction parse - surprise fail\n"); - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - THROW(e); - } - // before the finally to restore the surrounding context if an exception - // is raised during finally - FINALLY { - } - } - END_TRY; + LEDGER_ASSERT(false, "Transaction parse - fail\n"); + ok: + return; + } diff --git a/include/btchip.h b/lib-app-bitcoin/transaction.h similarity index 67% rename from include/btchip.h rename to lib-app-bitcoin/transaction.h index f53e0e1d..fa88a83b 100644 --- a/include/btchip.h +++ b/lib-app-bitcoin/transaction.h @@ -15,22 +15,19 @@ * limitations under the License. ********************************************************************************/ -#ifndef H +#pragma once -#define H -#include "config.h" -#include "os.h" -#include "os_io_seproxyhal.h" +#define TRANSACTION_HASH_NONE 0x00 +#define TRANSACTION_HASH_FULL 0x01 +#define TRANSACTION_HASH_AUTHORIZATION 0x02 +#define TRANSACTION_HASH_BOTH 0x03 -#include "stdlib.h" -#include "stdbool.h" -#include "string.h" +#define PARSE_MODE_TRUSTED_INPUT 0x01 +#define PARSE_MODE_SIGNATURE 0x02 -#define L_DEBUG_NOPREFIX(x) +#define TRUSTED_INPUT_SIZE 48 +#define TRUSTED_INPUT_TOTAL_SIZE (TRUSTED_INPUT_SIZE + 8) -#define SW_TECHNICAL_DETAILS(x) SW_TECHNICAL_PROBLEM +void transaction_parse(unsigned char parseMode); -#include "secure_value.h" - -#endif diff --git a/src/display_variables.h b/lib-app-bitcoin/ui/display_variables.h similarity index 87% rename from src/display_variables.h rename to lib-app-bitcoin/ui/display_variables.h index c0ac6f8f..723009ab 100644 --- a/src/display_variables.h +++ b/lib-app-bitcoin/ui/display_variables.h @@ -1,7 +1,7 @@ -#ifndef _DISPLAY_VARIABLES_H_ -#define _DISPLAY_VARIABLES_H_ +#pragma once #include "os.h" + // A path contains 10 elements max, which max length in ascii is 1 whitespace + 10 char + optional quote "'" + "/" + \0" #define MAX_DERIV_PATH_ASCII_LENGTH 1 + 10*(10+2) + 1 #define MAX_CHAR_PER_LINE 25 @@ -26,8 +26,8 @@ union display_variables { // of char fullAddress[65]; // the address - char fullAmount[20]; // full amount - char feesAmount[20]; // fees + char fullAmount[28]; // full amount + char feesAmount[28]; // fees } tmp; struct { @@ -38,5 +38,3 @@ union display_variables { }; extern union display_variables vars; - -#endif diff --git a/src/bagl_extensions.h b/lib-app-bitcoin/ui/extensions.h similarity index 57% rename from src/bagl_extensions.h rename to lib-app-bitcoin/ui/extensions.h index c3029694..7aed64c9 100644 --- a/src/bagl_extensions.h +++ b/lib-app-bitcoin/ui/extensions.h @@ -15,44 +15,40 @@ * limitations under the License. ********************************************************************************/ -#ifndef _BAGL_H_ -#define _BAGL_H_ +#pragma once // btchip asking the per-output UI -unsigned int bagl_confirm_single_output(void); +unsigned int confirm_single_output(void); // btchip display token -void bagl_display_token(void); +void display_token(void); // btchip finalizing the transaction -unsigned int bagl_finalize_tx(void); +unsigned int finalize_tx(void); // UI response to btchip to finish the exchange -unsigned char bagl_user_action(unsigned char confirming); +unsigned char user_action(unsigned char confirming); // request the UI to redisplay the idle screen -void bagl_idle(void); +void idle(void); // btchip asking message signing confirmation -void bagl_confirm_message_signature(void); +void confirm_message_signature(void); // UI response to message signature -void bagl_user_action_message_signing(unsigned char confirming); +int user_action_message_signing(unsigned char confirming); // Public key display -uint8_t set_key_path_to_display(unsigned char* keyPath); -void bagl_display_public_key(uint8_t is_derivation_path_unusual); -void bagl_user_action_display(unsigned char confirming); +uint8_t set_key_path_to_display(const unsigned char* keyPath); +void display_public_key(uint8_t is_derivation_path_unusual); +int user_action_display(unsigned char confirming); -void bagl_request_pubkey_approval(void); -void bagl_request_change_path_approval(unsigned char* change_path); +void request_pubkey_approval(void); +void request_change_path_approval(unsigned char* change_path); // UI to confirm processing of tx with segwit inputs -void bagl_request_segwit_input_approval(void); +void request_segwit_input_approval(void); // UI to confirm signing path -void bagl_request_sign_path_approval(unsigned char *derivation_path); -void bagl_user_action_signtx(unsigned char confirming, unsigned char direct); - - -#endif /* _BAGL_H_ */ +void request_sign_path_approval(unsigned char* change_path); +int user_action_signtx(unsigned char confirming, unsigned char direct); diff --git a/lib-app-bitcoin/ui/main_ui.c b/lib-app-bitcoin/ui/main_ui.c new file mode 100644 index 00000000..5d2579bb --- /dev/null +++ b/lib-app-bitcoin/ui/main_ui.c @@ -0,0 +1,311 @@ +/******************************************************************************* +* Ledger App - Bitcoin Wallet +* (c) 2016-2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ +#include "os.h" +#include "cx.h" +#include "format.h" +#include "read.h" +#include "write.h" +#include "bip32.h" +#include "swap.h" +#include "string.h" + + +#include "context.h" +#include "helpers.h" +#include "customizable_helpers.h" +#include "customizable_ui.h" +#include "extensions.h" +#include "display_utils.h" +#include "ux.h" +#include "display_variables.h" +#include "swap_lib_calls.h" +#include "handle_swap_sign_transaction.h" +#include "handle_get_printable_amount.h" +#include "handle_check_address.h" +#include "ui.h" +#include "be_operations.h" + +#define OMNI_ASSETID 1 +#define MAIDSAFE_ASSETID 3 +#define USDT_ASSETID 31 + +static uint8_t check_fee_swap() { + unsigned char fees[8]; + unsigned char borrow; + + borrow = transaction_amount_sub_be( + fees, context.transactionContext.transactionAmount, + context.totalOutputAmount); + if ((borrow != 0) || (memcmp(fees, vars.swap_data.fees, 8) != 0)) + return 0; + context.transactionContext.firstSigned = 0; + + if (context.usingSegwit && !context.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context.transactionContext.transactionState = + TRANSACTION_NONE; + } else { + context.transactionContext.transactionState = + TRANSACTION_SIGN_READY; + } + context.sw = 0x9000; + context.outLength = 0; + G_io_apdu_buffer[context.outLength++] = 0x90; + G_io_apdu_buffer[context.outLength++] = 0x00; + + return 1; +} + +#define OMNI_ASSETID 1 +#define MAIDSAFE_ASSETID 3 +#define USDT_ASSETID 31 + +static void prepare_single_output(void) { + // TODO : special display for OP_RETURN + unsigned char amount[8]; + unsigned int offset = 0; + char tmp[80] = {0}; + + swap_bytes(amount, context.currentOutput + offset, 8); + offset += 8; + + get_address_from_output_script(context.currentOutput + offset, sizeof(context.currentOutput) - offset, tmp, sizeof(tmp)); + strncpy(vars.tmp.fullAddress, tmp, sizeof(vars.tmp.fullAddress) - 1); + + // Prepare amount + + // Handle Omni simple send + if ((context.currentOutput[offset + 2] == 0x14) && + (memcmp(context.currentOutput + offset + 3, "omni", 4) == 0) && + (memcmp(context.currentOutput + offset + 3 + 4, "\0\0\0\0", 4) == 0)) { + uint32_t omniAssetId = read_u32_be(context.currentOutput, offset + 3 + 4 + 4); + switch(omniAssetId) { + case OMNI_ASSETID: + strcpy(vars.tmp.fullAmount, "OMNI "); + break; + case USDT_ASSETID: + strcpy(vars.tmp.fullAmount, "USDT "); + break; + case MAIDSAFE_ASSETID: + strcpy(vars.tmp.fullAmount, "MAID "); + break; + default: + snprintf(vars.tmp.fullAmount, sizeof(vars.tmp.fullAmount), "OMNI asset %d ", omniAssetId); + break; + } + format_sats_amount(vars.tmp.fullAmount, + (uint64_t) read_u64_be(context.currentOutput, offset + 3 + 4 + 4 + 4), // Cast prevents weird compilo bug + vars.tmp.fullAmount); + } + else { + format_sats_amount(COIN_COINID_SHORT, + (uint64_t)read_u64_be(amount, 0), // Cast prevents weird compilo bug + vars.tmp.fullAmount); + } +} + +static uint8_t prepare_message_signature(void) { + uint8_t buffer[32]; + + if (cx_hash_no_throw(&context.transactionHashAuthorization.header, CX_LAST, + (uint8_t*)vars.tmp.fullAmount, 0, buffer, 32)) { + return 0; + } + + format_hex((const uint8_t*) buffer, sizeof(buffer), vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress)); + + return 1; +} + + +extern int handle_output_state(unsigned int* processed); +extern void hash_input_finalize_full_reset(void); + +// Analog of confirm_single_output to work +// in silent mode, when called from SWAP app +unsigned int silent_confirm_single_output() { + char tmp[80] = {0}; + unsigned char amount[8]; + while (true) { + // in swap operation we can only have 1 "external" output + if (vars.swap_data.was_address_checked) { + PRINTF("Address was already checked\n"); + return 0; + } + vars.swap_data.was_address_checked = 1; + // check amount + swap_bytes(amount, context.currentOutput, 8); + if (memcmp(amount, vars.swap_data.amount, 8) != 0) { + PRINTF("Amount not matched\n"); + return 0; + } + get_address_from_output_script(context.currentOutput + 8, sizeof(context.currentOutput) - 8, tmp, sizeof(tmp)); + if (strcmp(tmp, vars.swap_data.destination_address) != 0) { + PRINTF("Address not matched\n"); + return 0; + } + + // Check if all inputs have been confirmed + + if (context.outputParsingState == + OUTPUT_PARSING_OUTPUT) { + context.remainingOutputs--; + if (context.remainingOutputs == 0) + break; + } + + memmove(context.currentOutput, + context.currentOutput + + context.discardSize, + context.currentOutputOffset - + context.discardSize); + context.currentOutputOffset -= context.discardSize; + unsigned int processed = true; + while (processed == 1) { + if (handle_output_state(&processed)) { + PRINTF("Error in handle output state \n"); + return 0; + } + } + + if (processed != 2) { + // Out of data to process, wait for the next call + break; + } + } + + if ((context.outputParsingState == OUTPUT_PARSING_OUTPUT) && + (context.remainingOutputs == 0)) { + context.outputParsingState = OUTPUT_FINALIZE_TX; + // check fees + unsigned char fees[8]; + + if ((transaction_amount_sub_be(fees, + context.transactionContext.transactionAmount, + context.totalOutputAmount) != 0) || + (memcmp(fees, vars.swap_data.fees, 8) != 0)) { + PRINTF("Fees is not matched\n"); + return 0; + } + } + + if (context.outputParsingState == OUTPUT_FINALIZE_TX) { + context.transactionContext.firstSigned = 0; + + if (context.usingSegwit && + !context.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context.transactionContext.transactionState = + TRANSACTION_NONE; + } else { + context.transactionContext.transactionState = + TRANSACTION_SIGN_READY; + } + } + if (context.outputParsingState == OUTPUT_FINALIZE_TX) { + // we've finished the processing of the input + hash_input_finalize_full_reset(); + } + + return 1; +} + +unsigned int confirm_single_output(void) { + if (G_called_from_swap) { + if (silent_confirm_single_output()) { + return 2; + } + return 0; + } + prepare_single_output(); + + ui_confirm_single_flow(); + return 1; +} + +unsigned int finalize_tx(void) { + if (G_called_from_swap) { + if (check_fee_swap()) { + return 2; + } + } + + if (!prepare_fees()) { + return 0; + } + + ui_finalize_flow(); + return 1; +} + +void confirm_message_signature(void) { + if (!prepare_message_signature()) { + return; + } + + ui_sign_message_flow(); +} + +uint8_t set_key_path_to_display(const unsigned char* keyPath) { + format_path(keyPath, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); + return bip44_derivation_guard(keyPath, false); +} + +void display_public_key(uint8_t is_derivation_path_unusual) { + // append a white space at the end of the address to avoid glitch on nano S + strlcat((char *)G_io_apdu_buffer + 200, " ", sizeof(G_io_apdu_buffer) - 200); + + if (is_derivation_path_unusual) { + ui_display_public_with_warning_flow(); + } + else { + ui_display_public_flow(); + } +} + +void display_token(void) +{ + ui_display_token_flow(); +} + +void request_pubkey_approval(void) +{ + ui_request_pubkey_approval_flow(); +} + +void request_change_path_approval(unsigned char* change_path) +{ + format_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); + ui_request_change_path_approval_flow(); +} + +void request_sign_path_approval(unsigned char* change_path) +{ + format_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); + ui_request_sign_path_approval_flow(); +} + +void request_segwit_input_approval(void) +{ + ui_request_segwit_input_approval_flow(); +} + + diff --git a/src/ui.h b/lib-app-bitcoin/ui/ui.h similarity index 100% rename from src/ui.h rename to lib-app-bitcoin/ui/ui.h diff --git a/src/ui_bagl.c b/lib-app-bitcoin/ui/ui_bagl.c similarity index 97% rename from src/ui_bagl.c rename to lib-app-bitcoin/ui/ui_bagl.c index 6c4ee66e..9a60828b 100644 --- a/src/ui_bagl.c +++ b/lib-app-bitcoin/ui/ui_bagl.c @@ -18,17 +18,18 @@ #ifdef HAVE_BAGL ////////////////////////////////////////////////////////////////////// #include "display_variables.h" -#include "internal.h" +#include "transaction.h" +#include "context.h" #include "ui.h" -#include "bagl_extensions.h" +#include "extensions.h" bagl_element_t tmp_element; static unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { UNUSED(e); // user denied the transaction, tell the USB side - if (!bagl_user_action(0)) { + if (!user_action(0)) { // redraw ui ui_idle_flow(); } @@ -38,7 +39,7 @@ static unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { static unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e) { UNUSED(e); // user accepted the transaction, tell the USB side - if (!bagl_user_action(1)) { + if (!user_action(1)) { // redraw ui ui_idle_flow(); } @@ -49,7 +50,7 @@ static unsigned int io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e) { UNUSED(e); // user denied the transaction, tell the USB side - bagl_user_action_message_signing(0); + user_action_message_signing(0); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -59,7 +60,7 @@ static unsigned int io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { UNUSED(e); // user accepted the transaction, tell the USB side - bagl_user_action_message_signing(1); + user_action_message_signing(1); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -69,7 +70,7 @@ static unsigned int io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { UNUSED(e); // user denied the transaction, tell the USB side - bagl_user_action_display(0); + user_action_display(0); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -78,16 +79,15 @@ io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { static unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { UNUSED(e); // user accepted the transaction, tell the USB side - bagl_user_action_display(1); // redraw ui ui_idle_flow(); - return 0; // DO NOT REDRAW THE BUTTON + return user_action_display(1); } static unsigned int io_seproxyhal_touch_sign_cancel(const bagl_element_t *e) { UNUSED(e); // user denied the transaction, tell the USB side - bagl_user_action_signtx(0, 0); + user_action_signtx(0, 0); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -96,7 +96,7 @@ static unsigned int io_seproxyhal_touch_sign_cancel(const bagl_element_t *e) { static unsigned int io_seproxyhal_touch_sign_ok(const bagl_element_t *e) { UNUSED(e); // user accepted the transaction, tell the USB side - bagl_user_action_signtx(1, 0); + user_action_signtx(1, 0); // redraw ui ui_idle_flow(); return 0; // DO NOT REDRAW THE BUTTON @@ -107,8 +107,7 @@ void io_seproxyhal_display(const bagl_element_t *element) { io_seproxyhal_display_default((bagl_element_t *)element); } } - -////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////// UX_STEP_NOCB(ux_idle_flow_1_step, nn, { "Application", @@ -390,7 +389,7 @@ void ui_sign_message_flow(void) { ux_flow_init(0, ux_sign_flow, NULL); } void ui_confirm_single_flow(void) { snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "output #%d", - context_D.totalOutputs - context_D.remainingOutputs + + context.totalOutputs - context.remainingOutputs + 1); ux_flow_init(0, ux_confirm_single_flow, NULL); } diff --git a/src/ui_menu_nbgl.c b/lib-app-bitcoin/ui/ui_menu_nbgl.c similarity index 97% rename from src/ui_menu_nbgl.c rename to lib-app-bitcoin/ui/ui_menu_nbgl.c index 20b865e6..de876fc7 100644 --- a/src/ui_menu_nbgl.c +++ b/lib-app-bitcoin/ui/ui_menu_nbgl.c @@ -17,10 +17,9 @@ #ifdef HAVE_NBGL #include "display_variables.h" -#include "internal.h" #include "ui.h" -#include "bagl_extensions.h" +#include "extensions.h" #include "nbgl_use_case.h" #define NB_INFO_FIELDS 2 diff --git a/src/ui_nbgl.c b/lib-app-bitcoin/ui/ui_nbgl.c similarity index 96% rename from src/ui_nbgl.c rename to lib-app-bitcoin/ui/ui_nbgl.c index ee41f795..8876b6bd 100644 --- a/src/ui_nbgl.c +++ b/lib-app-bitcoin/ui/ui_nbgl.c @@ -19,9 +19,9 @@ #include "ui.h" #include "nbgl_use_case.h" #include "display_variables.h" -#include "internal.h" +#include "context.h" -#include "bagl_extensions.h" +#include "extensions.h" typedef enum { MESSAGE_TYPE, @@ -55,55 +55,55 @@ static UiContext_t uiContext = {.transaction_prompt_done = 0}; // User action callbacks static void approved_user_action_callback(void) { - if (!bagl_user_action(1)) { + if (!user_action(1)) { ui_idle_flow(); } } static void approved_user_action_processing_callback(void) { - if (!bagl_user_action(1)) { + if (!user_action(1)) { nbgl_useCaseSpinner("Processing"); } } static void abandon_user_action_callback(void) { - if (!bagl_user_action(0)) { + if (!user_action(0)) { ui_idle_flow(); } } static void approved_user_action_message_signing_callback(void) { - bagl_user_action_message_signing(1); + user_action_message_signing(1); ui_idle_flow(); } static void abandon_user_action_message_signing_callback(void) { - bagl_user_action_message_signing(0); + user_action_message_signing(0); ui_idle_flow(); } static void approved_user_action_display_processing_callback(void) { - bagl_user_action_display(1); + user_action_display(1); nbgl_useCaseSpinner("Processing"); } static void approved_user_action_display_callback(void) { - bagl_user_action_display(1); + user_action_display(1); ui_idle_flow(); } static void abandon_user_action_display_callback(void) { - bagl_user_action_display(0); + user_action_display(0); ui_idle_flow(); } static void approved_user_action_signtx_callback(void) { - bagl_user_action_signtx(1, 0); + user_action_signtx(1, 0); ui_idle_flow(); } static void abandon_user_action_signtx_callback(void) { - bagl_user_action_signtx(0, 0); + user_action_signtx(0, 0); ui_idle_flow(); } @@ -310,7 +310,7 @@ void ui_confirm_single_flow(void) { ui_transaction_start(ui_confirm_single_flow); } else { snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "#%d", - context_D.totalOutputs - context_D.remainingOutputs + + context.totalOutputs - context.remainingOutputs + 1); uiContext.tagValues[0].item = "Output"; @@ -479,7 +479,7 @@ static void prompt_public_key(bool warning) { } } -static void display_public_key(bool warning) { +static void display_show_public_key(bool warning) { uiContext.abandon_status = "Address verification\ncancelled"; uiContext.approved_status = "ADDRESS\nVERIFIED"; uiContext.prompt_cancel_message = "Reject\nAddress?"; @@ -507,11 +507,11 @@ static void display_public_key(bool warning) { } void ui_display_public_with_warning_flow(void) { - display_public_key(true); + display_show_public_key(true); } void ui_display_public_flow(void) { - display_public_key(false); + display_show_public_key(false); } void ui_transaction_finish(void) { diff --git a/lib-app-bitcoin/utils/be_operations.c b/lib-app-bitcoin/utils/be_operations.c new file mode 100644 index 00000000..43c916e3 --- /dev/null +++ b/lib-app-bitcoin/utils/be_operations.c @@ -0,0 +1,42 @@ +#include "be_operations.h" + +unsigned char transaction_amount_add_be(unsigned char *target, + unsigned char *a, + unsigned char *b) { + unsigned char carry = 0; + unsigned char i; + for (i = 0; i < 8; i++) { + unsigned short val = a[8 - 1 - i] + b[8 - 1 - i] + (carry ? 1 : 0); + carry = (val > 255); + target[8 - 1 - i] = (val & 255); + } + return carry; +} + +unsigned char transaction_amount_sub_be(unsigned char *target, + unsigned char *a, + unsigned char *b) { + unsigned char borrow = 0; + unsigned char i; + for (i = 0; i < 8; i++) { + unsigned short tmpA = a[8 - 1 - i]; + unsigned short tmpB = b[8 - 1 - i]; + if (borrow) { + if (tmpA <= tmpB) { + tmpA += (255 + 1) - 1; + } else { + borrow = 0; + tmpA--; + } + } + if (tmpA < tmpB) { + borrow = 1; + tmpA += 255 + 1; + } + target[8 - 1 - i] = (unsigned char)(tmpA - tmpB); + } + + return borrow; +} + + diff --git a/src/transaction.h b/lib-app-bitcoin/utils/be_operations.h similarity index 71% rename from src/transaction.h rename to lib-app-bitcoin/utils/be_operations.h index 01b50048..8dc7a9a2 100644 --- a/src/transaction.h +++ b/lib-app-bitcoin/utils/be_operations.h @@ -15,23 +15,7 @@ * limitations under the License. ********************************************************************************/ -#ifndef _TRANSACTION_H_ -#define _TRANSACTION_H_ - -#include "secure_value.h" - -#define TRANSACTION_HASH_NONE 0x00 -#define TRANSACTION_HASH_FULL 0x01 -#define TRANSACTION_HASH_AUTHORIZATION 0x02 -#define TRANSACTION_HASH_BOTH 0x03 - -#define PARSE_MODE_TRUSTED_INPUT 0x01 -#define PARSE_MODE_SIGNATURE 0x02 - -#define TRUSTED_INPUT_SIZE 48 -#define TRUSTED_INPUT_TOTAL_SIZE (TRUSTED_INPUT_SIZE + 8) - -void transaction_parse(unsigned char parseMode); +#pragma once // target = a + b unsigned char transaction_amount_add_be(unsigned char *target, @@ -42,5 +26,3 @@ unsigned char transaction_amount_add_be(unsigned char *target, unsigned char transaction_amount_sub_be(unsigned char *target, unsigned char *a, unsigned char *b); - -#endif /* _TRANSACTION_H_ */ diff --git a/src/cashaddr.c b/lib-app-bitcoin/utils/cashaddr.c similarity index 100% rename from src/cashaddr.c rename to lib-app-bitcoin/utils/cashaddr.c diff --git a/src/cashaddr.h b/lib-app-bitcoin/utils/cashaddr.h similarity index 98% rename from src/cashaddr.h rename to lib-app-bitcoin/utils/cashaddr.h index 16d277d6..9eeb4bd4 100644 --- a/src/cashaddr.h +++ b/lib-app-bitcoin/utils/cashaddr.h @@ -24,6 +24,7 @@ #define _CASHADDR_H_ #include +#include #define CASHADDR_P2PKH 0 #define CASHADDR_P2SH 1 diff --git a/src/segwit_addr.c b/lib-app-bitcoin/utils/segwit_addr.c similarity index 100% rename from src/segwit_addr.c rename to lib-app-bitcoin/utils/segwit_addr.c diff --git a/src/segwit_addr.h b/lib-app-bitcoin/utils/segwit_addr.h similarity index 100% rename from src/segwit_addr.h rename to lib-app-bitcoin/utils/segwit_addr.h diff --git a/src/apdu_get_wallet_public_key.h b/src/apdu_get_wallet_public_key.h deleted file mode 100644 index 429076d6..00000000 --- a/src/apdu_get_wallet_public_key.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _APDU_GET_WALLET_PUBLIC_KEY_H_ -#define _APDU_GET_WALLET_PUBLIC_KEY_H_ - -#define P1_NO_DISPLAY 0x00 -#define P1_DISPLAY 0x01 -#define P1_REQUEST_TOKEN 0x02 - -#define P2_LEGACY 0x00 -#define P2_SEGWIT 0x01 -#define P2_NATIVE_SEGWIT 0x02 -#define P2_CASHADDR 0x03 - -#endif //_APDU_GET_WALLET_PUBLIC_KEY_H_ \ No newline at end of file diff --git a/src/apdu_hash_input_finalize_full.c b/src/apdu_hash_input_finalize_full.c deleted file mode 100644 index 3e69d334..00000000 --- a/src/apdu_hash_input_finalize_full.c +++ /dev/null @@ -1,647 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -// TODO Trustlet, BAGL : process each output separately. -// review nvm_write policy - -#include "internal.h" -#include "apdu_constants.h" -#include "bagl_extensions.h" -#include "ui.h" -#include "lib_standard_app/crypto_helpers.h" -#include "lib_standard_app/read.h" -#include "swap.h" - -#define FINALIZE_P1_MORE 0x00 -#define FINALIZE_P1_LAST 0x80 -#define FINALIZE_P1_CHANGEINFO 0xFF - -#define FINALIZE_P2_DEFAULT 0x00 - -#define FLAG_SIGNATURE 0x01 -#define FLAG_CHANGE_VALIDATED 0x80 - -void apdu_hash_input_finalize_full_reset(void) { - context_D.currentOutputOffset = 0; - context_D.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; - memset(context_D.totalOutputAmount, 0, - sizeof(context_D.totalOutputAmount)); - context_D.changeOutputFound = 0; -} - -static bool check_output_displayable() { - bool displayable = true; - unsigned char amount[8], isOpReturn, isP2sh, isNativeSegwit, j, - nullAmount = 1; - unsigned char isOpCreate, isOpCall; - - for (j = 0; j < 8; j++) { - if (context_D.currentOutput[j] != 0) { - nullAmount = 0; - break; - } - } - if (!nullAmount) { - swap_bytes(amount, context_D.currentOutput, 8); - transaction_amount_add_be(context_D.totalOutputAmount, - context_D.totalOutputAmount, amount); - } - isOpReturn = - output_script_is_op_return(context_D.currentOutput + 8); - isP2sh = output_script_is_p2sh(context_D.currentOutput + 8); - isNativeSegwit = output_script_is_native_witness( - context_D.currentOutput + 8); - isOpCreate = - output_script_is_op_create(context_D.currentOutput + 8, - sizeof(context_D.currentOutput) - 8); - isOpCall = - output_script_is_op_call(context_D.currentOutput + 8, - sizeof(context_D.currentOutput) - 8); - if (((COIN_KIND == COIN_KIND_HYDRA) && - !output_script_is_regular(context_D.currentOutput + 8) && - !isP2sh && !(nullAmount && isOpReturn) && !isOpCreate && !isOpCall) || - (!(COIN_KIND == COIN_KIND_HYDRA) && - !output_script_is_regular(context_D.currentOutput + 8) && - !isP2sh && !(nullAmount && isOpReturn))) { - PRINTF("Error : Unrecognized output script"); - THROW(EXCEPTION); - } - if (context_D.tmpCtx.output.changeInitialized && !isOpReturn) { - bool changeFound = false; - unsigned char addressOffset = - (isNativeSegwit ? OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET - : isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH - : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); - if (!isP2sh && - memcmp(context_D.currentOutput + 8 + addressOffset, - context_D.tmpCtx.output.changeAddress, - 20) == 0) { - changeFound = true; - } else if (isP2sh && context_D.usingSegwit) { - unsigned char changeSegwit[22]; - changeSegwit[0] = 0x00; - changeSegwit[1] = 0x14; - memmove(changeSegwit + 2, - context_D.tmpCtx.output.changeAddress, 20); - public_key_hash160(changeSegwit, 22, changeSegwit); - if (memcmp(context_D.currentOutput + 8 + addressOffset, - changeSegwit, 20) == 0) { - if (COIN_FLAGS & FLAG_SEGWIT_CHANGE_SUPPORT) { - changeFound = true; - } else { - // Attempt to avoid fatal failures on Bitcoin Cash - PRINTF("Error : Non spendable Segwit change"); - THROW(EXCEPTION); - } - } - } - if (changeFound) { - if (context_D.changeOutputFound) { - PRINTF("Error : Multiple change output found"); - THROW(EXCEPTION); - } - context_D.changeOutputFound = true; - displayable = false; - } - } - - return displayable; -} - -bool handle_output_state() { - uint32_t discardSize = 0; - context_D.discardSize = 0; - bool processed = false; - switch (context_D.outputParsingState) { - case OUTPUT_PARSING_NUMBER_OUTPUTS: { - context_D.totalOutputs = 0; - if (context_D.currentOutputOffset < 1) { - break; - } - if (context_D.currentOutput[0] < 0xFD) { - context_D.totalOutputs = context_D.remainingOutputs = - context_D.currentOutput[0]; - discardSize = 1; - context_D.outputParsingState = OUTPUT_PARSING_OUTPUT; - processed = true; - break; - } - if (context_D.currentOutput[0] == 0xFD) { - if (context_D.currentOutputOffset < 3) { - break; - } - context_D.totalOutputs = context_D.remainingOutputs = - (context_D.currentOutput[2] << 8) | - context_D.currentOutput[1]; - discardSize = 3; - context_D.outputParsingState = OUTPUT_PARSING_OUTPUT; - processed = true; - break; - } else if (context_D.currentOutput[0] == 0xFE) { - if (context_D.currentOutputOffset < 5) { - break; - } - context_D.totalOutputs = context_D.remainingOutputs = - read_u32_le(context_D.currentOutput, 1); - discardSize = 5; - context_D.outputParsingState = OUTPUT_PARSING_OUTPUT; - processed = true; - break; - } else { - THROW(EXCEPTION); - } - } break; - - case OUTPUT_PARSING_OUTPUT: { - unsigned int scriptSize; - if (context_D.currentOutputOffset < 9) { - break; - } - if (context_D.currentOutput[8] < 0xFD) { - scriptSize = context_D.currentOutput[8]; - discardSize = 1; - } else if (context_D.currentOutput[8] == 0xFD) { - if (context_D.currentOutputOffset < 9 + 2) { - break; - } - scriptSize = read_u32_le(context_D.currentOutput, 9); - discardSize = 3; - } else { - // Unrealistically large script - THROW(EXCEPTION); - } - if (context_D.currentOutputOffset < - 8 + discardSize + scriptSize) { - discardSize = 0; - break; - } - - processed = true; - - discardSize += 8 + scriptSize; - - if (check_output_displayable()) { - context_D.io_flags |= IO_ASYNCH_REPLY; - - // The output can be processed by the UI - - context_D.discardSize = discardSize; - discardSize = 0; - } else { - context_D.remainingOutputs--; - } - } break; - - default: - THROW(EXCEPTION); - } - - if (discardSize != 0) { - memmove(context_D.currentOutput, - context_D.currentOutput + discardSize, - context_D.currentOutputOffset - discardSize); - context_D.currentOutputOffset -= discardSize; - } - - return processed; -} - -// out should be 32 bytes, even only 20 bytes is significant for output -int get_pubkey_hash160(unsigned char* keyPath, size_t keyPath_len, unsigned char* out) { - cx_ecfp_public_key_t public_key; - int keyLength; - if (get_public_key(keyPath, keyPath_len, public_key.W, NULL)) { - return -1; - } - - compress_public_key_value(public_key.W); - keyLength = 33; - - public_key_hash160( - public_key.W, // IN - keyLength, // INLEN - out // OUT - ); - return 0; -} - -unsigned short apdu_hash_input_finalize_full_internal( - transaction_summary_t *transactionSummary) { - unsigned char authorizationHash[32]; - unsigned char apduLength; - unsigned short sw = SW_OK; - unsigned char *target = G_io_apdu_buffer; - unsigned char p1 = G_io_apdu_buffer[ISO_OFFSET_P1]; - unsigned char hashOffset = 0; - - apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - - if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && - (p1 != FINALIZE_P1_CHANGEINFO)) { - return SW_INCORRECT_P1_P2; - } - - // See if there is a hashing offset - if (context_D.usingSegwit && - (context_D.tmpCtx.output.multipleOutput == 0)) { - unsigned char firstByte = G_io_apdu_buffer[ISO_OFFSET_CDATA]; - if (firstByte < 0xfd) { - hashOffset = 1; - } else if (firstByte == 0xfd) { - hashOffset = 3; - } else if (firstByte == 0xfe) { - hashOffset = 5; - } - } - - // Check state - if (context_D.transactionContext.transactionState != - TRANSACTION_PRESIGN_READY) { - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - - if (p1 == FINALIZE_P1_CHANGEINFO) { - if (!context_D.transactionContext.firstSigned) { - // Already validated, should be prevented on the client side -return_OK: - return SW_OK; - } - if (!context_D.tmpCtx.output.changeAccepted) { - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - memset(transactionSummary, 0, - sizeof(transaction_summary_t)); - if (G_io_apdu_buffer[ISO_OFFSET_CDATA] == 0x00) { - // Called with no change path, abort, should be prevented on - // the client side - goto return_OK; - } - memmove(transactionSummary->keyPath, - G_io_apdu_buffer + ISO_OFFSET_CDATA, - MAX_BIP32_PATH_LENGTH); - - if (get_pubkey_hash160(transactionSummary->keyPath, sizeof(transactionSummary->keyPath), context_D.tmpCtx.output.changeAddress)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - PRINTF("Change address = %.*H\n", 20, context_D.tmpCtx.output.changeAddress); - - context_D.tmpCtx.output.changeInitialized = 1; - context_D.tmpCtx.output.changeAccepted = 0; - - // if the bip44 change path provided is not canonical or its index are unsual, ask for user approval - if(bip44_derivation_guard(transactionSummary->keyPath, true)) { - if (G_called_from_swap) { - PRINTF("In swap mode only standart path is allowed\n"); - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - context_D.io_flags |= IO_ASYNCH_REPLY; - context_D.outputParsingState = BIP44_CHANGE_PATH_VALIDATION; - bagl_request_change_path_approval(transactionSummary->keyPath); - } - - goto return_OK; - } - - // Always update the transaction & authorization hashes with the - // given data - // For SegWit, this has been reset to hold hashOutputs - if (!context_D.segwitParsedOnce) { - if ((int)(apduLength - hashOffset) < 0) { - sw = SW_INCORRECT_DATA; - goto discardTransaction; - } - if (context_D.usingOverwinter) { - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, 0, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, apduLength - hashOffset, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - } - else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", apduLength - hashOffset, G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset); - if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, - G_io_apdu_buffer + ISO_OFFSET_CDATA + hashOffset, - apduLength - hashOffset, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - } - } - - if (context_D.transactionContext.firstSigned) { - if ((context_D.currentOutputOffset + apduLength) > - sizeof(context_D.currentOutput)) { - PRINTF("Output is too long to be checked\n"); - sw = SW_INCORRECT_DATA; - goto discardTransaction; - } - memmove(context_D.currentOutput + - context_D.currentOutputOffset, - G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength); - context_D.currentOutputOffset += apduLength; - - while (handle_output_state() && - (!(context_D.io_flags & IO_ASYNCH_REPLY))) - ; - - // Finalize the TX if necessary - - if ((context_D.remainingOutputs == 0) && - (!(context_D.io_flags & IO_ASYNCH_REPLY))) { - context_D.io_flags |= IO_ASYNCH_REPLY; - context_D.outputParsingState = - OUTPUT_FINALIZE_TX; - } - } - - if (G_io_apdu_buffer[ISO_OFFSET_P1] == FINALIZE_P1_MORE) { - if (!context_D.usingSegwit) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", apduLength, G_io_apdu_buffer + ISO_OFFSET_CDATA); - if (cx_hash_no_throw( - &context_D.transactionHashAuthorization.header, - 0, G_io_apdu_buffer + ISO_OFFSET_CDATA, apduLength, - NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - } - G_io_apdu_buffer[0] = 0x00; - context_D.outLength = 1; - context_D.tmpCtx.output.multipleOutput = 1; - goto return_OK; - } - - if (!context_D.usingSegwit) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", apduLength, G_io_apdu_buffer + ISO_OFFSET_CDATA); - if (cx_hash_no_throw(&context_D.transactionHashAuthorization.header, - CX_LAST, G_io_apdu_buffer + ISO_OFFSET_CDATA, - apduLength, authorizationHash, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - } - - if (context_D.usingSegwit) { - if (!context_D.segwitParsedOnce) { - if (context_D.usingOverwinter) { - if (cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, CX_LAST, context_D.segwit.cache.hashedOutputs, 0, context_D.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - } - else { - if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, - CX_LAST, - context_D.segwit.cache.hashedOutputs, 0, - context_D.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - if (cx_sha256_init_no_throw(&context_D.transactionHashFull.sha256)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, - CX_LAST, - context_D.segwit.cache.hashedOutputs, - sizeof(context_D.segwit.cache.hashedOutputs), - context_D.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - } - PRINTF("hashOutputs\n%.*H\n",32,context_D.segwit.cache.hashedOutputs); - if (cx_hash_no_throw( - &context_D.transactionHashAuthorization.header, - CX_LAST, G_io_apdu_buffer, 0, authorizationHash, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); - } else { - if (cx_hash_no_throw( - &context_D.transactionHashAuthorization.header, - CX_LAST, - (unsigned char *)&context_D.segwit.cache, - sizeof(context_D.segwit.cache), - authorizationHash, 32)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discardTransaction; - } - PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); - } - } - - if (context_D.transactionContext.firstSigned) { - if (!context_D.tmpCtx.output.changeInitialized) { - memset(transactionSummary, 0, - sizeof(transaction_summary_t)); - } - - transactionSummary->payToAddressVersion = COIN_P2PKH_VERSION; - transactionSummary->payToScriptHashVersion = COIN_P2SH_VERSION; - - // Generate new nonce - - cx_rng(transactionSummary->transactionNonce, 8); - } - - G_io_apdu_buffer[0] = 0x00; - target++; - - *target = 0x00; - target++; - - context_D.outLength = (target - G_io_apdu_buffer); - - // Check that the input being signed is part of the same - // transaction, otherwise abort - // (this is done to keep the transaction counter limit per session - // synchronized) - if (context_D.transactionContext.firstSigned) { - memmove(transactionSummary->authorizationHash, - authorizationHash, - sizeof(transactionSummary->authorizationHash)); - goto return_OK; - } else { - if (os_secure_memcmp( - authorizationHash, - transactionSummary->authorizationHash, - sizeof(transactionSummary->authorizationHash))) { - PRINTF("Authorization hash not matching, aborting\n"); - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - - if (context_D.usingSegwit && - !context_D.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context_D.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - } else { - context_D.transactionContext.transactionState = - TRANSACTION_SIGN_READY; - } - sw = SW_OK; - } - apdu_hash_input_finalize_full_reset(); - return sw; - -discardTransaction: - apdu_hash_input_finalize_full_reset(); - ui_transaction_error(); - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - context_D.outLength = 0; - - memmove(G_io_apdu_buffer, context_D.currentOutput, - context_D.currentOutputOffset); - context_D.outLength = context_D.currentOutputOffset; - return sw; -} - -unsigned short apdu_hash_input_finalize_full() { - PRINTF("state=%d\n", context_D.outputParsingState); - unsigned short sw = apdu_hash_input_finalize_full_internal( - &context_D.transactionSummary); - if (context_D.io_flags & IO_ASYNCH_REPLY) { - // if the UI reject the processing of the request, then reply - // immediately - bool status; - if(context_D.outputParsingState == BIP44_CHANGE_PATH_VALIDATION) { - context_D.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; - return sw; - } - else if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { - status = bagl_finalize_tx(); - } - else { - status = bagl_confirm_single_output(); - } - if (!status) { - ui_transaction_error(); - context_D.io_flags &= ~IO_ASYNCH_REPLY; - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - context_D.outLength = 0; - sw = SW_INCORRECT_DATA; - } - } - return sw; -} - -unsigned char bagl_user_action(unsigned char confirming) { - unsigned short sw = SW_OK; - - // confirm and finish the apdu exchange //spaghetti - - if (confirming) { - // Check if all inputs have been confirmed - - if (context_D.outputParsingState == - OUTPUT_PARSING_OUTPUT) { - context_D.remainingOutputs--; - } - - while (context_D.remainingOutputs != 0) { - memmove(context_D.currentOutput, - context_D.currentOutput + - context_D.discardSize, - context_D.currentOutputOffset - - context_D.discardSize); - context_D.currentOutputOffset -= - context_D.discardSize; - context_D.io_flags &= ~IO_ASYNCH_REPLY; - while (handle_output_state() && - (!(context_D.io_flags & IO_ASYNCH_REPLY))) - ; - if (context_D.io_flags & IO_ASYNCH_REPLY) { - if (!bagl_confirm_single_output()) { - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - sw = SW_INCORRECT_DATA; - break; - } else { - // Let the UI play - return 1; - } - } else { - // Out of data to process, wait for the next call - break; - } - } - - if ((context_D.outputParsingState == - OUTPUT_PARSING_OUTPUT) && - (context_D.remainingOutputs == 0)) { - context_D.outputParsingState = OUTPUT_FINALIZE_TX; - if (!bagl_finalize_tx()) { - context_D.outputParsingState = - OUTPUT_PARSING_NONE; - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - sw = SW_INCORRECT_DATA; - } else { - // Let the UI play - return 1; - } - } - - if (context_D.outputParsingState == - OUTPUT_FINALIZE_TX) { - context_D.transactionContext.firstSigned = 0; - - if (context_D.usingSegwit && - !context_D.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context_D.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - } else { - context_D.transactionContext.transactionState = - TRANSACTION_SIGN_READY; - } - } - context_D.outLength -= - 2; // status was already set by the last call - } else { - // Discard transaction - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - context_D.outLength = 0; - } - G_io_apdu_buffer[context_D.outLength++] = sw >> 8; - G_io_apdu_buffer[context_D.outLength++] = sw; - - if ((context_D.outputParsingState == OUTPUT_FINALIZE_TX) || - (sw != SW_OK)) { - - // we've finished the processing of the input - apdu_hash_input_finalize_full_reset(); - } - - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, context_D.outLength); - - return 0; -} diff --git a/src/apdu_hash_input_start.c b/src/apdu_hash_input_start.c deleted file mode 100644 index bc315ae5..00000000 --- a/src/apdu_hash_input_start.c +++ /dev/null @@ -1,128 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" -#include "apdu_constants.h" -#include "bagl_extensions.h" -#include "swap.h" - -#define P1_FIRST 0x00 -#define P1_NEXT 0x80 -#define P2_NEW 0x00 -#define P2_NEW_SEGWIT 0x02 -#define P2_NEW_SEGWIT_CASHADDR 0x03 -#define P2_NEW_SEGWIT_OVERWINTER 0x04 -#define P2_NEW_SEGWIT_SAPLING 0x05 -#define P2_CONTINUE 0x80 - -#define IS_INPUT() \ - (G_io_apdu_buffer[ISO_OFFSET_LC] - 1 > 8 \ - && G_io_apdu_buffer[ISO_OFFSET_LC] - 1 <= TRUSTED_INPUT_TOTAL_SIZE + 2 \ - && G_io_apdu_buffer[ISO_OFFSET_CDATA] <= 0x02) \ - -#define IS_INPUT_TRUSTED() \ - (G_io_apdu_buffer[ISO_OFFSET_CDATA] == 0x01 \ - && G_io_apdu_buffer[ISO_OFFSET_CDATA + 1] == TRUSTED_INPUT_TOTAL_SIZE \ - && G_io_apdu_buffer[ISO_OFFSET_CDATA + 2] == MAGIC_TRUSTED_INPUT \ - && G_io_apdu_buffer[ISO_OFFSET_CDATA + 3] == 0x00) - -unsigned short apdu_hash_input_start() { - unsigned char apduLength; - apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - - if (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_FIRST) { - // Initialize - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - context_D.transactionHashOption = TRANSACTION_HASH_BOTH; - } else if (G_io_apdu_buffer[ISO_OFFSET_P1] != P1_NEXT) { - return SW_INCORRECT_P1_P2; - } - - if ((G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_CASHADDR) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_OVERWINTER) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_SAPLING)) { - if (G_io_apdu_buffer[ISO_OFFSET_P1] == P1_FIRST) { - unsigned char usingSegwit = - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_CASHADDR) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_OVERWINTER) || - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_SAPLING); - unsigned char usingCashAddr = - (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_CASHADDR); - // Master transaction reset - context_D.transactionContext.firstSigned = 1; - context_D.transactionContext.consumeP2SH = 0; - context_D.transactionContext.relaxed = 0; - context_D.usingSegwit = usingSegwit; - context_D.usingCashAddr = - (COIN_KIND == COIN_KIND_BITCOIN_CASH ? usingCashAddr - : 0); - context_D.usingOverwinter = 0; - if ((COIN_KIND == COIN_KIND_ZCASH) || (COIN_KIND == COIN_KIND_KOMODO) || (COIN_KIND == COIN_KIND_ZCLASSIC) || (COIN_KIND == COIN_KIND_RESISTANCE)) { - if (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_OVERWINTER) { - context_D.usingOverwinter = ZCASH_USING_OVERWINTER; - } - else - if (G_io_apdu_buffer[ISO_OFFSET_P2] == P2_NEW_SEGWIT_SAPLING) { - context_D.usingOverwinter = ZCASH_USING_OVERWINTER_SAPLING; - } - } - context_D.overwinterSignReady = 0; - context_D.segwitParsedOnce = 0; - // Initialize for screen pairing - memset(&context_D.tmpCtx.output, 0, - sizeof(context_D.tmpCtx.output)); - context_D.tmpCtx.output.changeAccepted = 1; - // Reset segwitWarningSeen flag to prevent displaying the warning for each - // segwit input when coontinuing from a previous session (P2=0x80) - context_D.segwitWarningSeen = 0; - } - } else if (G_io_apdu_buffer[ISO_OFFSET_P2] != P2_CONTINUE) { - return SW_INCORRECT_P1_P2; - } - - // In segwit mode, warn user one time only to update its client wallet... - if (context_D.usingSegwit - && !context_D.segwitWarningSeen - &&(G_io_apdu_buffer[ISO_OFFSET_P1] == P1_NEXT) - && (G_io_apdu_buffer[ISO_OFFSET_P2] != P2_CONTINUE) - // ...if input is not passed as a TrustedInput - && IS_INPUT() - && !IS_INPUT_TRUSTED()) - { - if(G_called_from_swap){ - /* There is no point in displaying a warning when the app is signing - in silent mode, as its UI is hidden behind the exchange app*/ - return SW_SWAP_WITHOUT_TRUSTED_INPUTS; - } - context_D.segwitWarningSeen = 1; - context_D.io_flags |= IO_ASYNCH_REPLY; - bagl_request_segwit_input_approval(); - } - - // Start parsing of the 1st chunk - context_D.transactionBufferPointer = - G_io_apdu_buffer + ISO_OFFSET_CDATA; - context_D.transactionDataRemaining = apduLength; - - transaction_parse(PARSE_MODE_SIGNATURE); - - return SW_OK; -} diff --git a/src/apdu_hash_sign.c b/src/apdu_hash_sign.c deleted file mode 100644 index 9f670031..00000000 --- a/src/apdu_hash_sign.c +++ /dev/null @@ -1,196 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" -#include "apdu_constants.h" -#include "bagl_extensions.h" -#include "display_variables.h" -#include "ui.h" -#include "ledger_assert.h" -#include "lib_standard_app/read.h" -#include "lib_standard_app/write.h" -#include "swap.h" - -#define SIGHASH_ALL 0x01 - -#ifndef COIN_FORKID -#define COIN_FORKID 0 -#endif - -unsigned short apdu_hash_sign() { - unsigned long int lockTime; - uint32_t sighashType; - unsigned char dataBuffer[8]; - unsigned char authorizationLength; - unsigned char *parameters = G_io_apdu_buffer + ISO_OFFSET_CDATA; - unsigned short sw = SW_TECHNICAL_DETAILS(0xF); - - if ((G_io_apdu_buffer[ISO_OFFSET_P1] != 0) || - (G_io_apdu_buffer[ISO_OFFSET_P2] != 0)) { - return SW_INCORRECT_P1_P2; - } - - if (G_io_apdu_buffer[ISO_OFFSET_LC] < (1 + 1 + 4 + 1)) { - return SW_INCORRECT_LENGTH; - } - - // Zcash special - store parameters for later - - if ((context_D.usingOverwinter) && - (!context_D.overwinterSignReady) && - (context_D.segwitParsedOnce) && - (context_D.transactionContext.transactionState == TRANSACTION_NONE)) { - unsigned long int expiryHeight; - parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; - authorizationLength = *(parameters++); - parameters += authorizationLength; - lockTime = read_u32_be(parameters, 0); - parameters += 4; - sighashType = *(parameters++); - expiryHeight = read_u32_be(parameters, 0); - write_u32_le(context_D.nLockTime, 0, lockTime); - write_u32_le(context_D.sigHashType, 0, sighashType); - write_u32_le(context_D.nExpiryHeight, 0, expiryHeight); - context_D.overwinterSignReady = 1; - return SW_OK; - } - - if (context_D.transactionContext.transactionState != - TRANSACTION_SIGN_READY) { - PRINTF("Invalid transaction state %d\n", context_D.transactionContext.transactionState); - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - - if (context_D.usingOverwinter && !context_D.overwinterSignReady) { - PRINTF("Overwinter not ready to sign\n"); - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - - // Read parameters - if (G_io_apdu_buffer[ISO_OFFSET_CDATA] > MAX_BIP32_PATH) { - sw = SW_INCORRECT_DATA; - goto discardTransaction; - } - memmove(context_D.transactionSummary.keyPath, - G_io_apdu_buffer + ISO_OFFSET_CDATA, - MAX_BIP32_PATH_LENGTH); - parameters += (4 * G_io_apdu_buffer[ISO_OFFSET_CDATA]) + 1; - authorizationLength = *(parameters++); - parameters += authorizationLength; - lockTime = read_u32_be(parameters, 0); - parameters += 4; - sighashType = *(parameters++); - context_D.transactionSummary.sighashType = sighashType; - - // if bitcoin cash OR forkid is set, then use the fork id - if (COIN_KIND == COIN_KIND_BITCOIN_CASH || (COIN_FORKID)) { -#define SIGHASH_FORKID 0x40 - if (sighashType != (SIGHASH_ALL | SIGHASH_FORKID)) { - sw = SW_INCORRECT_DATA; - goto discardTransaction; - } - sighashType |= (COIN_FORKID << 8); - } else { - if (sighashType != SIGHASH_ALL) { - sw = SW_INCORRECT_DATA; - goto discardTransaction; - } - } - - // Finalize the hash - if (!context_D.usingOverwinter) { - write_u32_le(dataBuffer, 0, lockTime); - write_u32_le(dataBuffer, 4, sighashType); - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(dataBuffer), dataBuffer); - if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, - dataBuffer, sizeof(dataBuffer), NULL, 0)) { - goto discardTransaction; - } - } - - // Check if the path needs to be enforced - if (!enforce_bip44_coin_type(context_D.transactionSummary.keyPath, false)) { - context_D.io_flags |= IO_ASYNCH_REPLY; - bagl_request_sign_path_approval(context_D.transactionSummary.keyPath); - } - else { - // Sign immediately - bagl_user_action_signtx(1, 1); - } - sw = SW_OK; - if (G_called_from_swap) { - // if we signed all outputs we should exit, - // but only after sending response, so lets raise the - // vars.swap_data.should_exit flag and check it on timer later - vars.swap_data.alreadySignedInputs++; - if (vars.swap_data.alreadySignedInputs >= vars.swap_data.totalNumberOfInputs) { - vars.swap_data.should_exit = 1; - } - } - - return sw; - - discardTransaction: - context_D.transactionContext.transactionState = TRANSACTION_NONE; - return sw; -} - -void bagl_user_action_signtx(unsigned char confirming, unsigned char direct) { - unsigned short sw = SW_OK; - // confirm and finish the apdu exchange //spaghetti - if (confirming) { - unsigned char hash[32]; - if (context_D.usingOverwinter) { - LEDGER_ASSERT(cx_hash_no_throw(&context_D.transactionHashFull.blake2b.header, CX_LAST, hash, 0, hash, 32) == CX_OK, "Hash Failed"); - } - else { - LEDGER_ASSERT(cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, CX_LAST, - hash, 0, hash, 32) == CX_OK, "Hash Failed"); - PRINTF("Hash1\n%.*H\n", sizeof(hash), hash); - - // Rehash - cx_hash_sha256(hash, sizeof(hash), hash, 32); - } - PRINTF("Hash2\n%.*H\n", sizeof(hash), hash); - // Sign - size_t out_len = sizeof(G_io_apdu_buffer); - sign_finalhash( - context_D.transactionSummary.keyPath, - sizeof(context_D.transactionSummary.keyPath), - hash, sizeof(hash), - G_io_apdu_buffer, &out_len, - 1); - - context_D.outLength = G_io_apdu_buffer[1] + 2; - G_io_apdu_buffer[context_D.outLength++] = context_D.transactionSummary.sighashType; - ui_transaction_finish(); - - } else { - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - context_D.outLength = 0; - } - - if (!direct) { - G_io_apdu_buffer[context_D.outLength++] = sw >> 8; - G_io_apdu_buffer[context_D.outLength++] = sw; - - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, context_D.outLength); - } -} - diff --git a/src/apdu_sign_message.c b/src/apdu_sign_message.c deleted file mode 100644 index 9a5bbc54..00000000 --- a/src/apdu_sign_message.c +++ /dev/null @@ -1,290 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" -#include "apdu_constants.h" -#include "bagl_extensions.h" -#include "lib_standard_app/read.h" -#include "swap.h" - -#define P1_PREPARE 0x00 -#define P1_SIGN 0x80 -#define P2_LEGACY 0x00 -#define P2_FIRST 0x01 -#define P2_OTHER 0x80 - -#define BITID_NONE 0 -#define BITID_POWERCYCLE 1 -#define BITID_MULTIPLE 2 - -//#define SLIP_13 0x8000000D - -unsigned short compute_hash(void); - -unsigned char checkBitId(unsigned char *bip32Path) { - unsigned char i; - unsigned char bip32PathLength = bip32Path[0]; - bip32Path++; - for (i = 0; i < bip32PathLength; i++) { - unsigned short account = read_u32_be(bip32Path, 0); - bip32Path += 4; - - if (account == BITID_DERIVE) { - return BITID_POWERCYCLE; - } - if (account == BITID_DERIVE_MULTIPLE) { - return BITID_MULTIPLE; - } - } - return BITID_NONE; -} - -// TODO : support longer messages - -unsigned short apdu_sign_message_internal() { - unsigned short sw = SW_OK; - unsigned char p1 = G_io_apdu_buffer[ISO_OFFSET_P1]; - unsigned char p2 = G_io_apdu_buffer[ISO_OFFSET_P2]; - unsigned char apduLength = G_io_apdu_buffer[ISO_OFFSET_LC]; - unsigned short offset = ISO_OFFSET_CDATA; - - if ((p1 != P1_PREPARE) && (p1 != P1_SIGN)) { - return SW_INCORRECT_P1_P2; - } - if (p1 == P1_PREPARE) { - if ((p2 != P2_FIRST) && (p2 != P2_OTHER) && (p2 != P2_LEGACY)) { - return SW_INCORRECT_P1_P2; - } - } - - if (p1 == P1_PREPARE) { - if ((p2 == P2_FIRST) || (p2 == P2_LEGACY)) { - unsigned char chunkLength; - unsigned char messageLength[3]; - unsigned char messageLengthSize; - memset(&context_D.transactionSummary, 0, - sizeof(transaction_summary_t)); - if (G_io_apdu_buffer[offset] > MAX_BIP32_PATH) { - PRINTF("Invalid path\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - context_D.transactionSummary.payToAddressVersion = COIN_P2PKH_VERSION; - context_D.transactionSummary.payToScriptHashVersion = COIN_P2SH_VERSION; - memmove( - context_D.transactionSummary.keyPath, - G_io_apdu_buffer + offset, MAX_BIP32_PATH_LENGTH); - offset += (4 * G_io_apdu_buffer[offset]) + 1; - if (p2 == P2_LEGACY) { - context_D.transactionSummary.messageLength = - G_io_apdu_buffer[offset]; - offset++; - } else { - context_D.transactionSummary.messageLength = - (G_io_apdu_buffer[offset] << 8) | - (G_io_apdu_buffer[offset + 1]); - offset += 2; - } - if (context_D.transactionSummary.messageLength == - 0) { - PRINTF("Null message length\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - context_D.hashedMessageLength = 0; - if (cx_sha256_init_no_throw(&context_D.transactionHashFull.sha256)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discard; - } - if (cx_sha256_init_no_throw( - &context_D.transactionHashAuthorization)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discard; - } - // Horizen signed message magic header is "Zcash" - // See https://github.com/HorizenOfficial/zen/blob/v5.0.0/src/main.cpp#L122 - const char* magicHeader = (COIN_KIND != COIN_KIND_HORIZEN) ? COIN_COINID : "Zcash"; - chunkLength = - strlen(magicHeader) + SIGNMAGIC_LENGTH; - if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, - &chunkLength, 1, NULL, 0)) { - goto discard; - } - if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, - (uint8_t *)magicHeader, - strlen(magicHeader), NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discard; - } - if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, - (unsigned char *)SIGNMAGIC, SIGNMAGIC_LENGTH, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discard; - } - if (context_D.transactionSummary.messageLength < - 0xfd) { - messageLength[0] = - context_D.transactionSummary.messageLength; - messageLengthSize = 1; - } else { - messageLength[0] = 0xfd; - messageLength[1] = - (context_D.transactionSummary.messageLength & - 0xff); - messageLength[2] = ((context_D.transactionSummary - .messageLength >> - 8) & - 0xff); - messageLengthSize = 3; - } - if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, - messageLength, messageLengthSize, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discard; - } - chunkLength = apduLength - (offset - ISO_OFFSET_CDATA); - if ((context_D.hashedMessageLength + chunkLength) > - context_D.transactionSummary.messageLength) { - PRINTF("Invalid data length\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, - G_io_apdu_buffer + offset, chunkLength, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discard; - } - if (cx_hash_no_throw( - &context_D.transactionHashAuthorization.header, - 0, G_io_apdu_buffer + offset, chunkLength, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discard; - } - context_D.hashedMessageLength += chunkLength; - G_io_apdu_buffer[0] = 0x00; - if (context_D.hashedMessageLength == - context_D.transactionSummary.messageLength) { - G_io_apdu_buffer[1] = 0x00; - context_D.outLength = 2; - } else { - context_D.outLength = 1; - } - } else { - if ((context_D.hashedMessageLength + apduLength) > - context_D.transactionSummary.messageLength) { - PRINTF("Invalid data length\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, 0, - G_io_apdu_buffer + offset, apduLength, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discard; - } - if (cx_hash_no_throw( - &context_D.transactionHashAuthorization.header, - 0, G_io_apdu_buffer + offset, apduLength, NULL, 0)) { - sw = SW_TECHNICAL_DETAILS(0x0F); - goto discard; - } - context_D.hashedMessageLength += apduLength; - G_io_apdu_buffer[0] = 0x00; - if (context_D.hashedMessageLength == - context_D.transactionSummary.messageLength) { - G_io_apdu_buffer[1] = 0x00; - context_D.outLength = 2; - } else { - context_D.outLength = 1; - } - } - } else { - if ((context_D.transactionSummary.messageLength == 0) || - (context_D.hashedMessageLength != - context_D.transactionSummary.messageLength)) { - PRINTF("Invalid length to sign\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - if (checkBitId(context_D.transactionSummary.keyPath) != BITID_NONE) { - sw = compute_hash(); - } else { - context_D.io_flags |= IO_ASYNCH_REPLY; - return SW_OK; - } - } - return sw; - - discard : - memset(&context_D.transactionSummary, 0, - sizeof(transaction_summary_t)); - return sw; -} - -unsigned short apdu_sign_message() { - if (G_called_from_swap) { - return SW_SECURITY_STATUS_NOT_SATISFIED; - } - unsigned short sw = apdu_sign_message_internal(); - if (context_D.io_flags & IO_ASYNCH_REPLY) { - bagl_confirm_message_signature(); - } - return sw; -} - -unsigned short compute_hash() { - unsigned char hash[32]; - unsigned short sw = SW_OK; - - context_D.outLength = 0; - if (cx_hash_no_throw(&context_D.transactionHashFull.sha256.header, CX_LAST, hash, - 0, hash, 32)) { - goto discard; - } - - if (cx_hash_sha256(hash, sizeof(hash), hash, 32) == 0) { - goto discard; - } - - size_t out_len = 100; - sign_finalhash( - context_D.transactionSummary.keyPath, - sizeof(context_D.transactionSummary.keyPath), - hash, sizeof(hash), // IN - G_io_apdu_buffer, &out_len, // OUT - 1); - context_D.outLength = G_io_apdu_buffer[1] + 2; - memset(&context_D.transactionSummary, 0, - sizeof(transaction_summary_t)); - return sw; - - discard: - sw = SW_TECHNICAL_DETAILS(0x0F); - return sw; -} - -void bagl_user_action_message_signing(unsigned char confirming) { - unsigned short sw; - if (confirming) { - sw = compute_hash(); - } else { - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - } - G_io_apdu_buffer[context_D.outLength++] = sw >> 8; - G_io_apdu_buffer[context_D.outLength++] = sw; - - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, context_D.outLength); -} diff --git a/src/bcd.c b/src/bcd.c deleted file mode 100644 index a7878d0b..00000000 --- a/src/bcd.c +++ /dev/null @@ -1,103 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" - -#define SCRATCH_SIZE 21 - -unsigned char -convert_hex_amount_to_displayable_no_globals(unsigned char *amount, unsigned int config_flag, unsigned char* out) { - unsigned char LOOP1; - unsigned char LOOP2; - if (!(config_flag & FLAG_PEERCOIN_UNITS)) { - LOOP1 = 13; - LOOP2 = 8; - } else { - LOOP1 = 15; - LOOP2 = 6; - } - unsigned short scratch[SCRATCH_SIZE]; - unsigned char offset = 0; - unsigned char nonZero = 0; - unsigned char i; - unsigned char targetOffset = 0; - unsigned char workOffset; - unsigned char j; - unsigned char nscratch = SCRATCH_SIZE; - unsigned char smin = nscratch - 2; - unsigned char comma = 0; - - for (i = 0; i < SCRATCH_SIZE; i++) { - scratch[i] = 0; - } - for (i = 0; i < 8; i++) { - for (j = 0; j < 8; j++) { - unsigned char k; - unsigned short shifted_in = - (((amount[i] & 0xff) & ((1 << (7 - j)))) != 0) ? (short)1 - : (short)0; - for (k = smin; k < nscratch; k++) { - scratch[k] += ((scratch[k] >= 5) ? 3 : 0); - } - if (scratch[smin] >= 8) { - smin -= 1; - } - for (k = smin; k < nscratch - 1; k++) { - scratch[k] = - ((scratch[k] << 1) & 0xF) | ((scratch[k + 1] >= 8) ? 1 : 0); - } - scratch[nscratch - 1] = ((scratch[nscratch - 1] << 1) & 0x0F) | - (shifted_in == 1 ? 1 : 0); - } - } - - for (i = 0; i < LOOP1; i++) { - if (!nonZero && (scratch[offset] == 0)) { - offset++; - } else { - nonZero = 1; - out[targetOffset++] = scratch[offset++] + '0'; - } - } - if (targetOffset == 0) { - out[targetOffset++] = '0'; - } - workOffset = offset; - for (i = 0; i < LOOP2; i++) { - unsigned char allZero = 1; - for (j = i; j < LOOP2; j++) { - if (scratch[workOffset + j] != 0) { - allZero = 0; - break; - } - } - if (allZero) { - break; - } - if (!comma) { - out[targetOffset++] = '.'; - comma = 1; - } - out[targetOffset++] = scratch[offset++] + '0'; - } - return targetOffset; -} - -unsigned char -convert_hex_amount_to_displayable(unsigned char *amount) { - return convert_hex_amount_to_displayable_no_globals(amount, COIN_FLAGS, context_D.tmp); -} diff --git a/src/bip32_path.c b/src/bip32_path.c deleted file mode 100644 index 8be5d787..00000000 --- a/src/bip32_path.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "lib_standard_app/read.h" -#include "bip32_path.h" -#include "helpers.h" - -bool parse_serialized_path(bip32_path_t* path, unsigned char* serialized_path, unsigned char serialized_path_length) { - if (serialized_path_length < 1 || - serialized_path[0] > MAX_BIP32_PATH || - serialized_path[0] * 4 + 1 > serialized_path_length) - return false; - path->length = serialized_path[0]; - serialized_path++; - for (int i = 0; i < path->length; i += 1, serialized_path += 4) { - path->path[i] = read_u32_be(serialized_path, 0); - } - return true; -} diff --git a/src/bip32_path.h b/src/bip32_path.h deleted file mode 100644 index 819ea8c9..00000000 --- a/src/bip32_path.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _BIP32_PATH_H_ -#define _BIP32_PATH_H_ - -#include "stdbool.h" - -#define MAX_BIP32_PATH 10 -#define MAX_BIP32_PATH_LENGTH (4 * MAX_BIP32_PATH) + 1 - -typedef struct bip32_path { - unsigned char length; - unsigned int path[MAX_BIP32_PATH]; -} bip32_path_t; - -bool parse_serialized_path(bip32_path_t* path, unsigned char* serialized_path, unsigned char serialized_path_length); - -#endif \ No newline at end of file diff --git a/src/btchip.c b/src/btchip.c deleted file mode 100644 index 2d65d16f..00000000 --- a/src/btchip.c +++ /dev/null @@ -1,606 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ -#include "os.h" -#include "cx.h" - -#include "string.h" - -#include "internal.h" - -#include "bagl_extensions.h" - -#include "segwit_addr.h" -#include "cashaddr.h" - -#include "ux.h" -#include "display_variables.h" -#include "swap_lib_calls.h" - -#include "handle_swap_sign_transaction.h" -#include "handle_get_printable_amount.h" -#include "handle_check_address.h" -#include "ui.h" -#include "lib_standard_app/format.h" -#include "read.h" -#include "write.h" -#include "bip32.h" -#include "swap.h" - -unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { - switch (channel & ~(IO_FLAGS)) { - case CHANNEL_KEYBOARD: - break; - - // multiplexed io exchange over a SPI channel and TLV encapsulated protocol - case CHANNEL_SPI: - if (tx_len) { - io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); - - if (channel & IO_RESET_AFTER_REPLIED) { - reset(); - } - return 0; // nothing received from the master so far (it's a tx - // transaction) - } else { - return io_seproxyhal_spi_recv(G_io_apdu_buffer, - sizeof(G_io_apdu_buffer), 0); - } - - default: - THROW(INVALID_PARAMETER); - } - return 0; -} - -unsigned char io_event(unsigned char channel) { - UNUSED(channel); - // nothing done with the event, throw an error on the transport layer if - // needed - - // can't have more than one tag in the reply, not supported yet. - switch (G_io_seproxyhal_spi_buffer[0]) { -#ifdef HAVE_NBGL - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; -#endif // HAVE_NBGL - - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: -#ifdef HAVE_BAGL - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); -#endif // HAVE_BAGL - break; - - case SEPROXYHAL_TAG_STATUS_EVENT: - if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && - !(U4BE(G_io_seproxyhal_spi_buffer, 3) & - SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { - THROW(EXCEPTION_IO_RESET); - } - __attribute__((fallthrough)); - default: - UX_DEFAULT_EVENT(); - break; - - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: -#ifdef HAVE_BAGL - UX_DISPLAYED_EVENT({}); -#endif // HAVE_BAGL -#ifdef HAVE_NBGL - UX_DEFAULT_EVENT(); -#endif // HAVE_NBGL - break; - - case SEPROXYHAL_TAG_TICKER_EVENT: - // TODO: found less hacky way to exit library after sending response - // this mechanism is used for Swap/Exchange functionality - // when application is in silent mode, and should return to caller, - // after responding some APDUs - UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {}); - break; - } - - // close the event if not done previously (by a display or whatever) - if (!io_seproxyhal_spi_is_status_sent()) { - io_seproxyhal_general_status(); - } - - // command has been processed, DO NOT reset the current APDU transport - return 1; -} - -uint8_t check_fee_swap() { - unsigned char fees[8]; - unsigned char borrow; - - borrow = transaction_amount_sub_be( - fees, context_D.transactionContext.transactionAmount, - context_D.totalOutputAmount); - if ((borrow != 0) || (memcmp(fees, vars.swap_data.fees, 8) != 0)) - return 0; - context_D.transactionContext.firstSigned = 0; - - if (context_D.usingSegwit && !context_D.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context_D.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - } else { - context_D.transactionContext.transactionState = - TRANSACTION_SIGN_READY; - } - context_D.sw = 0x9000; - context_D.outLength = 0; - G_io_apdu_buffer[context_D.outLength++] = 0x90; - G_io_apdu_buffer[context_D.outLength++] = 0x00; - - return 1; -} - -uint8_t prepare_fees(void) { - if (context_D.transactionContext.relaxed) { - memmove(vars.tmp.feesAmount, "UNKNOWN", 7); - vars.tmp.feesAmount[7] = '\0'; - } else { - unsigned char fees[8]; - unsigned short textSize; - unsigned char borrow; - - borrow = transaction_amount_sub_be( - fees, context_D.transactionContext.transactionAmount, - context_D.totalOutputAmount); - if (borrow && COIN_KIND == COIN_KIND_KOMODO) { - memmove(vars.tmp.feesAmount, "REWARD", 6); - vars.tmp.feesAmount[6] = '\0'; - } - else { - if (borrow) { - PRINTF("Error : Fees not consistent"); - goto error; - } - memmove(vars.tmp.feesAmount, COIN_COINID_SHORT, - strlen(COIN_COINID_SHORT)); - vars.tmp.feesAmount[strlen(COIN_COINID_SHORT)] = ' '; - context_D.tmp = - (unsigned char *)(vars.tmp.feesAmount + - strlen(COIN_COINID_SHORT) + 1); - textSize = convert_hex_amount_to_displayable(fees); - vars.tmp.feesAmount[textSize + strlen(COIN_COINID_SHORT) + 1] = - '\0'; - } - } - return 1; -error: - return 0; -} - -#define OMNI_ASSETID 1 -#define MAIDSAFE_ASSETID 3 -#define USDT_ASSETID 31 - -void get_address_from_output_script(unsigned char* script, int script_size, char* out, int out_size) { - if (output_script_is_op_return(script)) { - strncpy(out, "OP_RETURN", out_size); - return; - } - if ((COIN_KIND == COIN_KIND_HYDRA) && - output_script_is_op_create(script, script_size)) { - strncpy(out, "OP_CREATE", out_size); - return; - } - if ((COIN_KIND == COIN_KIND_HYDRA) && - output_script_is_op_call(script, script_size)) { - strncpy(out, "OP_CALL", out_size); - return; - } - if (output_script_is_native_witness(script)) { - if (COIN_NATIVE_SEGWIT_PREFIX) { - segwit_addr_encode( - out, (char *)PIC(COIN_NATIVE_SEGWIT_PREFIX), 0, - script + OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET, - script[OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET - 1]); - } - return; - } - unsigned char versionSize; - unsigned char address[22]; - unsigned short textSize; - int addressOffset = 3; - unsigned short version = COIN_P2SH_VERSION; - - if (output_script_is_regular(script)) { - addressOffset = 4; - version = COIN_P2PKH_VERSION; - } - - if (version > 255) { - versionSize = 2; - address[0] = (version >> 8); - address[1] = version; - } else { - versionSize = 1; - address[0] = version; - } - memmove(address + versionSize, script + addressOffset, 20); - - // Prepare address - if (context_D.usingCashAddr) { - cashaddr_encode( - address + versionSize, 20, (uint8_t *)out, out_size, - (version == COIN_P2SH_VERSION - ? CASHADDR_P2SH - : CASHADDR_P2PKH)); - } else { - textSize = public_key_to_encoded_base58( - address, 20 + versionSize, (unsigned char *)out, - out_size, version, 1); - out[textSize] = '\0'; - } -} - -uint8_t prepare_single_output(void) { - // TODO : special display for OP_RETURN - unsigned char amount[8]; - unsigned int offset = 0; - unsigned short textSize; - char tmp[80] = {0}; - - swap_bytes(amount, context_D.currentOutput + offset, 8); - offset += 8; - - get_address_from_output_script(context_D.currentOutput + offset, sizeof(context_D.currentOutput) - offset, tmp, sizeof(tmp)); - strncpy(vars.tmp.fullAddress, tmp, sizeof(vars.tmp.fullAddress) - 1); - - // Prepare amount - - // Handle Omni simple send - if ((context_D.currentOutput[offset + 2] == 0x14) && - (memcmp(context_D.currentOutput + offset + 3, "omni", 4) == 0) && - (memcmp(context_D.currentOutput + offset + 3 + 4, "\0\0\0\0", 4) == 0)) { - uint8_t headerLength; - uint32_t omniAssetId = read_u32_be(context_D.currentOutput, offset + 3 + 4 + 4); - switch(omniAssetId) { - case OMNI_ASSETID: - strcpy(vars.tmp.fullAmount, "OMNI "); - break; - case USDT_ASSETID: - strcpy(vars.tmp.fullAmount, "USDT "); - break; - case MAIDSAFE_ASSETID: - strcpy(vars.tmp.fullAmount, "MAID "); - break; - default: - snprintf(vars.tmp.fullAmount, sizeof(vars.tmp.fullAmount), "OMNI asset %d ", omniAssetId); - break; - } - headerLength = strlen(vars.tmp.fullAmount); - context_D.tmp = (uint8_t *)vars.tmp.fullAmount + headerLength; - textSize = convert_hex_amount_to_displayable(context_D.currentOutput + offset + 3 + 4 + 4 + 4); - vars.tmp.fullAmount[textSize + headerLength] = '\0'; - } - else { - memmove(vars.tmp.fullAmount, COIN_COINID_SHORT, - strlen(COIN_COINID_SHORT)); - vars.tmp.fullAmount[strlen(COIN_COINID_SHORT)] = ' '; - context_D.tmp = - (unsigned char *)(vars.tmp.fullAmount + - strlen(COIN_COINID_SHORT) + 1); - textSize = convert_hex_amount_to_displayable(amount); - vars.tmp.fullAmount[textSize + strlen(COIN_COINID_SHORT) + 1] = - '\0'; - } - - return 1; -} - -uint8_t prepare_message_signature(void) { - uint8_t buffer[32]; - - if (cx_hash_no_throw(&context_D.transactionHashAuthorization.header, CX_LAST, - (uint8_t*)vars.tmp.fullAmount, 0, buffer, 32)) { - return 0; - } - - format_hex((const uint8_t*) buffer, sizeof(buffer), vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress)); - - return 1; -} - - -extern bool handle_output_state(void); -extern void apdu_hash_input_finalize_full_reset(void); - -// Analog of bagl_confirm_single_output to work -// in silent mode, when called from SWAP app -unsigned int silent_confirm_single_output() { - char tmp[80] = {0}; - unsigned char amount[8]; - while (true) { - // in swap operation we can only have 1 "external" output - if (vars.swap_data.was_address_checked) { - PRINTF("Address was already checked\n"); - return 0; - } - vars.swap_data.was_address_checked = 1; - // check amount - swap_bytes(amount, context_D.currentOutput, 8); - if (memcmp(amount, vars.swap_data.amount, 8) != 0) { - PRINTF("Amount not matched\n"); - return 0; - } - get_address_from_output_script(context_D.currentOutput + 8, sizeof(context_D.currentOutput) - 8, tmp, sizeof(tmp)); - if (strcmp(tmp, vars.swap_data.destination_address) != 0) { - PRINTF("Address not matched\n"); - return 0; - } - - // Check if all inputs have been confirmed - - if (context_D.outputParsingState == - OUTPUT_PARSING_OUTPUT) { - context_D.remainingOutputs--; - if (context_D.remainingOutputs == 0) - break; - } - - memmove(context_D.currentOutput, - context_D.currentOutput + - context_D.discardSize, - context_D.currentOutputOffset - - context_D.discardSize); - context_D.currentOutputOffset -= context_D.discardSize; - context_D.io_flags &= ~IO_ASYNCH_REPLY; - while (handle_output_state() && - (!(context_D.io_flags & IO_ASYNCH_REPLY))) - ; - if (!(context_D.io_flags & IO_ASYNCH_REPLY)) { - // Out of data to process, wait for the next call - break; - } - } - - if ((context_D.outputParsingState == OUTPUT_PARSING_OUTPUT) && - (context_D.remainingOutputs == 0)) { - context_D.outputParsingState = OUTPUT_FINALIZE_TX; - // check fees - unsigned char fees[8]; - - if ((transaction_amount_sub_be(fees, - context_D.transactionContext.transactionAmount, - context_D.totalOutputAmount) != 0) || - (memcmp(fees, vars.swap_data.fees, 8) != 0)) { - PRINTF("Fees is not matched\n"); - return 0; - } - } - - if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { - context_D.transactionContext.firstSigned = 0; - - if (context_D.usingSegwit && - !context_D.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context_D.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context_D.transactionContext.transactionState = - TRANSACTION_NONE; - } else { - context_D.transactionContext.transactionState = - TRANSACTION_SIGN_READY; - } - } - if (context_D.outputParsingState == OUTPUT_FINALIZE_TX) { - // we've finished the processing of the input - apdu_hash_input_finalize_full_reset(); - } - - return 1; -} - -unsigned int bagl_confirm_single_output(void) { - if (G_called_from_swap) { - return silent_confirm_single_output(); - } - if (!prepare_single_output()) { - return 0; - } - - ui_confirm_single_flow(); - return 1; -} - -unsigned int bagl_finalize_tx(void) { - if (G_called_from_swap) { - return check_fee_swap(); - } - - if (!prepare_fees()) { - return 0; - } - - ui_finalize_flow(); - return 1; -} - -void bagl_confirm_message_signature(void) { - if (!prepare_message_signature()) { - return; - } - - ui_sign_message_flow(); -} - -uint8_t set_key_path_to_display(unsigned char* keyPath) { - bip32_print_path(keyPath, vars.tmp_warning.derivation_path, MAX_DERIV_PATH_ASCII_LENGTH); - return bip44_derivation_guard(keyPath, false); -} - -void bagl_display_public_key(uint8_t is_derivation_path_unusual) { - // append a white space at the end of the address to avoid glitch on nano S - strlcat((char *)G_io_apdu_buffer + 200, " ", sizeof(G_io_apdu_buffer) - 200); - - if (is_derivation_path_unusual) { - ui_display_public_with_warning_flow(); - } - else { - ui_display_public_flow(); - } -} - -void bagl_display_token(void) -{ - ui_display_token_flow(); -} - -void bagl_request_pubkey_approval(void) -{ - ui_request_pubkey_approval_flow(); -} - -void bagl_request_change_path_approval(unsigned char* change_path) -{ - - bip32_print_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); - ui_request_change_path_approval_flow(); -} - -void bagl_request_sign_path_approval(unsigned char* change_path) -{ - bip32_print_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); - ui_request_sign_path_approval_flow(); -} - -void bagl_request_segwit_input_approval(void) -{ - ui_request_segwit_input_approval_flow(); -} - - -#include "os.h" - -#include "internal.h" - -#include "os_io_seproxyhal.h" - -#include "apdu_constants.h" -#include "display_variables.h" - -#include "handle_swap_sign_transaction.h" - -#define TECHNICAL_NOT_IMPLEMENTED 0x99 - -#define COMMON_CLA 0xB0 - -void app_dispatch(void) { - unsigned char cla; - unsigned char ins; - unsigned char dispatched; - - // nothing to reply for now - context_D.outLength = 0; - context_D.io_flags = 0; - - cla = G_io_apdu_buffer[ISO_OFFSET_CLA]; - ins = G_io_apdu_buffer[ISO_OFFSET_INS]; - for (dispatched = 0; dispatched < DISPATCHER_APDUS; dispatched++) { - if ((cla == DISPATCHER_CLA[dispatched]) && - (ins == DISPATCHER_INS[dispatched])) { - break; - } - } - if (dispatched == DISPATCHER_APDUS) { - context_D.sw = SW_INS_NOT_SUPPORTED; - goto sendSW; - } - if (DISPATCHER_DATA_IN[dispatched]) { - if (G_io_apdu_buffer[ISO_OFFSET_LC] == 0x00 || - context_D.inLength - 5 == 0) { - context_D.sw = SW_INCORRECT_LENGTH; - goto sendSW; - } - // notify we need to receive data - // io_exchange(CHANNEL_APDU | IO_RECEIVE_DATA, 0); - } - // call the apdu handler - context_D.sw = ((apduProcessingFunction)PIC( - DISPATCHER_FUNCTIONS[dispatched]))(); - - // an APDU has been replied. request for power off time extension from the - // common ux -#ifdef IO_APP_ACTIVITY - IO_APP_ACTIVITY(); -#endif // IO_APP_ACTIVITY - -sendSW: - if (G_called_from_swap) { - context_D.io_flags &= ~IO_ASYNCH_REPLY; - if(context_D.sw != SW_OK) { - vars.swap_data.should_exit = 1; - } - } - // prepare SW after replied data - G_io_apdu_buffer[context_D.outLength] = - (context_D.sw >> 8); - G_io_apdu_buffer[context_D.outLength + 1] = - (context_D.sw & 0xff); - context_D.outLength += 2; - return; -} - -void app_main(void) { - context_init(); - - ui_idle_flow(); - - memset(G_io_apdu_buffer, 0, 255); // paranoia - - // Process the incoming APDUs - - // first exchange, no out length :) only wait the apdu - context_D.outLength = 0; - context_D.io_flags = 0; - for (;;) { - - // memset(G_io_apdu_buffer, 0, 255); // paranoia - - if (G_called_from_swap && vars.swap_data.should_exit) { - context_D.io_flags |= IO_RETURN_AFTER_TX; - } - - // receive the whole apdu using the 7 bytes headers (ledger transport) - context_D.inLength = - io_exchange(CHANNEL_APDU | context_D.io_flags, - // use the previous outlength as the reply - context_D.outLength); - - if (G_called_from_swap && vars.swap_data.should_exit) { - swap_finalize_exchange_sign_transaction(context_D.sw == SW_OK); - } - - PRINTF("New APDU received:\n%.*H\n", context_D.inLength, G_io_apdu_buffer); - - app_dispatch(); - - // reply during reception of next apdu - } - - PRINTF("End of main loop\n"); - - // in case reached - reset(); -} diff --git a/src/ecc.c b/src/ecc.c deleted file mode 100644 index 69092c81..00000000 --- a/src/ecc.c +++ /dev/null @@ -1,22 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" - -void compress_public_key_value(unsigned char *value) { - value[0] = ((value[64] & 1) ? 0x03 : 0x02); -} diff --git a/src/helpers.c b/src/helpers.c deleted file mode 100644 index 605acb06..00000000 --- a/src/helpers.c +++ /dev/null @@ -1,407 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" -#include "apdu_constants.h" -#include "lib_standard_app/crypto_helpers.h" -#include "lib_standard_app/read.h" -#include "lib_standard_app/base58.h" -#include "bip32_path.h" -#include "ledger_assert.h" - -const unsigned char TRANSACTION_OUTPUT_SCRIPT_PRE[] = { - 0x19, 0x76, 0xA9, - 0x14}; // script length, OP_DUP, OP_HASH160, address length -const unsigned char TRANSACTION_OUTPUT_SCRIPT_POST[] = { - 0x88, 0xAC}; // OP_EQUALVERIFY, OP_CHECKSIG - -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { - 0x17, 0xA9, 0x14}; // script length, OP_HASH160, address length -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL - -const unsigned char ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { - 0x3D, 0xA9, - 0x14}; // script length, OP_HASH160, address length - -const unsigned char ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = { - 0x87, // OP_EQUAL - 0x20, 0x9E, 0xC9, 0x84, 0x5A, 0xCB, 0x02, 0xFA, 0XB2, 0X4E, - 0x1C, 0x03, 0x68, 0xB3, 0xB5, 0x17, 0xC1, 0xA4, 0x48, 0x8F, - 0xBA, 0x97, 0xF0, 0xE3, 0x45, 0x9A, 0xC0, 0x53, 0xEA, 0x01, - 0x00, 0x00, 0x00, // ParamHash - 0x03, // Push 3 bytes to stack to make ParamHeight line up properly - 0xC0, 0x1F, 0x02, // ParamHeight (139200) -> hex -> endianness swapped - 0xB4}; // OP_CHECKBLOCKATHEIGHT - -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE[] = {0x16, 0x00, 0x14}; -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE[] = {0x22, 0x00, 0x20}; - -const unsigned char ZEN_OUTPUT_SCRIPT_PRE[] = { - 0x3F, 0x76, 0xA9, - 0x14}; // script length, OP_DUP, OP_HASH160, address length -const unsigned char ZEN_OUTPUT_SCRIPT_POST[] = { - 0x88, 0xAC, // OP_EQUALVERIFY, OP_CHECKSIG - 0x20, 0x9e, 0xc9, 0x84, 0x5a, 0xcb, 0x02, 0xfa, 0xb2, 0x4e, 0x1c, 0x03, - 0x68, 0xb3, 0xb5, 0x17, 0xc1, 0xa4, 0x48, 0x8f, 0xba, 0x97, 0xf0, 0xe3, - 0x45, 0x9a, 0xc0, 0x53, 0xea, 0x01, 0x00, 0x00, 0x00, // ParamHash - 0x03, // Push 3 bytes to stack to make ParamHeight line up properly - 0xc0, 0x1f, 0x02, // ParamHeight (139200) -> hex -> endianness swapped - 0xb4 // OP_CHECKBLOCKATHEIGHT -}; // BIP0115 Replay Protection - -unsigned char output_script_is_regular(unsigned char *buffer) { - if (COIN_NATIVE_SEGWIT_PREFIX) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || - (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { - return 1; - } - } - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) && - (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, - TRANSACTION_OUTPUT_SCRIPT_POST, - sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { - return 1; - } - if (COIN_KIND == COIN_KIND_HORIZEN) { - if ((memcmp(buffer, ZEN_OUTPUT_SCRIPT_PRE, - sizeof(ZEN_OUTPUT_SCRIPT_PRE)) == 0) && - (memcmp(buffer + sizeof(ZEN_OUTPUT_SCRIPT_PRE) + 20, - ZEN_OUTPUT_SCRIPT_POST, - sizeof(ZEN_OUTPUT_SCRIPT_POST)) == 0)) { - return 1; - } - } - - return 0; -} - -unsigned char output_script_is_p2sh(unsigned char *buffer) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && - (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, - TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { - return 1; - } - if (COIN_KIND == COIN_KIND_HORIZEN) { - if ((memcmp(buffer, ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, - sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && - (memcmp(buffer + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, - ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, - sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { - return 1; - } - } - return 0; -} - -unsigned char output_script_is_native_witness(unsigned char *buffer) { - if (COIN_NATIVE_SEGWIT_PREFIX) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || - (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { - return 1; - } - } - return 0; -} - -unsigned char output_script_is_op_return(unsigned char *buffer) { - if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { - return ((buffer[1] == 0x6A) || ((buffer[1] == 0x00) && (buffer[2] == 0x6A))); - } - else { - return (buffer[1] == 0x6A); - } -} - -static unsigned char output_script_is_op_create_or_call(unsigned char *buffer, - size_t size, - unsigned char value) { - return (!output_script_is_regular(buffer) && - !output_script_is_p2sh(buffer) && - !output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && - (buffer[0] < size) && - (buffer[buffer[0]] == value)); -} - -unsigned char output_script_is_op_create(unsigned char *buffer, - size_t size) { - return output_script_is_op_create_or_call(buffer, size, 0xC1); -} - -unsigned char output_script_is_op_call(unsigned char *buffer, - size_t size) { - return output_script_is_op_create_or_call(buffer, size, 0xC2); -} - -void public_key_hash160(unsigned char *in, unsigned short inlen, - unsigned char *out) { - cx_ripemd160_t riprip; - unsigned char buffer[32]; - cx_hash_sha256(in, inlen, buffer, 32); - cx_ripemd160_init(&riprip); - LEDGER_ASSERT(cx_hash_no_throw(&riprip.header, CX_LAST, buffer, 32, out, 20) == CX_OK, "hash160"); -} - -void compute_checksum(unsigned char* in, unsigned short inlen, unsigned char * output) { - unsigned char checksumBuffer[32]; - cx_hash_sha256(in, inlen, checksumBuffer, 32); - cx_hash_sha256(checksumBuffer, 32, checksumBuffer, 32); - - PRINTF("Checksum\n%.*H\n",4,checksumBuffer); - memmove(output, checksumBuffer, 4); -} - -unsigned short public_key_to_encoded_base58( - unsigned char *in, unsigned short inlen, unsigned char *out, - unsigned short outlen, unsigned short version, - unsigned char alreadyHashed) { - unsigned char tmpBuffer[34]; - - unsigned char versionSize = (version > 255 ? 2 : 1); - size_t outputLen; - - if (!alreadyHashed) { - PRINTF("To hash\n%.*H\n",inlen,in); - public_key_hash160(in, inlen, tmpBuffer + versionSize); - PRINTF("Hash160\n%.*H\n",20,(tmpBuffer + versionSize)); - if (version > 255) { - tmpBuffer[0] = (version >> 8); - tmpBuffer[1] = version; - } else { - tmpBuffer[0] = version; - } - } else { - memmove(tmpBuffer, in, 20 + versionSize); - } - - compute_checksum(tmpBuffer, 20 + versionSize, tmpBuffer + 20 + versionSize); - - outputLen = base58_encode(tmpBuffer, 24 + versionSize, (char *)out, outlen); - if (outputLen < 0) { - THROW(EXCEPTION); - } - return outputLen; -} - -void swap_bytes(unsigned char *target, unsigned char *source, - unsigned char size) { - unsigned char i; - for (i = 0; i < size; i++) { - target[i] = source[size - 1 - i]; - } -} - -/* -Checks if the values of a derivation path are within "normal" (arbitrary) ranges: -Account < 100, change == 1 or 0, address index < 50000 -Returns 1 if the path is unusual, or not compliant with BIP44*/ -unsigned char bip44_derivation_guard(unsigned char *bip32Path, bool is_change_path) { - - unsigned char path_len; - bip32_path_t bip32PathInt; - - path_len = bip32Path[0]; - if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { - return 1; - } - - // If the path length is not compliant with BIP44 or if the purpose don't match regular usage, return a warning - if(path_len != BIP44_PATH_LEN || - ((bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 44 && - (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 49 && - (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 84)) { - return 1; - } - - // If the coin type doesn't match, return a warning - if ((BIP44_COIN_TYPE != 0) && - (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != BIP44_COIN_TYPE) && - ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != BIP44_COIN_TYPE_2))) { - return 1; - } - - // If the account or address index is very high or if the change isn't 1, return a warning - if((bip32PathInt.path[BIP44_ACCOUNT_OFFSET]^0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || - bip32PathInt.path[BIP44_CHANGE_OFFSET] != is_change_path?1:0 || - bip32PathInt.path[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { - return 1; - } - - return 0; -} - -/* -Only enforce the structure or coin type for consumed UTXOs or a public address -Returns 0 if the path is non compliant, or 1 if compliant -*/ -unsigned char enforce_bip44_coin_type(unsigned char *bip32Path, bool for_pubkey) { - bip32_path_t bip32PathInt; - // No enforcement required - if (BIP44_COIN_TYPE == 0) { - return 1; - } - // Path is too short - always require a user validation if signing - if (bip32Path[0] < 2) { - return for_pubkey; - } - - if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { - return 1; - } - - // Path is not compliant with BIP 44 or derivatives - valid if not signing - if (!(((bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 44 || - (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 49 || - (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 84))) { - return for_pubkey; - } - - if (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == BIP44_COIN_TYPE) || - ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == BIP44_COIN_TYPE_2)) { - // Valid BIP 44 path - return 1; - } - // Everything else needs a user validation - return 0; -} - -// Print a BIP32 path as an ascii string to display on the device screen -// On the Ledger Blue, if the string is longer than 30 char, the string will be split in multiple lines -unsigned char bip32_print_path(unsigned char *bip32Path, char* out, unsigned char max_out_len) { - - unsigned char bip32PathLength; - unsigned char i, offset; - unsigned int current_level; - bool hardened; - - bip32PathLength = bip32Path[0]; - if (bip32PathLength > MAX_BIP32_PATH) { - THROW(INVALID_PARAMETER); - } - bip32Path++; - out[0] = ' '; - offset=1; - for (i = 0; i < bip32PathLength; i++) { - current_level = read_u32_be(bip32Path, 0); - hardened = (bool)(current_level & 0x80000000); - if(hardened) { - //remove hardening flag - current_level ^= 0x80000000; - } - bip32Path += 4; - snprintf(out+offset, max_out_len-offset, "%u", current_level); - offset = strnlen(out, max_out_len); - if(offset >= max_out_len - 2) THROW(EXCEPTION_OVERFLOW); - if(hardened) out[offset++] = '\''; - - out[offset++] = '/'; - out[offset] = '\0'; - } - // remove last '/' - out[offset-1] = '\0'; - - return offset -1; -} - -void transaction_add_output(unsigned char *hash160Address, - unsigned char *amount, unsigned char p2sh) { - const unsigned char *pre = (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE - : TRANSACTION_OUTPUT_SCRIPT_PRE); - const unsigned char *post = (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_POST - : TRANSACTION_OUTPUT_SCRIPT_POST); - unsigned char sizePre = (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) - : sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)); - unsigned char sizePost = (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST) - : sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)); - if (amount != NULL) { - swap_bytes(context_D.tmp, amount, 8); - context_D.tmp += 8; - } - memmove(context_D.tmp, (void *)pre, sizePre); - context_D.tmp += sizePre; - memmove(context_D.tmp, hash160Address, 20); - context_D.tmp += 20; - memmove(context_D.tmp, (void *)post, sizePost); - context_D.tmp += sizePost; -} - - -int sign_finalhash(unsigned char* path, size_t path_len, unsigned char *in, unsigned short inlen, - unsigned char *out, size_t* outlen, - unsigned char rfc6979) { - - unsigned int info = 0; - - io_seproxyhal_io_heartbeat(); - - bip32_path_t bip32Path; - bip32Path.length = path[0]; - - if (!parse_serialized_path(&bip32Path, path, path_len)) { - return -1; - } - - if (bip32_derive_ecdsa_sign_hash_256( - CX_CURVE_SECP256K1, - bip32Path.path, - bip32Path.length, - CX_LAST | (rfc6979 ? CX_RND_RFC6979 : CX_RND_TRNG), - CX_SHA256, - in, - inlen, - out, - outlen, - &info) != CX_OK) { - return -1; - } - - // Store information about the parity of the 'y' coordinate - if (info & CX_ECCINFO_PARITY_ODD) { - out[0] |= 0x01; - } - - io_seproxyhal_io_heartbeat(); - return 0; -} - -int get_public_key(unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode) { - - bip32_path_t bip32Path; - - if (!parse_serialized_path(&bip32Path, keyPath, keyPath_len)) { - return -1; - } - - if (bip32_derive_get_pubkey_256( - CX_CURVE_SECP256K1, - bip32Path.path, - bip32Path.length, - raw_pubkey, - chainCode, - CX_SHA512) != CX_OK) - { - return -1; - } - - return 0; -} diff --git a/src/internal.h b/src/internal.h deleted file mode 100644 index 1b84471e..00000000 --- a/src/internal.h +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef INTERNAL_H -#define INTERNAL_H - -#include "btchip.h" -#include "public_ram_variables.h" -#include "rom_variables.h" -#include "filesystem.h" -#include "bcd.h" -#include "ecc.h" -#include "helpers.h" -#include "transaction.h" - -#endif diff --git a/src/nvram.c b/src/nvram.c deleted file mode 100644 index a956708f..00000000 --- a/src/nvram.c +++ /dev/null @@ -1,22 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" - -#include "public_ram_variables.h" - -storage_t const N_real; diff --git a/src/public_ram_variables.c b/src/public_ram_variables.c deleted file mode 100644 index a0acc359..00000000 --- a/src/public_ram_variables.c +++ /dev/null @@ -1,21 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "public_ram_variables.h" - -context_t context_D; - diff --git a/src/rom_variables.c b/src/rom_variables.c deleted file mode 100644 index 375e3d86..00000000 --- a/src/rom_variables.c +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#include "internal.h" -#include "apdu_constants.h" - -unsigned char const SIGNMAGIC[] = {' ', 'S', 'i', 'g', 'n', 'e', 'd', ' ', 'M', - 'e', 's', 's', 'a', 'g', 'e', ':', '\n'}; - -unsigned char const OVERWINTER_PARAM_PREVOUTS[16] = { 'Z', 'c', 'a', 's', 'h', 'P', 'r', 'e', 'v', 'o', 'u', 't', 'H', 'a', 's', 'h' }; -unsigned char const OVERWINTER_PARAM_SEQUENCE[16] = { 'Z', 'c', 'a', 's', 'h', 'S', 'e', 'q', 'u', 'e', 'n', 'c', 'H', 'a', 's', 'h' }; -unsigned char const OVERWINTER_PARAM_OUTPUTS[16] = { 'Z', 'c', 'a', 's', 'h', 'O', 'u', 't', 'p', 'u', 't', 's', 'H', 'a', 's', 'h' }; -unsigned char const OVERWINTER_PARAM_SIGHASH[16] = { 'Z', 'c', 'a', 's', 'h', 'S', 'i', 'g', 'H', 'a', 's', 'h', 0, 0, 0, 0 }; -unsigned char const OVERWINTER_NO_JOINSPLITS[32] = { 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 }; - -unsigned char const DISPATCHER_CLA[] = { - CLA, // apdu_get_wallet_public_key, - CLA, // apdu_get_trusted_input, - CLA, // apdu_hash_input_start, - CLA, // apdu_hash_sign, - CLA, // apdu_hash_input_finalize_full, - CLA, // apdu_sign_message, - CLA, // apdu_get_firmware_version, - CLA, // apdu_get_coin_version -}; - -unsigned char const DISPATCHER_INS[] = { - INS_GET_WALLET_PUBLIC_KEY, // apdu_get_wallet_public_key, - INS_GET_TRUSTED_INPUT, // apdu_get_trusted_input, - INS_HASH_INPUT_START, // apdu_hash_input_start, - INS_HASH_SIGN, // apdu_hash_sign, - INS_HASH_INPUT_FINALIZE_FULL, // apdu_hash_input_finalize_full, - INS_SIGN_MESSAGE, // apdu_sign_message, - INS_GET_FIRMWARE_VERSION, // apdu_get_firmware_version, - INS_GET_COIN_VER, // apdu_get_coin_version -}; - -unsigned char const DISPATCHER_DATA_IN[] = { - 1, // apdu_get_wallet_public_key, - 1, // apdu_get_trusted_input, - 1, // apdu_hash_input_start, - 1, // apdu_hash_sign, - 1, // apdu_hash_input_finalize_full, - 1, // apdu_sign_message, - 0, // apdu_get_firmware_version, - 0, // apdu_get_coin_version -}; - -apduProcessingFunction const DISPATCHER_FUNCTIONS[] = { - apdu_get_wallet_public_key, - apdu_get_trusted_input, - apdu_hash_input_start, - apdu_hash_sign, - apdu_hash_input_finalize_full, - apdu_sign_message, - apdu_get_firmware_version, - apdu_get_coin_version, -}; diff --git a/src/rom_variables.h b/src/rom_variables.h deleted file mode 100644 index 82d5fa89..00000000 --- a/src/rom_variables.h +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#ifndef _ROM_VARIABLES_ -#define _ROM_VARIABLES_ - -#include "internal.h" - -#define SIGNMAGIC_LENGTH 17 - -extern unsigned char const SIGNMAGIC[SIGNMAGIC_LENGTH]; - -extern unsigned char const OVERWINTER_PARAM_PREVOUTS[16]; -extern unsigned char const OVERWINTER_PARAM_SEQUENCE[16]; -extern unsigned char const OVERWINTER_PARAM_OUTPUTS[16]; -extern unsigned char const OVERWINTER_PARAM_SIGHASH[16]; -extern unsigned char const OVERWINTER_NO_JOINSPLITS[32]; - -#define HDKEY_VERSION_LENGTH 4 - -#define APDU_DEBUG_LENGTH 0 - -#define APDU_NFCPAYMENT_LENGTH 0 - -#define APDU_BIP70_LENGTH 0 - -#define APDU_MOFN_LENGTH 0 - -#define APDU_KEYCARD_LENGTH 0 - -#define APDU_PORTABLE_LENGTH 5 - -#define APDU_KEYBOARD_LENGTH 0 - -#define APDU_LEGACY_SETUP_LENGTH 0 - -#define APDU_DEVELOPER_MODE_LENGTH 0 - -#define APDU_BASE_LENGTH 13 - -#define DISPATCHER_APDUS 13 - -typedef unsigned short (*apduProcessingFunction)(void); - -extern unsigned char const DISPATCHER_CLA[DISPATCHER_APDUS]; -extern unsigned char const DISPATCHER_INS[DISPATCHER_APDUS]; -extern unsigned char const DISPATCHER_DATA_IN[DISPATCHER_APDUS]; -extern apduProcessingFunction const DISPATCHER_FUNCTIONS[DISPATCHER_APDUS]; - -#endif /* _ROM_VARIABLES_ */ \ No newline at end of file diff --git a/src/swap/handle_get_printable_amount.c b/src/swap/handle_get_printable_amount.c deleted file mode 100644 index 8f9d8fd7..00000000 --- a/src/swap/handle_get_printable_amount.c +++ /dev/null @@ -1,21 +0,0 @@ -#include "handle_get_printable_amount.h" -#include "bcd.h" -#include - -void swap_handle_get_printable_amount(get_printable_amount_parameters_t* params) { - params->printable_amount[0] = 0; - if (params->amount_length > 8) { - PRINTF("Amount is too big"); - return; - } - unsigned char amount[8]; - memset(amount, 0, 8); - memcpy(amount + (8 - params->amount_length), params->amount, params->amount_length); - unsigned char coin_name_length = strlen(COIN_COINID_SHORT); - memmove(params->printable_amount, COIN_COINID_SHORT, coin_name_length); - params->printable_amount[coin_name_length] = ' '; - int res_length = convert_hex_amount_to_displayable_no_globals(amount, COIN_FLAGS, (uint8_t *)params->printable_amount + coin_name_length + 1); - params->printable_amount[res_length + coin_name_length + 1] = '\0'; - - return; -} \ No newline at end of file From 22a1e6feae8c9c06923938e8c63e9703dbbabd24 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 4 Apr 2024 12:49:22 +0200 Subject: [PATCH 74/85] Lint: apply clang-format --- .github/workflows/coding_style_checks.yml | 25 + lib-app-bitcoin/apdu/apdu_constants.h | 49 +- lib-app-bitcoin/apdu/dispatcher.c | 172 +- lib-app-bitcoin/app_main.c | 100 +- lib-app-bitcoin/context.c | 48 +- lib-app-bitcoin/context.h | 385 ++-- lib-app-bitcoin/customizable_helpers.c | 174 +- lib-app-bitcoin/customizable_helpers.h | 39 +- lib-app-bitcoin/customizable_ui.c | 197 +- lib-app-bitcoin/customizable_ui.h | 37 +- lib-app-bitcoin/display_utils.c | 216 ++- lib-app-bitcoin/display_utils.h | 26 +- lib-app-bitcoin/filesystem.h | 44 +- lib-app-bitcoin/filesystem_tx.h | 47 +- lib-app-bitcoin/handler/get_coin_version.c | 66 +- .../handler/get_firmware_version.c | 52 +- lib-app-bitcoin/handler/get_trusted_input.c | 132 +- .../handler/get_wallet_public_key.c | 309 +-- .../handler/hash_input_finalize_full.c | 1098 +++++------ lib-app-bitcoin/handler/hash_input_start.c | 195 +- lib-app-bitcoin/handler/hash_sign.c | 303 ++- lib-app-bitcoin/handler/sign_message.c | 450 +++-- lib-app-bitcoin/helpers.c | 358 ++-- lib-app-bitcoin/helpers.h | 60 +- lib-app-bitcoin/swap/handle_check_address.c | 226 ++- lib-app-bitcoin/swap/handle_check_address.h | 3 +- .../swap/handle_get_printable_amount.c | 31 +- .../swap/handle_get_printable_amount.h | 5 +- .../swap/handle_swap_sign_transaction.c | 100 +- .../swap/handle_swap_sign_transaction.h | 6 +- lib-app-bitcoin/transaction.c | 1694 ++++++++--------- lib-app-bitcoin/transaction.h | 34 +- lib-app-bitcoin/ui/display_variables.h | 51 +- lib-app-bitcoin/ui/extensions.h | 40 +- lib-app-bitcoin/ui/main_ui.c | 460 +++-- lib-app-bitcoin/ui/ui_bagl.c | 13 +- lib-app-bitcoin/ui/ui_menu_nbgl.c | 7 +- lib-app-bitcoin/ui/ui_nbgl.c | 229 ++- lib-app-bitcoin/utils/be_operations.c | 62 +- lib-app-bitcoin/utils/be_operations.h | 36 +- lib-app-bitcoin/utils/cashaddr.c | 189 +- lib-app-bitcoin/utils/segwit_addr.c | 274 +-- 42 files changed, 3974 insertions(+), 4068 deletions(-) create mode 100644 .github/workflows/coding_style_checks.yml diff --git a/.github/workflows/coding_style_checks.yml b/.github/workflows/coding_style_checks.yml new file mode 100644 index 00000000..797dfee4 --- /dev/null +++ b/.github/workflows/coding_style_checks.yml @@ -0,0 +1,25 @@ +name: Run coding style check through reusable workflow + +# This workflow will run linting checks to ensure a level of uniformization among all Ledger applications. +# +# The presence of this workflow is mandatory as a minimal level of linting is required. +# You are however free to modify the content of the .clang-format file and thus the coding style of your application. +# We simply ask you to not diverge too much from the linting of the Boilerplate application. + +on: + workflow_dispatch: + push: + branches: + - master + - main + - develop + pull_request: + +jobs: + check_linting: + name: Check linting using the reusable workflow + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_lint.yml@v1 + with: + source: './lib-app-bitcoin/' + extensions: 'h,c' + version: 11 diff --git a/lib-app-bitcoin/apdu/apdu_constants.h b/lib-app-bitcoin/apdu/apdu_constants.h index f5265425..ce412089 100644 --- a/lib-app-bitcoin/apdu/apdu_constants.h +++ b/lib-app-bitcoin/apdu/apdu_constants.h @@ -1,24 +1,24 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once -#include "os.h" #include "buffer.h" #include "macros.h" +#include "os.h" #define CLA 0xE0 @@ -49,12 +49,15 @@ #define ZCASH_USING_OVERWINTER 0x01 #define ZCASH_USING_OVERWINTER_SAPLING 0x02 -unsigned short handler_sign_message(buffer_t* buffer, uint8_t p1, uint8_t p2); -unsigned short handler_hash_sign(buffer_t* buffer, uint8_t p1, uint8_t p2); -unsigned short handler_hash_input_start(buffer_t* buffer, uint8_t p1, uint8_t p2); -unsigned short handler_hash_input_finalize_full(buffer_t* buffer, uint8_t p1, uint8_t p2); -unsigned short handler_get_wallet_public_key(buffer_t* buffer, uint8_t p1, uint8_t p2); -unsigned short handler_get_trusted_input(buffer_t* buffer, uint8_t p1, uint8_t p2); +unsigned short handler_sign_message(buffer_t *buffer, uint8_t p1, uint8_t p2); +unsigned short handler_hash_sign(buffer_t *buffer, uint8_t p1, uint8_t p2); +unsigned short handler_hash_input_start(buffer_t *buffer, uint8_t p1, + uint8_t p2); +unsigned short handler_hash_input_finalize_full(buffer_t *buffer, uint8_t p1, + uint8_t p2); +unsigned short handler_get_wallet_public_key(buffer_t *buffer, uint8_t p1, + uint8_t p2); +unsigned short handler_get_trusted_input(buffer_t *buffer, uint8_t p1, + uint8_t p2); unsigned short handler_get_firmware_version(void); unsigned short handler_get_coin_version(void); - diff --git a/lib-app-bitcoin/apdu/dispatcher.c b/lib-app-bitcoin/apdu/dispatcher.c index 7e2c6c0e..1c44fae9 100644 --- a/lib-app-bitcoin/apdu/dispatcher.c +++ b/lib-app-bitcoin/apdu/dispatcher.c @@ -15,103 +15,103 @@ * limitations under the License. *****************************************************************************/ -#include #include +#include #include "buffer.h" #include "io.h" #include "ledger_assert.h" -#include "dispatcher.h" #include "apdu_constants.h" +#include "dispatcher.h" int apdu_dispatcher(const command_t *cmd) { - LEDGER_ASSERT(cmd != NULL, "NULL cmd"); + LEDGER_ASSERT(cmd != NULL, "NULL cmd"); + + if (cmd->cla != CLA) { + return io_send_sw(SW_CLA_NOT_SUPPORTED); + } + + buffer_t buf = {0}; - if (cmd->cla != CLA) { - return io_send_sw(SW_CLA_NOT_SUPPORTED); + switch (cmd->ins) { + case INS_GET_WALLET_PUBLIC_KEY: + PRINTF("Get wallet public key\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); } + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_get_wallet_public_key(&buf, cmd->p1, cmd->p2); + + case INS_GET_TRUSTED_INPUT: + PRINTF("Get trusted input\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_get_trusted_input(&buf, cmd->p1, cmd->p2); + + case INS_HASH_INPUT_START: + PRINTF("Hash input start\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_hash_input_start(&buf, cmd->p1, cmd->p2); - buffer_t buf = {0}; - - switch (cmd->ins) { - case INS_GET_WALLET_PUBLIC_KEY: - PRINTF("Get wallet public key\n"); - if (!cmd->data) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - buf.ptr = cmd->data; - buf.size = cmd->lc; - buf.offset = 0; - return handler_get_wallet_public_key(&buf, cmd->p1, cmd->p2); - - case INS_GET_TRUSTED_INPUT: - PRINTF("Get trusted input\n"); - if (!cmd->data) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - - buf.ptr = cmd->data; - buf.size = cmd->lc; - buf.offset = 0; - return handler_get_trusted_input(&buf, cmd->p1, cmd->p2); - - case INS_HASH_INPUT_START: - PRINTF("Hash input start\n"); - if (!cmd->data) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - - buf.ptr = cmd->data; - buf.size = cmd->lc; - buf.offset = 0; - return handler_hash_input_start(&buf, cmd->p1, cmd->p2); - - case INS_HASH_SIGN: - PRINTF("Hash sign\n"); - if (!cmd->data) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - - buf.ptr = cmd->data; - buf.size = cmd->lc; - buf.offset = 0; - return handler_hash_sign(&buf, cmd->p1, cmd->p2); - - case INS_HASH_INPUT_FINALIZE_FULL: - PRINTF("Hash input finalize full\n"); - if (!cmd->data) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - - buf.ptr = cmd->data; - buf.size = cmd->lc; - buf.offset = 0; - return handler_hash_input_finalize_full(&buf, cmd->p1, cmd->p2); - - case INS_SIGN_MESSAGE: - PRINTF("Sign message\n"); - if (!cmd->data) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - - buf.ptr = cmd->data; - buf.size = cmd->lc; - buf.offset = 0; - return handler_sign_message(&buf, cmd->p1, cmd->p2); - - case INS_GET_FIRMWARE_VERSION: - PRINTF("Get firmware version\n"); - - return handler_get_firmware_version(); - - case INS_GET_COIN_VER: - PRINTF("Get coin version\n"); - - return handler_get_coin_version(); - - default: - PRINTF("Instruction not supported\n"); - return io_send_sw(SW_INS_NOT_SUPPORTED); + case INS_HASH_SIGN: + PRINTF("Hash sign\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_hash_sign(&buf, cmd->p1, cmd->p2); + + case INS_HASH_INPUT_FINALIZE_FULL: + PRINTF("Hash input finalize full\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_hash_input_finalize_full(&buf, cmd->p1, cmd->p2); + + case INS_SIGN_MESSAGE: + PRINTF("Sign message\n"); + if (!cmd->data) { + return io_send_sw(SW_INCORRECT_LENGTH); + } + + buf.ptr = cmd->data; + buf.size = cmd->lc; + buf.offset = 0; + return handler_sign_message(&buf, cmd->p1, cmd->p2); + + case INS_GET_FIRMWARE_VERSION: + PRINTF("Get firmware version\n"); + + return handler_get_firmware_version(); + + case INS_GET_COIN_VER: + PRINTF("Get coin version\n"); + + return handler_get_coin_version(); + + default: + PRINTF("Instruction not supported\n"); + return io_send_sw(SW_INS_NOT_SUPPORTED); + } } diff --git a/lib-app-bitcoin/app_main.c b/lib-app-bitcoin/app_main.c index c2f9a62b..9c32e633 100644 --- a/lib-app-bitcoin/app_main.c +++ b/lib-app-bitcoin/app_main.c @@ -1,72 +1,66 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ -#include "swap.h" + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #include "io.h" +#include "swap.h" -#include "context.h" #include "apdu_constants.h" +#include "context.h" #include "dispatcher.h" #include "ui.h" - void app_main(void) { - // Structured APDU command - command_t cmd; + // Structured APDU command + command_t cmd; - io_init(); + io_init(); - if (!G_called_from_swap) { - ui_idle_flow(); - } + if (!G_called_from_swap) { + ui_idle_flow(); + } - context_init(); + context_init(); - for (;;) { - // Length of APDU command received in G_io_apdu_buffer - int input_len = 0; + for (;;) { + // Length of APDU command received in G_io_apdu_buffer + int input_len = 0; - // Receive command bytes in G_io_apdu_buffer - if ((input_len = io_recv_command()) < 0) { - PRINTF("=> io_recv_command failure\n"); - return; - } + // Receive command bytes in G_io_apdu_buffer + if ((input_len = io_recv_command()) < 0) { + PRINTF("=> io_recv_command failure\n"); + return; + } - // Parse APDU command from G_io_apdu_buffer - if (!apdu_parser(&cmd, G_io_apdu_buffer, input_len)) { - PRINTF("=> /!\\ BAD LENGTH: %.*H\n", input_len, G_io_apdu_buffer); - io_send_sw(SW_INCORRECT_LENGTH); - continue; - } + // Parse APDU command from G_io_apdu_buffer + if (!apdu_parser(&cmd, G_io_apdu_buffer, input_len)) { + PRINTF("=> /!\\ BAD LENGTH: %.*H\n", input_len, G_io_apdu_buffer); + io_send_sw(SW_INCORRECT_LENGTH); + continue; + } - PRINTF("=> CLA=%02X | INS=%02X | P1=%02X | P2=%02X | Lc=%02X | CData=%.*H\n", - cmd.cla, - cmd.ins, - cmd.p1, - cmd.p2, - cmd.lc, - cmd.lc, - cmd.data); + PRINTF( + "=> CLA=%02X | INS=%02X | P1=%02X | P2=%02X | Lc=%02X | CData=%.*H\n", + cmd.cla, cmd.ins, cmd.p1, cmd.p2, cmd.lc, cmd.lc, cmd.data); - context.outLength = 0; + context.outLength = 0; - // Dispatch structured APDU command to handler - if (apdu_dispatcher(&cmd) < 0) { - PRINTF("=> apdu_dispatcher failure\n"); - return; - } + // Dispatch structured APDU command to handler + if (apdu_dispatcher(&cmd) < 0) { + PRINTF("=> apdu_dispatcher failure\n"); + return; } + } } diff --git a/lib-app-bitcoin/context.c b/lib-app-bitcoin/context.c index 2cf6da40..1f19b25b 100644 --- a/lib-app-bitcoin/context.c +++ b/lib-app-bitcoin/context.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #include "context.h" #include "filesystem.h" @@ -25,14 +25,12 @@ storage_t const N_real; * Initialize the application context on boot */ void context_init() { - PRINTF("Context init\n"); - PRINTF("Backup size %d\n", sizeof(g_nvram_data.bkp)); - memset(&context, 0, sizeof(context)); - context.currentOutputOffset = 0; - context.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; - memset(context.totalOutputAmount, 0, - sizeof(context.totalOutputAmount)); - context.changeOutputFound = 0; - context.segwitWarningSeen = 0; + PRINTF("Context init\n"); + PRINTF("Backup size %d\n", sizeof(g_nvram_data.bkp)); + memset(&context, 0, sizeof(context)); + context.currentOutputOffset = 0; + context.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; + memset(context.totalOutputAmount, 0, sizeof(context.totalOutputAmount)); + context.changeOutputFound = 0; + context.segwitWarningSeen = 0; } - diff --git a/lib-app-bitcoin/context.h b/lib-app-bitcoin/context.h index 48a4aa1a..08978a7a 100644 --- a/lib-app-bitcoin/context.h +++ b/lib-app-bitcoin/context.h @@ -1,30 +1,29 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once -#include "os.h" #include "cx.h" #include "filesystem_tx.h" +#include "os.h" #ifdef HAVE_NBGL #include "nbgl_types.h" #endif // HAVE_NBGL - #define MAX_OUTPUT_TO_CHECK 100 #define MAX_COIN_ID 13 #define MAX_SHORT_COIN_ID 5 @@ -35,222 +34,218 @@ * Current state of an untrusted transaction hashing */ enum transaction_state_e { - /** No transaction in progress */ - TRANSACTION_NONE = 0x00, - /** Transaction defined, waiting for an input to be hashed */ - TRANSACTION_DEFINED_WAIT_INPUT = 0x01, - /** Transaction defined, input hashing in progress, pending input script - data */ - TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT = 0x02, - /** Transaction defined, input hashing done, pending output hashing for this - input */ - TRANSACTION_INPUT_HASHING_DONE = 0x03, - /** Transaction defined, waiting for an output to be hashed */ - TRANSACTION_DEFINED_WAIT_OUTPUT = 0x04, - /** Transaction defined, output hashing in progress for a complex script, - pending output script data */ - TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT = 0x05, - /** Transaction defined, output hashing done, pending finalization */ - TRANSACTION_OUTPUT_HASHING_DONE = 0x06, - /** Extra data present */ - TRANSACTION_PROCESS_EXTRA = 0x07, - /** Transaction parsed */ - TRANSACTION_PARSED = 0x08, - /** Transaction parsed, ready to prepare for signature after validating the - user outputs */ - TRANSACTION_PRESIGN_READY = 0x09, - /** Transaction fully parsed, ready to be signed */ - TRANSACTION_SIGN_READY = 0x0a, + /** No transaction in progress */ + TRANSACTION_NONE = 0x00, + /** Transaction defined, waiting for an input to be hashed */ + TRANSACTION_DEFINED_WAIT_INPUT = 0x01, + /** Transaction defined, input hashing in progress, pending input script + data */ + TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT = 0x02, + /** Transaction defined, input hashing done, pending output hashing for this + input */ + TRANSACTION_INPUT_HASHING_DONE = 0x03, + /** Transaction defined, waiting for an output to be hashed */ + TRANSACTION_DEFINED_WAIT_OUTPUT = 0x04, + /** Transaction defined, output hashing in progress for a complex script, + pending output script data */ + TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT = 0x05, + /** Transaction defined, output hashing done, pending finalization */ + TRANSACTION_OUTPUT_HASHING_DONE = 0x06, + /** Extra data present */ + TRANSACTION_PROCESS_EXTRA = 0x07, + /** Transaction parsed */ + TRANSACTION_PARSED = 0x08, + /** Transaction parsed, ready to prepare for signature after validating the + user outputs */ + TRANSACTION_PRESIGN_READY = 0x09, + /** Transaction fully parsed, ready to be signed */ + TRANSACTION_SIGN_READY = 0x0a, }; typedef enum transaction_state_e transaction_state_t; enum output_parsing_state_e { - OUTPUT_PARSING_NONE = 0x00, - OUTPUT_PARSING_NUMBER_OUTPUTS = 0x01, - OUTPUT_PARSING_OUTPUT = 0x02, - OUTPUT_FINALIZE_TX = 0x03, - BIP44_CHANGE_PATH_VALIDATION = 0x04 + OUTPUT_PARSING_NONE = 0x00, + OUTPUT_PARSING_NUMBER_OUTPUTS = 0x01, + OUTPUT_PARSING_OUTPUT = 0x02, + OUTPUT_FINALIZE_TX = 0x03, + BIP44_CHANGE_PATH_VALIDATION = 0x04 }; typedef enum output_parsing_state_e output_parsing_state_t; - typedef union multi_hash { - cx_sha256_t sha256; - cx_blake2b_t blake2b; + cx_sha256_t sha256; + cx_blake2b_t blake2b; } multi_hash; struct segwit_hash_s { - union multi_hash hashPrevouts; + union multi_hash hashPrevouts; }; struct segwit_cache_s { - unsigned char hashedPrevouts[32]; - unsigned char hashedSequence[32]; - unsigned char hashedOutputs[32]; + unsigned char hashedPrevouts[32]; + unsigned char hashedSequence[32]; + unsigned char hashedOutputs[32]; }; /** * Structure defining an operation on a transaction */ struct transaction_context_s { - /** Transient over signing components */ - - /** Remaining number of inputs/outputs to process for this transaction */ - unsigned long int transactionRemainingInputsOutputs; - /** Index of the currently processed input/output for this transaction */ - unsigned long int transactionCurrentInputOutput; - /** Remaining script bytes to process for the current input or output */ - unsigned long int scriptRemaining; - - /** Persistent over signing components */ - - /** State of the transaction, type transaction_state_t */ - unsigned char transactionState; - /** Computed sum of transaction inputs or value of the output to convert to - * a trusted input */ - unsigned char transactionAmount[8]; - /** Flag indicating if this transaction has been processed before */ - unsigned char firstSigned; - /** If the transaction is relaxed */ - unsigned char relaxed; - /** If the transaction consumes a P2SH input */ - unsigned char consumeP2SH; + /** Transient over signing components */ + + /** Remaining number of inputs/outputs to process for this transaction */ + unsigned long int transactionRemainingInputsOutputs; + /** Index of the currently processed input/output for this transaction */ + unsigned long int transactionCurrentInputOutput; + /** Remaining script bytes to process for the current input or output */ + unsigned long int scriptRemaining; + + /** Persistent over signing components */ + + /** State of the transaction, type transaction_state_t */ + unsigned char transactionState; + /** Computed sum of transaction inputs or value of the output to convert to + * a trusted input */ + unsigned char transactionAmount[8]; + /** Flag indicating if this transaction has been processed before */ + unsigned char firstSigned; + /** If the transaction is relaxed */ + unsigned char relaxed; + /** If the transaction consumes a P2SH input */ + unsigned char consumeP2SH; }; typedef struct transaction_context_s transaction_context_t; struct tmp_output_s { - /** Change address if initialized */ - unsigned char changeAddress[20]; - /** Flag set if the change address was initialized */ - unsigned char changeInitialized; - /** Flag set if the change address was checked */ - unsigned char changeChecked; - /** Flag set if the change address can be submitted */ - unsigned char changeAccepted; - /** Flag set if the outputs have been fragmented */ - unsigned char multipleOutput; + /** Change address if initialized */ + unsigned char changeAddress[20]; + /** Flag set if the change address was initialized */ + unsigned char changeInitialized; + /** Flag set if the change address was checked */ + unsigned char changeChecked; + /** Flag set if the change address can be submitted */ + unsigned char changeAccepted; + /** Flag set if the outputs have been fragmented */ + unsigned char multipleOutput; }; typedef struct tmp_output_s tmp_output_t; struct context_s { - /** Index of the output to convert into a trusted input in a transaction */ - unsigned long int trustedInputIndex; - /** (Integrity protected) transaction context */ - transaction_context_t transactionContext; - - /** Full transaction hash context */ - union multi_hash transactionHashFull; - /** Authorization transaction hash context */ - cx_sha256_t transactionHashAuthorization; - /** Current hash to perform (TRANSACTION_HASH_) */ - unsigned char transactionHashOption; - - /* Segregated Witness changes */ - - union { - struct segwit_hash_s hash; - struct segwit_cache_s cache; - } segwit; - unsigned char transactionVersion[4]; - unsigned char inputValue[8]; - unsigned char usingSegwit; - unsigned char usingCashAddr; - unsigned char segwitParsedOnce; - /** Prevents display of segwit input warning at each InputHashStart APDU */ - unsigned char segwitWarningSeen; - - /* /Segregated Witness changes */ - - /** Size currently available to the transaction parser */ - unsigned char transactionDataRemaining; - /** Current pointer to the transaction buffer for the transaction parser */ - unsigned char *transactionBufferPointer; - /** Trusted Input index processed */ - unsigned char trustedInputProcessed; - /** Transaction input to catch for a Trusted Input lookup */ - unsigned long int transactionTargetInput; - - /** Length of the incoming command */ - unsigned short inLength; - /** Length of the outgoing command */ - unsigned short outLength; - - /** Status Word of the response */ - unsigned short sw; - - /** Current scratch buffer */ - unsigned char *tmp; - - // was previously in NVRAM - transaction_summary_t transactionSummary; - - - unsigned short hashedMessageLength; - - union { - tmp_output_t output; - } tmpCtx; - - unsigned char currentOutput[MAX_OUTPUT_TO_CHECK]; - unsigned short currentOutputOffset; - unsigned int remainingOutputs; - unsigned int totalOutputs; - unsigned int discardSize; - unsigned char outputParsingState; - unsigned char totalOutputAmount[8]; - unsigned char changeOutputFound; - - /* Overwinter */ - unsigned char usingOverwinter; - unsigned char overwinterSignReady; - unsigned char nVersionGroupId[4]; - unsigned char nExpiryHeight[4]; - unsigned char nLockTime[4]; - unsigned char sigHashType[4]; + /** Index of the output to convert into a trusted input in a transaction */ + unsigned long int trustedInputIndex; + /** (Integrity protected) transaction context */ + transaction_context_t transactionContext; + + /** Full transaction hash context */ + union multi_hash transactionHashFull; + /** Authorization transaction hash context */ + cx_sha256_t transactionHashAuthorization; + /** Current hash to perform (TRANSACTION_HASH_) */ + unsigned char transactionHashOption; + + /* Segregated Witness changes */ + + union { + struct segwit_hash_s hash; + struct segwit_cache_s cache; + } segwit; + unsigned char transactionVersion[4]; + unsigned char inputValue[8]; + unsigned char usingSegwit; + unsigned char usingCashAddr; + unsigned char segwitParsedOnce; + /** Prevents display of segwit input warning at each InputHashStart APDU */ + unsigned char segwitWarningSeen; + + /* /Segregated Witness changes */ + + /** Size currently available to the transaction parser */ + unsigned char transactionDataRemaining; + /** Current pointer to the transaction buffer for the transaction parser */ + unsigned char *transactionBufferPointer; + /** Trusted Input index processed */ + unsigned char trustedInputProcessed; + /** Transaction input to catch for a Trusted Input lookup */ + unsigned long int transactionTargetInput; + + /** Length of the incoming command */ + unsigned short inLength; + /** Length of the outgoing command */ + unsigned short outLength; + + /** Status Word of the response */ + unsigned short sw; + + /** Current scratch buffer */ + unsigned char *tmp; + + // was previously in NVRAM + transaction_summary_t transactionSummary; + + unsigned short hashedMessageLength; + + union { + tmp_output_t output; + } tmpCtx; + + unsigned char currentOutput[MAX_OUTPUT_TO_CHECK]; + unsigned short currentOutputOffset; + unsigned int remainingOutputs; + unsigned int totalOutputs; + unsigned int discardSize; + unsigned char outputParsingState; + unsigned char totalOutputAmount[8]; + unsigned char changeOutputFound; + + /* Overwinter */ + unsigned char usingOverwinter; + unsigned char overwinterSignReady; + unsigned char nVersionGroupId[4]; + unsigned char nExpiryHeight[4]; + unsigned char nLockTime[4]; + unsigned char sigHashType[4]; }; typedef struct context_s context_t; - /** * Structure to configure the bitcoin application for a given altcoin * */ typedef enum coin_flags_e { - FLAG_PEERCOIN_UNITS=1, - FLAG_PEERCOIN_SUPPORT=2, - FLAG_SEGWIT_CHANGE_SUPPORT=4 + FLAG_PEERCOIN_UNITS = 1, + FLAG_PEERCOIN_SUPPORT = 2, + FLAG_SEGWIT_CHANGE_SUPPORT = 4 } coin_flags_t; - typedef enum coin_kind_e { - COIN_KIND_BITCOIN_TESTNET, - COIN_KIND_BITCOIN, - COIN_KIND_BITCOIN_CASH, - COIN_KIND_BITCOIN_GOLD, - COIN_KIND_LITECOIN, - COIN_KIND_DOGE, - COIN_KIND_DASH, - COIN_KIND_ZCASH, - COIN_KIND_KOMODO, - COIN_KIND_RFU, - COIN_KIND_STRATIS, - COIN_KIND_PEERCOIN, - COIN_KIND_PIVX, - COIN_KIND_STEALTH, - COIN_KIND_VIACOIN, - COIN_KIND_VERTCOIN, - COIN_KIND_DIGIBYTE, - COIN_KIND_BITCOIN_PRIVATE, - COIN_KIND_XRHODIUM, - COIN_KIND_HORIZEN, - COIN_KIND_GAMECREDITS, - COIN_KIND_FIRO, - COIN_KIND_ZCLASSIC, - COIN_KIND_XSN, - COIN_KIND_NIX, - COIN_KIND_LBRY, - COIN_KIND_RESISTANCE, - COIN_KIND_RAVENCOIN, - COIN_KIND_HYDRA + COIN_KIND_BITCOIN_TESTNET, + COIN_KIND_BITCOIN, + COIN_KIND_BITCOIN_CASH, + COIN_KIND_BITCOIN_GOLD, + COIN_KIND_LITECOIN, + COIN_KIND_DOGE, + COIN_KIND_DASH, + COIN_KIND_ZCASH, + COIN_KIND_KOMODO, + COIN_KIND_RFU, + COIN_KIND_STRATIS, + COIN_KIND_PEERCOIN, + COIN_KIND_PIVX, + COIN_KIND_STEALTH, + COIN_KIND_VIACOIN, + COIN_KIND_VERTCOIN, + COIN_KIND_DIGIBYTE, + COIN_KIND_BITCOIN_PRIVATE, + COIN_KIND_XRHODIUM, + COIN_KIND_HORIZEN, + COIN_KIND_GAMECREDITS, + COIN_KIND_FIRO, + COIN_KIND_ZCLASSIC, + COIN_KIND_XSN, + COIN_KIND_NIX, + COIN_KIND_LBRY, + COIN_KIND_RESISTANCE, + COIN_KIND_RAVENCOIN, + COIN_KIND_HYDRA } coin_kind_t; void context_init(void); diff --git a/lib-app-bitcoin/customizable_helpers.c b/lib-app-bitcoin/customizable_helpers.c index 78e70a39..098e4670 100644 --- a/lib-app-bitcoin/customizable_helpers.c +++ b/lib-app-bitcoin/customizable_helpers.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #include "macros.h" #include "context.h" @@ -30,18 +30,16 @@ const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL const unsigned char ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { - 0x3D, 0xA9, - 0x14}; // script length, OP_HASH160, address length + 0x3D, 0xA9, 0x14}; // script length, OP_HASH160, address length const unsigned char ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = { - 0x87, // OP_EQUAL - 0x20, 0x9E, 0xC9, 0x84, 0x5A, 0xCB, 0x02, 0xFA, 0XB2, 0X4E, - 0x1C, 0x03, 0x68, 0xB3, 0xB5, 0x17, 0xC1, 0xA4, 0x48, 0x8F, - 0xBA, 0x97, 0xF0, 0xE3, 0x45, 0x9A, 0xC0, 0x53, 0xEA, 0x01, - 0x00, 0x00, 0x00, // ParamHash - 0x03, // Push 3 bytes to stack to make ParamHeight line up properly - 0xC0, 0x1F, 0x02, // ParamHeight (139200) -> hex -> endianness swapped - 0xB4}; // OP_CHECKBLOCKATHEIGHT + 0x87, // OP_EQUAL + 0x20, 0x9E, 0xC9, 0x84, 0x5A, 0xCB, 0x02, 0xFA, 0XB2, 0X4E, 0x1C, 0x03, + 0x68, 0xB3, 0xB5, 0x17, 0xC1, 0xA4, 0x48, 0x8F, 0xBA, 0x97, 0xF0, 0xE3, + 0x45, 0x9A, 0xC0, 0x53, 0xEA, 0x01, 0x00, 0x00, 0x00, // ParamHash + 0x03, // Push 3 bytes to stack to make ParamHeight line up properly + 0xC0, 0x1F, 0x02, // ParamHeight (139200) -> hex -> endianness swapped + 0xB4}; // OP_CHECKBLOCKATHEIGHT const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE[] = {0x16, 0x00, 0x14}; const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE[] = {0x22, 0x00, 0x20}; @@ -60,92 +58,88 @@ const unsigned char ZEN_OUTPUT_SCRIPT_POST[] = { }; // BIP0115 Replay Protection WEAK unsigned char output_script_is_regular(unsigned char *buffer) { - if (COIN_NATIVE_SEGWIT_PREFIX) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || - (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { - return 1; - } - } - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) && - (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, - TRANSACTION_OUTPUT_SCRIPT_POST, - sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { - return 1; + if (COIN_NATIVE_SEGWIT_PREFIX) { + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || + (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { + return 1; } - if (COIN_KIND == COIN_KIND_HORIZEN) { - if ((memcmp(buffer, ZEN_OUTPUT_SCRIPT_PRE, - sizeof(ZEN_OUTPUT_SCRIPT_PRE)) == 0) && - (memcmp(buffer + sizeof(ZEN_OUTPUT_SCRIPT_PRE) + 20, - ZEN_OUTPUT_SCRIPT_POST, - sizeof(ZEN_OUTPUT_SCRIPT_POST)) == 0)) { - return 1; - } + } + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) && + (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, + TRANSACTION_OUTPUT_SCRIPT_POST, + sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { + return 1; + } + if (COIN_KIND == COIN_KIND_HORIZEN) { + if ((memcmp(buffer, ZEN_OUTPUT_SCRIPT_PRE, sizeof(ZEN_OUTPUT_SCRIPT_PRE)) == + 0) && + (memcmp(buffer + sizeof(ZEN_OUTPUT_SCRIPT_PRE) + 20, + ZEN_OUTPUT_SCRIPT_POST, sizeof(ZEN_OUTPUT_SCRIPT_POST)) == 0)) { + return 1; } + } - return 0; + return 0; } WEAK unsigned char output_script_is_p2sh(unsigned char *buffer) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && - (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, - TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { - return 1; + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && + (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, + TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { + return 1; + } + if (COIN_KIND == COIN_KIND_HORIZEN) { + if ((memcmp(buffer, ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && + (memcmp(buffer + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, + ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { + return 1; } - if (COIN_KIND == COIN_KIND_HORIZEN) { - if ((memcmp(buffer, ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, - sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && - (memcmp(buffer + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, - ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, - sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { - return 1; - } - } - return 0; + } + return 0; } WEAK unsigned char output_script_is_native_witness(unsigned char *buffer) { - if (COIN_NATIVE_SEGWIT_PREFIX) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || - (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { - return 1; - } + if (COIN_NATIVE_SEGWIT_PREFIX) { + if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || + (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { + return 1; } - return 0; + } + return 0; } WEAK unsigned char output_script_is_op_return(unsigned char *buffer) { - if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { - return ((buffer[1] == 0x6A) || ((buffer[1] == 0x00) && (buffer[2] == 0x6A))); - } - else { - return (buffer[1] == 0x6A); - } + if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { + return ((buffer[1] == 0x6A) || + ((buffer[1] == 0x00) && (buffer[2] == 0x6A))); + } else { + return (buffer[1] == 0x6A); + } } WEAK unsigned char output_script_is_op_create_or_call(unsigned char *buffer, - size_t size, - unsigned char value) { - return (!output_script_is_regular(buffer) && - !output_script_is_p2sh(buffer) && - !output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && - (buffer[0] < size) && - (buffer[buffer[0]] == value)); + size_t size, + unsigned char value) { + return (!output_script_is_regular(buffer) && !output_script_is_p2sh(buffer) && + !output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && + (buffer[0] < size) && (buffer[buffer[0]] == value)); } WEAK unsigned char output_script_is_op_create(unsigned char *buffer, - size_t size) { - return output_script_is_op_create_or_call(buffer, size, 0xC1); + size_t size) { + return output_script_is_op_create_or_call(buffer, size, 0xC1); } WEAK unsigned char output_script_is_op_call(unsigned char *buffer, - size_t size) { - return output_script_is_op_create_or_call(buffer, size, 0xC2); + size_t size) { + return output_script_is_op_create_or_call(buffer, size, 0xC2); } - diff --git a/lib-app-bitcoin/customizable_helpers.h b/lib-app-bitcoin/customizable_helpers.h index ab7ac1c9..4f6e911c 100644 --- a/lib-app-bitcoin/customizable_helpers.h +++ b/lib-app-bitcoin/customizable_helpers.h @@ -1,31 +1,28 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once -#include "os.h" #include "cx.h" +#include "os.h" unsigned char output_script_is_regular(unsigned char *buffer); unsigned char output_script_is_p2sh(unsigned char *buffer); unsigned char output_script_is_op_return(unsigned char *buffer); unsigned char output_script_is_native_witness(unsigned char *buffer); -unsigned char output_script_is_op_create(unsigned char *buffer, - size_t size); -unsigned char output_script_is_op_call(unsigned char *buffer, - size_t size); - +unsigned char output_script_is_op_create(unsigned char *buffer, size_t size); +unsigned char output_script_is_op_call(unsigned char *buffer, size_t size); diff --git a/lib-app-bitcoin/customizable_ui.c b/lib-app-bitcoin/customizable_ui.c index 8a10da47..4e82ade0 100644 --- a/lib-app-bitcoin/customizable_ui.c +++ b/lib-app-bitcoin/customizable_ui.c @@ -1,117 +1,114 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #include "customizable_ui.h" -#include "customizable_helpers.h" -#include "helpers.h" -#include "context.h" -#include "display_variables.h" -#include "segwit_addr.h" -#include "cashaddr.h" #include "be_operations.h" +#include "cashaddr.h" +#include "context.h" +#include "customizable_helpers.h" #include "display_utils.h" +#include "display_variables.h" +#include "helpers.h" #include "read.h" +#include "segwit_addr.h" - -WEAK void get_address_from_output_script(unsigned char* script, int script_size, char* out, int out_size) { - if (output_script_is_op_return(script)) { - strncpy(out, "OP_RETURN", out_size); - return; - } - if ((COIN_KIND == COIN_KIND_HYDRA) && - output_script_is_op_create(script, script_size)) { - strncpy(out, "OP_CREATE", out_size); - return; - } - if ((COIN_KIND == COIN_KIND_HYDRA) && - output_script_is_op_call(script, script_size)) { - strncpy(out, "OP_CALL", out_size); - return; +WEAK void get_address_from_output_script(unsigned char *script, int script_size, + char *out, int out_size) { + if (output_script_is_op_return(script)) { + strncpy(out, "OP_RETURN", out_size); + return; + } + if ((COIN_KIND == COIN_KIND_HYDRA) && + output_script_is_op_create(script, script_size)) { + strncpy(out, "OP_CREATE", out_size); + return; + } + if ((COIN_KIND == COIN_KIND_HYDRA) && + output_script_is_op_call(script, script_size)) { + strncpy(out, "OP_CALL", out_size); + return; + } + if (output_script_is_native_witness(script)) { + if (COIN_NATIVE_SEGWIT_PREFIX) { + segwit_addr_encode( + out, (char *)PIC(COIN_NATIVE_SEGWIT_PREFIX), 0, + script + OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET, + script[OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET - 1]); } - if (output_script_is_native_witness(script)) { - if (COIN_NATIVE_SEGWIT_PREFIX) { - segwit_addr_encode( - out, (char *)PIC(COIN_NATIVE_SEGWIT_PREFIX), 0, - script + OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET, - script[OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET - 1]); - } - return; - } - unsigned char versionSize; - unsigned char address[22]; - unsigned short textSize; - int addressOffset = 3; - unsigned short version = COIN_P2SH_VERSION; + return; + } + unsigned char versionSize; + unsigned char address[22]; + unsigned short textSize; + int addressOffset = 3; + unsigned short version = COIN_P2SH_VERSION; - if (output_script_is_regular(script)) { - addressOffset = 4; - version = COIN_P2PKH_VERSION; - } + if (output_script_is_regular(script)) { + addressOffset = 4; + version = COIN_P2PKH_VERSION; + } - if (version > 255) { - versionSize = 2; - address[0] = (version >> 8); - address[1] = version; - } else { - versionSize = 1; - address[0] = version; - } - memmove(address + versionSize, script + addressOffset, 20); + if (version > 255) { + versionSize = 2; + address[0] = (version >> 8); + address[1] = version; + } else { + versionSize = 1; + address[0] = version; + } + memmove(address + versionSize, script + addressOffset, 20); - // Prepare address - if (context.usingCashAddr) { - cashaddr_encode( - address + versionSize, 20, (uint8_t *)out, out_size, - (version == COIN_P2SH_VERSION - ? CASHADDR_P2SH - : CASHADDR_P2PKH)); - } else { - textSize = public_key_to_encoded_base58( - address, 20 + versionSize, (unsigned char *)out, - out_size, version, 1); - out[textSize] = '\0'; - } + // Prepare address + if (context.usingCashAddr) { + cashaddr_encode( + address + versionSize, 20, (uint8_t *)out, out_size, + (version == COIN_P2SH_VERSION ? CASHADDR_P2SH : CASHADDR_P2PKH)); + } else { + textSize = public_key_to_encoded_base58( + address, 20 + versionSize, (unsigned char *)out, out_size, version, 1); + out[textSize] = '\0'; + } } WEAK uint8_t prepare_fees(void) { - if (context.transactionContext.relaxed) { - memmove(vars.tmp.feesAmount, "UNKNOWN", 7); - vars.tmp.feesAmount[7] = '\0'; - } else { - unsigned char fees[8]; - unsigned char borrow; + if (context.transactionContext.relaxed) { + memmove(vars.tmp.feesAmount, "UNKNOWN", 7); + vars.tmp.feesAmount[7] = '\0'; + } else { + unsigned char fees[8]; + unsigned char borrow; - borrow = transaction_amount_sub_be( - fees, context.transactionContext.transactionAmount, - context.totalOutputAmount); - if (borrow && COIN_KIND == COIN_KIND_KOMODO) { - memmove(vars.tmp.feesAmount, "REWARD", 6); - vars.tmp.feesAmount[6] = '\0'; - } - else { - if (borrow) { - PRINTF("Error : Fees not consistent"); - goto error; - } - format_sats_amount(COIN_COINID_SHORT, - (uint64_t)read_u64_be(fees, 0), // Cast prevents weird compilo bug - vars.tmp.feesAmount); - } + borrow = transaction_amount_sub_be( + fees, context.transactionContext.transactionAmount, + context.totalOutputAmount); + if (borrow && COIN_KIND == COIN_KIND_KOMODO) { + memmove(vars.tmp.feesAmount, "REWARD", 6); + vars.tmp.feesAmount[6] = '\0'; + } else { + if (borrow) { + PRINTF("Error : Fees not consistent"); + goto error; + } + format_sats_amount( + COIN_COINID_SHORT, + (uint64_t)read_u64_be(fees, 0), // Cast prevents weird compilo bug + vars.tmp.feesAmount); } - return 1; + } + return 1; error: - return 0; + return 0; } diff --git a/lib-app-bitcoin/customizable_ui.h b/lib-app-bitcoin/customizable_ui.h index 75649c2b..767b2211 100644 --- a/lib-app-bitcoin/customizable_ui.h +++ b/lib-app-bitcoin/customizable_ui.h @@ -1,23 +1,24 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ -#pragma once -#include "os.h" + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ +#pragma once #include "macros.h" +#include "os.h" -void get_address_from_output_script(unsigned char* script, int script_size, char* out, int out_size); +void get_address_from_output_script(unsigned char *script, int script_size, + char *out, int out_size); uint8_t prepare_fees(void); diff --git a/lib-app-bitcoin/display_utils.c b/lib-app-bitcoin/display_utils.c index 4bfae3f5..a871b8f2 100644 --- a/lib-app-bitcoin/display_utils.c +++ b/lib-app-bitcoin/display_utils.c @@ -1,132 +1,138 @@ +#include "filesystem_tx.h" +#include "ledger_assert.h" +#include "read.h" #include #include #include -#include "ledger_assert.h" -#include "read.h" -#include "filesystem_tx.h" #include "./display_utils.h" -// Division and modulus operators over uint64_t causes the inclusion of the __udivmoddi4 and other -// library functions that occupy more than 400 bytes. Since performance is not critical and division -// by 10 is sufficient, we avoid it with a binary search instead. +// Division and modulus operators over uint64_t causes the inclusion of the +// __udivmoddi4 and other library functions that occupy more than 400 bytes. +// Since performance is not critical and division by 10 is sufficient, we avoid +// it with a binary search instead. static uint64_t div10(uint64_t n) { - if (n < 10) return 0; // special case needed to make sure that n - 10 is safe - - // Since low, mid and high are always <= UINT64_MAX / 10, there is no risk of overflow - uint64_t low = 0; - uint64_t high = UINT64_MAX / 10; - - while (true) { - uint64_t mid = (low + high) / 2; - - // the result equals mid if and only if mid * 10 <= n < mid * 10 + 10 - // care is taken to make sure overflows and underflows are impossible - if (mid * 10 > n - 10 && n >= mid * 10) { - return mid; - } else if (n < mid * 10) { - high = mid - 1; - } else /* n >= 10 * mid + 10 */ { - low = mid + 1; - } + if (n < 10) + return 0; // special case needed to make sure that n - 10 is safe + + // Since low, mid and high are always <= UINT64_MAX / 10, there is no risk of + // overflow + uint64_t low = 0; + uint64_t high = UINT64_MAX / 10; + + while (true) { + uint64_t mid = (low + high) / 2; + + // the result equals mid if and only if mid * 10 <= n < mid * 10 + 10 + // care is taken to make sure overflows and underflows are impossible + if (mid * 10 > n - 10 && n >= mid * 10) { + return mid; + } else if (n < mid * 10) { + high = mid - 1; + } else /* n >= 10 * mid + 10 */ { + low = mid + 1; } + } } static uint64_t div100000000(uint64_t n) { - uint64_t res = n; - for (int i = 0; i < 8; i++) res = div10(res); - return res; + uint64_t res = n; + for (int i = 0; i < 8; i++) + res = div10(res); + return res; } static size_t n_digits(uint64_t number) { - size_t count = 0; - do { - count++; + size_t count = 0; + do { + count++; - // HACK: avoid __udivmoddi4 - // number /= 10; + // HACK: avoid __udivmoddi4 + // number /= 10; - number = div10(number); - } while (number != 0); - return count; + number = div10(number); + } while (number != 0); + return count; } -void format_sats_amount(const char *coin_name, - uint64_t amount, +void format_sats_amount(const char *coin_name, uint64_t amount, char out[static MAX_AMOUNT_LENGTH + 1]) { - size_t coin_name_len = strlen(coin_name); - strncpy(out, coin_name, MAX_AMOUNT_LENGTH + 1); - out[coin_name_len] = ' '; + size_t coin_name_len = strlen(coin_name); + strncpy(out, coin_name, MAX_AMOUNT_LENGTH + 1); + out[coin_name_len] = ' '; - char *amount_str = out + coin_name_len + 1; + char *amount_str = out + coin_name_len + 1; - // HACK: avoid __udivmoddi4 - // uint64_t integral_part = amount / 100000000; - // uint32_t fractional_part = (uint32_t) (amount % 100000000); - uint64_t integral_part = div100000000(amount); - uint32_t fractional_part = (uint32_t) (amount - integral_part * 100000000); - - // format the integral part, starting from the least significant digit - size_t integral_part_digit_count = n_digits(integral_part); - for (unsigned int i = 0; i < integral_part_digit_count; i++) { - // HACK: avoid __udivmoddi4 - // amount_str[integral_part_digit_count - 1 - i] = '0' + (integral_part % 10); - // integral_part /= 10; - - uint64_t tmp_quotient = div10(integral_part); - char tmp_remainder = (char) (integral_part - 10 * tmp_quotient); - amount_str[integral_part_digit_count - 1 - i] = '0' + tmp_remainder; - integral_part = tmp_quotient; - } + // HACK: avoid __udivmoddi4 + // uint64_t integral_part = amount / 100000000; + // uint32_t fractional_part = (uint32_t) (amount % 100000000); + uint64_t integral_part = div100000000(amount); + uint32_t fractional_part = (uint32_t)(amount - integral_part * 100000000); - if (fractional_part == 0) { - amount_str[integral_part_digit_count] = '\0'; - } else { - // format the fractional part (exactly 8 digits, possibly with trailing zeros) - amount_str[integral_part_digit_count] = '.'; - char *fract_part_str = amount_str + integral_part_digit_count + 1; - snprintf(fract_part_str, 8 + 1, "%08u", fractional_part); - - // drop trailing zeros - for (int i = 7; i > 0 && fract_part_str[i] == '0'; i--) { - fract_part_str[i] = '\0'; - } + // format the integral part, starting from the least significant digit + size_t integral_part_digit_count = n_digits(integral_part); + for (unsigned int i = 0; i < integral_part_digit_count; i++) { + // HACK: avoid __udivmoddi4 + // amount_str[integral_part_digit_count - 1 - i] = '0' + (integral_part % + // 10); integral_part /= 10; + + uint64_t tmp_quotient = div10(integral_part); + char tmp_remainder = (char)(integral_part - 10 * tmp_quotient); + amount_str[integral_part_digit_count - 1 - i] = '0' + tmp_remainder; + integral_part = tmp_quotient; + } + + if (fractional_part == 0) { + amount_str[integral_part_digit_count] = '\0'; + } else { + // format the fractional part (exactly 8 digits, possibly with trailing + // zeros) + amount_str[integral_part_digit_count] = '.'; + char *fract_part_str = amount_str + integral_part_digit_count + 1; + snprintf(fract_part_str, 8 + 1, "%08u", fractional_part); + + // drop trailing zeros + for (int i = 7; i > 0 && fract_part_str[i] == '0'; i--) { + fract_part_str[i] = '\0'; } + } } -unsigned char format_path(const unsigned char *bip32Path, char* out, unsigned char max_out_len) { - - unsigned char bip32PathLength; - unsigned char i, offset; - unsigned int current_level; - bool hardened; - - bip32PathLength = bip32Path[0]; - - LEDGER_ASSERT(bip32PathLength <= MAX_BIP32_PATH, "Wrong path len: %d", bip32PathLength); - - bip32Path++; - out[0] = ' '; - offset=1; - for (i = 0; i < bip32PathLength; i++) { - current_level = read_u32_be(bip32Path, 0); - hardened = (bool)(current_level & 0x80000000); - if(hardened) { - //remove hardening flag - current_level ^= 0x80000000; - } - bip32Path += 4; - snprintf(out+offset, max_out_len-offset, "%u", current_level); - offset = strnlen(out, max_out_len); - LEDGER_ASSERT(offset < max_out_len - 2, "OVERFLOW"); - if(hardened) out[offset++] = '\''; - - out[offset++] = '/'; - out[offset] = '\0'; - } - // remove last '/' - out[offset-1] = '\0'; +unsigned char format_path(const unsigned char *bip32Path, char *out, + unsigned char max_out_len) { - return offset -1; -} + unsigned char bip32PathLength; + unsigned char i, offset; + unsigned int current_level; + bool hardened; + bip32PathLength = bip32Path[0]; + + LEDGER_ASSERT(bip32PathLength <= MAX_BIP32_PATH, "Wrong path len: %d", + bip32PathLength); + + bip32Path++; + out[0] = ' '; + offset = 1; + for (i = 0; i < bip32PathLength; i++) { + current_level = read_u32_be(bip32Path, 0); + hardened = (bool)(current_level & 0x80000000); + if (hardened) { + // remove hardening flag + current_level ^= 0x80000000; + } + bip32Path += 4; + snprintf(out + offset, max_out_len - offset, "%u", current_level); + offset = strnlen(out, max_out_len); + LEDGER_ASSERT(offset < max_out_len - 2, "OVERFLOW"); + if (hardened) + out[offset++] = '\''; + + out[offset++] = '/'; + out[offset] = '\0'; + } + // remove last '/' + out[offset - 1] = '\0'; + + return offset - 1; +} diff --git a/lib-app-bitcoin/display_utils.h b/lib-app-bitcoin/display_utils.h index f5f28ba7..09cb9405 100644 --- a/lib-app-bitcoin/display_utils.h +++ b/lib-app-bitcoin/display_utils.h @@ -2,23 +2,25 @@ #include -// up to 5 chars for ticker, 1 space, up to 20 digits (20 = digits of 2^64), + 1 decimal separator +// up to 5 chars for ticker, 1 space, up to 20 digits (20 = digits of 2^64), + 1 +// decimal separator #define MAX_AMOUNT_LENGTH (5 + 1 + 20 + 1) /** - * Converts a 64-bits unsigned integer into a decimal rapresentation, where the `amount` is a - * multiple of 1/100_000_000th. Trailing decimal zeros are not appended (and no decimal point is - * present if the `amount` is a multiple of 100_000_000). The resulting string is prefixed with a - * ticker name (up to 5 characters long), followed by a space. + * Converts a 64-bits unsigned integer into a decimal rapresentation, where the + * `amount` is a multiple of 1/100_000_000th. Trailing decimal zeros are not + * appended (and no decimal point is present if the `amount` is a multiple of + * 100_000_000). The resulting string is prefixed with a ticker name (up to 5 + * characters long), followed by a space. * - * @param coin_name a zero-terminated ticker name, at most 5 characterso long (not including the - * terminating 0) + * @param coin_name a zero-terminated ticker name, at most 5 characterso long + * (not including the terminating 0) * @param amount the amount to format - * @param out the output array which must be at least MAX_AMOUNT_LENGTH + 1 bytes long + * @param out the output array which must be at least MAX_AMOUNT_LENGTH + 1 + * bytes long */ -void format_sats_amount(const char *coin_name, - uint64_t amount, +void format_sats_amount(const char *coin_name, uint64_t amount, char out[static MAX_AMOUNT_LENGTH + 1]); -unsigned char format_path(const unsigned char *bip32Path, char* out, unsigned char max_out_len); - +unsigned char format_path(const unsigned char *bip32Path, char *out, + unsigned char max_out_len); diff --git a/lib-app-bitcoin/filesystem.h b/lib-app-bitcoin/filesystem.h index fd615b04..208f644f 100644 --- a/lib-app-bitcoin/filesystem.h +++ b/lib-app-bitcoin/filesystem.h @@ -1,38 +1,38 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ -#pragma once +#pragma once -#include "os.h" #include "context.h" #include "filesystem_tx.h" +#include "os.h" enum family_e { - FAMILY_BITCOIN = 0x01, - FAMILY_PEERCOIN = 0x02, - FAMILY_STEALTH = 0x04 + FAMILY_BITCOIN = 0x01, + FAMILY_PEERCOIN = 0x02, + FAMILY_STEALTH = 0x04 }; typedef struct backup_area_s { - uint8_t trustedinput_key[32]; + uint8_t trustedinput_key[32]; } backup_area_t; typedef struct storage_s { - backup_area_t bkp; + backup_area_t bkp; } storage_t; // the global nvram memory variable diff --git a/lib-app-bitcoin/filesystem_tx.h b/lib-app-bitcoin/filesystem_tx.h index 8a413c08..f045e380 100644 --- a/lib-app-bitcoin/filesystem_tx.h +++ b/lib-app-bitcoin/filesystem_tx.h @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once #include "os.h" @@ -30,13 +30,14 @@ #define MAX_BIP44_ADDRESS_INDEX_RECOMMENDED 50000 struct transaction_summary_s { - unsigned char active; - unsigned char payToAddressVersion; - unsigned char payToScriptHashVersion; - unsigned char authorizationHash[32]; - unsigned char keyPath[MAX_BIP32_PATH_LENGTH]; - unsigned char transactionNonce[8]; // used to bind to the current set of inputs - unsigned short messageLength; - unsigned char sighashType; + unsigned char active; + unsigned char payToAddressVersion; + unsigned char payToScriptHashVersion; + unsigned char authorizationHash[32]; + unsigned char keyPath[MAX_BIP32_PATH_LENGTH]; + unsigned char + transactionNonce[8]; // used to bind to the current set of inputs + unsigned short messageLength; + unsigned char sighashType; }; typedef struct transaction_summary_s transaction_summary_t; diff --git a/lib-app-bitcoin/handler/get_coin_version.c b/lib-app-bitcoin/handler/get_coin_version.c index 6b2aebf9..5dbd8976 100644 --- a/lib-app-bitcoin/handler/get_coin_version.c +++ b/lib-app-bitcoin/handler/get_coin_version.c @@ -1,49 +1,49 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #include "io.h" #include "write.h" -#include "context.h" #include "apdu_constants.h" +#include "context.h" WEAK unsigned short handler_get_coin_version(void) { - uint8_t offset = 0; - size_t string_size; + uint8_t offset = 0; + size_t string_size; - write_u16_be(G_io_apdu_buffer, offset, COIN_P2PKH_VERSION); - offset += 2; + write_u16_be(G_io_apdu_buffer, offset, COIN_P2PKH_VERSION); + offset += 2; - write_u16_be(G_io_apdu_buffer, offset, COIN_P2SH_VERSION); - offset += 2; + write_u16_be(G_io_apdu_buffer, offset, COIN_P2SH_VERSION); + offset += 2; - G_io_apdu_buffer[offset++] = COIN_FAMILY; + G_io_apdu_buffer[offset++] = COIN_FAMILY; - string_size = strlen(COIN_COINID); - G_io_apdu_buffer[offset++] = string_size; - memmove(G_io_apdu_buffer + offset, COIN_COINID, string_size); - offset += string_size; + string_size = strlen(COIN_COINID); + G_io_apdu_buffer[offset++] = string_size; + memmove(G_io_apdu_buffer + offset, COIN_COINID, string_size); + offset += string_size; - string_size = strlen(COIN_COINID_SHORT); - G_io_apdu_buffer[offset++] = string_size; - memmove(G_io_apdu_buffer + offset, COIN_COINID_SHORT, string_size); - offset += string_size; + string_size = strlen(COIN_COINID_SHORT); + G_io_apdu_buffer[offset++] = string_size; + memmove(G_io_apdu_buffer + offset, COIN_COINID_SHORT, string_size); + offset += string_size; - context.outLength = offset; + context.outLength = offset; - return io_send_response_pointer(G_io_apdu_buffer, offset, SW_OK); + return io_send_response_pointer(G_io_apdu_buffer, offset, SW_OK); } diff --git a/lib-app-bitcoin/handler/get_firmware_version.c b/lib-app-bitcoin/handler/get_firmware_version.c index 6f11725a..7c9dad9a 100644 --- a/lib-app-bitcoin/handler/get_firmware_version.c +++ b/lib-app-bitcoin/handler/get_firmware_version.c @@ -1,23 +1,23 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #include "io.h" -#include "context.h" #include "apdu_constants.h" +#include "context.h" #define FEATURES_SELF_SCREEN_BUTTONS 0x02 #define FEATURES_NFC 0x08 @@ -35,16 +35,16 @@ WEAK unsigned short handler_get_firmware_version() { - G_io_apdu_buffer[0] = FEATURES; - G_io_apdu_buffer[1] = ARCH_ID; - G_io_apdu_buffer[2] = MAJOR_VERSION; - G_io_apdu_buffer[3] = MINOR_VERSION; - G_io_apdu_buffer[4] = PATCH_VERSION; - G_io_apdu_buffer[5] = 1; - G_io_apdu_buffer[6] = TCS_LOADER_PATCH_VERSION; - G_io_apdu_buffer[7] = MODE; + G_io_apdu_buffer[0] = FEATURES; + G_io_apdu_buffer[1] = ARCH_ID; + G_io_apdu_buffer[2] = MAJOR_VERSION; + G_io_apdu_buffer[3] = MINOR_VERSION; + G_io_apdu_buffer[4] = PATCH_VERSION; + G_io_apdu_buffer[5] = 1; + G_io_apdu_buffer[6] = TCS_LOADER_PATCH_VERSION; + G_io_apdu_buffer[7] = MODE; - context.outLength = 0x08; + context.outLength = 0x08; - return io_send_response_pointer(G_io_apdu_buffer, 0x08, SW_OK); + return io_send_response_pointer(G_io_apdu_buffer, 0x08, SW_OK); } diff --git a/lib-app-bitcoin/handler/get_trusted_input.c b/lib-app-bitcoin/handler/get_trusted_input.c index 6925b36b..dd634eae 100644 --- a/lib-app-bitcoin/handler/get_trusted_input.c +++ b/lib-app-bitcoin/handler/get_trusted_input.c @@ -1,89 +1,87 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ +#include "io.h" #include "lib_standard_app/read.h" #include "lib_standard_app/write.h" -#include "io.h" +#include "apdu_constants.h" #include "context.h" #include "filesystem.h" #include "transaction.h" -#include "apdu_constants.h" #define GET_TRUSTED_INPUT_P1_FIRST 0x00 #define GET_TRUSTED_INPUT_P1_NEXT 0x80 -WEAK unsigned short handler_get_trusted_input(buffer_t* buffer, uint8_t p1, uint8_t p2) { - unsigned char dataOffset = 0; +WEAK unsigned short handler_get_trusted_input(buffer_t *buffer, uint8_t p1, + uint8_t p2) { + unsigned char dataOffset = 0; - if (p1 == GET_TRUSTED_INPUT_P1_FIRST) { - // Initialize - context.transactionTargetInput = - read_u32_be(buffer->ptr, 0); - context.transactionContext.transactionState = - TRANSACTION_NONE; - context.trustedInputProcessed = 0; - context.transactionContext.consumeP2SH = 0; - dataOffset = 4; - context.transactionHashOption = TRANSACTION_HASH_FULL; - context.usingSegwit = 0; - context.usingOverwinter = 0; - } else if (p1 != GET_TRUSTED_INPUT_P1_NEXT) { - return io_send_sw(SW_INCORRECT_P1_P2); - } + if (p1 == GET_TRUSTED_INPUT_P1_FIRST) { + // Initialize + context.transactionTargetInput = read_u32_be(buffer->ptr, 0); + context.transactionContext.transactionState = TRANSACTION_NONE; + context.trustedInputProcessed = 0; + context.transactionContext.consumeP2SH = 0; + dataOffset = 4; + context.transactionHashOption = TRANSACTION_HASH_FULL; + context.usingSegwit = 0; + context.usingOverwinter = 0; + } else if (p1 != GET_TRUSTED_INPUT_P1_NEXT) { + return io_send_sw(SW_INCORRECT_P1_P2); + } - if (p2 != 0x00) { - return io_send_sw(SW_INCORRECT_P1_P2); - } + if (p2 != 0x00) { + return io_send_sw(SW_INCORRECT_P1_P2); + } - context.transactionBufferPointer = (uint8_t* ) buffer->ptr + dataOffset; - context.transactionDataRemaining = buffer->size - dataOffset; + context.transactionBufferPointer = (uint8_t *)buffer->ptr + dataOffset; + context.transactionDataRemaining = buffer->size - dataOffset; - transaction_parse(PARSE_MODE_TRUSTED_INPUT); + transaction_parse(PARSE_MODE_TRUSTED_INPUT); - if (context.transactionContext.transactionState == - TRANSACTION_PARSED) { + if (context.transactionContext.transactionState == TRANSACTION_PARSED) { - context.transactionContext.transactionState = - TRANSACTION_NONE; - if (!context.trustedInputProcessed) { - // Output was not found - return io_send_sw(SW_INCORRECT_DATA); - } + context.transactionContext.transactionState = TRANSACTION_NONE; + if (!context.trustedInputProcessed) { + // Output was not found + return io_send_sw(SW_INCORRECT_DATA); + } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, CX_LAST, - NULL, 0, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32)) { - return io_send_sw(SW_TECHNICAL_PROBLEM); - } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, CX_LAST, + NULL, 0, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32)) { + return io_send_sw(SW_TECHNICAL_PROBLEM); + } - // Otherwise prepare - cx_rng(G_io_apdu_buffer, 8); - G_io_apdu_buffer[0] = MAGIC_TRUSTED_INPUT; - G_io_apdu_buffer[1] = 0x00; - cx_hash_sha256(G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32, G_io_apdu_buffer + 4, 32); + // Otherwise prepare + cx_rng(G_io_apdu_buffer, 8); + G_io_apdu_buffer[0] = MAGIC_TRUSTED_INPUT; + G_io_apdu_buffer[1] = 0x00; + cx_hash_sha256(G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32, + G_io_apdu_buffer + 4, 32); - write_u32_le(G_io_apdu_buffer, 4 + 32, - context.transactionTargetInput); - memmove(G_io_apdu_buffer + 4 + 32 + 4, - context.transactionContext.transactionAmount, 8); + write_u32_le(G_io_apdu_buffer, 4 + 32, context.transactionTargetInput); + memmove(G_io_apdu_buffer + 4 + 32 + 4, + context.transactionContext.transactionAmount, 8); - cx_hmac_sha256((uint8_t *)g_nvram_data.bkp.trustedinput_key, - sizeof(g_nvram_data.bkp.trustedinput_key), G_io_apdu_buffer, - TRUSTED_INPUT_SIZE, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32); - context.outLength = TRUSTED_INPUT_TOTAL_SIZE; - } - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); + cx_hmac_sha256((uint8_t *)g_nvram_data.bkp.trustedinput_key, + sizeof(g_nvram_data.bkp.trustedinput_key), G_io_apdu_buffer, + TRUSTED_INPUT_SIZE, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, + 32); + context.outLength = TRUSTED_INPUT_TOTAL_SIZE; + } + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); } diff --git a/lib-app-bitcoin/handler/get_wallet_public_key.c b/lib-app-bitcoin/handler/get_wallet_public_key.c index d376bda6..d7edfb36 100644 --- a/lib-app-bitcoin/handler/get_wallet_public_key.c +++ b/lib-app-bitcoin/handler/get_wallet_public_key.c @@ -1,31 +1,31 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ +#include "apdu_constants.h" #include "context.h" #include "helpers.h" -#include "apdu_constants.h" #include "extensions.h" -#include "segwit_addr.h" #include "cashaddr.h" +#include "io.h" #include "lib_standard_app/read.h" +#include "segwit_addr.h" #include "swap.h" -#include "io.h" #define P1_NO_DISPLAY 0x00 #define P1_DISPLAY 0x01 @@ -36,151 +36,154 @@ #define P2_NATIVE_SEGWIT 0x02 #define P2_CASHADDR 0x03 -static int get_public_key_chain_code(const unsigned char* keyPath, size_t keyPath_len, unsigned char* publicKey, unsigned char* chainCode) { - uint8_t public_key[65]; - int keyLength = 0; - - if (get_public_key(keyPath, keyPath_len, public_key, chainCode)) { - return keyLength; - } - // Then encode it - compress_public_key_value(public_key); - keyLength = 33; +static int get_public_key_chain_code(const unsigned char *keyPath, + size_t keyPath_len, + unsigned char *publicKey, + unsigned char *chainCode) { + uint8_t public_key[65]; + int keyLength = 0; - memmove(publicKey, public_key, - sizeof(public_key)); + if (get_public_key(keyPath, keyPath_len, public_key, chainCode)) { return keyLength; -} - -WEAK unsigned short handler_get_wallet_public_key(buffer_t* buffer, uint8_t p1, uint8_t p2) { - unsigned char keyLength; - unsigned char chainCode[32]; - uint8_t is_derivation_path_unusual = 0; - - bool display = (p1 == P1_DISPLAY); - bool segwit = (p2 == P2_SEGWIT); - bool nativeSegwit = (p2 == P2_NATIVE_SEGWIT); - bool cashAddr = (p2 == P2_CASHADDR); - - if (display && G_called_from_swap) { - PRINTF("Refused INS when in SWAP mode\n"); - return io_send_sw(SW_INS_NOT_SUPPORTED); - } - - if (p1 != P1_NO_DISPLAY && p1 != P1_DISPLAY) { - PRINTF("Wrong P1 value\n"); - return io_send_sw(SW_INCORRECT_P1_P2); - } - - if (p2 == P2_NATIVE_SEGWIT && !COIN_NATIVE_SEGWIT_PREFIX) { - PRINTF("Wrong P2 value\n"); - return io_send_sw(SW_INCORRECT_P1_P2); - } - - if (p2 == P2_CASHADDR && COIN_KIND != COIN_KIND_BITCOIN_CASH) { - PRINTF("Wrong P2 value\n"); - return io_send_sw(SW_INCORRECT_P1_P2); - } - - if (p2 != P2_NATIVE_SEGWIT && p2 != P2_LEGACY && p2 != P2_SEGWIT && p2 != P2_CASHADDR) { - PRINTF("Wrong P2 value\n"); - return io_send_sw(SW_INCORRECT_P1_P2); - } - - if (buffer->size < 0x01) { - PRINTF("Wrong size\n"); - return io_send_sw(SW_INCORRECT_LENGTH); - } - - if (display) { - is_derivation_path_unusual = set_key_path_to_display(buffer->ptr); - } - - unsigned char bip44_enforced = enforce_bip44_coin_type(buffer->ptr, true); - - G_io_apdu_buffer[0] = 65; - keyLength = get_public_key_chain_code(buffer->ptr, MAX_BIP32_PATH_LENGTH, G_io_apdu_buffer + 1, chainCode); + } + // Then encode it + compress_public_key_value(public_key); + keyLength = 33; - if (keyLength == 0) { - return io_send_sw(SW_TECHNICAL_PROBLEM); - } + memmove(publicKey, public_key, sizeof(public_key)); + return keyLength; +} - if (cashAddr) { - uint8_t tmp[20]; - public_key_hash160(G_io_apdu_buffer + 1, // IN - keyLength, // INLEN - tmp); - keyLength = - cashaddr_encode(tmp, 20, G_io_apdu_buffer + 67, 50, CASHADDR_P2PKH); - } else if (!(segwit || nativeSegwit)) { - keyLength = public_key_to_encoded_base58( - G_io_apdu_buffer + 1, // IN - keyLength, // INLEN - G_io_apdu_buffer + 67, // OUT - 150, // MAXOUTLEN - COIN_P2PKH_VERSION, 0); +WEAK unsigned short handler_get_wallet_public_key(buffer_t *buffer, uint8_t p1, + uint8_t p2) { + unsigned char keyLength; + unsigned char chainCode[32]; + uint8_t is_derivation_path_unusual = 0; + + bool display = (p1 == P1_DISPLAY); + bool segwit = (p2 == P2_SEGWIT); + bool nativeSegwit = (p2 == P2_NATIVE_SEGWIT); + bool cashAddr = (p2 == P2_CASHADDR); + + if (display && G_called_from_swap) { + PRINTF("Refused INS when in SWAP mode\n"); + return io_send_sw(SW_INS_NOT_SUPPORTED); + } + + if (p1 != P1_NO_DISPLAY && p1 != P1_DISPLAY) { + PRINTF("Wrong P1 value\n"); + return io_send_sw(SW_INCORRECT_P1_P2); + } + + if (p2 == P2_NATIVE_SEGWIT && !COIN_NATIVE_SEGWIT_PREFIX) { + PRINTF("Wrong P2 value\n"); + return io_send_sw(SW_INCORRECT_P1_P2); + } + + if (p2 == P2_CASHADDR && COIN_KIND != COIN_KIND_BITCOIN_CASH) { + PRINTF("Wrong P2 value\n"); + return io_send_sw(SW_INCORRECT_P1_P2); + } + + if (p2 != P2_NATIVE_SEGWIT && p2 != P2_LEGACY && p2 != P2_SEGWIT && + p2 != P2_CASHADDR) { + PRINTF("Wrong P2 value\n"); + return io_send_sw(SW_INCORRECT_P1_P2); + } + + if (buffer->size < 0x01) { + PRINTF("Wrong size\n"); + return io_send_sw(SW_INCORRECT_LENGTH); + } + + if (display) { + is_derivation_path_unusual = set_key_path_to_display(buffer->ptr); + } + + unsigned char bip44_enforced = enforce_bip44_coin_type(buffer->ptr, true); + + G_io_apdu_buffer[0] = 65; + keyLength = get_public_key_chain_code(buffer->ptr, MAX_BIP32_PATH_LENGTH, + G_io_apdu_buffer + 1, chainCode); + + if (keyLength == 0) { + return io_send_sw(SW_TECHNICAL_PROBLEM); + } + + if (cashAddr) { + uint8_t tmp[20]; + public_key_hash160(G_io_apdu_buffer + 1, // IN + keyLength, // INLEN + tmp); + keyLength = + cashaddr_encode(tmp, 20, G_io_apdu_buffer + 67, 50, CASHADDR_P2PKH); + } else if (!(segwit || nativeSegwit)) { + keyLength = public_key_to_encoded_base58(G_io_apdu_buffer + 1, // IN + keyLength, // INLEN + G_io_apdu_buffer + 67, // OUT + 150, // MAXOUTLEN + COIN_P2PKH_VERSION, 0); + } else { + uint8_t tmp[22]; + tmp[0] = 0x00; + tmp[1] = 0x14; + public_key_hash160(G_io_apdu_buffer + 1, // IN + keyLength, // INLEN + tmp + 2 // OUT + ); + if (!nativeSegwit) { + keyLength = public_key_to_encoded_base58(tmp, // IN + 22, // INLEN + G_io_apdu_buffer + 67, // OUT + 150, // MAXOUTLEN + COIN_P2SH_VERSION, 0); } else { - uint8_t tmp[22]; - tmp[0] = 0x00; - tmp[1] = 0x14; - public_key_hash160(G_io_apdu_buffer + 1, // IN - keyLength, // INLEN - tmp + 2 // OUT - ); - if (!nativeSegwit) { - keyLength = public_key_to_encoded_base58( - tmp, // IN - 22, // INLEN - G_io_apdu_buffer + 67, // OUT - 150, // MAXOUTLEN - COIN_P2SH_VERSION, 0); - } else { - if (COIN_NATIVE_SEGWIT_PREFIX) { - keyLength = segwit_addr_encode( - (char *)(G_io_apdu_buffer + 67), - (char *)PIC(COIN_NATIVE_SEGWIT_PREFIX), 0, tmp + 2, 20); - if (keyLength == 1) { - keyLength = strlen((char *)(G_io_apdu_buffer + 67)); - } - } + if (COIN_NATIVE_SEGWIT_PREFIX) { + keyLength = segwit_addr_encode((char *)(G_io_apdu_buffer + 67), + (char *)PIC(COIN_NATIVE_SEGWIT_PREFIX), + 0, tmp + 2, 20); + if (keyLength == 1) { + keyLength = strlen((char *)(G_io_apdu_buffer + 67)); } + } } - G_io_apdu_buffer[66] = keyLength; - PRINTF("Length %d\n", keyLength); - // Restore for the full key component - G_io_apdu_buffer[1] = 0x04; - - // output chain code - memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, - sizeof(chainCode)); - context.outLength = 1 + 65 + 1 + keyLength + sizeof(chainCode); - - // privacy : force display the address if the path isn't standard - // and could reveal another fork holdings according to BIP 44 rules - if (!display && !bip44_enforced) { - display = true; - } - - if (display) { - if (keyLength > 50) { - return io_send_sw(SW_INCORRECT_DATA); - } - // Hax, avoid wasting space - memmove(G_io_apdu_buffer + 200, G_io_apdu_buffer + 67, keyLength); - G_io_apdu_buffer[200 + keyLength] = '\0'; - display_public_key(is_derivation_path_unusual); - return 0; + } + G_io_apdu_buffer[66] = keyLength; + PRINTF("Length %d\n", keyLength); + // Restore for the full key component + G_io_apdu_buffer[1] = 0x04; + + // output chain code + memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, + sizeof(chainCode)); + context.outLength = 1 + 65 + 1 + keyLength + sizeof(chainCode); + + // privacy : force display the address if the path isn't standard + // and could reveal another fork holdings according to BIP 44 rules + if (!display && !bip44_enforced) { + display = true; + } + + if (display) { + if (keyLength > 50) { + return io_send_sw(SW_INCORRECT_DATA); } - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); + // Hax, avoid wasting space + memmove(G_io_apdu_buffer + 200, G_io_apdu_buffer + 67, keyLength); + G_io_apdu_buffer[200 + keyLength] = '\0'; + display_public_key(is_derivation_path_unusual); + return 0; + } + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); } int user_action_display(unsigned char confirming) { - // confirm and finish the apdu exchange //spaghetti - if (confirming) { - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); + // confirm and finish the apdu exchange //spaghetti + if (confirming) { + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); - } else { - context.outLength = 0; - return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); - } + } else { + context.outLength = 0; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); + } } diff --git a/lib-app-bitcoin/handler/hash_input_finalize_full.c b/lib-app-bitcoin/handler/hash_input_finalize_full.c index 8fc61a9d..4c34b104 100644 --- a/lib-app-bitcoin/handler/hash_input_finalize_full.c +++ b/lib-app-bitcoin/handler/hash_input_finalize_full.c @@ -1,35 +1,35 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ // TODO Trustlet, BAGL : process each output separately. // review nvm_write policy #include "crypto_helpers.h" +#include "io.h" #include "read.h" #include "swap.h" -#include "io.h" +#include "apdu_constants.h" +#include "be_operations.h" #include "context.h" -#include "helpers.h" #include "customizable_helpers.h" -#include "apdu_constants.h" #include "extensions.h" +#include "helpers.h" #include "ui.h" -#include "be_operations.h" #define FINALIZE_P1_MORE 0x00 #define FINALIZE_P1_LAST 0x80 @@ -41,621 +41,579 @@ #define FLAG_CHANGE_VALIDATED 0x80 void hash_input_finalize_full_reset(void) { - context.currentOutputOffset = 0; - context.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; - memset(context.totalOutputAmount, 0, - sizeof(context.totalOutputAmount)); - context.changeOutputFound = 0; + context.currentOutputOffset = 0; + context.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; + memset(context.totalOutputAmount, 0, sizeof(context.totalOutputAmount)); + context.changeOutputFound = 0; } -static int check_output_displayable(bool* displayable) { - *displayable = true; - unsigned char amount[8], isOpReturn, isP2sh, isNativeSegwit, j, - nullAmount = 1; +static int check_output_displayable(bool *displayable) { + *displayable = true; + unsigned char amount[8], isOpReturn, isP2sh, isNativeSegwit, j, + nullAmount = 1; - for (j = 0; j < 8; j++) { - if (context.currentOutput[j] != 0) { - nullAmount = 0; - break; - } - } - if (!nullAmount) { - swap_bytes(amount, context.currentOutput, 8); - transaction_amount_add_be(context.totalOutputAmount, - context.totalOutputAmount, amount); + for (j = 0; j < 8; j++) { + if (context.currentOutput[j] != 0) { + nullAmount = 0; + break; } - isOpReturn = - output_script_is_op_return(context.currentOutput + 8); - isP2sh = output_script_is_p2sh(context.currentOutput + 8); - isNativeSegwit = output_script_is_native_witness( - context.currentOutput + 8); + } + if (!nullAmount) { + swap_bytes(amount, context.currentOutput, 8); + transaction_amount_add_be(context.totalOutputAmount, + context.totalOutputAmount, amount); + } + isOpReturn = output_script_is_op_return(context.currentOutput + 8); + isP2sh = output_script_is_p2sh(context.currentOutput + 8); + isNativeSegwit = output_script_is_native_witness(context.currentOutput + 8); #ifndef __clang_analyzer__ - unsigned char isOpCreate = - output_script_is_op_create(context.currentOutput + 8, - sizeof(context.currentOutput) - 8); - unsigned char isOpCall = - output_script_is_op_call(context.currentOutput + 8, - sizeof(context.currentOutput) - 8); - if (((COIN_KIND == COIN_KIND_HYDRA) && - !output_script_is_regular(context.currentOutput + 8) && - !isP2sh && !(nullAmount && isOpReturn) && !isOpCreate && !isOpCall) || - (!(COIN_KIND == COIN_KIND_HYDRA) && - !output_script_is_regular(context.currentOutput + 8) && - !isP2sh && !(nullAmount && isOpReturn))) { - PRINTF("Error : Unrecognized output script"); - return -1; - } + unsigned char isOpCreate = output_script_is_op_create( + context.currentOutput + 8, sizeof(context.currentOutput) - 8); + unsigned char isOpCall = output_script_is_op_call( + context.currentOutput + 8, sizeof(context.currentOutput) - 8); + if (((COIN_KIND == COIN_KIND_HYDRA) && + !output_script_is_regular(context.currentOutput + 8) && !isP2sh && + !(nullAmount && isOpReturn) && !isOpCreate && !isOpCall) || + (!(COIN_KIND == COIN_KIND_HYDRA) && + !output_script_is_regular(context.currentOutput + 8) && !isP2sh && + !(nullAmount && isOpReturn))) { + PRINTF("Error : Unrecognized output script"); + return -1; + } #endif - if (context.tmpCtx.output.changeInitialized && !isOpReturn) { - bool changeFound = false; - unsigned char addressOffset = - (isNativeSegwit ? OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET - : isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH - : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); - if (!isP2sh && - memcmp(context.currentOutput + 8 + addressOffset, - context.tmpCtx.output.changeAddress, - 20) == 0) { - changeFound = true; - } else if (isP2sh && context.usingSegwit) { - unsigned char changeSegwit[22]; - changeSegwit[0] = 0x00; - changeSegwit[1] = 0x14; - memmove(changeSegwit + 2, - context.tmpCtx.output.changeAddress, 20); - public_key_hash160(changeSegwit, 22, changeSegwit); - if (memcmp(context.currentOutput + 8 + addressOffset, - changeSegwit, 20) == 0) { - if (COIN_FLAGS & FLAG_SEGWIT_CHANGE_SUPPORT) { - changeFound = true; - } else { - // Attempt to avoid fatal failures on Bitcoin Cash - PRINTF("Error : Non spendable Segwit change"); - return -1; - } - } - } - if (changeFound) { - if (context.changeOutputFound) { - PRINTF("Error : Multiple change output found"); - return -1; - } - context.changeOutputFound = true; - *displayable = false; + if (context.tmpCtx.output.changeInitialized && !isOpReturn) { + bool changeFound = false; + unsigned char addressOffset = + (isNativeSegwit ? OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET + : isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH + : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); + if (!isP2sh && memcmp(context.currentOutput + 8 + addressOffset, + context.tmpCtx.output.changeAddress, 20) == 0) { + changeFound = true; + } else if (isP2sh && context.usingSegwit) { + unsigned char changeSegwit[22]; + changeSegwit[0] = 0x00; + changeSegwit[1] = 0x14; + memmove(changeSegwit + 2, context.tmpCtx.output.changeAddress, 20); + public_key_hash160(changeSegwit, 22, changeSegwit); + if (memcmp(context.currentOutput + 8 + addressOffset, changeSegwit, 20) == + 0) { + if (COIN_FLAGS & FLAG_SEGWIT_CHANGE_SUPPORT) { + changeFound = true; + } else { + // Attempt to avoid fatal failures on Bitcoin Cash + PRINTF("Error : Non spendable Segwit change"); + return -1; } + } } - return 0; + if (changeFound) { + if (context.changeOutputFound) { + PRINTF("Error : Multiple change output found"); + return -1; + } + context.changeOutputFound = true; + *displayable = false; + } + } + return 0; } -int handle_output_state(unsigned int* processed) { - uint32_t discardSize = 0; - context.discardSize = 0; - *processed = 0; - switch (context.outputParsingState) { - case OUTPUT_PARSING_NUMBER_OUTPUTS: { - context.totalOutputs = 0; - if (context.currentOutputOffset < 1) { - break; - } - if (context.currentOutput[0] < 0xFD) { - context.totalOutputs = context.remainingOutputs = - context.currentOutput[0]; - discardSize = 1; - context.outputParsingState = OUTPUT_PARSING_OUTPUT; - *processed = 1; - break; - } - if (context.currentOutput[0] == 0xFD) { - if (context.currentOutputOffset < 3) { - break; - } - context.totalOutputs = context.remainingOutputs = - (context.currentOutput[2] << 8) | - context.currentOutput[1]; - discardSize = 3; - context.outputParsingState = OUTPUT_PARSING_OUTPUT; - *processed = 1; - break; - } else if (context.currentOutput[0] == 0xFE) { - if (context.currentOutputOffset < 5) { - break; - } - context.totalOutputs = context.remainingOutputs = - read_u32_le(context.currentOutput, 1); - discardSize = 5; - context.outputParsingState = OUTPUT_PARSING_OUTPUT; - *processed = 1; - break; - } else { - return -1; - } - } break; - - case OUTPUT_PARSING_OUTPUT: { - unsigned int scriptSize = 0; - if (context.currentOutputOffset < 9) { - break; - } - if (context.currentOutput[8] < 0xFD) { - scriptSize = context.currentOutput[8]; - discardSize = 1; - } else if (context.currentOutput[8] == 0xFD) { - if (context.currentOutputOffset < 9 + 2) { - break; - } - scriptSize = read_u32_le(context.currentOutput, 9); - discardSize = 3; - } else { - // Unrealistically large script - return -1; - } - if (context.currentOutputOffset < - 8 + discardSize + scriptSize) { - discardSize = 0; - break; - } +int handle_output_state(unsigned int *processed) { + uint32_t discardSize = 0; + context.discardSize = 0; + *processed = 0; + switch (context.outputParsingState) { + case OUTPUT_PARSING_NUMBER_OUTPUTS: { + context.totalOutputs = 0; + if (context.currentOutputOffset < 1) { + break; + } + if (context.currentOutput[0] < 0xFD) { + context.totalOutputs = context.remainingOutputs = + context.currentOutput[0]; + discardSize = 1; + context.outputParsingState = OUTPUT_PARSING_OUTPUT; + *processed = 1; + break; + } + if (context.currentOutput[0] == 0xFD) { + if (context.currentOutputOffset < 3) { + break; + } + context.totalOutputs = context.remainingOutputs = + (context.currentOutput[2] << 8) | context.currentOutput[1]; + discardSize = 3; + context.outputParsingState = OUTPUT_PARSING_OUTPUT; + *processed = 1; + break; + } else if (context.currentOutput[0] == 0xFE) { + if (context.currentOutputOffset < 5) { + break; + } + context.totalOutputs = context.remainingOutputs = + read_u32_le(context.currentOutput, 1); + discardSize = 5; + context.outputParsingState = OUTPUT_PARSING_OUTPUT; + *processed = 1; + break; + } else { + return -1; + } + } break; - *processed = 1; + case OUTPUT_PARSING_OUTPUT: { + unsigned int scriptSize = 0; + if (context.currentOutputOffset < 9) { + break; + } + if (context.currentOutput[8] < 0xFD) { + scriptSize = context.currentOutput[8]; + discardSize = 1; + } else if (context.currentOutput[8] == 0xFD) { + if (context.currentOutputOffset < 9 + 2) { + break; + } + scriptSize = read_u32_le(context.currentOutput, 9); + discardSize = 3; + } else { + // Unrealistically large script + return -1; + } + if (context.currentOutputOffset < 8 + discardSize + scriptSize) { + discardSize = 0; + break; + } - discardSize += 8 + scriptSize; + *processed = 1; - bool displayable; - if (check_output_displayable(&displayable)) { - return -1; - } + discardSize += 8 + scriptSize; - if (displayable) { - // The output can be processed by the UI + bool displayable; + if (check_output_displayable(&displayable)) { + return -1; + } - context.discardSize = discardSize; - discardSize = 0; - *processed = 2; - } else { - context.remainingOutputs--; - } - } break; + if (displayable) { + // The output can be processed by the UI - default: - return -1; + context.discardSize = discardSize; + discardSize = 0; + *processed = 2; + } else { + context.remainingOutputs--; } + } break; - if (discardSize != 0) { - memmove(context.currentOutput, - context.currentOutput + discardSize, - context.currentOutputOffset - discardSize); - context.currentOutputOffset -= discardSize; - } + default: + return -1; + } - return 0; + if (discardSize != 0) { + memmove(context.currentOutput, context.currentOutput + discardSize, + context.currentOutputOffset - discardSize); + context.currentOutputOffset -= discardSize; + } + + return 0; } // out should be 32 bytes, even only 20 bytes is significant for output -int get_pubkey_hash160(unsigned char* keyPath, size_t keyPath_len, unsigned char* out) { - cx_ecfp_public_key_t public_key; - if (get_public_key(keyPath, keyPath_len, public_key.W, NULL)) { - return -1; - } - compress_public_key_value(public_key.W); - - public_key_hash160( - public_key.W, // IN - 33, // INLEN - out // OUT - ); - return 0; +int get_pubkey_hash160(unsigned char *keyPath, size_t keyPath_len, + unsigned char *out) { + cx_ecfp_public_key_t public_key; + if (get_public_key(keyPath, keyPath_len, public_key.W, NULL)) { + return -1; + } + compress_public_key_value(public_key.W); + + public_key_hash160(public_key.W, // IN + 33, // INLEN + out // OUT + ); + return 0; } -static unsigned short hash_input_finalize_full_internal(transaction_summary_t *transactionSummary, buffer_t* buffer, uint8_t p1, uint8_t p2, bool *async) { - unsigned char authorizationHash[32]; - unsigned short sw = SW_OK; - unsigned char *target = G_io_apdu_buffer; - unsigned char hashOffset = 0; - - (void) p2; - - if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && - (p1 != FINALIZE_P1_CHANGEINFO)) { - return SW_INCORRECT_P1_P2; - } - - // See if there is a hashing offset - if (context.usingSegwit && - (context.tmpCtx.output.multipleOutput == 0)) { - unsigned char firstByte = buffer->ptr[0]; - if (firstByte < 0xfd) { - hashOffset = 1; - } else if (firstByte == 0xfd) { - hashOffset = 3; - } else if (firstByte == 0xfe) { - hashOffset = 5; - } +static unsigned short +hash_input_finalize_full_internal(transaction_summary_t *transactionSummary, + buffer_t *buffer, uint8_t p1, uint8_t p2, + bool *async) { + unsigned char authorizationHash[32]; + unsigned short sw = SW_OK; + unsigned char *target = G_io_apdu_buffer; + unsigned char hashOffset = 0; + + (void)p2; + + if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && + (p1 != FINALIZE_P1_CHANGEINFO)) { + return SW_INCORRECT_P1_P2; + } + + // See if there is a hashing offset + if (context.usingSegwit && (context.tmpCtx.output.multipleOutput == 0)) { + unsigned char firstByte = buffer->ptr[0]; + if (firstByte < 0xfd) { + hashOffset = 1; + } else if (firstByte == 0xfd) { + hashOffset = 3; + } else if (firstByte == 0xfe) { + hashOffset = 5; + } + } + + // Check state + if (context.transactionContext.transactionState != + TRANSACTION_PRESIGN_READY) { + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; + } + + if (p1 == FINALIZE_P1_CHANGEINFO) { + if (!context.transactionContext.firstSigned) { + // Already validated, should be prevented on the client side + return SW_OK; + } + if (!context.tmpCtx.output.changeAccepted) { + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; } + memset(transactionSummary, 0, sizeof(transaction_summary_t)); + if (buffer->ptr[0] == 0x00) { + // Called with no change path, abort, should be prevented on + // the client side + return SW_OK; + } + memmove(transactionSummary->keyPath, buffer->ptr, MAX_BIP32_PATH_LENGTH); + + if (get_pubkey_hash160(transactionSummary->keyPath, + sizeof(transactionSummary->keyPath), + context.tmpCtx.output.changeAddress)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + PRINTF("Change address = %.*H\n", 20, context.tmpCtx.output.changeAddress); + + context.tmpCtx.output.changeInitialized = 1; + context.tmpCtx.output.changeAccepted = 0; - // Check state - if (context.transactionContext.transactionState != - TRANSACTION_PRESIGN_READY) { + // if the bip44 change path provided is not canonical or its index are + // unsual, ask for user approval + if (bip44_derivation_guard(transactionSummary->keyPath, true)) { + if (G_called_from_swap) { + PRINTF("In swap mode only standart path is allowed\n"); sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; goto discardTransaction; + } + *async = true; + context.outputParsingState = BIP44_CHANGE_PATH_VALIDATION; + request_change_path_approval(transactionSummary->keyPath); } - if (p1 == FINALIZE_P1_CHANGEINFO) { - if (!context.transactionContext.firstSigned) { - // Already validated, should be prevented on the client side - return SW_OK; - } - if (!context.tmpCtx.output.changeAccepted) { - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - memset(transactionSummary, 0, - sizeof(transaction_summary_t)); - if (buffer->ptr[0] == 0x00) { - // Called with no change path, abort, should be prevented on - // the client side - return SW_OK; - } - memmove(transactionSummary->keyPath, - buffer->ptr, - MAX_BIP32_PATH_LENGTH); + return SW_OK; + } - if (get_pubkey_hash160(transactionSummary->keyPath, sizeof(transactionSummary->keyPath), context.tmpCtx.output.changeAddress)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - PRINTF("Change address = %.*H\n", 20, context.tmpCtx.output.changeAddress); - - context.tmpCtx.output.changeInitialized = 1; - context.tmpCtx.output.changeAccepted = 0; - - // if the bip44 change path provided is not canonical or its index are unsual, ask for user approval - if(bip44_derivation_guard(transactionSummary->keyPath, true)) { - if (G_called_from_swap) { - PRINTF("In swap mode only standart path is allowed\n"); - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - *async = true; - context.outputParsingState = BIP44_CHANGE_PATH_VALIDATION; - request_change_path_approval(transactionSummary->keyPath); - } - - return SW_OK; + // Always update the transaction & authorization hashes with the + // given data + // For SegWit, this has been reset to hold hashOutputs + if (!context.segwitParsedOnce) { + if ((int)(buffer->size - hashOffset) < 0) { + sw = SW_INCORRECT_DATA; + goto discardTransaction; } - - // Always update the transaction & authorization hashes with the - // given data - // For SegWit, this has been reset to hold hashOutputs - if (!context.segwitParsedOnce) { - if ((int)(buffer->size - hashOffset) < 0) { - sw = SW_INCORRECT_DATA; - goto discardTransaction; - } - if (context.usingOverwinter) { - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, buffer->ptr + hashOffset, buffer->size - hashOffset, NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - } - else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", buffer->size - hashOffset, buffer->ptr + hashOffset); - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - buffer->ptr + hashOffset, - buffer->size - hashOffset, NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - } + if (context.usingOverwinter) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, + buffer->ptr + hashOffset, buffer->size - hashOffset, + NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + } else { + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", buffer->size - hashOffset, + buffer->ptr + hashOffset); + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + buffer->ptr + hashOffset, buffer->size - hashOffset, + NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + } + } + + if (context.transactionContext.firstSigned) { + if ((context.currentOutputOffset + buffer->size) > + sizeof(context.currentOutput)) { + PRINTF("Output is too long to be checked\n"); + sw = SW_INCORRECT_DATA; + goto discardTransaction; + } + memmove(context.currentOutput + context.currentOutputOffset, buffer->ptr, + buffer->size); + context.currentOutputOffset += buffer->size; + + unsigned int processed = 1; + while (processed == 1) { + if (handle_output_state(&processed)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } } - if (context.transactionContext.firstSigned) { - if ((context.currentOutputOffset + buffer->size) > - sizeof(context.currentOutput)) { - PRINTF("Output is too long to be checked\n"); - sw = SW_INCORRECT_DATA; - goto discardTransaction; - } - memmove(context.currentOutput + - context.currentOutputOffset, - buffer->ptr, buffer->size); - context.currentOutputOffset += buffer->size; - - unsigned int processed = 1; - while (processed == 1) { - if (handle_output_state(&processed)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - } - - if (processed == 2) { - *async = true; - } - // Finalize the TX if necessary - - if ((context.remainingOutputs == 0) && - (!*async)) { - *async = true; - context.outputParsingState = - OUTPUT_FINALIZE_TX; - } + if (processed == 2) { + *async = true; } + // Finalize the TX if necessary - if (p1 == FINALIZE_P1_MORE) { - if (!context.usingSegwit) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", buffer->size, buffer->ptr); - if (cx_hash_no_throw( - &context.transactionHashAuthorization.header, - 0, buffer->ptr, buffer->size, - NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - } - G_io_apdu_buffer[0] = 0x00; - context.outLength = 1; - context.tmpCtx.output.multipleOutput = 1; - return SW_OK; + if ((context.remainingOutputs == 0) && (!*async)) { + *async = true; + context.outputParsingState = OUTPUT_FINALIZE_TX; } + } + if (p1 == FINALIZE_P1_MORE) { if (!context.usingSegwit) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", buffer->size, buffer->ptr); - if (cx_hash_no_throw(&context.transactionHashAuthorization.header, - CX_LAST, buffer->ptr, - buffer->size, authorizationHash, 32)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", buffer->size, buffer->ptr); + if (cx_hash_no_throw(&context.transactionHashAuthorization.header, 0, + buffer->ptr, buffer->size, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } } - - if (context.usingSegwit) { - if (!context.segwitParsedOnce) { - if (context.usingOverwinter) { - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, CX_LAST, context.segwit.cache.hashedOutputs, 0, context.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - } - else { - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, - CX_LAST, - context.segwit.cache.hashedOutputs, 0, - context.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, - CX_LAST, - context.segwit.cache.hashedOutputs, - sizeof(context.segwit.cache.hashedOutputs), - context.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - } - PRINTF("hashOutputs\n%.*H\n",32,context.segwit.cache.hashedOutputs); - if (cx_hash_no_throw( - &context.transactionHashAuthorization.header, - CX_LAST, G_io_apdu_buffer, 0, authorizationHash, 32)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); - } else { - if (cx_hash_no_throw( - &context.transactionHashAuthorization.header, - CX_LAST, - (unsigned char *)&context.segwit.cache, - sizeof(context.segwit.cache), - authorizationHash, 32)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); - } + G_io_apdu_buffer[0] = 0x00; + context.outLength = 1; + context.tmpCtx.output.multipleOutput = 1; + return SW_OK; + } + + if (!context.usingSegwit) { + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", buffer->size, buffer->ptr); + if (cx_hash_no_throw(&context.transactionHashAuthorization.header, CX_LAST, + buffer->ptr, buffer->size, authorizationHash, 32)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; } + } - if (context.transactionContext.firstSigned) { - if (!context.tmpCtx.output.changeInitialized) { - memset(transactionSummary, 0, - sizeof(transaction_summary_t)); - } - - transactionSummary->payToAddressVersion = COIN_P2PKH_VERSION; - transactionSummary->payToScriptHashVersion = COIN_P2SH_VERSION; + if (context.usingSegwit) { + if (!context.segwitParsedOnce) { + if (context.usingOverwinter) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, + CX_LAST, context.segwit.cache.hashedOutputs, 0, + context.segwit.cache.hashedOutputs, 32)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + } else { + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, + CX_LAST, context.segwit.cache.hashedOutputs, 0, + context.segwit.cache.hashedOutputs, 32)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, + CX_LAST, context.segwit.cache.hashedOutputs, + sizeof(context.segwit.cache.hashedOutputs), + context.segwit.cache.hashedOutputs, 32)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + } + PRINTF("hashOutputs\n%.*H\n", 32, context.segwit.cache.hashedOutputs); + if (cx_hash_no_throw(&context.transactionHashAuthorization.header, + CX_LAST, G_io_apdu_buffer, 0, authorizationHash, + 32)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); + } else { + if (cx_hash_no_throw(&context.transactionHashAuthorization.header, + CX_LAST, (unsigned char *)&context.segwit.cache, + sizeof(context.segwit.cache), authorizationHash, + 32)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discardTransaction; + } + PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); + } + } - // Generate new nonce + if (context.transactionContext.firstSigned) { + if (!context.tmpCtx.output.changeInitialized) { + memset(transactionSummary, 0, sizeof(transaction_summary_t)); + } - cx_rng(transactionSummary->transactionNonce, 8); + transactionSummary->payToAddressVersion = COIN_P2PKH_VERSION; + transactionSummary->payToScriptHashVersion = COIN_P2SH_VERSION; + + // Generate new nonce + + cx_rng(transactionSummary->transactionNonce, 8); + } + + G_io_apdu_buffer[0] = 0x00; + target++; + + *target = 0x00; + target++; + + context.outLength = (target - G_io_apdu_buffer); + + // Check that the input being signed is part of the same + // transaction, otherwise abort + // (this is done to keep the transaction counter limit per session + // synchronized) + if (context.transactionContext.firstSigned) { + memmove(transactionSummary->authorizationHash, authorizationHash, + sizeof(transactionSummary->authorizationHash)); + return SW_OK; + } else { + if (os_secure_memcmp(authorizationHash, + transactionSummary->authorizationHash, + sizeof(transactionSummary->authorizationHash))) { + PRINTF("Authorization hash not matching, aborting\n"); + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + goto discardTransaction; } - G_io_apdu_buffer[0] = 0x00; - target++; - - *target = 0x00; - target++; - - context.outLength = (target - G_io_apdu_buffer); - - // Check that the input being signed is part of the same - // transaction, otherwise abort - // (this is done to keep the transaction counter limit per session - // synchronized) - if (context.transactionContext.firstSigned) { - memmove(transactionSummary->authorizationHash, - authorizationHash, - sizeof(transactionSummary->authorizationHash)); - return SW_OK; + if (context.usingSegwit && !context.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context.transactionContext.transactionState = TRANSACTION_NONE; } else { - if (os_secure_memcmp( - authorizationHash, - transactionSummary->authorizationHash, - sizeof(transactionSummary->authorizationHash))) { - PRINTF("Authorization hash not matching, aborting\n"); - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - - if (context.usingSegwit && - !context.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context.transactionContext.transactionState = - TRANSACTION_NONE; - } else { - context.transactionContext.transactionState = - TRANSACTION_SIGN_READY; - } - hash_input_finalize_full_reset(); - return SW_OK; + context.transactionContext.transactionState = TRANSACTION_SIGN_READY; } - -discardTransaction: hash_input_finalize_full_reset(); - ui_transaction_error(); - context.transactionContext.transactionState = - TRANSACTION_NONE; - context.outLength = 0; + return SW_OK; + } - memmove(G_io_apdu_buffer, context.currentOutput, - context.currentOutputOffset); - context.outLength = context.currentOutputOffset; - return sw; +discardTransaction: + hash_input_finalize_full_reset(); + ui_transaction_error(); + context.transactionContext.transactionState = TRANSACTION_NONE; + context.outLength = 0; + + memmove(G_io_apdu_buffer, context.currentOutput, context.currentOutputOffset); + context.outLength = context.currentOutputOffset; + return sw; } -unsigned short handler_hash_input_finalize_full(buffer_t* buffer, uint8_t p1, uint8_t p2) { - bool is_async = false; - PRINTF("state=%d\n", context.outputParsingState); - unsigned short sw = hash_input_finalize_full_internal( - &context.transactionSummary, buffer, p1, p2, &is_async); - - if (is_async) { - // if the UI reject the processing of the request, then reply - // immediately - int status; - if(context.outputParsingState == BIP44_CHANGE_PATH_VALIDATION) { - context.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; - return 0; - } - else if (context.outputParsingState == OUTPUT_FINALIZE_TX) { - status = finalize_tx(); - } - else { - status = confirm_single_output(); - } - if (status == 0) { - ui_transaction_error(); - context.transactionContext.transactionState = - TRANSACTION_NONE; - context.outLength = 0; - sw = SW_INCORRECT_DATA; - return io_send_sw(sw); - } - else if (status == 2) { - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); - } - return 0; +unsigned short handler_hash_input_finalize_full(buffer_t *buffer, uint8_t p1, + uint8_t p2) { + bool is_async = false; + PRINTF("state=%d\n", context.outputParsingState); + unsigned short sw = hash_input_finalize_full_internal( + &context.transactionSummary, buffer, p1, p2, &is_async); + + if (is_async) { + // if the UI reject the processing of the request, then reply + // immediately + int status; + if (context.outputParsingState == BIP44_CHANGE_PATH_VALIDATION) { + context.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; + return 0; + } else if (context.outputParsingState == OUTPUT_FINALIZE_TX) { + status = finalize_tx(); + } else { + status = confirm_single_output(); } - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); + if (status == 0) { + ui_transaction_error(); + context.transactionContext.transactionState = TRANSACTION_NONE; + context.outLength = 0; + sw = SW_INCORRECT_DATA; + return io_send_sw(sw); + } else if (status == 2) { + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, + SW_OK); + } + return 0; + } + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); } unsigned char user_action(unsigned char confirming) { - unsigned short sw = SW_OK; - - // confirm and finish the apdu exchange //spaghetti - - if (confirming) { - // Check if all inputs have been confirmed + unsigned short sw = SW_OK; - if (context.outputParsingState == - OUTPUT_PARSING_OUTPUT) { - context.remainingOutputs--; - } + // confirm and finish the apdu exchange //spaghetti - while (context.remainingOutputs != 0) { - memmove(context.currentOutput, - context.currentOutput + - context.discardSize, - context.currentOutputOffset - - context.discardSize); - context.currentOutputOffset -= - context.discardSize; - unsigned int processed = 1; - while (processed == 1) { - if (handle_output_state(&processed)) { - context.transactionContext.transactionState = - TRANSACTION_NONE; - sw = SW_INCORRECT_DATA; - break; - } - } - - if (processed == 2) { - if (!confirm_single_output()) { - context.transactionContext.transactionState = - TRANSACTION_NONE; - sw = SW_INCORRECT_DATA; - break; - } else { - // Let the UI play - return 1; - } - } else { - // Out of data to process, wait for the next call - break; - } - } + if (confirming) { + // Check if all inputs have been confirmed - if ((context.outputParsingState == - OUTPUT_PARSING_OUTPUT) && - (context.remainingOutputs == 0)) { - context.outputParsingState = OUTPUT_FINALIZE_TX; - if (!finalize_tx()) { - context.outputParsingState = - OUTPUT_PARSING_NONE; - context.transactionContext.transactionState = - TRANSACTION_NONE; - sw = SW_INCORRECT_DATA; - } else { - // Let the UI play - return 1; - } - } + if (context.outputParsingState == OUTPUT_PARSING_OUTPUT) { + context.remainingOutputs--; + } - if (context.outputParsingState == - OUTPUT_FINALIZE_TX) { - context.transactionContext.firstSigned = 0; - - if (context.usingSegwit && - !context.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context.transactionContext.transactionState = - TRANSACTION_NONE; - } else { - context.transactionContext.transactionState = - TRANSACTION_SIGN_READY; - } + while (context.remainingOutputs != 0) { + memmove(context.currentOutput, + context.currentOutput + context.discardSize, + context.currentOutputOffset - context.discardSize); + context.currentOutputOffset -= context.discardSize; + unsigned int processed = 1; + while (processed == 1) { + if (handle_output_state(&processed)) { + context.transactionContext.transactionState = TRANSACTION_NONE; + sw = SW_INCORRECT_DATA; + break; + } + } + + if (processed == 2) { + if (!confirm_single_output()) { + context.transactionContext.transactionState = TRANSACTION_NONE; + sw = SW_INCORRECT_DATA; + break; + } else { + // Let the UI play + return 1; } - } else { - // Discard transaction - context.transactionContext.transactionState = - TRANSACTION_NONE; - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - context.outLength = 0; + } else { + // Out of data to process, wait for the next call + break; + } } - if ((context.outputParsingState == OUTPUT_FINALIZE_TX) || - (sw != SW_OK)) { + if ((context.outputParsingState == OUTPUT_PARSING_OUTPUT) && + (context.remainingOutputs == 0)) { + context.outputParsingState = OUTPUT_FINALIZE_TX; + if (!finalize_tx()) { + context.outputParsingState = OUTPUT_PARSING_NONE; + context.transactionContext.transactionState = TRANSACTION_NONE; + sw = SW_INCORRECT_DATA; + } else { + // Let the UI play + return 1; + } + } - // we've finished the processing of the input - hash_input_finalize_full_reset(); + if (context.outputParsingState == OUTPUT_FINALIZE_TX) { + context.transactionContext.firstSigned = 0; + + if (context.usingSegwit && !context.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context.transactionContext.transactionState = TRANSACTION_NONE; + } else { + context.transactionContext.transactionState = TRANSACTION_SIGN_READY; + } } - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); + } else { + // Discard transaction + context.transactionContext.transactionState = TRANSACTION_NONE; + sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; + context.outLength = 0; + } + + if ((context.outputParsingState == OUTPUT_FINALIZE_TX) || (sw != SW_OK)) { + // we've finished the processing of the input + hash_input_finalize_full_reset(); + } + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); } diff --git a/lib-app-bitcoin/handler/hash_input_start.c b/lib-app-bitcoin/handler/hash_input_start.c index 274418a9..787f0bbd 100644 --- a/lib-app-bitcoin/handler/hash_input_start.c +++ b/lib-app-bitcoin/handler/hash_input_start.c @@ -1,27 +1,27 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #include "io.h" -#include "context.h" -#include "transaction.h" #include "apdu_constants.h" +#include "context.h" #include "extensions.h" #include "swap.h" +#include "transaction.h" #define P1_FIRST 0x00 #define P1_NEXT 0x80 @@ -32,105 +32,92 @@ #define P2_NEW_SEGWIT_SAPLING 0x05 #define P2_CONTINUE 0x80 -#define IS_INPUT() \ - (buffer->size - 1 > 8 \ - && buffer->size - 1 <= TRUSTED_INPUT_TOTAL_SIZE + 2 \ - && buffer->ptr[0] <= 0x02) \ +#define IS_INPUT() \ + (buffer->size - 1 > 8 && buffer->size - 1 <= TRUSTED_INPUT_TOTAL_SIZE + 2 && \ + buffer->ptr[0] <= 0x02) -#define IS_INPUT_TRUSTED() \ - (buffer->ptr[0] == 0x01 \ - && buffer->ptr[1] == TRUSTED_INPUT_TOTAL_SIZE \ - && buffer->ptr[2] == MAGIC_TRUSTED_INPUT \ - && buffer->ptr[3] == 0x00) +#define IS_INPUT_TRUSTED() \ + (buffer->ptr[0] == 0x01 && buffer->ptr[1] == TRUSTED_INPUT_TOTAL_SIZE && \ + buffer->ptr[2] == MAGIC_TRUSTED_INPUT && buffer->ptr[3] == 0x00) -WEAK unsigned short handler_hash_input_start(buffer_t* buffer, uint8_t p1, uint8_t p2) { - if (p1 == P1_FIRST) { - // Initialize - context.transactionContext.transactionState = - TRANSACTION_NONE; - context.transactionHashOption = TRANSACTION_HASH_BOTH; - } else if (p1 != P1_NEXT) { - return io_send_sw(SW_INCORRECT_P1_P2); - } +WEAK unsigned short handler_hash_input_start(buffer_t *buffer, uint8_t p1, + uint8_t p2) { + if (p1 == P1_FIRST) { + // Initialize + context.transactionContext.transactionState = TRANSACTION_NONE; + context.transactionHashOption = TRANSACTION_HASH_BOTH; + } else if (p1 != P1_NEXT) { + return io_send_sw(SW_INCORRECT_P1_P2); + } - if ((p2 == P2_NEW) || - (p2 == P2_NEW_SEGWIT) || - (p2 == P2_NEW_SEGWIT_CASHADDR) || - (p2 == P2_NEW_SEGWIT_OVERWINTER) || - (p2 == P2_NEW_SEGWIT_SAPLING)) { - if (p1 == P1_FIRST) { - unsigned char usingSegwit = - (p2 == P2_NEW_SEGWIT) || - (p2 == P2_NEW_SEGWIT_CASHADDR) || - (p2 == P2_NEW_SEGWIT_OVERWINTER) || - (p2 == P2_NEW_SEGWIT_SAPLING); - // Master transaction reset - context.transactionContext.firstSigned = 1; - context.transactionContext.consumeP2SH = 0; - context.transactionContext.relaxed = 0; - context.usingSegwit = usingSegwit; + if ((p2 == P2_NEW) || (p2 == P2_NEW_SEGWIT) || + (p2 == P2_NEW_SEGWIT_CASHADDR) || (p2 == P2_NEW_SEGWIT_OVERWINTER) || + (p2 == P2_NEW_SEGWIT_SAPLING)) { + if (p1 == P1_FIRST) { + unsigned char usingSegwit = + (p2 == P2_NEW_SEGWIT) || (p2 == P2_NEW_SEGWIT_CASHADDR) || + (p2 == P2_NEW_SEGWIT_OVERWINTER) || (p2 == P2_NEW_SEGWIT_SAPLING); + // Master transaction reset + context.transactionContext.firstSigned = 1; + context.transactionContext.consumeP2SH = 0; + context.transactionContext.relaxed = 0; + context.usingSegwit = usingSegwit; - if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { - unsigned char usingCashAddr = (p2 == P2_NEW_SEGWIT_CASHADDR); - context.usingCashAddr = usingCashAddr; - } - else { - context.usingCashAddr = 0; - } + if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { + unsigned char usingCashAddr = (p2 == P2_NEW_SEGWIT_CASHADDR); + context.usingCashAddr = usingCashAddr; + } else { + context.usingCashAddr = 0; + } - context.usingOverwinter = 0; - if ((COIN_KIND == COIN_KIND_ZCASH) || (COIN_KIND == COIN_KIND_KOMODO) || (COIN_KIND == COIN_KIND_ZCLASSIC) || (COIN_KIND == COIN_KIND_RESISTANCE)) { - if (p2 == P2_NEW_SEGWIT_OVERWINTER) { - context.usingOverwinter = ZCASH_USING_OVERWINTER; - } - else - if (p2 == P2_NEW_SEGWIT_SAPLING) { - context.usingOverwinter = ZCASH_USING_OVERWINTER_SAPLING; - } - } - context.overwinterSignReady = 0; - context.segwitParsedOnce = 0; - // Initialize for screen pairing - memset(&context.tmpCtx.output, 0, - sizeof(context.tmpCtx.output)); - context.tmpCtx.output.changeAccepted = 1; - // Reset segwitWarningSeen flag to prevent displaying the warning for each - // segwit input when coontinuing from a previous session (P2=0x80) - context.segwitWarningSeen = 0; + context.usingOverwinter = 0; + if ((COIN_KIND == COIN_KIND_ZCASH) || (COIN_KIND == COIN_KIND_KOMODO) || + (COIN_KIND == COIN_KIND_ZCLASSIC) || + (COIN_KIND == COIN_KIND_RESISTANCE)) { + if (p2 == P2_NEW_SEGWIT_OVERWINTER) { + context.usingOverwinter = ZCASH_USING_OVERWINTER; + } else if (p2 == P2_NEW_SEGWIT_SAPLING) { + context.usingOverwinter = ZCASH_USING_OVERWINTER_SAPLING; } - } else if (p2 != P2_CONTINUE) { - return io_send_sw(SW_INCORRECT_P1_P2); + } + context.overwinterSignReady = 0; + context.segwitParsedOnce = 0; + // Initialize for screen pairing + memset(&context.tmpCtx.output, 0, sizeof(context.tmpCtx.output)); + context.tmpCtx.output.changeAccepted = 1; + // Reset segwitWarningSeen flag to prevent displaying the warning for each + // segwit input when coontinuing from a previous session (P2=0x80) + context.segwitWarningSeen = 0; } + } else if (p2 != P2_CONTINUE) { + return io_send_sw(SW_INCORRECT_P1_P2); + } - // In segwit mode, warn user one time only to update its client wallet... - if (context.usingSegwit - && !context.segwitWarningSeen - && (p1 == P1_NEXT) - && (p2 != P2_CONTINUE) - // ...if input is not passed as a TrustedInput - && IS_INPUT() - && !IS_INPUT_TRUSTED()) - { - if(G_called_from_swap){ - /* There is no point in displaying a warning when the app is signing - in silent mode, as its UI is hidden behind the exchange app*/ - return io_send_sw(SW_SWAP_WITHOUT_TRUSTED_INPUTS); - } - context.segwitWarningSeen = 1; - request_segwit_input_approval(); - // Start parsing of the 1st chunk - context.transactionBufferPointer = (uint8_t*) buffer->ptr; - context.transactionDataRemaining = buffer->size; - - transaction_parse(PARSE_MODE_SIGNATURE); - return 0; + // In segwit mode, warn user one time only to update its client wallet... + if (context.usingSegwit && !context.segwitWarningSeen && (p1 == P1_NEXT) && + (p2 != P2_CONTINUE) + // ...if input is not passed as a TrustedInput + && IS_INPUT() && !IS_INPUT_TRUSTED()) { + if (G_called_from_swap) { + /* There is no point in displaying a warning when the app is signing + in silent mode, as its UI is hidden behind the exchange app*/ + return io_send_sw(SW_SWAP_WITHOUT_TRUSTED_INPUTS); } - + context.segwitWarningSeen = 1; + request_segwit_input_approval(); // Start parsing of the 1st chunk - context.transactionBufferPointer = (uint8_t*) buffer->ptr; + context.transactionBufferPointer = (uint8_t *)buffer->ptr; context.transactionDataRemaining = buffer->size; transaction_parse(PARSE_MODE_SIGNATURE); + return 0; + } + + // Start parsing of the 1st chunk + context.transactionBufferPointer = (uint8_t *)buffer->ptr; + context.transactionDataRemaining = buffer->size; + + transaction_parse(PARSE_MODE_SIGNATURE); - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); } diff --git a/lib-app-bitcoin/handler/hash_sign.c b/lib-app-bitcoin/handler/hash_sign.c index c4496660..50b74e33 100644 --- a/lib-app-bitcoin/handler/hash_sign.c +++ b/lib-app-bitcoin/handler/hash_sign.c @@ -1,192 +1,191 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ -#include "macros.h" #include "io.h" #include "ledger_assert.h" +#include "macros.h" #include "read.h" -#include "write.h" #include "swap.h" +#include "write.h" -#include "context.h" -#include "helpers.h" #include "apdu_constants.h" -#include "extensions.h" +#include "context.h" #include "display_variables.h" +#include "extensions.h" +#include "helpers.h" #include "ui.h" #define SIGHASH_ALL 0x01 #ifndef COIN_FORKID #define COIN_FORKID 0 -#endif +#endif -WEAK unsigned short handler_hash_sign(buffer_t* buffer, uint8_t p1, uint8_t p2) { - unsigned long int lockTime; - uint32_t sighashType; - unsigned char dataBuffer[8]; - unsigned char authorizationLength; - unsigned char *parameters = (uint8_t*)buffer->ptr; +WEAK unsigned short handler_hash_sign(buffer_t *buffer, uint8_t p1, + uint8_t p2) { + unsigned long int lockTime; + uint32_t sighashType; + unsigned char dataBuffer[8]; + unsigned char authorizationLength; + unsigned char *parameters = (uint8_t *)buffer->ptr; - if ((p1 != 0) || (p2 != 0)) { - return io_send_sw(SW_INCORRECT_P1_P2); - } + if ((p1 != 0) || (p2 != 0)) { + return io_send_sw(SW_INCORRECT_P1_P2); + } #define HASH_LENGTH 1 + 1 + 4 + 1 - if (buffer->size < HASH_LENGTH) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - - // Zcash special - store parameters for later - - if ((context.usingOverwinter) && - (!context.overwinterSignReady) && - (context.segwitParsedOnce) && - (context.transactionContext.transactionState == TRANSACTION_NONE)) { - unsigned long int expiryHeight; - parameters += (4 * buffer->ptr[0]) + 1; - authorizationLength = *(parameters++); - parameters += authorizationLength; - lockTime = read_u32_be(parameters, 0); - parameters += 4; - sighashType = *(parameters++); - expiryHeight = read_u32_be(parameters, 0); - write_u32_le(context.nLockTime, 0, lockTime); - write_u32_le(context.sigHashType, 0, sighashType); - write_u32_le(context.nExpiryHeight, 0, expiryHeight); - context.overwinterSignReady = 1; - return io_send_sw(SW_OK); - } - - if (context.transactionContext.transactionState != - TRANSACTION_SIGN_READY) { - PRINTF("Invalid transaction state %d\n", context.transactionContext.transactionState); - context.transactionContext.transactionState = TRANSACTION_NONE; - return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); - } + if (buffer->size < HASH_LENGTH) { + return io_send_sw(SW_INCORRECT_LENGTH); + } - if (context.usingOverwinter && !context.overwinterSignReady) { - PRINTF("Overwinter not ready to sign\n"); - context.transactionContext.transactionState = TRANSACTION_NONE; - return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); - } + // Zcash special - store parameters for later - // Read parameters - if (buffer->ptr[0] > MAX_BIP32_PATH) { - context.transactionContext.transactionState = TRANSACTION_NONE; - return io_send_sw(SW_INCORRECT_DATA); - } - memmove(context.transactionSummary.keyPath, - buffer->ptr, - MAX_BIP32_PATH_LENGTH); + if ((context.usingOverwinter) && (!context.overwinterSignReady) && + (context.segwitParsedOnce) && + (context.transactionContext.transactionState == TRANSACTION_NONE)) { + unsigned long int expiryHeight; parameters += (4 * buffer->ptr[0]) + 1; authorizationLength = *(parameters++); parameters += authorizationLength; lockTime = read_u32_be(parameters, 0); parameters += 4; sighashType = *(parameters++); - context.transactionSummary.sighashType = sighashType; - - // if bitcoin cash OR forkid is set, then use the fork id - if ((COIN_KIND == COIN_KIND_BITCOIN_CASH) || - (COIN_FORKID)) { + expiryHeight = read_u32_be(parameters, 0); + write_u32_le(context.nLockTime, 0, lockTime); + write_u32_le(context.sigHashType, 0, sighashType); + write_u32_le(context.nExpiryHeight, 0, expiryHeight); + context.overwinterSignReady = 1; + return io_send_sw(SW_OK); + } + + if (context.transactionContext.transactionState != TRANSACTION_SIGN_READY) { + PRINTF("Invalid transaction state %d\n", + context.transactionContext.transactionState); + context.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); + } + + if (context.usingOverwinter && !context.overwinterSignReady) { + PRINTF("Overwinter not ready to sign\n"); + context.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); + } + + // Read parameters + if (buffer->ptr[0] > MAX_BIP32_PATH) { + context.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_INCORRECT_DATA); + } + memmove(context.transactionSummary.keyPath, buffer->ptr, + MAX_BIP32_PATH_LENGTH); + parameters += (4 * buffer->ptr[0]) + 1; + authorizationLength = *(parameters++); + parameters += authorizationLength; + lockTime = read_u32_be(parameters, 0); + parameters += 4; + sighashType = *(parameters++); + context.transactionSummary.sighashType = sighashType; + + // if bitcoin cash OR forkid is set, then use the fork id + if ((COIN_KIND == COIN_KIND_BITCOIN_CASH) || (COIN_FORKID)) { #define SIGHASH_FORKID 0x40 - if (sighashType != (SIGHASH_ALL | SIGHASH_FORKID)) { - context.transactionContext.transactionState = TRANSACTION_NONE; - return io_send_sw(SW_INCORRECT_DATA); - } - sighashType |= (COIN_FORKID << 8); - - } else { - if (sighashType != SIGHASH_ALL) { - context.transactionContext.transactionState = TRANSACTION_NONE; - return io_send_sw(SW_INCORRECT_DATA); - } - } - - // Finalize the hash - if (!context.usingOverwinter) { - write_u32_le(dataBuffer, 0, lockTime); - write_u32_le(dataBuffer, 4, sighashType); - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(dataBuffer), dataBuffer); - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - dataBuffer, sizeof(dataBuffer), NULL, 0)) { - context.transactionContext.transactionState = TRANSACTION_NONE; - return io_send_sw(SW_INCORRECT_DATA); - } + if (sighashType != (SIGHASH_ALL | SIGHASH_FORKID)) { + context.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_INCORRECT_DATA); } + sighashType |= (COIN_FORKID << 8); - // Check if the path needs to be enforced - if (!enforce_bip44_coin_type(context.transactionSummary.keyPath, false)) { - request_sign_path_approval(context.transactionSummary.keyPath); + } else { + if (sighashType != SIGHASH_ALL) { + context.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_INCORRECT_DATA); } - else { - // Sign immediately - user_action_signtx(1, 0); + } + + // Finalize the hash + if (!context.usingOverwinter) { + write_u32_le(dataBuffer, 0, lockTime); + write_u32_le(dataBuffer, 4, sighashType); + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(dataBuffer), dataBuffer); + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + dataBuffer, sizeof(dataBuffer), NULL, 0)) { + context.transactionContext.transactionState = TRANSACTION_NONE; + return io_send_sw(SW_INCORRECT_DATA); } - if (G_called_from_swap) { - // if we signed all outputs we should exit, - // but only after sending response, so lets raise the - // vars.swap_data.should_exit flag and check it on timer later - vars.swap_data.alreadySignedInputs++; - if (vars.swap_data.alreadySignedInputs >= vars.swap_data.totalNumberOfInputs) { - vars.swap_data.should_exit = 1; - } - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); + } + + // Check if the path needs to be enforced + if (!enforce_bip44_coin_type(context.transactionSummary.keyPath, false)) { + request_sign_path_approval(context.transactionSummary.keyPath); + } else { + // Sign immediately + user_action_signtx(1, 0); + } + if (G_called_from_swap) { + // if we signed all outputs we should exit, + // but only after sending response, so lets raise the + // vars.swap_data.should_exit flag and check it on timer later + vars.swap_data.alreadySignedInputs++; + if (vars.swap_data.alreadySignedInputs >= + vars.swap_data.totalNumberOfInputs) { + vars.swap_data.should_exit = 1; } - return 0; + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); + } + return 0; } int user_action_signtx(unsigned char confirming, unsigned char direct) { - // confirm and finish the apdu exchange //spaghetti - if (confirming) { - unsigned char hash[32]; - if (context.usingOverwinter) { - LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashFull.blake2b.header, CX_LAST, hash, 0, hash, 32) == CX_OK, "Hash Failed"); - } - else { - LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashFull.sha256.header, CX_LAST, - hash, 0, hash, 32) == CX_OK, "Hash Failed"); - PRINTF("Hash1\n%.*H\n", sizeof(hash), hash); - - // Rehash - cx_hash_sha256(hash, sizeof(hash), hash, 32); - } - PRINTF("Hash2\n%.*H\n", sizeof(hash), hash); - // Sign - size_t out_len = sizeof(G_io_apdu_buffer); - sign_finalhash( - context.transactionSummary.keyPath, - sizeof(context.transactionSummary.keyPath), - hash, sizeof(hash), - G_io_apdu_buffer, &out_len); - - context.outLength = G_io_apdu_buffer[1] + 2; - G_io_apdu_buffer[context.outLength++] = context.transactionSummary.sighashType; - ui_transaction_finish(); - + // confirm and finish the apdu exchange //spaghetti + if (confirming) { + unsigned char hash[32]; + if (context.usingOverwinter) { + LEDGER_ASSERT( + cx_hash_no_throw(&context.transactionHashFull.blake2b.header, CX_LAST, + hash, 0, hash, 32) == CX_OK, + "Hash Failed"); } else { - context.outLength = 0; - return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); - } + LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashFull.sha256.header, + CX_LAST, hash, 0, hash, 32) == CX_OK, + "Hash Failed"); + PRINTF("Hash1\n%.*H\n", sizeof(hash), hash); - if (!direct) { - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); + // Rehash + cx_hash_sha256(hash, sizeof(hash), hash, 32); } - return 0; + PRINTF("Hash2\n%.*H\n", sizeof(hash), hash); + // Sign + size_t out_len = sizeof(G_io_apdu_buffer); + sign_finalhash(context.transactionSummary.keyPath, + sizeof(context.transactionSummary.keyPath), hash, + sizeof(hash), G_io_apdu_buffer, &out_len); + + context.outLength = G_io_apdu_buffer[1] + 2; + G_io_apdu_buffer[context.outLength++] = + context.transactionSummary.sighashType; + ui_transaction_finish(); + + } else { + context.outLength = 0; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); + } + + if (!direct) { + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); + } + return 0; } - diff --git a/lib-app-bitcoin/handler/sign_message.c b/lib-app-bitcoin/handler/sign_message.c index 01a6a332..487cf44c 100644 --- a/lib-app-bitcoin/handler/sign_message.c +++ b/lib-app-bitcoin/handler/sign_message.c @@ -1,27 +1,27 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ -#include "context.h" -#include "helpers.h" #include "apdu_constants.h" +#include "context.h" #include "extensions.h" +#include "helpers.h" +#include "io.h" #include "lib_standard_app/read.h" #include "swap.h" -#include "io.h" #define P1_PREPARE 0x00 #define P1_SIGN 0x80 @@ -38,242 +38,230 @@ unsigned char const SIGNMAGIC[] = {' ', 'S', 'i', 'g', 'n', 'e', 'd', ' ', 'M', // TODO : support longer messages unsigned char message_check_bit_id(unsigned char *bip32Path) { - unsigned char i; - unsigned char bip32PathLength = bip32Path[0]; - bip32Path++; - for (i = 0; i < bip32PathLength; i++) { - unsigned short account = read_u32_be(bip32Path, 0); - bip32Path += 4; + unsigned char i; + unsigned char bip32PathLength = bip32Path[0]; + bip32Path++; + for (i = 0; i < bip32PathLength; i++) { + unsigned short account = read_u32_be(bip32Path, 0); + bip32Path += 4; - if (account == BITID_DERIVE) { - return BITID_POWERCYCLE; - } - if (account == BITID_DERIVE_MULTIPLE) { - return BITID_MULTIPLE; - } + if (account == BITID_DERIVE) { + return BITID_POWERCYCLE; + } + if (account == BITID_DERIVE_MULTIPLE) { + return BITID_MULTIPLE; } - return BITID_NONE; + } + return BITID_NONE; } unsigned short message_compute_hash(void) { - unsigned char hash[32]; - unsigned short sw = SW_OK; + unsigned char hash[32]; + unsigned short sw = SW_OK; - context.outLength = 0; - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, CX_LAST, hash, - 0, hash, 32)) { - goto discard; - } - - if (cx_hash_sha256(hash, sizeof(hash), hash, 32) == 0) { - goto discard; - } + context.outLength = 0; + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, CX_LAST, + hash, 0, hash, 32)) { + goto discard; + } - size_t out_len = 100; - sign_finalhash( - context.transactionSummary.keyPath, - sizeof(context.transactionSummary.keyPath), - hash, sizeof(hash), // IN - G_io_apdu_buffer, &out_len); // OUT - context.outLength = G_io_apdu_buffer[1] + 2; - memset(&context.transactionSummary, 0, - sizeof(transaction_summary_t)); - return sw; + if (cx_hash_sha256(hash, sizeof(hash), hash, 32) == 0) { + goto discard; + } - discard: - sw = SW_TECHNICAL_PROBLEM_2; - return sw; -} + size_t out_len = 100; + sign_finalhash(context.transactionSummary.keyPath, + sizeof(context.transactionSummary.keyPath), hash, + sizeof(hash), // IN + G_io_apdu_buffer, &out_len); // OUT + context.outLength = G_io_apdu_buffer[1] + 2; + memset(&context.transactionSummary, 0, sizeof(transaction_summary_t)); + return sw; +discard: + sw = SW_TECHNICAL_PROBLEM_2; + return sw; +} -static unsigned short sign_message_internal(buffer_t* buffer, uint8_t p1, uint8_t p2) { - unsigned short sw = SW_OK; - unsigned char apduLength = buffer->size; - unsigned short offset = 0; +static unsigned short sign_message_internal(buffer_t *buffer, uint8_t p1, + uint8_t p2) { + unsigned short sw = SW_OK; + unsigned char apduLength = buffer->size; + unsigned short offset = 0; - if ((p1 != P1_PREPARE) && (p1 != P1_SIGN)) { - return io_send_sw(SW_INCORRECT_P1_P2); - } - if (p1 == P1_PREPARE) { - if ((p2 != P2_FIRST) && (p2 != P2_OTHER) && (p2 != P2_LEGACY)) { - return io_send_sw(SW_INCORRECT_P1_P2); - } + if ((p1 != P1_PREPARE) && (p1 != P1_SIGN)) { + return io_send_sw(SW_INCORRECT_P1_P2); + } + if (p1 == P1_PREPARE) { + if ((p2 != P2_FIRST) && (p2 != P2_OTHER) && (p2 != P2_LEGACY)) { + return io_send_sw(SW_INCORRECT_P1_P2); } + } - if (p1 == P1_PREPARE) { - if ((p2 == P2_FIRST) || (p2 == P2_LEGACY)) { - unsigned char chunkLength; - unsigned char messageLength[3]; - unsigned char messageLengthSize; - memset(&context.transactionSummary, 0, - sizeof(transaction_summary_t)); - if (buffer->ptr[0] > MAX_BIP32_PATH) { - PRINTF("Invalid path\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - context.transactionSummary.payToAddressVersion = COIN_P2PKH_VERSION; - context.transactionSummary.payToScriptHashVersion = COIN_P2SH_VERSION; - memmove( - context.transactionSummary.keyPath, - buffer->ptr, MAX_BIP32_PATH_LENGTH); - offset += (4 * buffer->ptr[0]) + 1; - if (p2 == P2_LEGACY) { - context.transactionSummary.messageLength = - buffer->ptr[offset]; - offset++; - } else { - context.transactionSummary.messageLength = - (buffer->ptr[offset] << 8) | - (buffer->ptr[offset + 1]); - offset += 2; - } - if (context.transactionSummary.messageLength == - 0) { - PRINTF("Null message length\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - context.hashedMessageLength = 0; + if (p1 == P1_PREPARE) { + if ((p2 == P2_FIRST) || (p2 == P2_LEGACY)) { + unsigned char chunkLength; + unsigned char messageLength[3]; + unsigned char messageLengthSize; + memset(&context.transactionSummary, 0, sizeof(transaction_summary_t)); + if (buffer->ptr[0] > MAX_BIP32_PATH) { + PRINTF("Invalid path\n"); + sw = SW_INCORRECT_DATA; + goto discard; + } + context.transactionSummary.payToAddressVersion = COIN_P2PKH_VERSION; + context.transactionSummary.payToScriptHashVersion = COIN_P2SH_VERSION; + memmove(context.transactionSummary.keyPath, buffer->ptr, + MAX_BIP32_PATH_LENGTH); + offset += (4 * buffer->ptr[0]) + 1; + if (p2 == P2_LEGACY) { + context.transactionSummary.messageLength = buffer->ptr[offset]; + offset++; + } else { + context.transactionSummary.messageLength = + (buffer->ptr[offset] << 8) | (buffer->ptr[offset + 1]); + offset += 2; + } + if (context.transactionSummary.messageLength == 0) { + PRINTF("Null message length\n"); + sw = SW_INCORRECT_DATA; + goto discard; + } + context.hashedMessageLength = 0; - // Horizen signed message magic header is "Zcash" - // See https://github.com/HorizenOfficial/zen/blob/v5.0.0/src/main.cpp#L122 - const char* magicHeader = (COIN_KIND != COIN_KIND_HORIZEN) ? COIN_COINID : "Zcash"; + // Horizen signed message magic header is "Zcash" + // See + // https://github.com/HorizenOfficial/zen/blob/v5.0.0/src/main.cpp#L122 + const char *magicHeader = + (COIN_KIND != COIN_KIND_HORIZEN) ? COIN_COINID : "Zcash"; - cx_sha256_init_no_throw(&context.transactionHashFull.sha256); - cx_sha256_init_no_throw(&context.transactionHashAuthorization); + cx_sha256_init_no_throw(&context.transactionHashFull.sha256); + cx_sha256_init_no_throw(&context.transactionHashAuthorization); - chunkLength = - strlen(magicHeader) + sizeof(SIGNMAGIC); - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - &chunkLength, 1, NULL, 0)) { - goto discard; - } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - (uint8_t *)magicHeader, - strlen(magicHeader), NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - (unsigned char *)SIGNMAGIC, sizeof(SIGNMAGIC), NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - if (context.transactionSummary.messageLength < - 0xfd) { - messageLength[0] = - context.transactionSummary.messageLength; - messageLengthSize = 1; - } else { - messageLength[0] = 0xfd; - messageLength[1] = - (context.transactionSummary.messageLength & - 0xff); - messageLength[2] = ((context.transactionSummary - .messageLength >> - 8) & - 0xff); - messageLengthSize = 3; - } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - messageLength, messageLengthSize, NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - chunkLength = apduLength - offset; - if ((context.hashedMessageLength + chunkLength) > - context.transactionSummary.messageLength) { - PRINTF("Invalid data length\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - buffer->ptr + offset, chunkLength, NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - if (cx_hash_no_throw( - &context.transactionHashAuthorization.header, - 0, buffer->ptr + offset, chunkLength, NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - context.hashedMessageLength += chunkLength; - G_io_apdu_buffer[0] = 0x00; - if (context.hashedMessageLength == - context.transactionSummary.messageLength) { - G_io_apdu_buffer[1] = 0x00; - context.outLength = 2; - } else { - context.outLength = 1; - } - } else { - if ((context.hashedMessageLength + apduLength) > - context.transactionSummary.messageLength) { - PRINTF("Invalid data length\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - buffer->ptr + offset, apduLength, NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - if (cx_hash_no_throw( - &context.transactionHashAuthorization.header, - 0, buffer->ptr + offset, apduLength, NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - context.hashedMessageLength += apduLength; - G_io_apdu_buffer[0] = 0x00; - if (context.hashedMessageLength == - context.transactionSummary.messageLength) { - G_io_apdu_buffer[1] = 0x00; - context.outLength = 2; - } else { - context.outLength = 1; - } - } + chunkLength = strlen(magicHeader) + sizeof(SIGNMAGIC); + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + &chunkLength, 1, NULL, 0)) { + goto discard; + } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + (uint8_t *)magicHeader, strlen(magicHeader), NULL, + 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + (unsigned char *)SIGNMAGIC, sizeof(SIGNMAGIC), NULL, + 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + if (context.transactionSummary.messageLength < 0xfd) { + messageLength[0] = context.transactionSummary.messageLength; + messageLengthSize = 1; + } else { + messageLength[0] = 0xfd; + messageLength[1] = (context.transactionSummary.messageLength & 0xff); + messageLength[2] = + ((context.transactionSummary.messageLength >> 8) & 0xff); + messageLengthSize = 3; + } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + messageLength, messageLengthSize, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + chunkLength = apduLength - offset; + if ((context.hashedMessageLength + chunkLength) > + context.transactionSummary.messageLength) { + PRINTF("Invalid data length\n"); + sw = SW_INCORRECT_DATA; + goto discard; + } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + buffer->ptr + offset, chunkLength, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + if (cx_hash_no_throw(&context.transactionHashAuthorization.header, 0, + buffer->ptr + offset, chunkLength, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + context.hashedMessageLength += chunkLength; + G_io_apdu_buffer[0] = 0x00; + if (context.hashedMessageLength == + context.transactionSummary.messageLength) { + G_io_apdu_buffer[1] = 0x00; + context.outLength = 2; + } else { + context.outLength = 1; + } + } else { + if ((context.hashedMessageLength + apduLength) > + context.transactionSummary.messageLength) { + PRINTF("Invalid data length\n"); + sw = SW_INCORRECT_DATA; + goto discard; + } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + buffer->ptr + offset, apduLength, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + if (cx_hash_no_throw(&context.transactionHashAuthorization.header, 0, + buffer->ptr + offset, apduLength, NULL, 0)) { + sw = SW_TECHNICAL_PROBLEM_2; + goto discard; + } + context.hashedMessageLength += apduLength; + G_io_apdu_buffer[0] = 0x00; + if (context.hashedMessageLength == + context.transactionSummary.messageLength) { + G_io_apdu_buffer[1] = 0x00; + context.outLength = 2; + } else { + context.outLength = 1; + } + } + } else { + if ((context.transactionSummary.messageLength == 0) || + (context.hashedMessageLength != + context.transactionSummary.messageLength)) { + PRINTF("Invalid length to sign\n"); + sw = SW_INCORRECT_DATA; + goto discard; + } + if (message_check_bit_id(context.transactionSummary.keyPath) != + BITID_NONE) { + sw = message_compute_hash(); } else { - if ((context.transactionSummary.messageLength == 0) || - (context.hashedMessageLength != - context.transactionSummary.messageLength)) { - PRINTF("Invalid length to sign\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - if (message_check_bit_id(context.transactionSummary.keyPath) != BITID_NONE) { - sw = message_compute_hash(); - } else { - confirm_message_signature(); - return 0; - } + confirm_message_signature(); + return 0; } - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); + } + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); - discard : - memset(&context.transactionSummary, 0, - sizeof(transaction_summary_t)); - return io_send_sw(sw); +discard: + memset(&context.transactionSummary, 0, sizeof(transaction_summary_t)); + return io_send_sw(sw); } -WEAK unsigned short handler_sign_message(buffer_t* buffer, uint8_t p1, uint8_t p2) { - if (G_called_from_swap) { - return io_send_sw(SW_SECURITY_STATUS_NOT_SATISFIED); - } +WEAK unsigned short handler_sign_message(buffer_t *buffer, uint8_t p1, + uint8_t p2) { + if (G_called_from_swap) { + return io_send_sw(SW_SECURITY_STATUS_NOT_SATISFIED); + } - return sign_message_internal(buffer, p1, p2); + return sign_message_internal(buffer, p1, p2); } int user_action_message_signing(unsigned char confirming) { - unsigned short sw; - if (confirming) { - sw = message_compute_hash(); - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); - } else { - context.outLength = 0; - return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); - } + unsigned short sw; + if (confirming) { + sw = message_compute_hash(); + return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); + } else { + context.outLength = 0; + return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); + } } diff --git a/lib-app-bitcoin/helpers.c b/lib-app-bitcoin/helpers.c index ba200359..2fe38b9f 100644 --- a/lib-app-bitcoin/helpers.c +++ b/lib-app-bitcoin/helpers.c @@ -1,232 +1,234 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ -#include "lib_standard_app/crypto_helpers.h" -#include "lib_standard_app/bip32.h" -#include "ledger_assert.h" -#include "io.h" #include "base58.h" +#include "io.h" +#include "ledger_assert.h" +#include "lib_standard_app/bip32.h" +#include "lib_standard_app/crypto_helpers.h" #include "read.h" #include "context.h" #include "helpers.h" void public_key_hash160(unsigned char *in, unsigned short inlen, - unsigned char out[static CX_RIPEMD160_SIZE]) { - unsigned char buffer[CX_SHA256_SIZE]; - cx_hash_sha256(in, inlen, buffer, sizeof(buffer)); - cx_ripemd160_hash(buffer, sizeof(buffer), out); + unsigned char out[static CX_RIPEMD160_SIZE]) { + unsigned char buffer[CX_SHA256_SIZE]; + cx_hash_sha256(in, inlen, buffer, sizeof(buffer)); + cx_ripemd160_hash(buffer, sizeof(buffer), out); } static void compute_checksum(unsigned char *in, unsigned short inlen, unsigned char output[static 4]) { - unsigned char checksumBuffer[32]; - cx_hash_sha256(in, inlen, checksumBuffer, 32); - cx_hash_sha256(checksumBuffer, 32, checksumBuffer, 32); + unsigned char checksumBuffer[32]; + cx_hash_sha256(in, inlen, checksumBuffer, 32); + cx_hash_sha256(checksumBuffer, 32, checksumBuffer, 32); - PRINTF("Checksum\n%.*H\n",4,checksumBuffer); - memmove(output, checksumBuffer, 4); + PRINTF("Checksum\n%.*H\n", 4, checksumBuffer); + memmove(output, checksumBuffer, 4); } -unsigned short public_key_to_encoded_base58( - unsigned char *in, unsigned short inlen, unsigned char *out, - unsigned short outlen, unsigned short version, - unsigned char alreadyHashed) { - unsigned char tmpBuffer[34]; - - unsigned char versionSize = (version > 255 ? 2 : 1); - short outputLen; - - if (!alreadyHashed) { - PRINTF("To hash\n%.*H\n",inlen,in); - public_key_hash160(in, inlen, tmpBuffer + versionSize); - PRINTF("Hash160\n%.*H\n",20,(tmpBuffer + versionSize)); - if (version > 255) { - tmpBuffer[0] = (version >> 8); - tmpBuffer[1] = version; - } else { - tmpBuffer[0] = version; - } +unsigned short public_key_to_encoded_base58(unsigned char *in, + unsigned short inlen, + unsigned char *out, + unsigned short outlen, + unsigned short version, + unsigned char alreadyHashed) { + unsigned char tmpBuffer[34]; + + unsigned char versionSize = (version > 255 ? 2 : 1); + short outputLen; + + if (!alreadyHashed) { + PRINTF("To hash\n%.*H\n", inlen, in); + public_key_hash160(in, inlen, tmpBuffer + versionSize); + PRINTF("Hash160\n%.*H\n", 20, (tmpBuffer + versionSize)); + if (version > 255) { + tmpBuffer[0] = (version >> 8); + tmpBuffer[1] = version; } else { - memmove(tmpBuffer, in, 20 + versionSize); + tmpBuffer[0] = version; } + } else { + memmove(tmpBuffer, in, 20 + versionSize); + } - compute_checksum(tmpBuffer, 20 + versionSize, tmpBuffer + 20 + versionSize); + compute_checksum(tmpBuffer, 20 + versionSize, tmpBuffer + 20 + versionSize); - outputLen = base58_encode(tmpBuffer, 24 + versionSize, (char *)out, outlen); - LEDGER_ASSERT(outputLen >= 0, "Error encoding public key"); + outputLen = base58_encode(tmpBuffer, 24 + versionSize, (char *)out, outlen); + LEDGER_ASSERT(outputLen >= 0, "Error encoding public key"); - return outputLen; + return outputLen; } void swap_bytes(unsigned char *target, unsigned char *source, - unsigned char size) { - unsigned char i; - for (i = 0; i < size; i++) { - target[i] = source[size - 1 - i]; - } + unsigned char size) { + unsigned char i; + for (i = 0; i < size; i++) { + target[i] = source[size - 1 - i]; + } } /* -Checks if the values of a derivation path are within "normal" (arbitrary) ranges: -Account < 100, change == 1 or 0, address index < 50000 +Checks if the values of a derivation path are within "normal" (arbitrary) +ranges: Account < 100, change == 1 or 0, address index < 50000 Returns 1 if the path is unusual, or not compliant with BIP44*/ -unsigned char bip44_derivation_guard(const unsigned char *bip32Path, bool is_change_path) { - unsigned char path_len; - bip32_path_t bip32PathInt; - - path_len = bip32Path[0]; - if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { - return 1; - } - - // If the path length is not compliant with BIP44 or if the purpose don't match regular usage, return a warning - if(path_len != BIP44_PATH_LEN || - ((bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 44 && - (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 49 && - (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) != 84)) { - return 1; - } - - // If the coin type doesn't match, return a warning - if ((BIP44_COIN_TYPE != 0) && - (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != BIP44_COIN_TYPE) && - ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) != BIP44_COIN_TYPE_2))) { - return 1; - } - - // If the account or address index is very high or if the change isn't 1, return a warning - if((bip32PathInt.path[BIP44_ACCOUNT_OFFSET]^0x80000000) > MAX_BIP44_ACCOUNT_RECOMMENDED || - bip32PathInt.path[BIP44_CHANGE_OFFSET] != is_change_path?1:0 || - bip32PathInt.path[BIP44_ADDRESS_INDEX_OFFSET] > MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { - return 1; - } - - return 0; +unsigned char bip44_derivation_guard(const unsigned char *bip32Path, + bool is_change_path) { + unsigned char path_len; + bip32_path_t bip32PathInt; + + path_len = bip32Path[0]; + if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { + return 1; + } + + // If the path length is not compliant with BIP44 or if the purpose don't + // match regular usage, return a warning + if (path_len != BIP44_PATH_LEN || + ((bip32PathInt.path[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 44 && + (bip32PathInt.path[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 49 && + (bip32PathInt.path[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 84)) { + return 1; + } + + // If the coin type doesn't match, return a warning + if ((BIP44_COIN_TYPE != 0) && (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET] ^ + 0x80000000) != BIP44_COIN_TYPE) && + ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET] ^ + 0x80000000) != BIP44_COIN_TYPE_2))) { + return 1; + } + + // If the account or address index is very high or if the change isn't 1, + // return a warning + if ((bip32PathInt.path[BIP44_ACCOUNT_OFFSET] ^ 0x80000000) > + MAX_BIP44_ACCOUNT_RECOMMENDED || + bip32PathInt.path[BIP44_CHANGE_OFFSET] != is_change_path + ? 1 + : 0 || bip32PathInt.path[BIP44_ADDRESS_INDEX_OFFSET] > + MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { + return 1; + } + + return 0; } /* Only enforce the structure or coin type for consumed UTXOs or a public address Returns 0 if the path is non compliant, or 1 if compliant */ -unsigned char enforce_bip44_coin_type(const unsigned char *bip32Path, bool for_pubkey) { - bip32_path_t bip32PathInt; - // No enforcement required - if (BIP44_COIN_TYPE == 0) { - return 1; - } - // Path is too short - always require a user validation if signing - if (bip32Path[0] < 2) { - return for_pubkey; - } - - if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { - return 1; - } - - // Path is not compliant with BIP 44 or derivatives - valid if not signing - if (!(((bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 44 || - (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 49 || - (bip32PathInt.path[BIP44_PURPOSE_OFFSET]^0x80000000) == 84))) { - return for_pubkey; - } - - if (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == BIP44_COIN_TYPE) || - ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET]^0x80000000) == BIP44_COIN_TYPE_2)) { - // Valid BIP 44 path - return 1; - } - // Everything else needs a user validation - return 0; +unsigned char enforce_bip44_coin_type(const unsigned char *bip32Path, + bool for_pubkey) { + bip32_path_t bip32PathInt; + // No enforcement required + if (BIP44_COIN_TYPE == 0) { + return 1; + } + // Path is too short - always require a user validation if signing + if (bip32Path[0] < 2) { + return for_pubkey; + } + + if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { + return 1; + } + + // Path is not compliant with BIP 44 or derivatives - valid if not signing + if (!(((bip32PathInt.path[BIP44_PURPOSE_OFFSET] ^ 0x80000000) == 44 || + (bip32PathInt.path[BIP44_PURPOSE_OFFSET] ^ 0x80000000) == 49 || + (bip32PathInt.path[BIP44_PURPOSE_OFFSET] ^ 0x80000000) == 84))) { + return for_pubkey; + } + + if (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET] ^ 0x80000000) == + BIP44_COIN_TYPE) || + ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET] ^ 0x80000000) == + BIP44_COIN_TYPE_2)) { + // Valid BIP 44 path + return 1; + } + // Everything else needs a user validation + return 0; } -int sign_finalhash(unsigned char* path, size_t path_len, unsigned char *in, unsigned short inlen, - unsigned char *out, size_t* outlen) { +int sign_finalhash(unsigned char *path, size_t path_len, unsigned char *in, + unsigned short inlen, unsigned char *out, size_t *outlen) { - unsigned int info = 0; + unsigned int info = 0; - io_seproxyhal_io_heartbeat(); - - bip32_path_t bip32Path; - bip32Path.length = path[0]; + io_seproxyhal_io_heartbeat(); - if (!parse_serialized_path(&bip32Path, path, path_len)) { - return -1; - } + bip32_path_t bip32Path; + bip32Path.length = path[0]; - if (bip32_derive_ecdsa_sign_hash_256( - CX_CURVE_SECP256K1, - bip32Path.path, - bip32Path.length, - CX_LAST | CX_RND_RFC6979, - CX_SHA256, - in, - inlen, - out, - outlen, - &info) != CX_OK) { - return -1; - } + if (!parse_serialized_path(&bip32Path, path, path_len)) { + return -1; + } - // Store information about the parity of the 'y' coordinate - if (info & CX_ECCINFO_PARITY_ODD) { - out[0] |= 0x01; - } + if (bip32_derive_ecdsa_sign_hash_256(CX_CURVE_SECP256K1, bip32Path.path, + bip32Path.length, + CX_LAST | CX_RND_RFC6979, CX_SHA256, in, + inlen, out, outlen, &info) != CX_OK) { + return -1; + } - io_seproxyhal_io_heartbeat(); - return 0; + // Store information about the parity of the 'y' coordinate + if (info & CX_ECCINFO_PARITY_ODD) { + out[0] |= 0x01; + } + + io_seproxyhal_io_heartbeat(); + return 0; } -int get_public_key(const unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode) { +int get_public_key(const unsigned char *keyPath, size_t keyPath_len, + uint8_t raw_pubkey[static 65], unsigned char *chainCode) { - bip32_path_t bip32Path; + bip32_path_t bip32Path; - if (!parse_serialized_path(&bip32Path, keyPath, keyPath_len)) { - return -1; - } + if (!parse_serialized_path(&bip32Path, keyPath, keyPath_len)) { + return -1; + } - if (bip32_derive_get_pubkey_256( - CX_CURVE_SECP256K1, - bip32Path.path, - bip32Path.length, - raw_pubkey, - chainCode, - CX_SHA512) != CX_OK) - { - return -1; - } + if (bip32_derive_get_pubkey_256(CX_CURVE_SECP256K1, bip32Path.path, + bip32Path.length, raw_pubkey, chainCode, + CX_SHA512) != CX_OK) { + return -1; + } - return 0; + return 0; } void compress_public_key_value(unsigned char *value) { - bool odd = (value[64] & 1); - value[0] = odd ? 0x03 : 0x02; + bool odd = (value[64] & 1); + value[0] = odd ? 0x03 : 0x02; } -bool parse_serialized_path(bip32_path_t* path, const unsigned char* serialized_path, unsigned char serialized_path_length) { - if (serialized_path_length < 1 || - serialized_path[0] > MAX_BIP32_PATH || - serialized_path[0] * 4 + 1 > serialized_path_length) - return false; - path->length = serialized_path[0]; - serialized_path++; - for (int i = 0; i < path->length; i += 1, serialized_path += 4) { - path->path[i] = read_u32_be(serialized_path, 0); - } - return true; +bool parse_serialized_path(bip32_path_t *path, + const unsigned char *serialized_path, + unsigned char serialized_path_length) { + if (serialized_path_length < 1 || serialized_path[0] > MAX_BIP32_PATH || + serialized_path[0] * 4 + 1 > serialized_path_length) + return false; + path->length = serialized_path[0]; + serialized_path++; + for (int i = 0; i < path->length; i += 1, serialized_path += 4) { + path->path[i] = read_u32_be(serialized_path, 0); + } + return true; } diff --git a/lib-app-bitcoin/helpers.h b/lib-app-bitcoin/helpers.h index 88314f74..9c100a83 100644 --- a/lib-app-bitcoin/helpers.h +++ b/lib-app-bitcoin/helpers.h @@ -1,26 +1,26 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once -#include "os.h" #include "cx.h" -#include "stdbool.h" #include "filesystem_tx.h" +#include "os.h" +#include "stdbool.h" #define OUTPUT_SCRIPT_REGULAR_PRE_LENGTH 4 #define OUTPUT_SCRIPT_REGULAR_POST_LENGTH 2 @@ -30,28 +30,32 @@ #define OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET 3 typedef struct bip32_path { - unsigned char length; - unsigned int path[MAX_BIP32_PATH]; + unsigned char length; + unsigned int path[MAX_BIP32_PATH]; } bip32_path_t; void public_key_hash160(unsigned char *in, unsigned short inlen, - unsigned char out [static CX_RIPEMD160_SIZE]); + unsigned char out[static CX_RIPEMD160_SIZE]); unsigned short public_key_to_encoded_base58( unsigned char *in, unsigned short inlen, unsigned char *out, unsigned short outlen, unsigned short version, unsigned char alreadyHashed); -unsigned char bip44_derivation_guard(const unsigned char *bip32Path, bool is_change_path); -unsigned char enforce_bip44_coin_type(const unsigned char *bip32Path, bool for_pubkey); +unsigned char bip44_derivation_guard(const unsigned char *bip32Path, + bool is_change_path); +unsigned char enforce_bip44_coin_type(const unsigned char *bip32Path, + bool for_pubkey); void swap_bytes(unsigned char *target, unsigned char *source, - unsigned char size); + unsigned char size); -int sign_finalhash(unsigned char *path, size_t path_len, - unsigned char *in, unsigned short inlen, - unsigned char *out, size_t* outlen); +int sign_finalhash(unsigned char *path, size_t path_len, unsigned char *in, + unsigned short inlen, unsigned char *out, size_t *outlen); -int get_public_key(const unsigned char* keyPath, size_t keyPath_len, uint8_t raw_pubkey[static 65], unsigned char* chainCode); +int get_public_key(const unsigned char *keyPath, size_t keyPath_len, + uint8_t raw_pubkey[static 65], unsigned char *chainCode); void compress_public_key_value(unsigned char *value); -bool parse_serialized_path(bip32_path_t* path, const unsigned char* serialized_path, unsigned char serialized_path_length); +bool parse_serialized_path(bip32_path_t *path, + const unsigned char *serialized_path, + unsigned char serialized_path_length); diff --git a/lib-app-bitcoin/swap/handle_check_address.c b/lib-app-bitcoin/swap/handle_check_address.c index 95e6d166..7b8e7f0b 100644 --- a/lib-app-bitcoin/swap/handle_check_address.c +++ b/lib-app-bitcoin/swap/handle_check_address.c @@ -1,7 +1,7 @@ #include "handle_check_address.h" -#include "helpers.h" -#include "context.h" #include "cashaddr.h" +#include "context.h" +#include "helpers.h" #include "segwit_addr.h" #define P1_NO_DISPLAY 0x00 @@ -13,137 +13,127 @@ #define P2_NATIVE_SEGWIT 0x02 #define P2_CASHADDR 0x03 -static bool derive_compressed_public_key( - unsigned char* serialized_path, unsigned char serialized_path_length, - unsigned char* public_key, unsigned char public_key_length) { - UNUSED(public_key_length); - uint8_t pubKey[65]; +static bool derive_compressed_public_key(unsigned char *serialized_path, + unsigned char serialized_path_length, + unsigned char *public_key, + unsigned char public_key_length) { + UNUSED(public_key_length); + uint8_t pubKey[65]; - if (get_public_key(serialized_path, serialized_path_length, pubKey, NULL)){ - return false; - } + if (get_public_key(serialized_path, serialized_path_length, pubKey, NULL)) { + return false; + } - compress_public_key_value(pubKey); - memcpy(public_key, pubKey, 33); - return true; + compress_public_key_value(pubKey); + memcpy(public_key, pubKey, 33); + return true; } static bool get_address_from_compressed_public_key( - unsigned char format, - unsigned char* compressed_pub_key, - unsigned short payToAddressVersion, - unsigned short payToScriptHashVersion, - const char* native_segwit_prefix, - char * address, - unsigned char max_address_length -) { - bool segwit = (format == P2_SEGWIT); - bool nativeSegwit = (format == P2_NATIVE_SEGWIT); - bool cashAddr = (format == P2_CASHADDR); - int address_length; - if (cashAddr) { - uint8_t tmp[20]; - public_key_hash160(compressed_pub_key, // IN - 33, // INLEN - tmp); - if (!cashaddr_encode(tmp, 20, (uint8_t *)address, max_address_length, CASHADDR_P2PKH)) - return false; - } else if (!(segwit || nativeSegwit)) { - // public_key_to_encoded_base58 doesn't add terminating 0, - // so we will do this ourself - address_length = public_key_to_encoded_base58( - compressed_pub_key, // IN - 33, // INLEN - (uint8_t *)address, // OUT - max_address_length - 1, // MAXOUTLEN - payToAddressVersion, 0); - address[address_length] = 0; + unsigned char format, unsigned char *compressed_pub_key, + unsigned short payToAddressVersion, unsigned short payToScriptHashVersion, + const char *native_segwit_prefix, char *address, + unsigned char max_address_length) { + bool segwit = (format == P2_SEGWIT); + bool nativeSegwit = (format == P2_NATIVE_SEGWIT); + bool cashAddr = (format == P2_CASHADDR); + int address_length; + if (cashAddr) { + uint8_t tmp[20]; + public_key_hash160(compressed_pub_key, // IN + 33, // INLEN + tmp); + if (!cashaddr_encode(tmp, 20, (uint8_t *)address, max_address_length, + CASHADDR_P2PKH)) + return false; + } else if (!(segwit || nativeSegwit)) { + // public_key_to_encoded_base58 doesn't add terminating 0, + // so we will do this ourself + address_length = + public_key_to_encoded_base58(compressed_pub_key, // IN + 33, // INLEN + (uint8_t *)address, // OUT + max_address_length - 1, // MAXOUTLEN + payToAddressVersion, 0); + address[address_length] = 0; + } else { + uint8_t tmp[22]; + tmp[0] = 0x00; + tmp[1] = 0x14; + public_key_hash160(compressed_pub_key, // IN + 33, // INLEN + tmp + 2 // OUT + ); + if (!nativeSegwit) { + address_length = public_key_to_encoded_base58(tmp, // IN + 22, // INLEN + (uint8_t *)address, // OUT + 150, // MAXOUTLEN + payToScriptHashVersion, 0); + address[address_length] = 0; } else { - uint8_t tmp[22]; - tmp[0] = 0x00; - tmp[1] = 0x14; - public_key_hash160(compressed_pub_key, // IN - 33, // INLEN - tmp + 2 // OUT - ); - if (!nativeSegwit) { - address_length = public_key_to_encoded_base58( - tmp, // IN - 22, // INLEN - (uint8_t *)address, // OUT - 150, // MAXOUTLEN - payToScriptHashVersion, 0); - address[address_length] = 0; - } else { - if (!native_segwit_prefix) - return false; - if (!segwit_addr_encode( - address, - native_segwit_prefix, 0, tmp + 2, 20)) { - return false; - } - } + if (!native_segwit_prefix) + return false; + if (!segwit_addr_encode(address, native_segwit_prefix, 0, tmp + 2, 20)) { + return false; + } } - return true; + } + return true; } -void swap_handle_check_address(check_address_parameters_t* params) { - PRINTF("Inside swap_handle_check_address\n"); - params->result = 0; +void swap_handle_check_address(check_address_parameters_t *params) { + PRINTF("Inside swap_handle_check_address\n"); + params->result = 0; - if (params->address_parameters == NULL) { - PRINTF("derivation path expected\n"); - return; - } + if (params->address_parameters == NULL) { + PRINTF("derivation path expected\n"); + return; + } - if (params->address_to_check == NULL) { - PRINTF("Address to check expected\n"); - return; - } - PRINTF("Address to check %s\n", params->address_to_check); + if (params->address_to_check == NULL) { + PRINTF("Address to check expected\n"); + return; + } + PRINTF("Address to check %s\n", params->address_to_check); - if (params->extra_id_to_check == NULL) { - PRINTF("extra_id_to_check expected\n"); - return; - } else if (params->extra_id_to_check[0] != '\0') { - PRINTF("extra_id_to_check expected empty, not '%s'\n", params->extra_id_to_check); - return; - } + if (params->extra_id_to_check == NULL) { + PRINTF("extra_id_to_check expected\n"); + return; + } else if (params->extra_id_to_check[0] != '\0') { + PRINTF("extra_id_to_check expected empty, not '%s'\n", + params->extra_id_to_check); + return; + } - if (params->address_to_check == 0) { - PRINTF("Address to check == 0\n"); - return; - } + if (params->address_to_check == 0) { + PRINTF("Address to check == 0\n"); + return; + } - unsigned char compressed_public_key[33]; - if (!derive_compressed_public_key( - params->address_parameters + 1, - params->address_parameters_length - 1, - compressed_public_key, - sizeof(compressed_public_key))) { - PRINTF("Failed to derive public key\n"); - return; - } + unsigned char compressed_public_key[33]; + if (!derive_compressed_public_key( + params->address_parameters + 1, params->address_parameters_length - 1, + compressed_public_key, sizeof(compressed_public_key))) { + PRINTF("Failed to derive public key\n"); + return; + } - char address[51]; - if (!get_address_from_compressed_public_key( - params->address_parameters[0], - compressed_public_key, - COIN_P2PKH_VERSION, - COIN_P2SH_VERSION, - COIN_NATIVE_SEGWIT_PREFIX, - address, - sizeof(address))) { - PRINTF("Can't create address from given public key\n"); - return; - } - if (strcmp(params->address_to_check, address) != 0) { - PRINTF("Address %s != %s\n", params->address_to_check, address); - return; - } + char address[51]; + if (!get_address_from_compressed_public_key( + params->address_parameters[0], compressed_public_key, + COIN_P2PKH_VERSION, COIN_P2SH_VERSION, COIN_NATIVE_SEGWIT_PREFIX, + address, sizeof(address))) { + PRINTF("Can't create address from given public key\n"); + return; + } + if (strcmp(params->address_to_check, address) != 0) { + PRINTF("Address %s != %s\n", params->address_to_check, address); + return; + } - PRINTF("Addresses match\n"); + PRINTF("Addresses match\n"); - params->result = 1; - return; + params->result = 1; + return; } \ No newline at end of file diff --git a/lib-app-bitcoin/swap/handle_check_address.h b/lib-app-bitcoin/swap/handle_check_address.h index 2e5eaa54..95361a26 100644 --- a/lib-app-bitcoin/swap/handle_check_address.h +++ b/lib-app-bitcoin/swap/handle_check_address.h @@ -3,6 +3,7 @@ #include "swap_lib_calls.h" -void swap_handle_check_address(check_address_parameters_t* check_address_params); +void swap_handle_check_address( + check_address_parameters_t *check_address_params); #endif // _HANDLE_CHECK_ADDRESS_H_ \ No newline at end of file diff --git a/lib-app-bitcoin/swap/handle_get_printable_amount.c b/lib-app-bitcoin/swap/handle_get_printable_amount.c index d801bfab..c6834598 100644 --- a/lib-app-bitcoin/swap/handle_get_printable_amount.c +++ b/lib-app-bitcoin/swap/handle_get_printable_amount.c @@ -1,20 +1,23 @@ #include "read.h" -#include "handle_get_printable_amount.h" #include "display_utils.h" +#include "handle_get_printable_amount.h" -void swap_handle_get_printable_amount(get_printable_amount_parameters_t* params) { - params->printable_amount[0] = 0; - if (params->amount_length > 8) { - PRINTF("Amount is too big"); - return; - } - unsigned char amount[8]; - memset(amount, 0, 8); - memcpy(amount + (8 - params->amount_length), params->amount, params->amount_length); - - format_sats_amount(COIN_COINID_SHORT, - (uint64_t)(read_u64_be(amount, 0)), // Cast prevents weird compilo bug - params->printable_amount); +void swap_handle_get_printable_amount( + get_printable_amount_parameters_t *params) { + params->printable_amount[0] = 0; + if (params->amount_length > 8) { + PRINTF("Amount is too big"); return; + } + unsigned char amount[8]; + memset(amount, 0, 8); + memcpy(amount + (8 - params->amount_length), params->amount, + params->amount_length); + + format_sats_amount( + COIN_COINID_SHORT, + (uint64_t)(read_u64_be(amount, 0)), // Cast prevents weird compilo bug + params->printable_amount); + return; } \ No newline at end of file diff --git a/lib-app-bitcoin/swap/handle_get_printable_amount.h b/lib-app-bitcoin/swap/handle_get_printable_amount.h index f47d46e0..2718126c 100644 --- a/lib-app-bitcoin/swap/handle_get_printable_amount.h +++ b/lib-app-bitcoin/swap/handle_get_printable_amount.h @@ -1,9 +1,10 @@ #ifndef _HANDLE_GET_PRINTABLE_AMOUNT_H_ #define _HANDLE_GET_PRINTABLE_AMOUNT_H_ -#include "swap_lib_calls.h" #include "context.h" +#include "swap_lib_calls.h" -void swap_handle_get_printable_amount(get_printable_amount_parameters_t* get_printable_amount_params); +void swap_handle_get_printable_amount( + get_printable_amount_parameters_t *get_printable_amount_params); #endif // _HANDLE_GET_PRINTABLE_AMOUNT_H_ \ No newline at end of file diff --git a/lib-app-bitcoin/swap/handle_swap_sign_transaction.c b/lib-app-bitcoin/swap/handle_swap_sign_transaction.c index 9452ef94..e30abb58 100644 --- a/lib-app-bitcoin/swap/handle_swap_sign_transaction.c +++ b/lib-app-bitcoin/swap/handle_swap_sign_transaction.c @@ -1,7 +1,7 @@ #include "handle_swap_sign_transaction.h" -#include "os_io_seproxyhal.h" -#include "display_variables.h" #include "context.h" +#include "display_variables.h" +#include "os_io_seproxyhal.h" #include "usbd_core.h" #include "ux.h" @@ -14,60 +14,64 @@ // Save the BSS address where we will write the return value when finished static uint8_t *G_swap_sign_return_value_address; -bool swap_copy_transaction_parameters(create_transaction_parameters_t* params) { - PRINTF("Inside swap_copy_transaction_parameters\n"); - - // Ensure no extraid - if (params->destination_address_extra_id == NULL) { - PRINTF("destination_address_extra_id expected\n"); - return false; - } else if (params->destination_address_extra_id[0] != '\0') { - PRINTF("destination_address_extra_id expected empty, not '%s'\n", - params->destination_address_extra_id); - return false; - } +bool swap_copy_transaction_parameters(create_transaction_parameters_t *params) { + PRINTF("Inside swap_copy_transaction_parameters\n"); - // We need this "trick" as the input data position can overlap with app globals - // and also because we want to memset the whole bss segment as it is not done - // when an app is called as a lib. - // This is necessary as many part of the code expect bss variables to - // initialized at 0. - swap_data_t swap_validated; - memset(&swap_validated, 0, sizeof(swap_validated)); + // Ensure no extraid + if (params->destination_address_extra_id == NULL) { + PRINTF("destination_address_extra_id expected\n"); + return false; + } else if (params->destination_address_extra_id[0] != '\0') { + PRINTF("destination_address_extra_id expected empty, not '%s'\n", + params->destination_address_extra_id); + return false; + } - // Save recipient - strlcpy(swap_validated.destination_address, - params->destination_address, - sizeof(swap_validated.destination_address)); - if (swap_validated.destination_address[sizeof(swap_validated.destination_address) - 1] != '\0') { - return false; - } + // We need this "trick" as the input data position can overlap with app + // globals and also because we want to memset the whole bss segment as it is + // not done when an app is called as a lib. This is necessary as many part of + // the code expect bss variables to initialized at 0. + swap_data_t swap_validated; + memset(&swap_validated, 0, sizeof(swap_validated)); - // store amount as big endian in 8 bytes, so the passed data should be alligned to right - // input {0xEE, 0x00, 0xFF} should be stored like {0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x00, 0xFF} - memcpy(swap_validated.amount + 8 - params->amount_length, params->amount, params->amount_length); - memcpy(swap_validated.fees + 8 - params->fee_amount_length, params->fee_amount, params->fee_amount_length); + // Save recipient + strlcpy(swap_validated.destination_address, params->destination_address, + sizeof(swap_validated.destination_address)); + if (swap_validated + .destination_address[sizeof(swap_validated.destination_address) - + 1] != '\0') { + return false; + } - // Save amount and fees -// swap_str_to_u64(params->amount, params->amount_length, &swap_validated.amount); -// swap_str_to_u64(params->fee_amount, params->fee_amount_length, &swap_validated.fees); -// - swap_validated.initialized = true; + // store amount as big endian in 8 bytes, so the passed data should be + // alligned to right input {0xEE, 0x00, 0xFF} should be stored like {0x00, + // 0x00, 0x00, 0x00, 0x00, 0xEE, 0x00, 0xFF} + memcpy(swap_validated.amount + 8 - params->amount_length, params->amount, + params->amount_length); + memcpy(swap_validated.fees + 8 - params->fee_amount_length, + params->fee_amount, params->fee_amount_length); - // Full reset the global variables - os_explicit_zero_BSS_segment(); + // Save amount and fees + // swap_str_to_u64(params->amount, params->amount_length, + // &swap_validated.amount); swap_str_to_u64(params->fee_amount, + // params->fee_amount_length, &swap_validated.fees); + // + swap_validated.initialized = true; - // Keep the address at which we'll reply the signing status - G_swap_sign_return_value_address = ¶ms->result; + // Full reset the global variables + os_explicit_zero_BSS_segment(); + // Keep the address at which we'll reply the signing status + G_swap_sign_return_value_address = ¶ms->result; - // Copy from stack back to global data segment - memcpy(&vars.swap_data, &swap_validated, sizeof(swap_validated)); - swap_validated.initialized = true; - return true; + // Copy from stack back to global data segment + memcpy(&vars.swap_data, &swap_validated, sizeof(swap_validated)); + swap_validated.initialized = true; + return true; } -void __attribute__((noreturn)) swap_finalize_exchange_sign_transaction(bool is_success) { - *G_swap_sign_return_value_address = is_success; - os_lib_end(); +void __attribute__((noreturn)) +swap_finalize_exchange_sign_transaction(bool is_success) { + *G_swap_sign_return_value_address = is_success; + os_lib_end(); } diff --git a/lib-app-bitcoin/swap/handle_swap_sign_transaction.h b/lib-app-bitcoin/swap/handle_swap_sign_transaction.h index a9e2914c..7b3d12e3 100644 --- a/lib-app-bitcoin/swap/handle_swap_sign_transaction.h +++ b/lib-app-bitcoin/swap/handle_swap_sign_transaction.h @@ -3,8 +3,10 @@ #include "swap_lib_calls.h" -bool swap_copy_transaction_parameters(create_transaction_parameters_t* sign_transaction_params); +bool swap_copy_transaction_parameters( + create_transaction_parameters_t *sign_transaction_params); -void __attribute__((noreturn)) swap_finalize_exchange_sign_transaction(bool is_success); +void __attribute__((noreturn)) +swap_finalize_exchange_sign_transaction(bool is_success); #endif // _HANDLE_SWAP_SIGN_TRANSACTION_H_ diff --git a/lib-app-bitcoin/transaction.c b/lib-app-bitcoin/transaction.c index ab59b215..2d6b0e1e 100644 --- a/lib-app-bitcoin/transaction.c +++ b/lib-app-bitcoin/transaction.c @@ -1,19 +1,19 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #include "ledger_assert.h" #include "lib_standard_app/read.h" @@ -21,37 +21,47 @@ #include "swap.h" #include "apdu_constants.h" -#include "display_variables.h" #include "be_operations.h" -#include "transaction.h" #include "context.h" +#include "display_variables.h" #include "filesystem.h" #include "helpers.h" +#include "transaction.h" #ifndef COIN_CONSENSUS_BRANCH_ID #define COIN_CONSENSUS_BRANCH_ID 0 -#endif +#endif #define CONSENSUS_BRANCH_ID_OVERWINTER 0x5ba81b19 #define CONSENSUS_BRANCH_ID_SAPLING 0x76b809bb #define CONSENSUS_BRANCH_ID_ZCLASSIC 0x930b540d -unsigned char const OVERWINTER_PARAM_PREVOUTS[16] = { 'Z', 'c', 'a', 's', 'h', 'P', 'r', 'e', 'v', 'o', 'u', 't', 'H', 'a', 's', 'h' }; -unsigned char const OVERWINTER_PARAM_SEQUENCE[16] = { 'Z', 'c', 'a', 's', 'h', 'S', 'e', 'q', 'u', 'e', 'n', 'c', 'H', 'a', 's', 'h' }; -unsigned char const OVERWINTER_PARAM_OUTPUTS[16] = { 'Z', 'c', 'a', 's', 'h', 'O', 'u', 't', 'p', 'u', 't', 's', 'H', 'a', 's', 'h' }; -unsigned char const OVERWINTER_PARAM_SIGHASH[16] = { 'Z', 'c', 'a', 's', 'h', 'S', 'i', 'g', 'H', 'a', 's', 'h', 0, 0, 0, 0 }; -unsigned char const OVERWINTER_NO_JOINSPLITS[32] = { 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 }; +unsigned char const OVERWINTER_PARAM_PREVOUTS[16] = { + 'Z', 'c', 'a', 's', 'h', 'P', 'r', 'e', + 'v', 'o', 'u', 't', 'H', 'a', 's', 'h'}; +unsigned char const OVERWINTER_PARAM_SEQUENCE[16] = { + 'Z', 'c', 'a', 's', 'h', 'S', 'e', 'q', + 'u', 'e', 'n', 'c', 'H', 'a', 's', 'h'}; +unsigned char const OVERWINTER_PARAM_OUTPUTS[16] = { + 'Z', 'c', 'a', 's', 'h', 'O', 'u', 't', + 'p', 'u', 't', 's', 'H', 'a', 's', 'h'}; +unsigned char const OVERWINTER_PARAM_SIGHASH[16] = { + 'Z', 'c', 'a', 's', 'h', 'S', 'i', 'g', 'H', 'a', 's', 'h', 0, 0, 0, 0}; +unsigned char const OVERWINTER_NO_JOINSPLITS[32] = { + 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}; // Check if fOverwintered flag is set and if nVersion is >= 0x03 -#define TRUSTED_INPUT_OVERWINTER ( (COIN_KIND == COIN_KIND_ZCASH || \ - COIN_KIND == COIN_KIND_ZCLASSIC || \ - COIN_KIND == COIN_KIND_KOMODO) && \ - (read_u32_le(context.transactionVersion, 0) & (1<<31)) && \ - (read_u32_le(context.transactionVersion, 0) ^ (1<<31)) >= 0x03 \ - ) +#define TRUSTED_INPUT_OVERWINTER \ + ((COIN_KIND == COIN_KIND_ZCASH || COIN_KIND == COIN_KIND_ZCLASSIC || \ + COIN_KIND == COIN_KIND_KOMODO) && \ + (read_u32_le(context.transactionVersion, 0) & (1 << 31)) && \ + (read_u32_le(context.transactionVersion, 0) ^ (1 << 31)) >= 0x03) static void check_transaction_available(unsigned char x) { - LEDGER_ASSERT(context.transactionDataRemaining >= x, "Check transaction available failed %d < %d\n", context.transactionDataRemaining, x); + LEDGER_ASSERT(context.transactionDataRemaining >= x, + "Check transaction available failed %d < %d\n", + context.transactionDataRemaining, x); } #define OP_HASH160 0xA9 @@ -59,848 +69,822 @@ static void check_transaction_available(unsigned char x) { #define OP_CHECKMULTISIG 0xAE static void transaction_offset(unsigned char value) { - if ((context.transactionHashOption & TRANSACTION_HASH_FULL) != 0) { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", value, context.transactionBufferPointer); - if (context.usingOverwinter) { - LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); - } - else { - LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - context.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); - } - } - if ((context.transactionHashOption & - TRANSACTION_HASH_AUTHORIZATION) != 0) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", value, context.transactionBufferPointer); - LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashAuthorization.header, 0, - context.transactionBufferPointer, value, NULL, 0) == CX_OK, "Hash Failed"); + if ((context.transactionHashOption & TRANSACTION_HASH_FULL) != 0) { + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", value, + context.transactionBufferPointer); + if (context.usingOverwinter) { + LEDGER_ASSERT( + cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, + context.transactionBufferPointer, value, NULL, + 0) == CX_OK, + "Hash Failed"); + } else { + LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashFull.sha256.header, + 0, context.transactionBufferPointer, value, + NULL, 0) == CX_OK, + "Hash Failed"); } + } + if ((context.transactionHashOption & TRANSACTION_HASH_AUTHORIZATION) != 0) { + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", value, + context.transactionBufferPointer); + LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashAuthorization.header, + 0, context.transactionBufferPointer, value, + NULL, 0) == CX_OK, + "Hash Failed"); + } } static void transaction_offset_increase(unsigned char value) { - transaction_offset(value); - context.transactionBufferPointer += value; - context.transactionDataRemaining -= value; + transaction_offset(value); + context.transactionBufferPointer += value; + context.transactionDataRemaining -= value; } static unsigned long int transaction_get_varint(void) { - unsigned char firstByte; - check_transaction_available(1); - firstByte = *context.transactionBufferPointer; - if (firstByte < 0xFD) { - transaction_offset_increase(1); - return firstByte; - } else if (firstByte == 0xFD) { - unsigned long int result; - transaction_offset_increase(1); - check_transaction_available(2); - result = - (unsigned long int)(*context.transactionBufferPointer) | - ((unsigned long int)(*(context.transactionBufferPointer + - 1)) - << 8); - transaction_offset_increase(2); - return result; - } else if (firstByte == 0xFE) { - unsigned long int result; - transaction_offset_increase(1); + unsigned char firstByte; + check_transaction_available(1); + firstByte = *context.transactionBufferPointer; + if (firstByte < 0xFD) { + transaction_offset_increase(1); + return firstByte; + } else if (firstByte == 0xFD) { + unsigned long int result; + transaction_offset_increase(1); + check_transaction_available(2); + result = + (unsigned long int)(*context.transactionBufferPointer) | + ((unsigned long int)(*(context.transactionBufferPointer + 1)) << 8); + transaction_offset_increase(2); + return result; + } else if (firstByte == 0xFE) { + unsigned long int result; + transaction_offset_increase(1); + check_transaction_available(4); + result = read_u32_le(context.transactionBufferPointer, 0); + transaction_offset_increase(4); + return result; + } else { + LEDGER_ASSERT(false, "Varint parsing failed"); + __builtin_unreachable(); + } +} + +void transaction_parse(unsigned char parseMode) { + for (;;) { + switch (context.transactionContext.transactionState) { + case TRANSACTION_NONE: { + PRINTF("Init transaction parser\n"); + // Reset transaction state + context.transactionContext.transactionRemainingInputsOutputs = 0; + context.transactionContext.transactionCurrentInputOutput = 0; + context.transactionContext.scriptRemaining = 0; + memset(context.transactionContext.transactionAmount, 0, + sizeof(context.transactionContext.transactionAmount)); + // TODO : transactionControlFid + // Reset hashes + if (context.usingOverwinter) { + if (context.segwitParsedOnce) { + uint8_t parameters[16]; + memmove(parameters, OVERWINTER_PARAM_SIGHASH, 16); + if (COIN_KIND == COIN_KIND_ZCLASSIC) { + write_u32_le(parameters, 12, CONSENSUS_BRANCH_ID_ZCLASSIC); + } else { + write_u32_le(parameters, 12, + context.usingOverwinter == + ZCASH_USING_OVERWINTER_SAPLING + ? (COIN_CONSENSUS_BRANCH_ID != 0 + ? COIN_CONSENSUS_BRANCH_ID + : CONSENSUS_BRANCH_ID_SAPLING) + : CONSENSUS_BRANCH_ID_OVERWINTER); + } + if (cx_blake2b_init2_no_throw(&context.transactionHashFull.blake2b, + 256, NULL, 0, parameters, 16)) { + goto fail; + } + } + } else { + if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { + goto fail; + } + } + if (cx_sha256_init_no_throw(&context.transactionHashAuthorization)) { + goto fail; + } + if (context.usingSegwit) { + context.transactionHashOption = 0; + if (!context.segwitParsedOnce) { + if (context.usingOverwinter) { + if (cx_blake2b_init2_no_throw( + &context.segwit.hash.hashPrevouts.blake2b, 256, NULL, 0, + (uint8_t *)OVERWINTER_PARAM_PREVOUTS, 16)) { + goto fail; + } + if (cx_blake2b_init2_no_throw( + &context.transactionHashFull.blake2b, 256, NULL, 0, + (uint8_t *)OVERWINTER_PARAM_SEQUENCE, 16)) { + goto fail; + } + } else { + if (cx_sha256_init_no_throw( + &context.segwit.hash.hashPrevouts.sha256)) { + goto fail; + } + } + } else { + PRINTF("Resume SegWit hash\n"); + PRINTF("SEGWIT Version\n%.*H\n", sizeof(context.transactionVersion), + context.transactionVersion); + PRINTF("SEGWIT HashedPrevouts\n%.*H\n", + sizeof(context.segwit.cache.hashedPrevouts), + context.segwit.cache.hashedPrevouts); + PRINTF("SEGWIT HashedSequence\n%.*H\n", + sizeof(context.segwit.cache.hashedSequence), + context.segwit.cache.hashedSequence); + if (context.usingOverwinter) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, + context.transactionVersion, + sizeof(context.transactionVersion), NULL, 0)) { + goto fail; + } + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, + context.nVersionGroupId, + sizeof(context.nVersionGroupId), NULL, 0)) { + goto fail; + } + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, + context.segwit.cache.hashedPrevouts, + sizeof(context.segwit.cache.hashedPrevouts), + NULL, 0)) { + goto fail; + } + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, + context.segwit.cache.hashedSequence, + sizeof(context.segwit.cache.hashedSequence), + NULL, 0)) { + goto fail; + } + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, + context.segwit.cache.hashedOutputs, + sizeof(context.segwit.cache.hashedOutputs), + NULL, 0)) { + goto fail; + } + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, + OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { + goto fail; + } + if (context.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, + 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, + 0)) { // sapling hashShieldedSpend) + goto fail; + } + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, + 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, + 0)) { // sapling hashShieldedOutputs + goto fail; + } + } + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, + context.nLockTime, sizeof(context.nLockTime), + NULL, 0)) { + goto fail; + } + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, + context.nExpiryHeight, + sizeof(context.nExpiryHeight), NULL, 0)) { + goto fail; + } + if (context.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { + unsigned char valueBalance[8]; + memset(valueBalance, 0, sizeof(valueBalance)); + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, + 0, valueBalance, sizeof(valueBalance), NULL, + 0)) { // sapling valueBalance + goto fail; + } + } + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, + context.sigHashType, + sizeof(context.sigHashType), NULL, 0)) { + goto fail; + } + } else { + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", + sizeof(context.transactionVersion), + context.transactionVersion); + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + context.transactionVersion, + sizeof(context.transactionVersion), NULL, 0)) { + goto fail; + } + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", + sizeof(context.segwit.cache.hashedPrevouts), + context.segwit.cache.hashedPrevouts); + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + context.segwit.cache.hashedPrevouts, + sizeof(context.segwit.cache.hashedPrevouts), + NULL, 0)) { + goto fail; + } + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", + sizeof(context.segwit.cache.hashedSequence), + context.segwit.cache.hashedSequence); + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + context.segwit.cache.hashedSequence, + sizeof(context.segwit.cache.hashedSequence), + NULL, 0)) { + goto fail; + } + PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", + sizeof(context.segwit.cache), + (unsigned char *)&context.segwit.cache); + if (cx_hash_no_throw(&context.transactionHashAuthorization.header, + 0, (unsigned char *)&context.segwit.cache, + sizeof(context.segwit.cache), NULL, 0)) { + goto fail; + } + } + } + } + // Parse the beginning of the transaction + // Version + check_transaction_available(4); + memmove(context.transactionVersion, context.transactionBufferPointer, 4); + transaction_offset_increase(4); + + if (context.usingOverwinter || TRUSTED_INPUT_OVERWINTER) { + // nVersionGroupId check_transaction_available(4); - result = read_u32_le(context.transactionBufferPointer, 0); + memmove(context.nVersionGroupId, context.transactionBufferPointer, 4); transaction_offset_increase(4); - return result; - } else { - LEDGER_ASSERT(false, "Varint parsing failed"); - __builtin_unreachable(); + } + + if (COIN_FLAGS & FLAG_PEERCOIN_SUPPORT) { + if (((COIN_FAMILY == FAMILY_PEERCOIN && + (context.transactionVersion[0] < 3))) || + ((COIN_FAMILY == FAMILY_STEALTH) && + (context.transactionVersion[0] < 2))) { + // Timestamp + check_transaction_available(4); + transaction_offset_increase(4); + } + } + + // Number of inputs + context.transactionContext.transactionRemainingInputsOutputs = + transaction_get_varint(); + PRINTF("Number of inputs : %d\n", + context.transactionContext.transactionRemainingInputsOutputs); + if (G_called_from_swap && parseMode == PARSE_MODE_SIGNATURE) { + // remember number of inputs to know when to exit from library + // we will count number of already signed inputs and compare with this + // value As there are a lot of different states in which we can have + // different number of input (when for ex. we sign segregated witness) + if (vars.swap_data.totalNumberOfInputs == 0) { + vars.swap_data.totalNumberOfInputs = + context.transactionContext.transactionRemainingInputsOutputs; + } + // Reseting the flag, because we should check address ones for each + // input + vars.swap_data.was_address_checked = 0; + } + // Ready to proceed + context.transactionContext.transactionState = + TRANSACTION_DEFINED_WAIT_INPUT; + + __attribute__((fallthrough)); } -} -void transaction_parse(unsigned char parseMode) { - for (;;) { - switch (context.transactionContext.transactionState) { - case TRANSACTION_NONE: { - PRINTF("Init transaction parser\n"); - // Reset transaction state - context.transactionContext - .transactionRemainingInputsOutputs = 0; - context.transactionContext - .transactionCurrentInputOutput = 0; - context.transactionContext.scriptRemaining = 0; - memset( - context.transactionContext.transactionAmount, - 0, sizeof(context.transactionContext - .transactionAmount)); - // TODO : transactionControlFid - // Reset hashes - if (context.usingOverwinter) { - if (context.segwitParsedOnce) { - uint8_t parameters[16]; - memmove(parameters, OVERWINTER_PARAM_SIGHASH, 16); - if (COIN_KIND == COIN_KIND_ZCLASSIC) { - write_u32_le(parameters, 12, CONSENSUS_BRANCH_ID_ZCLASSIC); - } - else { - write_u32_le(parameters, 12, - context.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING ? - (COIN_CONSENSUS_BRANCH_ID != 0 ? COIN_CONSENSUS_BRANCH_ID : CONSENSUS_BRANCH_ID_SAPLING) : CONSENSUS_BRANCH_ID_OVERWINTER); - } - if (cx_blake2b_init2_no_throw(&context.transactionHashFull.blake2b, 256, NULL, 0, parameters, 16)) { - goto fail; - } - } - } - else { - if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { - goto fail; - } - } - if (cx_sha256_init_no_throw( - &context.transactionHashAuthorization)) { - goto fail; - } - if (context.usingSegwit) { - context.transactionHashOption = 0; - if (!context.segwitParsedOnce) { - if (context.usingOverwinter) { - if (cx_blake2b_init2_no_throw(&context.segwit.hash.hashPrevouts.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_PREVOUTS, 16)) { - goto fail; - } - if (cx_blake2b_init2_no_throw(&context.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_SEQUENCE, 16)) { - goto fail; - } - } - else { - if (cx_sha256_init_no_throw( - &context.segwit.hash.hashPrevouts.sha256)) { - goto fail; - } - } - } else { - PRINTF("Resume SegWit hash\n"); - PRINTF("SEGWIT Version\n%.*H\n",sizeof(context.transactionVersion),context.transactionVersion); - PRINTF("SEGWIT HashedPrevouts\n%.*H\n",sizeof(context.segwit.cache.hashedPrevouts),context.segwit.cache.hashedPrevouts); - PRINTF("SEGWIT HashedSequence\n%.*H\n",sizeof(context.segwit.cache.hashedSequence),context.segwit.cache.hashedSequence); - if (context.usingOverwinter) { - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.transactionVersion, sizeof(context.transactionVersion), NULL, 0)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.nVersionGroupId, sizeof(context.nVersionGroupId), NULL, 0)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.segwit.cache.hashedPrevouts, sizeof(context.segwit.cache.hashedPrevouts), NULL, 0)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.segwit.cache.hashedSequence, sizeof(context.segwit.cache.hashedSequence), NULL, 0)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.segwit.cache.hashedOutputs, sizeof(context.segwit.cache.hashedOutputs), NULL, 0)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { - goto fail; - } - if (context.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { // sapling hashShieldedSpend) - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { // sapling hashShieldedOutputs - goto fail; - } - - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.nLockTime, sizeof(context.nLockTime), NULL, 0)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.nExpiryHeight, sizeof(context.nExpiryHeight), NULL, 0)) { - goto fail; - } - if (context.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { - unsigned char valueBalance[8]; - memset(valueBalance, 0, sizeof(valueBalance)); - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, valueBalance, sizeof(valueBalance), NULL, 0)) { // sapling valueBalance - goto fail; - } - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.sigHashType, sizeof(context.sigHashType), NULL, 0)) { - goto fail; - } - } - else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context.transactionVersion), context.transactionVersion); - if (cx_hash_no_throw( - &context.transactionHashFull.sha256.header, 0, - context.transactionVersion, - sizeof(context.transactionVersion), - NULL, 0)) { - goto fail; - } - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context.segwit.cache.hashedPrevouts), context.segwit.cache.hashedPrevouts); - if (cx_hash_no_throw( - &context.transactionHashFull.sha256.header, 0, - context.segwit.cache.hashedPrevouts, - sizeof(context.segwit.cache - .hashedPrevouts), - NULL, 0)) { - goto fail; - } - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context.segwit.cache.hashedSequence), context.segwit.cache.hashedSequence); - if (cx_hash_no_throw( - &context.transactionHashFull.sha256.header, 0, - context.segwit.cache.hashedSequence, - sizeof(context.segwit.cache - .hashedSequence), - NULL, 0)) { - goto fail; - } - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", sizeof(context.segwit.cache), (unsigned char *)&context.segwit.cache); - if (cx_hash_no_throw(&context - .transactionHashAuthorization.header, - 0, - (unsigned char *)&context - .segwit.cache, - sizeof(context.segwit.cache), - NULL, 0)) { - goto fail; - } - } - } - } - // Parse the beginning of the transaction - // Version - check_transaction_available(4); - memmove(context.transactionVersion, - context.transactionBufferPointer, 4); - transaction_offset_increase(4); - - if (context.usingOverwinter || - TRUSTED_INPUT_OVERWINTER) { - // nVersionGroupId - check_transaction_available(4); - memmove(context.nVersionGroupId, - context.transactionBufferPointer, 4); - transaction_offset_increase(4); - } - - if (COIN_FLAGS & FLAG_PEERCOIN_SUPPORT) { - if (((COIN_FAMILY == - FAMILY_PEERCOIN && - (context.transactionVersion[0] < 3))) || - ((COIN_FAMILY == FAMILY_STEALTH) && - (context.transactionVersion[0] < 2))) { - // Timestamp - check_transaction_available(4); - transaction_offset_increase(4); - } - } - - // Number of inputs - context.transactionContext - .transactionRemainingInputsOutputs = - transaction_get_varint(); - PRINTF("Number of inputs : %d\n", context.transactionContext.transactionRemainingInputsOutputs); - if (G_called_from_swap && parseMode == PARSE_MODE_SIGNATURE) { - // remember number of inputs to know when to exit from library - // we will count number of already signed inputs and compare with this value - // As there are a lot of different states in which we can have different number of input - // (when for ex. we sign segregated witness) - if (vars.swap_data.totalNumberOfInputs == 0) { - vars.swap_data.totalNumberOfInputs = - context.transactionContext.transactionRemainingInputsOutputs; - } - // Reseting the flag, because we should check address ones for each input - vars.swap_data.was_address_checked = 0; - } - // Ready to proceed - context.transactionContext.transactionState = - TRANSACTION_DEFINED_WAIT_INPUT; - - __attribute__((fallthrough)); - } + case TRANSACTION_DEFINED_WAIT_INPUT: { + unsigned char trustedInputFlag = 1; + PRINTF("Process input\n"); + if (context.transactionContext.transactionRemainingInputsOutputs == 0) { + // No more inputs to hash, move forward + context.transactionContext.transactionState = + TRANSACTION_INPUT_HASHING_DONE; + continue; + } + if (context.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Proceed with the next input + if (parseMode == PARSE_MODE_TRUSTED_INPUT) { + check_transaction_available(36); // prevout : 32 hash + 4 index + transaction_offset_increase(36); + } + if (parseMode == PARSE_MODE_SIGNATURE) { + unsigned char trustedInputLength; + unsigned char trustedInput[TRUSTED_INPUT_TOTAL_SIZE]; + unsigned char amount[8]; + unsigned char *savePointer; + + // Expect the trusted input flag and trusted input length + check_transaction_available(2); + switch (*context.transactionBufferPointer) { + case 0: + if (context.usingSegwit) { + PRINTF("Non trusted input used in segwit mode\n"); + goto fail; + } + trustedInputFlag = 0; + break; + case 1: + if (context.usingSegwit) { + // Segwit inputs can be passed as TrustedInput also + PRINTF("Trusted input used in segwit mode\n"); + } + trustedInputFlag = 1; + break; + case 2: + if (!context.usingSegwit) { + PRINTF("Segwit input not used in segwit mode\n"); + goto fail; + } + trustedInputFlag = 0; + break; + default: + PRINTF("Invalid trusted input flag\n"); + goto fail; + } + // Check TrustedInput (TI) integrity, be it a non-segwit TI or a segwit + // TI + if (trustedInputFlag) { + trustedInputLength = *(context.transactionBufferPointer + 1); + if ((trustedInputLength > sizeof(trustedInput)) || + (trustedInputLength < 8)) { + PRINTF("Invalid trusted input size\n"); + goto fail; + } + + check_transaction_available(2 + trustedInputLength); + // Check TrustedInput Hmac + cx_hmac_sha256((uint8_t *)g_nvram_data.bkp.trustedinput_key, + sizeof(g_nvram_data.bkp.trustedinput_key), + context.transactionBufferPointer + 2, + trustedInputLength - 8, trustedInput, + trustedInputLength); + PRINTF("====> Input HMAC: %.*H\n", 8, + context.transactionBufferPointer + 2 + trustedInputLength - 8); + PRINTF("====> Computed HMAC: %.*H\n", 8, trustedInput); + + if (os_secure_memcmp(trustedInput, // Contains computed Hmac for now + context.transactionBufferPointer + 2 + + trustedInputLength - 8, + 8) != 0) { + PRINTF("Invalid signature\n"); + goto fail; + } + // Hmac is valid. If TrustedInput contains a segwit input, update data + // pointer & length to fake the parser into believing a normal segwit + // input was received. Do not use transaction_offset_increase() here + // as it could update the hash being computed. + if (context.usingSegwit) { + // Overwrite the no longer needed HMAC's 1st byte w/ the input + // script length byte. + *(context.transactionBufferPointer + 1 + TRUSTED_INPUT_SIZE + 1) = + *(context.transactionBufferPointer + 1 + + TRUSTED_INPUT_TOTAL_SIZE + 1); + // Set tx data pointer on TI header's (i.e. 0x38||0x32||0x00||Nonce + // (2B)) last byte before prevout tx hash. Also remove HMAC size + // from remaining data length. + context.transactionBufferPointer += 5; + context.transactionDataRemaining -= (5 + 8); + } + } + // Handle pure segwit inputs, whether trusted or not (i.e. + // InputHashStart 1st APDU's P2==02 & data[0]=={0x01, 0x02}) + if (context.usingSegwit) { + transaction_offset_increase(1); // Set tx pointer on 1st byte of hash + check_transaction_available(36); // prevout : 32 hash + 4 index + if (!context.segwitParsedOnce) { + if (context.usingOverwinter) { + if (cx_hash_no_throw( + &context.segwit.hash.hashPrevouts.blake2b.header, 0, + context.transactionBufferPointer, 36, NULL, 0)) { + goto fail; + } + } else { + if (cx_hash_no_throw( + &context.segwit.hash.hashPrevouts.sha256.header, 0, + context.transactionBufferPointer, 36, NULL, 0)) { + goto fail; + } + } + transaction_offset_increase(36); + check_transaction_available(8); // update amount + swap_bytes(amount, context.transactionBufferPointer, 8); + if (transaction_amount_add_be( + context.transactionContext.transactionAmount, + context.transactionContext.transactionAmount, amount)) { + PRINTF("Overflow\n"); + goto fail; + } + PRINTF("Adding amount\n%.*H\n", 8, + context.transactionBufferPointer); + PRINTF("New amount\n%.*H\n", 8, + context.transactionContext.transactionAmount); + transaction_offset_increase(8); + } else { + context.transactionHashOption = TRANSACTION_HASH_FULL; + transaction_offset_increase(36); + context.transactionHashOption = 0; + check_transaction_available(8); // save amount + memmove(context.inputValue, context.transactionBufferPointer, 8); + transaction_offset_increase(8); + context.transactionHashOption = TRANSACTION_HASH_FULL; + } + } + // Handle non-segwit inputs (i.e. InputHashStart 1st APDU's P2==00 && + // data[0]==0x00) + else if (!trustedInputFlag) { + PRINTF("Untrusted input not authorized\n"); + goto fail; + } + // Handle non-segwit TrustedInput (i.e. InputHashStart 1st APDU's P2==00 + // & data[0]==0x01) + else if (trustedInputFlag && !context.usingSegwit) { + memmove(trustedInput, context.transactionBufferPointer + 2, + trustedInputLength - 8); + if (trustedInput[0] != MAGIC_TRUSTED_INPUT) { + PRINTF("Failed to verify trusted input signature\n"); + goto fail; + } + // Update the hash with prevout data + savePointer = context.transactionBufferPointer; + context.transactionBufferPointer = trustedInput + 4; + PRINTF("Trusted input hash\n%.*H\n", 36, + context.transactionBufferPointer); + transaction_offset(36); + + context.transactionBufferPointer = + savePointer + (2 + trustedInputLength); + context.transactionDataRemaining -= (2 + trustedInputLength); + + // Update the amount + + swap_bytes(amount, trustedInput + 40, 8); + if (transaction_amount_add_be( + context.transactionContext.transactionAmount, + context.transactionContext.transactionAmount, amount)) { + PRINTF("Overflow\n"); + goto fail; + } + + PRINTF("Adding amount\n%.*H\n", 8, (trustedInput + 40)); + PRINTF("New amount\n%.*H\n", 8, + context.transactionContext.transactionAmount); + } - case TRANSACTION_DEFINED_WAIT_INPUT: { - unsigned char trustedInputFlag = 1; - PRINTF("Process input\n"); - if (context.transactionContext - .transactionRemainingInputsOutputs == 0) { - // No more inputs to hash, move forward - context.transactionContext.transactionState = - TRANSACTION_INPUT_HASHING_DONE; - continue; - } - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Proceed with the next input - if (parseMode == PARSE_MODE_TRUSTED_INPUT) { - check_transaction_available( - 36); // prevout : 32 hash + 4 index - transaction_offset_increase(36); - } - if (parseMode == PARSE_MODE_SIGNATURE) { - unsigned char trustedInputLength; - unsigned char trustedInput[TRUSTED_INPUT_TOTAL_SIZE]; - unsigned char amount[8]; - unsigned char *savePointer; - - // Expect the trusted input flag and trusted input length - check_transaction_available(2); - switch (*context.transactionBufferPointer) { - case 0: - if (context.usingSegwit) { - PRINTF("Non trusted input used in segwit mode\n"); - goto fail; - } - trustedInputFlag = 0; - break; - case 1: - if (context.usingSegwit) { - // Segwit inputs can be passed as TrustedInput also - PRINTF("Trusted input used in segwit mode\n"); - } - trustedInputFlag = 1; - break; - case 2: - if (!context.usingSegwit) { - PRINTF("Segwit input not used in segwit mode\n"); - goto fail; - } - trustedInputFlag = 0; - break; - default: - PRINTF("Invalid trusted input flag\n"); - goto fail; - } - // Check TrustedInput (TI) integrity, be it a non-segwit TI or a segwit TI - if (trustedInputFlag) { - trustedInputLength = *( - context.transactionBufferPointer + 1); - if ((trustedInputLength > sizeof(trustedInput)) || - (trustedInputLength < 8)) { - PRINTF("Invalid trusted input size\n"); - goto fail; - } - - check_transaction_available(2 + trustedInputLength); - // Check TrustedInput Hmac - cx_hmac_sha256( - (uint8_t *)g_nvram_data.bkp.trustedinput_key, - sizeof(g_nvram_data.bkp.trustedinput_key), - context.transactionBufferPointer + 2, - trustedInputLength - 8, trustedInput, trustedInputLength); - PRINTF("====> Input HMAC: %.*H\n", 8, context.transactionBufferPointer + 2 + trustedInputLength - 8); - PRINTF("====> Computed HMAC: %.*H\n", 8, trustedInput); - - if (os_secure_memcmp( - trustedInput, // Contains computed Hmac for now - context.transactionBufferPointer + - 2 + trustedInputLength - 8, - 8) != 0) { - PRINTF("Invalid signature\n"); - goto fail; - } - // Hmac is valid. If TrustedInput contains a segwit input, update data pointer & length - // to fake the parser into believing a normal segwit input was received. Do not use - // transaction_offset_increase() here as it could update the hash being computed. - if (context.usingSegwit) { - // Overwrite the no longer needed HMAC's 1st byte w/ the input script length byte. - *(context.transactionBufferPointer + 1 + TRUSTED_INPUT_SIZE + 1) = - *(context.transactionBufferPointer + 1 + TRUSTED_INPUT_TOTAL_SIZE + 1); - // Set tx data pointer on TI header's (i.e. 0x38||0x32||0x00||Nonce (2B)) last byte - // before prevout tx hash. Also remove HMAC size from remaining data length. - context.transactionBufferPointer += 5; - context.transactionDataRemaining -= (5+8); - } - } - // Handle pure segwit inputs, whether trusted or not (i.e. InputHashStart 1st APDU's P2==02 - // & data[0]=={0x01, 0x02}) - if (context.usingSegwit) { - transaction_offset_increase(1); // Set tx pointer on 1st byte of hash - check_transaction_available( - 36); // prevout : 32 hash + 4 index - if (!context.segwitParsedOnce) { - if (context.usingOverwinter) { - if (cx_hash_no_throw(&context.segwit.hash.hashPrevouts.blake2b.header, 0, context.transactionBufferPointer, 36, NULL, 0)) { - goto fail; - } - } - else { - if (cx_hash_no_throw( - &context.segwit.hash.hashPrevouts - .sha256.header, - 0, - context.transactionBufferPointer, - 36, NULL, 0)) { - goto fail; - } - } - transaction_offset_increase(36); - check_transaction_available(8); // update amount - swap_bytes( - amount, - context.transactionBufferPointer, - 8); - if (transaction_amount_add_be( - context.transactionContext - .transactionAmount, - context.transactionContext - .transactionAmount, - amount)) { - PRINTF("Overflow\n"); - goto fail; - } - PRINTF("Adding amount\n%.*H\n",8,context.transactionBufferPointer); - PRINTF("New amount\n%.*H\n",8,context.transactionContext.transactionAmount); - transaction_offset_increase(8); - } else { - context.transactionHashOption = - TRANSACTION_HASH_FULL; - transaction_offset_increase(36); - context.transactionHashOption = 0; - check_transaction_available(8); // save amount - memmove( - context.inputValue, - context.transactionBufferPointer, - 8); - transaction_offset_increase(8); - context.transactionHashOption = - TRANSACTION_HASH_FULL; - } - } - // Handle non-segwit inputs (i.e. InputHashStart 1st APDU's P2==00 && data[0]==0x00) - else if (!trustedInputFlag) { - PRINTF("Untrusted input not authorized\n"); - goto fail; - } - // Handle non-segwit TrustedInput (i.e. InputHashStart 1st APDU's P2==00 & data[0]==0x01) - else if (trustedInputFlag && !context.usingSegwit) { - memmove( - trustedInput, - context.transactionBufferPointer + 2, - trustedInputLength - 8); - if (trustedInput[0] != MAGIC_TRUSTED_INPUT) { - PRINTF("Failed to verify trusted input signature\n"); - goto fail; - } - // Update the hash with prevout data - savePointer = - context.transactionBufferPointer; - context.transactionBufferPointer = - trustedInput + 4; - PRINTF("Trusted input hash\n%.*H\n",36,context.transactionBufferPointer); - transaction_offset(36); - - context.transactionBufferPointer = - savePointer + (2 + trustedInputLength); - context.transactionDataRemaining -= - (2 + trustedInputLength); - - // Update the amount - - swap_bytes(amount, trustedInput + 40, 8); - if (transaction_amount_add_be( - context.transactionContext - .transactionAmount, - context.transactionContext - .transactionAmount, - amount)) { - PRINTF("Overflow\n"); - goto fail; - } - - PRINTF("Adding amount\n%.*H\n",8,(trustedInput + 40)); - PRINTF("New amount\n%.*H\n",8,context.transactionContext.transactionAmount); - } - - if (!context.usingSegwit) { - // Do not include the input script length + value in - // the authentication hash - context.transactionHashOption = - TRANSACTION_HASH_FULL; - } - } - // Read the script length - context.transactionContext.scriptRemaining = - transaction_get_varint(); - PRINTF("Script to read %d\n", context.transactionContext.scriptRemaining); - - if ((parseMode == PARSE_MODE_SIGNATURE) && - !trustedInputFlag && !context.usingSegwit) { - // Only proceeds if this is not to be signed - so length - // should be null - if (context.transactionContext - .scriptRemaining != 0) { - PRINTF("Request to sign relaxed input\n"); - goto fail; - } - } - // Move on - context.transactionContext.transactionState = - TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; - - __attribute__((fallthrough)); - } - case TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { - unsigned char dataAvailable; - PRINTF("Process input script, remaining %d\n", context.transactionContext.scriptRemaining); - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Scan for P2SH consumption - huge shortcut, but fine - // enough - // Also usable in SegWit mode - if (context.transactionContext.scriptRemaining == - 1) { - if (*context.transactionBufferPointer == - OP_CHECKMULTISIG) { - PRINTF("Marking P2SH consumption\n"); - context.transactionContext.consumeP2SH = 1; - } else { - // When using the P2SH shortcut, all inputs must use - // P2SH - PRINTF("Disabling P2SH consumption\n"); - context.transactionContext.consumeP2SH = 0; - } - transaction_offset_increase(1); - context.transactionContext.scriptRemaining--; - } - - if (context.transactionContext.scriptRemaining == - 0) { - if (parseMode == PARSE_MODE_SIGNATURE) { - if (!context.usingSegwit) { - // Restore dual hash for signature + - // authentication - context.transactionHashOption = - TRANSACTION_HASH_BOTH; - } else { - if (context.segwitParsedOnce) { - // Append the saved value - PRINTF("SEGWIT Add value\n%.*H\n",8,context.inputValue); - if (context.usingOverwinter) { - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.inputValue, 8, NULL, 0)) { - goto fail; - } - } - else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(context.inputValue), context.inputValue); - if (cx_hash_no_throw(&context - .transactionHashFull.sha256.header, - 0, context.inputValue, 8, - NULL, 0)) { - goto fail; - } - } - } - } - } - // Sequence - check_transaction_available(4); - if (context.usingSegwit && - !context.segwitParsedOnce) { - if (context.usingOverwinter) { - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, context.transactionBufferPointer, 4, NULL, 0)) { - goto fail; - } - } - else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", 4, context.transactionBufferPointer); - if (cx_hash_no_throw(&context.transactionHashFull - .sha256.header, - 0, - context.transactionBufferPointer, - 4, NULL, 0)) { - goto fail; - } - } - } - transaction_offset_increase(4); - // Move to next input - context.transactionContext - .transactionRemainingInputsOutputs--; - context.transactionContext - .transactionCurrentInputOutput++; - context.transactionContext.transactionState = - TRANSACTION_DEFINED_WAIT_INPUT; - continue; - } - // Save the last script byte for the P2SH check - dataAvailable = - (context.transactionDataRemaining > - context.transactionContext - .scriptRemaining - - 1 - ? context.transactionContext - .scriptRemaining - - 1 - : context.transactionDataRemaining); - if (dataAvailable == 0) { - goto ok; - } - transaction_offset_increase(dataAvailable); - context.transactionContext.scriptRemaining -= - dataAvailable; - break; - } - case TRANSACTION_INPUT_HASHING_DONE: { - PRINTF("Input hashing done\n"); - if (parseMode == PARSE_MODE_SIGNATURE) { - // inputs have been prepared, stop the parsing here - if (context.usingSegwit && - !context.segwitParsedOnce) { - unsigned char hashedPrevouts[32]; - unsigned char hashedSequence[32]; - // Flush the cache - if (context.usingOverwinter) { - if (cx_hash_no_throw(&context.segwit.hash.hashPrevouts.blake2b.header, CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, CX_LAST, hashedSequence, 0, hashedSequence, 32)) { - goto fail; - } - } - else { - if (cx_hash_no_throw(&context.segwit.hash.hashPrevouts - .sha256.header, - CX_LAST, hashedPrevouts, 0, hashedPrevouts, 32)) { - goto fail; - } - if (cx_sha256_init_no_throw( - &context.segwit.hash.hashPrevouts.sha256)) { - goto fail; - } - if (cx_hash_no_throw(&context.segwit.hash.hashPrevouts - .sha256.header, - CX_LAST, hashedPrevouts, - sizeof(hashedPrevouts), hashedPrevouts, 32)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull - .sha256.header, - CX_LAST, hashedSequence, 0, hashedSequence, 32)) { - goto fail; - } - if (cx_sha256_init_no_throw( - &context.transactionHashFull.sha256)) { - goto fail; - } - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(hashedSequence), hashedSequence); - if (cx_hash_no_throw(&context.transactionHashFull - .sha256.header, - CX_LAST, hashedSequence, - sizeof(hashedSequence), hashedSequence, 32)) { - goto fail; - } - - } - memmove( - context.segwit.cache.hashedPrevouts, - hashedPrevouts, sizeof(hashedPrevouts)); - memmove( - context.segwit.cache.hashedSequence, - hashedSequence, sizeof(hashedSequence)); - PRINTF("hashPrevout\n%.*H\n",32,context.segwit.cache.hashedPrevouts); - PRINTF("hashSequence\n%.*H\n",32,context.segwit.cache.hashedSequence); - } - if (context.usingSegwit && - context.segwitParsedOnce) { - if (!context.usingOverwinter) { - PRINTF("SEGWIT hashedOutputs\n%.*H\n",sizeof(context.segwit.cache.hashedOutputs),context.segwit.cache.hashedOutputs); - if (cx_hash_no_throw( - &context.transactionHashFull.sha256.header, 0, - context.segwit.cache.hashedOutputs, - sizeof(context.segwit.cache - .hashedOutputs), - NULL, 0)) { - goto fail; - } - } - context.transactionContext - .transactionState = - TRANSACTION_SIGN_READY; - } else { - context.transactionContext - .transactionState = - TRANSACTION_PRESIGN_READY; - if (context.usingOverwinter) { - if (cx_blake2b_init2_no_throw(&context.transactionHashFull.blake2b, 256, NULL, 0, (uint8_t *)OVERWINTER_PARAM_OUTPUTS, 16)) { - goto fail; - } - } - else - if (context.usingSegwit) { - if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { - goto fail; - } - } - } - continue; - } - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Number of outputs - context.transactionContext - .transactionRemainingInputsOutputs = - transaction_get_varint(); - context.transactionContext - .transactionCurrentInputOutput = 0; - PRINTF("Number of outputs : %d\n", - context.transactionContext.transactionRemainingInputsOutputs); - // Ready to proceed - context.transactionContext.transactionState = - TRANSACTION_DEFINED_WAIT_OUTPUT; - - __attribute__((fallthrough)); - } - case TRANSACTION_DEFINED_WAIT_OUTPUT: { - if (context.transactionContext - .transactionRemainingInputsOutputs == 0) { - // No more outputs to hash, move forward - context.transactionContext.transactionState = - TRANSACTION_OUTPUT_HASHING_DONE; - continue; - } - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Amount - check_transaction_available(8); - if ((parseMode == PARSE_MODE_TRUSTED_INPUT) && - (context.transactionContext - .transactionCurrentInputOutput == - context.transactionTargetInput)) { - // Save the amount - memmove(context.transactionContext - .transactionAmount, - context.transactionBufferPointer, - 8); - context.trustedInputProcessed = 1; - } - transaction_offset_increase(8); - // Read the script length - context.transactionContext.scriptRemaining = - transaction_get_varint(); - - PRINTF("Script to read %d\n", context.transactionContext.scriptRemaining); - // Move on - context.transactionContext.transactionState = - TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; - - __attribute__((fallthrough)); - } - case TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { - unsigned char dataAvailable; - PRINTF("Process output script, remaining %d\n", context.transactionContext.scriptRemaining); - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - if (context.transactionContext.scriptRemaining == - 0) { - // Move to next output - context.transactionContext - .transactionRemainingInputsOutputs--; - context.transactionContext - .transactionCurrentInputOutput++; - context.transactionContext.transactionState = - TRANSACTION_DEFINED_WAIT_OUTPUT; - continue; - } - dataAvailable = - (context.transactionDataRemaining > - context.transactionContext - .scriptRemaining - ? context.transactionContext - .scriptRemaining - : context.transactionDataRemaining); - if (dataAvailable == 0) { - goto ok; - } - transaction_offset_increase(dataAvailable); - context.transactionContext.scriptRemaining -= - dataAvailable; - break; - } - case TRANSACTION_OUTPUT_HASHING_DONE: { - PRINTF("Output hashing done\n"); - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Locktime - check_transaction_available(4); - transaction_offset_increase(4); - - if (context.transactionDataRemaining == 0) { - context.transactionContext.transactionState = - TRANSACTION_PARSED; - continue; - } else { - context.transactionHashOption = 0; - context.transactionContext.scriptRemaining = - transaction_get_varint(); - context.transactionHashOption = - TRANSACTION_HASH_FULL; - context.transactionContext.transactionState = - TRANSACTION_PROCESS_EXTRA; - continue; - } - } + if (!context.usingSegwit) { + // Do not include the input script length + value in + // the authentication hash + context.transactionHashOption = TRANSACTION_HASH_FULL; + } + } + // Read the script length + context.transactionContext.scriptRemaining = transaction_get_varint(); + PRINTF("Script to read %d\n", context.transactionContext.scriptRemaining); + + if ((parseMode == PARSE_MODE_SIGNATURE) && !trustedInputFlag && + !context.usingSegwit) { + // Only proceeds if this is not to be signed - so length + // should be null + if (context.transactionContext.scriptRemaining != 0) { + PRINTF("Request to sign relaxed input\n"); + goto fail; + } + } + // Move on + context.transactionContext.transactionState = + TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; - case TRANSACTION_PROCESS_EXTRA: { - unsigned char dataAvailable; - - if (context.transactionContext.scriptRemaining == - 0) { - context.transactionContext.transactionState = - TRANSACTION_PARSED; - continue; - } - - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - - dataAvailable = - (context.transactionDataRemaining > - context.transactionContext - .scriptRemaining - ? context.transactionContext - .scriptRemaining - : context.transactionDataRemaining); - if (dataAvailable == 0) { - goto ok; - } - transaction_offset_increase(dataAvailable); - context.transactionContext.scriptRemaining -= - dataAvailable; - break; + __attribute__((fallthrough)); + } + case TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { + unsigned char dataAvailable; + PRINTF("Process input script, remaining %d\n", + context.transactionContext.scriptRemaining); + if (context.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Scan for P2SH consumption - huge shortcut, but fine + // enough + // Also usable in SegWit mode + if (context.transactionContext.scriptRemaining == 1) { + if (*context.transactionBufferPointer == OP_CHECKMULTISIG) { + PRINTF("Marking P2SH consumption\n"); + context.transactionContext.consumeP2SH = 1; + } else { + // When using the P2SH shortcut, all inputs must use + // P2SH + PRINTF("Disabling P2SH consumption\n"); + context.transactionContext.consumeP2SH = 0; + } + transaction_offset_increase(1); + context.transactionContext.scriptRemaining--; + } + + if (context.transactionContext.scriptRemaining == 0) { + if (parseMode == PARSE_MODE_SIGNATURE) { + if (!context.usingSegwit) { + // Restore dual hash for signature + + // authentication + context.transactionHashOption = TRANSACTION_HASH_BOTH; + } else { + if (context.segwitParsedOnce) { + // Append the saved value + PRINTF("SEGWIT Add value\n%.*H\n", 8, context.inputValue); + if (context.usingOverwinter) { + if (cx_hash_no_throw( + &context.transactionHashFull.blake2b.header, 0, + context.inputValue, 8, NULL, 0)) { + goto fail; } - - case TRANSACTION_PARSED: { - PRINTF("Transaction parsed\n"); - goto ok; + } else { + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", + sizeof(context.inputValue), context.inputValue); + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, + 0, context.inputValue, 8, NULL, 0)) { + goto fail; } + } + } + } + } + // Sequence + check_transaction_available(4); + if (context.usingSegwit && !context.segwitParsedOnce) { + if (context.usingOverwinter) { + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, + context.transactionBufferPointer, 4, NULL, + 0)) { + goto fail; + } + } else { + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", 4, + context.transactionBufferPointer); + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + context.transactionBufferPointer, 4, NULL, + 0)) { + goto fail; + } + } + } + transaction_offset_increase(4); + // Move to next input + context.transactionContext.transactionRemainingInputsOutputs--; + context.transactionContext.transactionCurrentInputOutput++; + context.transactionContext.transactionState = + TRANSACTION_DEFINED_WAIT_INPUT; + continue; + } + // Save the last script byte for the P2SH check + dataAvailable = (context.transactionDataRemaining > + context.transactionContext.scriptRemaining - 1 + ? context.transactionContext.scriptRemaining - 1 + : context.transactionDataRemaining); + if (dataAvailable == 0) { + goto ok; + } + transaction_offset_increase(dataAvailable); + context.transactionContext.scriptRemaining -= dataAvailable; + break; + } + case TRANSACTION_INPUT_HASHING_DONE: { + PRINTF("Input hashing done\n"); + if (parseMode == PARSE_MODE_SIGNATURE) { + // inputs have been prepared, stop the parsing here + if (context.usingSegwit && !context.segwitParsedOnce) { + unsigned char hashedPrevouts[32]; + unsigned char hashedSequence[32]; + // Flush the cache + if (context.usingOverwinter) { + if (cx_hash_no_throw( + &context.segwit.hash.hashPrevouts.blake2b.header, CX_LAST, + hashedPrevouts, 0, hashedPrevouts, 32)) { + goto fail; + } + if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, + CX_LAST, hashedSequence, 0, hashedSequence, + 32)) { + goto fail; + } + } else { + if (cx_hash_no_throw( + &context.segwit.hash.hashPrevouts.sha256.header, CX_LAST, + hashedPrevouts, 0, hashedPrevouts, 32)) { + goto fail; + } + if (cx_sha256_init_no_throw( + &context.segwit.hash.hashPrevouts.sha256)) { + goto fail; + } + if (cx_hash_no_throw( + &context.segwit.hash.hashPrevouts.sha256.header, CX_LAST, + hashedPrevouts, sizeof(hashedPrevouts), hashedPrevouts, + 32)) { + goto fail; + } + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, + CX_LAST, hashedSequence, 0, hashedSequence, + 32)) { + goto fail; + } + if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { + goto fail; + } + PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(hashedSequence), + hashedSequence); + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, + CX_LAST, hashedSequence, + sizeof(hashedSequence), hashedSequence, 32)) { + goto fail; + } + } + memmove(context.segwit.cache.hashedPrevouts, hashedPrevouts, + sizeof(hashedPrevouts)); + memmove(context.segwit.cache.hashedSequence, hashedSequence, + sizeof(hashedSequence)); + PRINTF("hashPrevout\n%.*H\n", 32, + context.segwit.cache.hashedPrevouts); + PRINTF("hashSequence\n%.*H\n", 32, + context.segwit.cache.hashedSequence); + } + if (context.usingSegwit && context.segwitParsedOnce) { + if (!context.usingOverwinter) { + PRINTF("SEGWIT hashedOutputs\n%.*H\n", + sizeof(context.segwit.cache.hashedOutputs), + context.segwit.cache.hashedOutputs); + if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, + context.segwit.cache.hashedOutputs, + sizeof(context.segwit.cache.hashedOutputs), + NULL, 0)) { + goto fail; + } + } + context.transactionContext.transactionState = TRANSACTION_SIGN_READY; + } else { + context.transactionContext.transactionState = + TRANSACTION_PRESIGN_READY; + if (context.usingOverwinter) { + if (cx_blake2b_init2_no_throw( + &context.transactionHashFull.blake2b, 256, NULL, 0, + (uint8_t *)OVERWINTER_PARAM_OUTPUTS, 16)) { + goto fail; + } + } else if (context.usingSegwit) { + if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { + goto fail; + } + } + } + continue; + } + if (context.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Number of outputs + context.transactionContext.transactionRemainingInputsOutputs = + transaction_get_varint(); + context.transactionContext.transactionCurrentInputOutput = 0; + PRINTF("Number of outputs : %d\n", + context.transactionContext.transactionRemainingInputsOutputs); + // Ready to proceed + context.transactionContext.transactionState = + TRANSACTION_DEFINED_WAIT_OUTPUT; + + __attribute__((fallthrough)); + } + case TRANSACTION_DEFINED_WAIT_OUTPUT: { + if (context.transactionContext.transactionRemainingInputsOutputs == 0) { + // No more outputs to hash, move forward + context.transactionContext.transactionState = + TRANSACTION_OUTPUT_HASHING_DONE; + continue; + } + if (context.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Amount + check_transaction_available(8); + if ((parseMode == PARSE_MODE_TRUSTED_INPUT) && + (context.transactionContext.transactionCurrentInputOutput == + context.transactionTargetInput)) { + // Save the amount + memmove(context.transactionContext.transactionAmount, + context.transactionBufferPointer, 8); + context.trustedInputProcessed = 1; + } + transaction_offset_increase(8); + // Read the script length + context.transactionContext.scriptRemaining = transaction_get_varint(); + + PRINTF("Script to read %d\n", context.transactionContext.scriptRemaining); + // Move on + context.transactionContext.transactionState = + TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; + + __attribute__((fallthrough)); + } + case TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { + unsigned char dataAvailable; + PRINTF("Process output script, remaining %d\n", + context.transactionContext.scriptRemaining); + if (context.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + if (context.transactionContext.scriptRemaining == 0) { + // Move to next output + context.transactionContext.transactionRemainingInputsOutputs--; + context.transactionContext.transactionCurrentInputOutput++; + context.transactionContext.transactionState = + TRANSACTION_DEFINED_WAIT_OUTPUT; + continue; + } + dataAvailable = (context.transactionDataRemaining > + context.transactionContext.scriptRemaining + ? context.transactionContext.scriptRemaining + : context.transactionDataRemaining); + if (dataAvailable == 0) { + goto ok; + } + transaction_offset_increase(dataAvailable); + context.transactionContext.scriptRemaining -= dataAvailable; + break; + } + case TRANSACTION_OUTPUT_HASHING_DONE: { + PRINTF("Output hashing done\n"); + if (context.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + // Locktime + check_transaction_available(4); + transaction_offset_increase(4); + + if (context.transactionDataRemaining == 0) { + context.transactionContext.transactionState = TRANSACTION_PARSED; + continue; + } else { + context.transactionHashOption = 0; + context.transactionContext.scriptRemaining = transaction_get_varint(); + context.transactionHashOption = TRANSACTION_HASH_FULL; + context.transactionContext.transactionState = TRANSACTION_PROCESS_EXTRA; + continue; + } + } - case TRANSACTION_PRESIGN_READY: { - PRINTF("Presign ready\n"); - goto ok; - } + case TRANSACTION_PROCESS_EXTRA: { + unsigned char dataAvailable; + + if (context.transactionContext.scriptRemaining == 0) { + context.transactionContext.transactionState = TRANSACTION_PARSED; + continue; + } + + if (context.transactionDataRemaining < 1) { + // No more data to read, ok + goto ok; + } + + dataAvailable = (context.transactionDataRemaining > + context.transactionContext.scriptRemaining + ? context.transactionContext.scriptRemaining + : context.transactionDataRemaining); + if (dataAvailable == 0) { + goto ok; + } + transaction_offset_increase(dataAvailable); + context.transactionContext.scriptRemaining -= dataAvailable; + break; + } - case TRANSACTION_SIGN_READY: { - PRINTF("Sign ready\n"); - goto ok; - } - } - } + case TRANSACTION_PARSED: { + PRINTF("Transaction parsed\n"); + goto ok; + } + + case TRANSACTION_PRESIGN_READY: { + PRINTF("Presign ready\n"); + goto ok; + } - fail: - LEDGER_ASSERT(false, "Transaction parse - fail\n"); - ok: - return; + case TRANSACTION_SIGN_READY: { + PRINTF("Sign ready\n"); + goto ok; + } + } + } +fail: + LEDGER_ASSERT(false, "Transaction parse - fail\n"); +ok: + return; } diff --git a/lib-app-bitcoin/transaction.h b/lib-app-bitcoin/transaction.h index fa88a83b..249a5527 100644 --- a/lib-app-bitcoin/transaction.h +++ b/lib-app-bitcoin/transaction.h @@ -1,23 +1,22 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once - #define TRANSACTION_HASH_NONE 0x00 #define TRANSACTION_HASH_FULL 0x01 #define TRANSACTION_HASH_AUTHORIZATION 0x02 @@ -26,8 +25,7 @@ #define PARSE_MODE_TRUSTED_INPUT 0x01 #define PARSE_MODE_SIGNATURE 0x02 -#define TRUSTED_INPUT_SIZE 48 +#define TRUSTED_INPUT_SIZE 48 #define TRUSTED_INPUT_TOTAL_SIZE (TRUSTED_INPUT_SIZE + 8) void transaction_parse(unsigned char parseMode); - diff --git a/lib-app-bitcoin/ui/display_variables.h b/lib-app-bitcoin/ui/display_variables.h index 723009ab..ad292b2a 100644 --- a/lib-app-bitcoin/ui/display_variables.h +++ b/lib-app-bitcoin/ui/display_variables.h @@ -1,40 +1,41 @@ -#pragma once +#pragma once #include "os.h" -// A path contains 10 elements max, which max length in ascii is 1 whitespace + 10 char + optional quote "'" + "/" + \0" -#define MAX_DERIV_PATH_ASCII_LENGTH 1 + 10*(10+2) + 1 +// A path contains 10 elements max, which max length in ascii is 1 whitespace + +// 10 char + optional quote "'" + "/" + \0" +#define MAX_DERIV_PATH_ASCII_LENGTH 1 + 10 * (10 + 2) + 1 #define MAX_CHAR_PER_LINE 25 typedef struct swap_data_s { - int was_address_checked; - // total number of inputs to be signed - int totalNumberOfInputs; - // number of already signed input in the transaction, to compare with - // totalNumberOfInputs and exit properly - int alreadySignedInputs; - int initialized; - unsigned char amount[8]; - unsigned char fees[8]; - char destination_address[65]; - unsigned char should_exit; + int was_address_checked; + // total number of inputs to be signed + int totalNumberOfInputs; + // number of already signed input in the transaction, to compare with + // totalNumberOfInputs and exit properly + int alreadySignedInputs; + int initialized; + unsigned char amount[8]; + unsigned char fees[8]; + char destination_address[65]; + unsigned char should_exit; } swap_data_t; union display_variables { - struct { - // char addressSummary[40]; // beginning of the output address ... end - // of + struct { + // char addressSummary[40]; // beginning of the output address ... end + // of - char fullAddress[65]; // the address - char fullAmount[28]; // full amount - char feesAmount[28]; // fees - } tmp; + char fullAddress[65]; // the address + char fullAmount[28]; // full amount + char feesAmount[28]; // fees + } tmp; - struct { - char derivation_path [MAX_DERIV_PATH_ASCII_LENGTH]; - } tmp_warning; + struct { + char derivation_path[MAX_DERIV_PATH_ASCII_LENGTH]; + } tmp_warning; - swap_data_t swap_data; + swap_data_t swap_data; }; extern union display_variables vars; diff --git a/lib-app-bitcoin/ui/extensions.h b/lib-app-bitcoin/ui/extensions.h index 7aed64c9..c28d928a 100644 --- a/lib-app-bitcoin/ui/extensions.h +++ b/lib-app-bitcoin/ui/extensions.h @@ -1,21 +1,21 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ - -#pragma once + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ + +#pragma once // btchip asking the per-output UI unsigned int confirm_single_output(void); @@ -39,16 +39,16 @@ void confirm_message_signature(void); int user_action_message_signing(unsigned char confirming); // Public key display -uint8_t set_key_path_to_display(const unsigned char* keyPath); +uint8_t set_key_path_to_display(const unsigned char *keyPath); void display_public_key(uint8_t is_derivation_path_unusual); int user_action_display(unsigned char confirming); void request_pubkey_approval(void); -void request_change_path_approval(unsigned char* change_path); +void request_change_path_approval(unsigned char *change_path); // UI to confirm processing of tx with segwit inputs void request_segwit_input_approval(void); // UI to confirm signing path -void request_sign_path_approval(unsigned char* change_path); +void request_sign_path_approval(unsigned char *change_path); int user_action_signtx(unsigned char confirming, unsigned char direct); diff --git a/lib-app-bitcoin/ui/main_ui.c b/lib-app-bitcoin/ui/main_ui.c index 5d2579bb..2fd4e0fd 100644 --- a/lib-app-bitcoin/ui/main_ui.c +++ b/lib-app-bitcoin/ui/main_ui.c @@ -1,75 +1,72 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ -#include "os.h" + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ +#include "bip32.h" #include "cx.h" #include "format.h" +#include "os.h" #include "read.h" -#include "write.h" -#include "bip32.h" -#include "swap.h" #include "string.h" +#include "swap.h" +#include "write.h" - +#include "be_operations.h" #include "context.h" -#include "helpers.h" #include "customizable_helpers.h" #include "customizable_ui.h" -#include "extensions.h" #include "display_utils.h" -#include "ux.h" #include "display_variables.h" -#include "swap_lib_calls.h" -#include "handle_swap_sign_transaction.h" -#include "handle_get_printable_amount.h" +#include "extensions.h" #include "handle_check_address.h" +#include "handle_get_printable_amount.h" +#include "handle_swap_sign_transaction.h" +#include "helpers.h" +#include "swap_lib_calls.h" #include "ui.h" -#include "be_operations.h" +#include "ux.h" #define OMNI_ASSETID 1 #define MAIDSAFE_ASSETID 3 #define USDT_ASSETID 31 static uint8_t check_fee_swap() { - unsigned char fees[8]; - unsigned char borrow; - - borrow = transaction_amount_sub_be( - fees, context.transactionContext.transactionAmount, - context.totalOutputAmount); - if ((borrow != 0) || (memcmp(fees, vars.swap_data.fees, 8) != 0)) - return 0; - context.transactionContext.firstSigned = 0; - - if (context.usingSegwit && !context.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context.transactionContext.transactionState = - TRANSACTION_NONE; - } else { - context.transactionContext.transactionState = - TRANSACTION_SIGN_READY; - } - context.sw = 0x9000; - context.outLength = 0; - G_io_apdu_buffer[context.outLength++] = 0x90; - G_io_apdu_buffer[context.outLength++] = 0x00; - - return 1; + unsigned char fees[8]; + unsigned char borrow; + + borrow = transaction_amount_sub_be( + fees, context.transactionContext.transactionAmount, + context.totalOutputAmount); + if ((borrow != 0) || (memcmp(fees, vars.swap_data.fees, 8) != 0)) + return 0; + context.transactionContext.firstSigned = 0; + + if (context.usingSegwit && !context.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context.transactionContext.transactionState = TRANSACTION_NONE; + } else { + context.transactionContext.transactionState = TRANSACTION_SIGN_READY; + } + context.sw = 0x9000; + context.outLength = 0; + G_io_apdu_buffer[context.outLength++] = 0x90; + G_io_apdu_buffer[context.outLength++] = 0x00; + + return 1; } #define OMNI_ASSETID 1 @@ -77,235 +74,228 @@ static uint8_t check_fee_swap() { #define USDT_ASSETID 31 static void prepare_single_output(void) { - // TODO : special display for OP_RETURN - unsigned char amount[8]; - unsigned int offset = 0; - char tmp[80] = {0}; - - swap_bytes(amount, context.currentOutput + offset, 8); - offset += 8; - - get_address_from_output_script(context.currentOutput + offset, sizeof(context.currentOutput) - offset, tmp, sizeof(tmp)); - strncpy(vars.tmp.fullAddress, tmp, sizeof(vars.tmp.fullAddress) - 1); - - // Prepare amount - - // Handle Omni simple send - if ((context.currentOutput[offset + 2] == 0x14) && - (memcmp(context.currentOutput + offset + 3, "omni", 4) == 0) && - (memcmp(context.currentOutput + offset + 3 + 4, "\0\0\0\0", 4) == 0)) { - uint32_t omniAssetId = read_u32_be(context.currentOutput, offset + 3 + 4 + 4); - switch(omniAssetId) { - case OMNI_ASSETID: - strcpy(vars.tmp.fullAmount, "OMNI "); - break; - case USDT_ASSETID: - strcpy(vars.tmp.fullAmount, "USDT "); - break; - case MAIDSAFE_ASSETID: - strcpy(vars.tmp.fullAmount, "MAID "); - break; - default: - snprintf(vars.tmp.fullAmount, sizeof(vars.tmp.fullAmount), "OMNI asset %d ", omniAssetId); - break; - } - format_sats_amount(vars.tmp.fullAmount, - (uint64_t) read_u64_be(context.currentOutput, offset + 3 + 4 + 4 + 4), // Cast prevents weird compilo bug - vars.tmp.fullAmount); - } - else { - format_sats_amount(COIN_COINID_SHORT, - (uint64_t)read_u64_be(amount, 0), // Cast prevents weird compilo bug - vars.tmp.fullAmount); + // TODO : special display for OP_RETURN + unsigned char amount[8]; + unsigned int offset = 0; + char tmp[80] = {0}; + + swap_bytes(amount, context.currentOutput + offset, 8); + offset += 8; + + get_address_from_output_script(context.currentOutput + offset, + sizeof(context.currentOutput) - offset, tmp, + sizeof(tmp)); + strncpy(vars.tmp.fullAddress, tmp, sizeof(vars.tmp.fullAddress) - 1); + + // Prepare amount + + // Handle Omni simple send + if ((context.currentOutput[offset + 2] == 0x14) && + (memcmp(context.currentOutput + offset + 3, "omni", 4) == 0) && + (memcmp(context.currentOutput + offset + 3 + 4, "\0\0\0\0", 4) == 0)) { + uint32_t omniAssetId = + read_u32_be(context.currentOutput, offset + 3 + 4 + 4); + switch (omniAssetId) { + case OMNI_ASSETID: + strcpy(vars.tmp.fullAmount, "OMNI "); + break; + case USDT_ASSETID: + strcpy(vars.tmp.fullAmount, "USDT "); + break; + case MAIDSAFE_ASSETID: + strcpy(vars.tmp.fullAmount, "MAID "); + break; + default: + snprintf(vars.tmp.fullAmount, sizeof(vars.tmp.fullAmount), + "OMNI asset %d ", omniAssetId); + break; } + format_sats_amount( + vars.tmp.fullAmount, + (uint64_t)read_u64_be(context.currentOutput, + offset + 3 + 4 + 4 + + 4), // Cast prevents weird compilo bug + vars.tmp.fullAmount); + } else { + format_sats_amount( + COIN_COINID_SHORT, + (uint64_t)read_u64_be(amount, 0), // Cast prevents weird compilo bug + vars.tmp.fullAmount); + } } static uint8_t prepare_message_signature(void) { - uint8_t buffer[32]; + uint8_t buffer[32]; - if (cx_hash_no_throw(&context.transactionHashAuthorization.header, CX_LAST, - (uint8_t*)vars.tmp.fullAmount, 0, buffer, 32)) { - return 0; - } + if (cx_hash_no_throw(&context.transactionHashAuthorization.header, CX_LAST, + (uint8_t *)vars.tmp.fullAmount, 0, buffer, 32)) { + return 0; + } - format_hex((const uint8_t*) buffer, sizeof(buffer), vars.tmp.fullAddress, sizeof(vars.tmp.fullAddress)); + format_hex((const uint8_t *)buffer, sizeof(buffer), vars.tmp.fullAddress, + sizeof(vars.tmp.fullAddress)); - return 1; + return 1; } - -extern int handle_output_state(unsigned int* processed); +extern int handle_output_state(unsigned int *processed); extern void hash_input_finalize_full_reset(void); // Analog of confirm_single_output to work // in silent mode, when called from SWAP app unsigned int silent_confirm_single_output() { - char tmp[80] = {0}; - unsigned char amount[8]; - while (true) { - // in swap operation we can only have 1 "external" output - if (vars.swap_data.was_address_checked) { - PRINTF("Address was already checked\n"); - return 0; - } - vars.swap_data.was_address_checked = 1; - // check amount - swap_bytes(amount, context.currentOutput, 8); - if (memcmp(amount, vars.swap_data.amount, 8) != 0) { - PRINTF("Amount not matched\n"); - return 0; - } - get_address_from_output_script(context.currentOutput + 8, sizeof(context.currentOutput) - 8, tmp, sizeof(tmp)); - if (strcmp(tmp, vars.swap_data.destination_address) != 0) { - PRINTF("Address not matched\n"); - return 0; - } - - // Check if all inputs have been confirmed - - if (context.outputParsingState == - OUTPUT_PARSING_OUTPUT) { - context.remainingOutputs--; - if (context.remainingOutputs == 0) - break; - } - - memmove(context.currentOutput, - context.currentOutput + - context.discardSize, - context.currentOutputOffset - - context.discardSize); - context.currentOutputOffset -= context.discardSize; - unsigned int processed = true; - while (processed == 1) { - if (handle_output_state(&processed)) { - PRINTF("Error in handle output state \n"); - return 0; - } - } - - if (processed != 2) { - // Out of data to process, wait for the next call - break; - } + char tmp[80] = {0}; + unsigned char amount[8]; + while (true) { + // in swap operation we can only have 1 "external" output + if (vars.swap_data.was_address_checked) { + PRINTF("Address was already checked\n"); + return 0; + } + vars.swap_data.was_address_checked = 1; + // check amount + swap_bytes(amount, context.currentOutput, 8); + if (memcmp(amount, vars.swap_data.amount, 8) != 0) { + PRINTF("Amount not matched\n"); + return 0; } + get_address_from_output_script(context.currentOutput + 8, + sizeof(context.currentOutput) - 8, tmp, + sizeof(tmp)); + if (strcmp(tmp, vars.swap_data.destination_address) != 0) { + PRINTF("Address not matched\n"); + return 0; + } + + // Check if all inputs have been confirmed - if ((context.outputParsingState == OUTPUT_PARSING_OUTPUT) && - (context.remainingOutputs == 0)) { - context.outputParsingState = OUTPUT_FINALIZE_TX; - // check fees - unsigned char fees[8]; - - if ((transaction_amount_sub_be(fees, - context.transactionContext.transactionAmount, - context.totalOutputAmount) != 0) || - (memcmp(fees, vars.swap_data.fees, 8) != 0)) { - PRINTF("Fees is not matched\n"); - return 0; - } + if (context.outputParsingState == OUTPUT_PARSING_OUTPUT) { + context.remainingOutputs--; + if (context.remainingOutputs == 0) + break; } - if (context.outputParsingState == OUTPUT_FINALIZE_TX) { - context.transactionContext.firstSigned = 0; - - if (context.usingSegwit && - !context.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context.transactionContext.transactionState = - TRANSACTION_NONE; - } else { - context.transactionContext.transactionState = - TRANSACTION_SIGN_READY; - } + memmove(context.currentOutput, context.currentOutput + context.discardSize, + context.currentOutputOffset - context.discardSize); + context.currentOutputOffset -= context.discardSize; + unsigned int processed = true; + while (processed == 1) { + if (handle_output_state(&processed)) { + PRINTF("Error in handle output state \n"); + return 0; + } + } + + if (processed != 2) { + // Out of data to process, wait for the next call + break; + } + } + + if ((context.outputParsingState == OUTPUT_PARSING_OUTPUT) && + (context.remainingOutputs == 0)) { + context.outputParsingState = OUTPUT_FINALIZE_TX; + // check fees + unsigned char fees[8]; + + if ((transaction_amount_sub_be(fees, + context.transactionContext.transactionAmount, + context.totalOutputAmount) != 0) || + (memcmp(fees, vars.swap_data.fees, 8) != 0)) { + PRINTF("Fees is not matched\n"); + return 0; } - if (context.outputParsingState == OUTPUT_FINALIZE_TX) { - // we've finished the processing of the input - hash_input_finalize_full_reset(); + } + + if (context.outputParsingState == OUTPUT_FINALIZE_TX) { + context.transactionContext.firstSigned = 0; + + if (context.usingSegwit && !context.segwitParsedOnce) { + // This input cannot be signed when using segwit - just restart. + context.segwitParsedOnce = 1; + PRINTF("Segwit parsed once\n"); + context.transactionContext.transactionState = TRANSACTION_NONE; + } else { + context.transactionContext.transactionState = TRANSACTION_SIGN_READY; } + } + if (context.outputParsingState == OUTPUT_FINALIZE_TX) { + // we've finished the processing of the input + hash_input_finalize_full_reset(); + } - return 1; + return 1; } unsigned int confirm_single_output(void) { - if (G_called_from_swap) { - if (silent_confirm_single_output()) { - return 2; - } - return 0; + if (G_called_from_swap) { + if (silent_confirm_single_output()) { + return 2; } - prepare_single_output(); + return 0; + } + prepare_single_output(); - ui_confirm_single_flow(); - return 1; + ui_confirm_single_flow(); + return 1; } unsigned int finalize_tx(void) { - if (G_called_from_swap) { - if (check_fee_swap()) { - return 2; - } + if (G_called_from_swap) { + if (check_fee_swap()) { + return 2; } + } - if (!prepare_fees()) { - return 0; - } + if (!prepare_fees()) { + return 0; + } - ui_finalize_flow(); - return 1; + ui_finalize_flow(); + return 1; } void confirm_message_signature(void) { - if (!prepare_message_signature()) { - return; - } + if (!prepare_message_signature()) { + return; + } - ui_sign_message_flow(); + ui_sign_message_flow(); } -uint8_t set_key_path_to_display(const unsigned char* keyPath) { - format_path(keyPath, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); - return bip44_derivation_guard(keyPath, false); +uint8_t set_key_path_to_display(const unsigned char *keyPath) { + format_path(keyPath, vars.tmp_warning.derivation_path, + sizeof(vars.tmp_warning.derivation_path)); + return bip44_derivation_guard(keyPath, false); } void display_public_key(uint8_t is_derivation_path_unusual) { - // append a white space at the end of the address to avoid glitch on nano S - strlcat((char *)G_io_apdu_buffer + 200, " ", sizeof(G_io_apdu_buffer) - 200); - - if (is_derivation_path_unusual) { - ui_display_public_with_warning_flow(); - } - else { - ui_display_public_flow(); - } + // append a white space at the end of the address to avoid glitch on nano S + strlcat((char *)G_io_apdu_buffer + 200, " ", sizeof(G_io_apdu_buffer) - 200); + + if (is_derivation_path_unusual) { + ui_display_public_with_warning_flow(); + } else { + ui_display_public_flow(); + } } -void display_token(void) -{ - ui_display_token_flow(); -} +void display_token(void) { ui_display_token_flow(); } -void request_pubkey_approval(void) -{ - ui_request_pubkey_approval_flow(); -} +void request_pubkey_approval(void) { ui_request_pubkey_approval_flow(); } -void request_change_path_approval(unsigned char* change_path) -{ - format_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); - ui_request_change_path_approval_flow(); +void request_change_path_approval(unsigned char *change_path) { + format_path(change_path, vars.tmp_warning.derivation_path, + sizeof(vars.tmp_warning.derivation_path)); + ui_request_change_path_approval_flow(); } -void request_sign_path_approval(unsigned char* change_path) -{ - format_path(change_path, vars.tmp_warning.derivation_path, sizeof(vars.tmp_warning.derivation_path)); - ui_request_sign_path_approval_flow(); +void request_sign_path_approval(unsigned char *change_path) { + format_path(change_path, vars.tmp_warning.derivation_path, + sizeof(vars.tmp_warning.derivation_path)); + ui_request_sign_path_approval_flow(); } -void request_segwit_input_approval(void) -{ - ui_request_segwit_input_approval_flow(); +void request_segwit_input_approval(void) { + ui_request_segwit_input_approval_flow(); } - - diff --git a/lib-app-bitcoin/ui/ui_bagl.c b/lib-app-bitcoin/ui/ui_bagl.c index 9a60828b..e4eaaf69 100644 --- a/lib-app-bitcoin/ui/ui_bagl.c +++ b/lib-app-bitcoin/ui/ui_bagl.c @@ -17,9 +17,9 @@ #ifdef HAVE_BAGL ////////////////////////////////////////////////////////////////////// +#include "context.h" #include "display_variables.h" #include "transaction.h" -#include "context.h" #include "ui.h" #include "extensions.h" @@ -389,8 +389,7 @@ void ui_sign_message_flow(void) { ux_flow_init(0, ux_sign_flow, NULL); } void ui_confirm_single_flow(void) { snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "output #%d", - context.totalOutputs - context.remainingOutputs + - 1); + context.totalOutputs - context.remainingOutputs + 1); ux_flow_init(0, ux_confirm_single_flow, NULL); } @@ -429,12 +428,10 @@ void ui_idle_flow(void) { ux_stack_push(); } ux_flow_init(0, ux_idle_flow, NULL); -} - -void ui_transaction_error(void) { } -void ui_transaction_finish(void) { -} +void ui_transaction_error(void) {} + +void ui_transaction_finish(void) {} #endif // HAVE_BAGL diff --git a/lib-app-bitcoin/ui/ui_menu_nbgl.c b/lib-app-bitcoin/ui/ui_menu_nbgl.c index de876fc7..e767e60c 100644 --- a/lib-app-bitcoin/ui/ui_menu_nbgl.c +++ b/lib-app-bitcoin/ui/ui_menu_nbgl.c @@ -34,9 +34,7 @@ static char text[20]; static const char *const infoTypes[] = {"Version", "Developer"}; static const char *const infoContents[] = {APPVERSION, "Ledger"}; -static void quit_cb(void) { - os_sched_exit(-1); -} +static void quit_cb(void) { os_sched_exit(-1); } static bool settings_navigation_cb(uint8_t page, nbgl_pageContent_t *content) { if (page == 0) { @@ -56,8 +54,7 @@ static void display_settings_menu(void) { snprintf(text, sizeof(text), "%s settings", COIN_COINID_NAME); nbgl_useCaseSettings(text, PAGE_START, NB_PAGE_SETTING, IS_TOUCHABLE, - ui_idle_flow, settings_navigation_cb, - NULL); + ui_idle_flow, settings_navigation_cb, NULL); } void ui_idle_flow(void) { diff --git a/lib-app-bitcoin/ui/ui_nbgl.c b/lib-app-bitcoin/ui/ui_nbgl.c index 8876b6bd..23828d56 100644 --- a/lib-app-bitcoin/ui/ui_nbgl.c +++ b/lib-app-bitcoin/ui/ui_nbgl.c @@ -16,31 +16,29 @@ ********************************************************************************/ #ifdef HAVE_NBGL -#include "ui.h" -#include "nbgl_use_case.h" -#include "display_variables.h" #include "context.h" +#include "display_variables.h" +#include "nbgl_use_case.h" +#include "ui.h" #include "extensions.h" -typedef enum { - MESSAGE_TYPE, - TRANSACTION_TYPE -} flow_type_t; +typedef enum { MESSAGE_TYPE, TRANSACTION_TYPE } flow_type_t; enum { - CANCEL_TOKEN, - CONFIRM_TOKEN, - BACK_TOKEN, + CANCEL_TOKEN, + CONFIRM_TOKEN, + BACK_TOKEN, }; - typedef struct { bool transaction_prompt_done; const char *prompt_cancel_message; - const char *prompt; // text displayed in last transaction page - const char *approved_status; // text displayed in confirmation page (after long press) - const char *abandon_status; // text displayed in rejection page (after reject confirmed) + const char *prompt; // text displayed in last transaction page + const char * + approved_status; // text displayed in confirmation page (after long press) + const char *abandon_status; // text displayed in rejection page (after reject + // confirmed) void (*approved_cb)(void); void (*abandon_cb)(void); nbgl_layoutTagValueList_t tagValueList; @@ -138,25 +136,21 @@ static void status_callback(bool confirm) { // Prompt Cancel static void prompt_cancel(flow_type_t type) { switch (type) { - case MESSAGE_TYPE: - nbgl_useCaseConfirm("Reject message", NULL, "Yes, Reject", - "Go back to message", abandon_status); - break; - - case TRANSACTION_TYPE: - nbgl_useCaseConfirm("Reject transaction", NULL, "Yes, Reject", - "Go back to transaction", abandon_status); - break; + case MESSAGE_TYPE: + nbgl_useCaseConfirm("Reject message", NULL, "Yes, Reject", + "Go back to message", abandon_status); + break; + + case TRANSACTION_TYPE: + nbgl_useCaseConfirm("Reject transaction", NULL, "Yes, Reject", + "Go back to transaction", abandon_status); + break; } } -static void prompt_cancel_message(void) { - prompt_cancel(MESSAGE_TYPE); -} +static void prompt_cancel_message(void) { prompt_cancel(MESSAGE_TYPE); } -static void prompt_cancel_transaction(void) { - prompt_cancel(TRANSACTION_TYPE); -} +static void prompt_cancel_transaction(void) { prompt_cancel(TRANSACTION_TYPE); } static void transaction_review_callback(bool token) { if (token) { @@ -168,45 +162,48 @@ static void transaction_review_callback(bool token) { } static void transaction_finish_callback(int token, uint8_t index) { - (void) index; + (void)index; switch (token) { - case CANCEL_TOKEN: - prompt_cancel_transaction(); - break; - case CONFIRM_TOKEN: - releaseContext(); - uiContext.approved_cb(); - break; - case BACK_TOKEN: - ui_finalize_flow(); - break; + case CANCEL_TOKEN: + prompt_cancel_transaction(); + break; + case CONFIRM_TOKEN: + releaseContext(); + uiContext.approved_cb(); + break; + case BACK_TOKEN: + ui_finalize_flow(); + break; } } static void transaction_fee_callback(int token, uint8_t index) { - (void) index; + (void)index; if (token) { - releaseContext(); - snprintf(text, sizeof(text), "Sign transaction\nto send %s?", COIN_COINID_NAME); - nbgl_pageNavigationInfo_t info = {.activePage = 0, - .nbPages = 0, - .navType = NAV_WITH_TAP, - .progressIndicator = true, - .navWithTap.backButton = true, - .navWithTap.backToken = BACK_TOKEN, - .navWithTap.nextPageText = NULL, - .navWithTap.quitText = "Reject transaction", - .quitToken = CANCEL_TOKEN, - .tuneId = TUNE_TAP_CASUAL}; - - nbgl_pageContent_t content = {.type = INFO_LONG_PRESS, - .infoLongPress.icon = &COIN_ICON, - .infoLongPress.text = text, - .infoLongPress.longPressText = "Hold to sign", - .infoLongPress.longPressToken = CONFIRM_TOKEN, - .infoLongPress.tuneId = TUNE_TAP_NEXT}; - - pageContext = nbgl_pageDrawGenericContent(&transaction_finish_callback, &info, &content); + releaseContext(); + snprintf(text, sizeof(text), "Sign transaction\nto send %s?", + COIN_COINID_NAME); + nbgl_pageNavigationInfo_t info = {.activePage = 0, + .nbPages = 0, + .navType = NAV_WITH_TAP, + .progressIndicator = true, + .navWithTap.backButton = true, + .navWithTap.backToken = BACK_TOKEN, + .navWithTap.nextPageText = NULL, + .navWithTap.quitText = + "Reject transaction", + .quitToken = CANCEL_TOKEN, + .tuneId = TUNE_TAP_CASUAL}; + + nbgl_pageContent_t content = {.type = INFO_LONG_PRESS, + .infoLongPress.icon = &COIN_ICON, + .infoLongPress.text = text, + .infoLongPress.longPressText = "Hold to sign", + .infoLongPress.longPressToken = CONFIRM_TOKEN, + .infoLongPress.tuneId = TUNE_TAP_NEXT}; + + pageContext = nbgl_pageDrawGenericContent(&transaction_finish_callback, + &info, &content); } else { prompt_cancel_transaction(); } @@ -232,36 +229,34 @@ static void continue_review(flow_type_t type) { uiContext.infoLongPress.text = uiContext.prompt; switch (type) { - case MESSAGE_TYPE: - nbgl_useCaseStaticReview(&uiContext.tagValueList, &uiContext.infoLongPress, - "Cancel", message_review_callback); - break; - - case TRANSACTION_TYPE: - nbgl_useCaseStaticReview(&uiContext.tagValueList, &uiContext.infoLongPress, - "Cancel", transaction_review_callback); - break; + case MESSAGE_TYPE: + nbgl_useCaseStaticReview(&uiContext.tagValueList, &uiContext.infoLongPress, + "Cancel", message_review_callback); + break; + + case TRANSACTION_TYPE: + nbgl_useCaseStaticReview(&uiContext.tagValueList, &uiContext.infoLongPress, + "Cancel", transaction_review_callback); + break; } } -static void continue_message_review(void) { - continue_review(MESSAGE_TYPE); -} +static void continue_message_review(void) { continue_review(MESSAGE_TYPE); } // UI Start static void ui_start(void (*cb)(void), flow_type_t type) { switch (type) { - case MESSAGE_TYPE: - nbgl_useCaseReviewStart(&COIN_ICON, "Review\nmessage", NULL, - "Cancel", continue_message_review, - prompt_cancel_message); - break; - - case TRANSACTION_TYPE: - snprintf(text, sizeof(text), "Review transaction\nto send %s", COIN_COINID_NAME); - nbgl_useCaseReviewStart(&COIN_ICON, text, NULL, - "Cancel", cb, prompt_cancel_transaction); - break; + case MESSAGE_TYPE: + nbgl_useCaseReviewStart(&COIN_ICON, "Review\nmessage", NULL, "Cancel", + continue_message_review, prompt_cancel_message); + break; + + case TRANSACTION_TYPE: + snprintf(text, sizeof(text), "Review transaction\nto send %s", + COIN_COINID_NAME); + nbgl_useCaseReviewStart(&COIN_ICON, text, NULL, "Cancel", cb, + prompt_cancel_transaction); + break; } } @@ -284,13 +279,14 @@ static void ui_message_start(void) { // Other callbacks static void display_pubkey_callback(void) { if (uiContext.nbPairs == 1) { - nbgl_useCaseAddressConfirmation(uiContext.tagValues[0].value, status_callback); - } - else { - uiContext.tagValueList.pairs = &uiContext.tagValues[1]; - uiContext.tagValueList.nbPairs = 1; + nbgl_useCaseAddressConfirmation(uiContext.tagValues[0].value, + status_callback); + } else { + uiContext.tagValueList.pairs = &uiContext.tagValues[1]; + uiContext.tagValueList.nbPairs = 1; - nbgl_useCaseAddressConfirmationExt(uiContext.tagValues[0].value, status_callback, &uiContext.tagValueList); + nbgl_useCaseAddressConfirmationExt( + uiContext.tagValues[0].value, status_callback, &uiContext.tagValueList); } } @@ -310,8 +306,7 @@ void ui_confirm_single_flow(void) { ui_transaction_start(ui_confirm_single_flow); } else { snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "#%d", - context.totalOutputs - context.remainingOutputs + - 1); + context.totalOutputs - context.remainingOutputs + 1); uiContext.tagValues[0].item = "Output"; uiContext.tagValues[0].value = vars.tmp.feesAmount; @@ -324,17 +319,17 @@ void ui_confirm_single_flow(void) { uiContext.nbPairs = 3; - nbgl_pageNavigationInfo_t info = { - .activePage = 0, - .nbPages = 0, - .navType = NAV_WITH_TAP, - .progressIndicator = true, - .navWithTap.backButton = false, - .navWithTap.nextPageText = "Tap to continue", - .navWithTap.nextPageToken = 1, - .navWithTap.quitText = "Cancel", - .quitToken = 0, - .tuneId = TUNE_TAP_CASUAL}; + nbgl_pageNavigationInfo_t info = {.activePage = 0, + .nbPages = 0, + .navType = NAV_WITH_TAP, + .progressIndicator = true, + .navWithTap.backButton = false, + .navWithTap.nextPageText = + "Tap to continue", + .navWithTap.nextPageToken = 1, + .navWithTap.quitText = "Cancel", + .quitToken = 0, + .tuneId = TUNE_TAP_CASUAL}; nbgl_pageContent_t content = { .type = TAG_VALUE_LIST, @@ -361,7 +356,8 @@ void ui_finalize_flow(void) { .navType = NAV_WITH_TAP, .progressIndicator = true, .navWithTap.backButton = false, - .navWithTap.nextPageText = "Tap to continue", + .navWithTap.nextPageText = + "Tap to continue", .navWithTap.nextPageToken = 1, .navWithTap.quitText = "Reject transaction", .quitToken = 0, @@ -370,10 +366,10 @@ void ui_finalize_flow(void) { nbgl_pageContent_t content = { .type = TAG_VALUE_LIST, .tagValueList.nbPairs = uiContext.nbPairs, - .tagValueList.pairs = (nbgl_layoutTagValue_t *)uiContext.tagValues - }; + .tagValueList.pairs = (nbgl_layoutTagValue_t *)uiContext.tagValues}; - pageContext = nbgl_pageDrawGenericContent(&transaction_fee_callback, &info, &content); + pageContext = + nbgl_pageDrawGenericContent(&transaction_fee_callback, &info, &content); nbgl_refresh(); } @@ -417,8 +413,8 @@ void ui_request_pubkey_approval_flow(void) { ui_transaction_start(ui_request_pubkey_approval_flow); } else { - nbgl_useCaseChoice(&COIN_ICON, "Export public key", NULL, - "Approve", "Reject", transaction_review_callback); + nbgl_useCaseChoice(&COIN_ICON, "Export public key", NULL, "Approve", + "Reject", transaction_review_callback); } } @@ -470,12 +466,11 @@ static void prompt_public_key(bool warning) { snprintf(text, sizeof(text), "Verify %s\naddress", COIN_COINID_NAME); if (warning) { - nbgl_useCaseReviewStart(&COIN_ICON, text, NULL, - "Cancel", warn_unusual_derivation_path, - abandon_status); + nbgl_useCaseReviewStart(&COIN_ICON, text, NULL, "Cancel", + warn_unusual_derivation_path, abandon_status); } else { - nbgl_useCaseReviewStart(&COIN_ICON, text, NULL, - "Cancel", display_pubkey_callback, abandon_status); + nbgl_useCaseReviewStart(&COIN_ICON, text, NULL, "Cancel", + display_pubkey_callback, abandon_status); } } @@ -510,9 +505,7 @@ void ui_display_public_with_warning_flow(void) { display_show_public_key(true); } -void ui_display_public_flow(void) { - display_show_public_key(false); -} +void ui_display_public_flow(void) { display_show_public_key(false); } void ui_transaction_finish(void) { if (uiContext.transaction_prompt_done) { diff --git a/lib-app-bitcoin/utils/be_operations.c b/lib-app-bitcoin/utils/be_operations.c index 43c916e3..c99d05be 100644 --- a/lib-app-bitcoin/utils/be_operations.c +++ b/lib-app-bitcoin/utils/be_operations.c @@ -1,42 +1,38 @@ #include "be_operations.h" -unsigned char transaction_amount_add_be(unsigned char *target, - unsigned char *a, +unsigned char transaction_amount_add_be(unsigned char *target, unsigned char *a, unsigned char *b) { - unsigned char carry = 0; - unsigned char i; - for (i = 0; i < 8; i++) { - unsigned short val = a[8 - 1 - i] + b[8 - 1 - i] + (carry ? 1 : 0); - carry = (val > 255); - target[8 - 1 - i] = (val & 255); - } - return carry; + unsigned char carry = 0; + unsigned char i; + for (i = 0; i < 8; i++) { + unsigned short val = a[8 - 1 - i] + b[8 - 1 - i] + (carry ? 1 : 0); + carry = (val > 255); + target[8 - 1 - i] = (val & 255); + } + return carry; } -unsigned char transaction_amount_sub_be(unsigned char *target, - unsigned char *a, +unsigned char transaction_amount_sub_be(unsigned char *target, unsigned char *a, unsigned char *b) { - unsigned char borrow = 0; - unsigned char i; - for (i = 0; i < 8; i++) { - unsigned short tmpA = a[8 - 1 - i]; - unsigned short tmpB = b[8 - 1 - i]; - if (borrow) { - if (tmpA <= tmpB) { - tmpA += (255 + 1) - 1; - } else { - borrow = 0; - tmpA--; - } - } - if (tmpA < tmpB) { - borrow = 1; - tmpA += 255 + 1; - } - target[8 - 1 - i] = (unsigned char)(tmpA - tmpB); + unsigned char borrow = 0; + unsigned char i; + for (i = 0; i < 8; i++) { + unsigned short tmpA = a[8 - 1 - i]; + unsigned short tmpB = b[8 - 1 - i]; + if (borrow) { + if (tmpA <= tmpB) { + tmpA += (255 + 1) - 1; + } else { + borrow = 0; + tmpA--; + } + } + if (tmpA < tmpB) { + borrow = 1; + tmpA += 255 + 1; } + target[8 - 1 - i] = (unsigned char)(tmpA - tmpB); + } - return borrow; + return borrow; } - - diff --git a/lib-app-bitcoin/utils/be_operations.h b/lib-app-bitcoin/utils/be_operations.h index 8dc7a9a2..81533086 100644 --- a/lib-app-bitcoin/utils/be_operations.h +++ b/lib-app-bitcoin/utils/be_operations.h @@ -1,28 +1,26 @@ /******************************************************************************* -* Ledger App - Bitcoin Wallet -* (c) 2016-2019 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * Ledger App - Bitcoin Wallet + * (c) 2016-2019 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once // target = a + b -unsigned char transaction_amount_add_be(unsigned char *target, - unsigned char *a, +unsigned char transaction_amount_add_be(unsigned char *target, unsigned char *a, unsigned char *b); // target = a - b -unsigned char transaction_amount_sub_be(unsigned char *target, - unsigned char *a, +unsigned char transaction_amount_sub_be(unsigned char *target, unsigned char *a, unsigned char *b); diff --git a/lib-app-bitcoin/utils/cashaddr.c b/lib-app-bitcoin/utils/cashaddr.c index fb14ad30..3214af13 100644 --- a/lib-app-bitcoin/utils/cashaddr.c +++ b/lib-app-bitcoin/utils/cashaddr.c @@ -20,134 +20,133 @@ * THE SOFTWARE. */ -#include "os.h" #include "cx.h" -#include +#include "os.h" +#include #include +#include #include -#include #include "cashaddr.h" static const char *charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; uint64_t cashaddr_polymod_step(uint64_t pre) { - uint8_t b = pre >> 35; - return ((pre & 0x07ffffffff) << 5) ^ (-((b >> 0) & 1) & 0x98f2bc8e61UL) ^ - (-((b >> 1) & 1) & 0x79b76d99e2UL) ^ - (-((b >> 2) & 1) & 0xf33e5fb3c4UL) ^ - (-((b >> 3) & 1) & 0xae2eabe2a8UL) ^ - (-((b >> 4) & 1) & 0x1e4f43e470UL); + uint8_t b = pre >> 35; + return ((pre & 0x07ffffffff) << 5) ^ (-((b >> 0) & 1) & 0x98f2bc8e61UL) ^ + (-((b >> 1) & 1) & 0x79b76d99e2UL) ^ + (-((b >> 2) & 1) & 0xf33e5fb3c4UL) ^ + (-((b >> 3) & 1) & 0xae2eabe2a8UL) ^ + (-((b >> 4) & 1) & 0x1e4f43e470UL); } uint64_t PolyMod(uint8_t *prefix, uint8_t *payload, size_t payload_length) { - size_t i; - uint64_t c = 1; - while (*prefix != 0) { - c = cashaddr_polymod_step(c) ^ (*prefix++ & 0x1f); // Prefix - } - c = cashaddr_polymod_step(c); // The zero valued separator - for (i = 0; i < payload_length; ++i) { - c = cashaddr_polymod_step(c) ^ (*payload++); // Hash - } - for (i = 0; i < 8; ++i) { - c = cashaddr_polymod_step(c); // 8 zeros for empty checksum - } - return c ^ 1; + size_t i; + uint64_t c = 1; + while (*prefix != 0) { + c = cashaddr_polymod_step(c) ^ (*prefix++ & 0x1f); // Prefix + } + c = cashaddr_polymod_step(c); // The zero valued separator + for (i = 0; i < payload_length; ++i) { + c = cashaddr_polymod_step(c) ^ (*payload++); // Hash + } + for (i = 0; i < 8; ++i) { + c = cashaddr_polymod_step(c); // 8 zeros for empty checksum + } + return c ^ 1; } static int convert_bits(uint8_t *out, size_t *outlen, int outbits, const uint8_t *in, size_t inlen, int inbits, int pad) { - uint32_t val = 0; - int bits = 0; - uint32_t maxv = (((uint32_t)1) << outbits) - 1; - while (inlen--) { - val = (val << inbits) | *(in++); - bits += inbits; - while (bits >= outbits) { - bits -= outbits; - out[(*outlen)++] = (val >> bits) & maxv; - } + uint32_t val = 0; + int bits = 0; + uint32_t maxv = (((uint32_t)1) << outbits) - 1; + while (inlen--) { + val = (val << inbits) | *(in++); + bits += inbits; + while (bits >= outbits) { + bits -= outbits; + out[(*outlen)++] = (val >> bits) & maxv; } - if (pad) { - if (bits) { - out[(*outlen)++] = (val << (outbits - bits)) & maxv; - } - } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { - return 0; + } + if (pad) { + if (bits) { + out[(*outlen)++] = (val << (outbits - bits)) & maxv; } - return 1; + } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { + return 0; + } + return 1; } void create_checksum(uint8_t *payload, size_t payload_length, uint8_t *checksum) { - uint8_t *prefix = (uint8_t *)"bitcoincash"; - uint64_t mod = PolyMod(prefix, payload, payload_length); + uint8_t *prefix = (uint8_t *)"bitcoincash"; + uint64_t mod = PolyMod(prefix, payload, payload_length); - for (size_t i = 0; i < 8; ++i) { - // Convert the 5-bit groups in mod to checksum values. - *checksum++ = (mod >> (5 * (7 - i))) & 0x1f; - } + for (size_t i = 0; i < 8; ++i) { + // Convert the 5-bit groups in mod to checksum values. + *checksum++ = (mod >> (5 * (7 - i))) & 0x1f; + } } int cashaddr_encode(uint8_t *hash, const size_t hash_length, uint8_t *addr, const size_t max_addr_len, const unsigned short version) { - uint8_t version_byte; - uint8_t checksum[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // 5-bit bytes. - uint8_t - tmp[40]; // 8-bit bytes. Should be enough for 1 version byte + 160 bit - uint8_t payload[40]; // 5-bit bytes. Should be enough for 1 version byte + - // 160 bit hash - uint8_t *addr_start; - size_t payload_length = 0; - size_t addr_length = 0; - size_t i; + uint8_t version_byte; + uint8_t checksum[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // 5-bit bytes. + uint8_t tmp[40]; // 8-bit bytes. Should be enough for 1 version byte + 160 bit + uint8_t payload[40]; // 5-bit bytes. Should be enough for 1 version byte + + // 160 bit hash + uint8_t *addr_start; + size_t payload_length = 0; + size_t addr_length = 0; + size_t i; - addr_start = addr; - *addr_start = 0; + addr_start = addr; + *addr_start = 0; - if (hash_length != 20) // Only support 160 bit hash - return 0; - if (version == CASHADDR_P2PKH) { // Support P2PKH = 0, P2SH = 1 - version_byte = 0; - } else if (version == CASHADDR_P2SH) { - version_byte = 8; - } else { - return 0; - } + if (hash_length != 20) // Only support 160 bit hash + return 0; + if (version == CASHADDR_P2PKH) { // Support P2PKH = 0, P2SH = 1 + version_byte = 0; + } else if (version == CASHADDR_P2SH) { + version_byte = 8; + } else { + return 0; + } - tmp[0] = version_byte; - memmove(tmp + 1, hash, hash_length); - convert_bits(payload, &payload_length, 5, tmp, hash_length + 1, 8, 1); + tmp[0] = version_byte; + memmove(tmp + 1, hash, hash_length); + convert_bits(payload, &payload_length, 5, tmp, hash_length + 1, 8, 1); - create_checksum(payload, payload_length, - checksum); // Assume prefix is 'bitcoincash' + create_checksum(payload, payload_length, + checksum); // Assume prefix is 'bitcoincash' - for (i = 0; i < payload_length; ++i) { - if (*payload >> 5) { - *addr_start = 0; - return 0; - } - addr_length++; - if (max_addr_len < addr_length) { - *addr_start = 0; - return 0; - } - *(addr++) = charset[payload[i]]; + for (i = 0; i < payload_length; ++i) { + if (*payload >> 5) { + *addr_start = 0; + return 0; + } + addr_length++; + if (max_addr_len < addr_length) { + *addr_start = 0; + return 0; + } + *(addr++) = charset[payload[i]]; + } + for (i = 0; i < 8; ++i) { + if (*checksum >> 5) { + *addr_start = 0; + return 0; } - for (i = 0; i < 8; ++i) { - if (*checksum >> 5) { - *addr_start = 0; - return 0; - } - addr_length++; - if (max_addr_len < addr_length) { - *addr_start = 0; - return 0; - } - *(addr++) = charset[checksum[i]]; + addr_length++; + if (max_addr_len < addr_length) { + *addr_start = 0; + return 0; } - *addr = 0; + *(addr++) = charset[checksum[i]]; + } + *addr = 0; - return addr_length; + return addr_length; } diff --git a/lib-app-bitcoin/utils/segwit_addr.c b/lib-app-bitcoin/utils/segwit_addr.c index 95c37e8e..bec567ec 100644 --- a/lib-app-bitcoin/utils/segwit_addr.c +++ b/lib-app-bitcoin/utils/segwit_addr.c @@ -19,17 +19,17 @@ * THE SOFTWARE. */ -#include #include +#include #include #include "segwit_addr.h" uint32_t bech32_polymod_step(uint32_t pre) { - uint8_t b = pre >> 25; - return ((pre & 0x1FFFFFF) << 5) ^ (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ - (-((b >> 1) & 1) & 0x26508e6dUL) ^ (-((b >> 2) & 1) & 0x1ea119faUL) ^ - (-((b >> 3) & 1) & 0x3d4233ddUL) ^ (-((b >> 4) & 1) & 0x2a1462b3UL); + uint8_t b = pre >> 25; + return ((pre & 0x1FFFFFF) << 5) ^ (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ + (-((b >> 1) & 1) & 0x26508e6dUL) ^ (-((b >> 2) & 1) & 0x1ea119faUL) ^ + (-((b >> 3) & 1) & 0x3d4233ddUL) ^ (-((b >> 4) & 1) & 0x2a1462b3UL); } static const char *charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; @@ -45,160 +45,160 @@ static const int8_t charset_rev[128] = { int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len) { - uint32_t chk = 1; - size_t i = 0; - while (hrp[i] != 0) { - if (hrp[i] >= 'A' && hrp[i] <= 'Z') - return 0; - if (!(hrp[i] >> 5)) - return 0; - chk = bech32_polymod_step(chk) ^ (hrp[i] >> 5); - ++i; - } - if (i + 7 + data_len > 90) - return 0; + uint32_t chk = 1; + size_t i = 0; + while (hrp[i] != 0) { + if (hrp[i] >= 'A' && hrp[i] <= 'Z') + return 0; + if (!(hrp[i] >> 5)) + return 0; + chk = bech32_polymod_step(chk) ^ (hrp[i] >> 5); + ++i; + } + if (i + 7 + data_len > 90) + return 0; + chk = bech32_polymod_step(chk); + while (*hrp != 0) { + chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f); + *(output++) = *(hrp++); + } + *(output++) = '1'; + for (i = 0; i < data_len; ++i) { + if (*data >> 5) + return 0; + chk = bech32_polymod_step(chk) ^ (*data); + *(output++) = charset[*(data++)]; + } + for (i = 0; i < 6; ++i) { chk = bech32_polymod_step(chk); - while (*hrp != 0) { - chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f); - *(output++) = *(hrp++); - } - *(output++) = '1'; - for (i = 0; i < data_len; ++i) { - if (*data >> 5) - return 0; - chk = bech32_polymod_step(chk) ^ (*data); - *(output++) = charset[*(data++)]; - } - for (i = 0; i < 6; ++i) { - chk = bech32_polymod_step(chk); - } - chk ^= 1; - for (i = 0; i < 6; ++i) { - *(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f]; - } - *output = 0; - return 1; + } + chk ^= 1; + for (i = 0; i < 6; ++i) { + *(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f]; + } + *output = 0; + return 1; } int bech32_decode(char *hrp, uint8_t *data, size_t *data_len, const char *input) { - uint32_t chk = 1; - size_t i; - size_t input_len = strlen(input); - size_t hrp_len; - int have_lower = 0, have_upper = 0; - if (input_len < 8 || input_len > 90) { - return 0; - } - *data_len = 0; - while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') { - ++(*data_len); + uint32_t chk = 1; + size_t i; + size_t input_len = strlen(input); + size_t hrp_len; + int have_lower = 0, have_upper = 0; + if (input_len < 8 || input_len > 90) { + return 0; + } + *data_len = 0; + while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') { + ++(*data_len); + } + hrp_len = input_len - (1 + *data_len); + if (hrp_len < 1 || *data_len < 6) { + return 0; + } + *(data_len) -= 6; + for (i = 0; i < hrp_len; ++i) { + int ch = input[i]; + if (ch < 33 || ch > 126) { + return 0; } - hrp_len = input_len - (1 + *data_len); - if (hrp_len < 1 || *data_len < 6) { - return 0; + if (ch >= 'a' && ch <= 'z') { + have_lower = 1; + } else if (ch >= 'A' && ch <= 'Z') { + have_upper = 1; + ch = (ch - 'A') + 'a'; } - *(data_len) -= 6; - for (i = 0; i < hrp_len; ++i) { - int ch = input[i]; - if (ch < 33 || ch > 126) { - return 0; - } - if (ch >= 'a' && ch <= 'z') { - have_lower = 1; - } else if (ch >= 'A' && ch <= 'Z') { - have_upper = 1; - ch = (ch - 'A') + 'a'; - } - hrp[i] = ch; - chk = bech32_polymod_step(chk) ^ (ch >> 5); + hrp[i] = ch; + chk = bech32_polymod_step(chk) ^ (ch >> 5); + } + hrp[i] = 0; + chk = bech32_polymod_step(chk); + for (i = 0; i < hrp_len; ++i) { + chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f); + } + ++i; + while (i < input_len) { + int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; + if (input[i] >= 'a' && input[i] <= 'z') + have_lower = 1; + if (input[i] >= 'A' && input[i] <= 'Z') + have_upper = 1; + if (v == -1) { + return 0; } - hrp[i] = 0; - chk = bech32_polymod_step(chk); - for (i = 0; i < hrp_len; ++i) { - chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f); + chk = bech32_polymod_step(chk) ^ v; + if (i + 6 < input_len) { + data[i - (1 + hrp_len)] = v; } ++i; - while (i < input_len) { - int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; - if (input[i] >= 'a' && input[i] <= 'z') - have_lower = 1; - if (input[i] >= 'A' && input[i] <= 'Z') - have_upper = 1; - if (v == -1) { - return 0; - } - chk = bech32_polymod_step(chk) ^ v; - if (i + 6 < input_len) { - data[i - (1 + hrp_len)] = v; - } - ++i; - } - if (have_lower && have_upper) { - return 0; - } - return chk == 1; + } + if (have_lower && have_upper) { + return 0; + } + return chk == 1; } static int convert_bits(uint8_t *out, size_t *outlen, int outbits, const uint8_t *in, size_t inlen, int inbits, int pad) { - uint32_t val = 0; - int bits = 0; - uint32_t maxv = (((uint32_t)1) << outbits) - 1; - while (inlen--) { - val = (val << inbits) | *(in++); - bits += inbits; - while (bits >= outbits) { - bits -= outbits; - out[(*outlen)++] = (val >> bits) & maxv; - } + uint32_t val = 0; + int bits = 0; + uint32_t maxv = (((uint32_t)1) << outbits) - 1; + while (inlen--) { + val = (val << inbits) | *(in++); + bits += inbits; + while (bits >= outbits) { + bits -= outbits; + out[(*outlen)++] = (val >> bits) & maxv; } - if (pad) { - if (bits) { - out[(*outlen)++] = (val << (outbits - bits)) & maxv; - } - } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { - return 0; + } + if (pad) { + if (bits) { + out[(*outlen)++] = (val << (outbits - bits)) & maxv; } - return 1; + } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { + return 0; + } + return 1; } int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) { - uint8_t data[65]; - size_t datalen = 0; - if (witver > 16) - return 0; - if (witver == 0 && witprog_len != 20 && witprog_len != 32) - return 0; - if (witprog_len < 2 || witprog_len > 40) - return 0; - data[0] = witver; - convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1); - ++datalen; - return bech32_encode(output, hrp, data, datalen); + uint8_t data[65]; + size_t datalen = 0; + if (witver > 16) + return 0; + if (witver == 0 && witprog_len != 20 && witprog_len != 32) + return 0; + if (witprog_len < 2 || witprog_len > 40) + return 0; + data[0] = witver; + convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1); + ++datalen; + return bech32_encode(output, hrp, data, datalen); } int segwit_addr_decode(int *witver, uint8_t *witdata, size_t *witdata_len, const char *hrp, const char *addr) { - uint8_t data[84]; - char hrp_actual[84]; - size_t data_len; - if (!bech32_decode(hrp_actual, data, &data_len, addr)) - return 0; - if (data_len == 0 || data_len > 65) - return 0; - if (strncmp(hrp, hrp_actual, 84) != 0) - return 0; - if (data[0] > 16) - return 0; - *witdata_len = 0; - if (!convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) - return 0; - if (*witdata_len < 2 || *witdata_len > 40) - return 0; - if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) - return 0; - *witver = data[0]; - return 1; + uint8_t data[84]; + char hrp_actual[84]; + size_t data_len; + if (!bech32_decode(hrp_actual, data, &data_len, addr)) + return 0; + if (data_len == 0 || data_len > 65) + return 0; + if (strncmp(hrp, hrp_actual, 84) != 0) + return 0; + if (data[0] > 16) + return 0; + *witdata_len = 0; + if (!convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) + return 0; + if (*witdata_len < 2 || *witdata_len > 40) + return 0; + if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) + return 0; + *witver = data[0]; + return 1; } From 45277bac1fef556a21793c78a15469a4db524a38 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 29 Apr 2024 14:20:29 +0200 Subject: [PATCH 75/85] Doc: update readme and add comments for WEAK functions --- README.md | 21 +++-- lib-app-bitcoin/customizable_helpers.c | 90 +++++++++++++++++++ lib-app-bitcoin/customizable_ui.c | 22 +++++ lib-app-bitcoin/handler/get_coin_version.c | 8 ++ .../handler/get_firmware_version.c | 8 ++ lib-app-bitcoin/handler/get_trusted_input.c | 18 ++++ .../handler/get_wallet_public_key.c | 17 ++++ lib-app-bitcoin/handler/hash_input_start.c | 20 +++++ lib-app-bitcoin/handler/hash_sign.c | 17 ++++ lib-app-bitcoin/handler/sign_message.c | 17 ++++ 10 files changed, 231 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9caaa6f2..357b7c47 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,29 @@ -# ledger-app-bitcoin +# Ledger Legacy Bitcoin Application -Bitcoin wallet application for Ledger Nano S and Nano X, up to version 1.6.5. +## Legacy bitcoin application +Bitcoin wallet application for Ledger Nano S, Ledger Nano S+ and Nano X, up to version 1.6.5. > **Warning** > This is currently only used in order to support and maintain altcoins cloned from Bitcoin. -> The last stable version of the app as it was used for Bitcoin is kept in the branch [legacy-1.6.6](https://github.com/LedgerHQ/app-bitcoin/tree/legacy-1.6.6) for future reference. +> The last stable version of the app as it was used for Bitcoin is kept in the branch [legacy-1.6.6](https://github.com/LedgerHQ/app-bitcoin/tree/legacy-1.6.6) for future reference and does not support Stax or Flex device. > > Versions starting from 2.0.0 are at https://github.com/LedgerHQ/app-bitcoin-new. Ledger Blue is not maintained anymore, but the app can still be compiled for this target using the branch `blue-final-release`. -This follows the beta specification at https://ledgerhq.github.io/btchip-doc/bitcoin-technical-beta.html - with the regular set of APDUs for standard wallet operations enabled. +The original beta specification can be found at https://ledgerhq.github.io/btchip-doc/bitcoin-technical-beta.html - with the regular set of APDUs for standard wallet operations enabled. -To compile and load it on a device, have a look here: https://developers.ledger.com/docs/nano-app/load/ +## How to use -Can be tested quickly tested with the Python API at https://github.com/LedgerHQ/btchip-python and Electrum (force noPin = True in getClient in plugins/ledger/ledger.py) +This application adheres with Ledger latest application guidelines. -## Usage +You can refer to [app-boilerplate Quick start guide](https://github.com/LedgerHQ/app-boilerplate/blob/master/README.md#quick-start-guide) for comprehensive up-to-date instructions. +## Are you developing a Ledger device application? +- See the developers’ documentation on the [Developer Portal](https://developers.ledger.com/) +- [Go on Discord](https://developers.ledger.com/discord-pro/) to chat with developer support and the developer community. + +## Client Library Include the necessary headers (copied from the js/ directory) in your web page ```html @@ -92,3 +98,4 @@ dongle.signP2SHTransaction_async( function(error) { console.log(error); }); ); ``` + diff --git a/lib-app-bitcoin/customizable_helpers.c b/lib-app-bitcoin/customizable_helpers.c index 098e4670..d1f0e387 100644 --- a/lib-app-bitcoin/customizable_helpers.c +++ b/lib-app-bitcoin/customizable_helpers.c @@ -57,6 +57,18 @@ const unsigned char ZEN_OUTPUT_SCRIPT_POST[] = { 0xb4 // OP_CHECKBLOCKATHEIGHT }; // BIP0115 Replay Protection +/* + * Function: output_script_is_regular + * ----------------------------------- + * Checks if the given output script is a regular script. + * + * Parameters: + * - buffer: Pointer to the output script buffer. + * + * Returns: + * - 1 if the output script is regular + * - 0 otherwise. + */ WEAK unsigned char output_script_is_regular(unsigned char *buffer) { if (COIN_NATIVE_SEGWIT_PREFIX) { if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, @@ -85,6 +97,18 @@ WEAK unsigned char output_script_is_regular(unsigned char *buffer) { return 0; } +/* + * Function: output_script_is_p2sh + * -------------------------------- + * Checks if the given output script is a pay-to-script-hash (P2SH) script. + * + * Parameters: + * - buffer: Pointer to the output script buffer. + * + * Returns: + * - 1 if the output script is a P2SH script. + * - 0 otherwise. + */ WEAK unsigned char output_script_is_p2sh(unsigned char *buffer) { if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && @@ -105,6 +129,19 @@ WEAK unsigned char output_script_is_p2sh(unsigned char *buffer) { return 0; } +/* + * Function: output_script_is_native_witness + * ------------------------------------------ + * Checks if the given output script is a native witness script (P2WPKH or + * P2WSH). + * + * Parameters: + * - buffer: Pointer to the output script buffer. + * + * Returns: + * - 1 if the output script is a native witness script. + * - 0 otherwise. + */ WEAK unsigned char output_script_is_native_witness(unsigned char *buffer) { if (COIN_NATIVE_SEGWIT_PREFIX) { if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, @@ -117,6 +154,19 @@ WEAK unsigned char output_script_is_native_witness(unsigned char *buffer) { return 0; } +/* + * Function: output_script_is_op_return + * ------------------------------------- + * Checks if the given output script is an OP_RETURN script. + * + * Parameters: + * - buffer: Pointer to the output script buffer. + * + * Returns: + * - 1 if the output script is an OP_RETURN script. + * - 0 otherwise. + * + */ WEAK unsigned char output_script_is_op_return(unsigned char *buffer) { if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { return ((buffer[1] == 0x6A) || @@ -126,6 +176,20 @@ WEAK unsigned char output_script_is_op_return(unsigned char *buffer) { } } +/* + * Function: output_script_is_op_create_or_call + * --------------------------------------------- + * Checks if the given output script is an OP_CREATE or OP_CALL script. + * + * Parameters: + * - buffer: Pointer to the output script buffer. + * - size: Size of the output script. + * - value: Value to match against the last byte of the script. + * + * Returns: + * - 1 if the output script is an OP_CREATE or OP_CALL script. + * - 0 otherwise. + */ WEAK unsigned char output_script_is_op_create_or_call(unsigned char *buffer, size_t size, unsigned char value) { @@ -134,11 +198,37 @@ WEAK unsigned char output_script_is_op_create_or_call(unsigned char *buffer, (buffer[0] < size) && (buffer[buffer[0]] == value)); } +/* + * Function: output_script_is_op_create + * ------------------------------------- + * Checks if the given output script is an OP_CREATE script. + * + * Parameters: + * - buffer: Pointer to the output script buffer. + * - size: Size of the output script. + * + * Returns: + * - 1 if the output script is an OP_CREATE script. + * - 0 otherwise. + */ WEAK unsigned char output_script_is_op_create(unsigned char *buffer, size_t size) { return output_script_is_op_create_or_call(buffer, size, 0xC1); } +/* + * Function: output_script_is_op_call + * ----------------------------------- + * Checks if the given output script is an OP_CALL script. + * + * Parameters: + * - buffer: Pointer to the output script buffer. + * - size: Size of the output script. + * + * Returns: + * - 1 if the output script is an OP_CALL script. + * - 0 otherwise. + */ WEAK unsigned char output_script_is_op_call(unsigned char *buffer, size_t size) { return output_script_is_op_create_or_call(buffer, size, 0xC2); diff --git a/lib-app-bitcoin/customizable_ui.c b/lib-app-bitcoin/customizable_ui.c index 4e82ade0..894d3f96 100644 --- a/lib-app-bitcoin/customizable_ui.c +++ b/lib-app-bitcoin/customizable_ui.c @@ -25,6 +25,19 @@ #include "read.h" #include "segwit_addr.h" +/* + * Function: get_address_from_output_script + * ----------------------------------------- + * Retrieves the address from a given output script and stores it in the + * provided buffer. + * + * Parameters: + * - script: Pointer to the output script data. + * - script_size: Size of the output script. + * - out: Pointer to the buffer where the address will be stored. + * - out_size: Size of the output buffer. + * + */ WEAK void get_address_from_output_script(unsigned char *script, int script_size, char *out, int out_size) { if (output_script_is_op_return(script)) { @@ -83,6 +96,15 @@ WEAK void get_address_from_output_script(unsigned char *script, int script_size, } } +/* + * Function: prepare_fees + * ----------------------- + * Prepares the fee amount for display + * + * Returns: + * - 1 if the fee amount is successfully prepared. + * - 0 if an error occurs. + */ WEAK uint8_t prepare_fees(void) { if (context.transactionContext.relaxed) { memmove(vars.tmp.feesAmount, "UNKNOWN", 7); diff --git a/lib-app-bitcoin/handler/get_coin_version.c b/lib-app-bitcoin/handler/get_coin_version.c index 5dbd8976..cf589124 100644 --- a/lib-app-bitcoin/handler/get_coin_version.c +++ b/lib-app-bitcoin/handler/get_coin_version.c @@ -21,6 +21,14 @@ #include "apdu_constants.h" #include "context.h" +/* + * Function: handler_get_coin_version + * ----------------------------------- + * Handles the retrieval of coin version information. + * + * Returns: + * - SW_OK if the operation is successful. + */ WEAK unsigned short handler_get_coin_version(void) { uint8_t offset = 0; size_t string_size; diff --git a/lib-app-bitcoin/handler/get_firmware_version.c b/lib-app-bitcoin/handler/get_firmware_version.c index 7c9dad9a..6ed5c123 100644 --- a/lib-app-bitcoin/handler/get_firmware_version.c +++ b/lib-app-bitcoin/handler/get_firmware_version.c @@ -33,6 +33,14 @@ #define TCS_LOADER_PATCH_VERSION 0 +/* + * Function: handler_get_firmware_version + * --------------------------------------- + * Retrieves the firmware version information. + * + * Returns: + * - -1 if the operation is unsuccessful. + */ WEAK unsigned short handler_get_firmware_version() { G_io_apdu_buffer[0] = FEATURES; diff --git a/lib-app-bitcoin/handler/get_trusted_input.c b/lib-app-bitcoin/handler/get_trusted_input.c index dd634eae..90aefa9d 100644 --- a/lib-app-bitcoin/handler/get_trusted_input.c +++ b/lib-app-bitcoin/handler/get_trusted_input.c @@ -26,6 +26,24 @@ #define GET_TRUSTED_INPUT_P1_FIRST 0x00 #define GET_TRUSTED_INPUT_P1_NEXT 0x80 +/* + * Function: handler_get_trusted_input + * ------------------------------------ + * Handles the retrieval of a trusted input for transaction signing. + * This function is defined as WEAK and can be overridden in the application own + * sources. + * + * The function manages the retrieval of a trusted input for transaction + * signing. It initializes transaction parameters, including the target input + * and hash option. It then parses the transaction data, processes the trusted + * input, and prepares the response. + * + * Parameters: + * - buffer: Pointer to the buffer containing transaction data. + * - p1: Instruction parameter 1. + * - p2: Instruction parameter 2. + * + */ WEAK unsigned short handler_get_trusted_input(buffer_t *buffer, uint8_t p1, uint8_t p2) { unsigned char dataOffset = 0; diff --git a/lib-app-bitcoin/handler/get_wallet_public_key.c b/lib-app-bitcoin/handler/get_wallet_public_key.c index d7edfb36..ca04f956 100644 --- a/lib-app-bitcoin/handler/get_wallet_public_key.c +++ b/lib-app-bitcoin/handler/get_wallet_public_key.c @@ -54,6 +54,23 @@ static int get_public_key_chain_code(const unsigned char *keyPath, return keyLength; } +/* + * Function: handler_get_wallet_public_key + * --------------------------------------- + * Handles the retrieval of the wallet's public key. + * This function is defined as WEAK and can be overridden in the application own + * sources. + * + * The function retrieves the wallet's public key and optionally displays it. + * It validates input parameters, computes the public key and chain code, + * encodes them, and prepares the response. If the public key is to be + * displayed, it ensures the key length is appropriate and sends it for display. + * Parameters: + * - buffer: Pointer to the buffer containing the instruction data. + * - p1: Instruction parameter 1. + * - p2: Instruction parameter 2. + * + */ WEAK unsigned short handler_get_wallet_public_key(buffer_t *buffer, uint8_t p1, uint8_t p2) { unsigned char keyLength; diff --git a/lib-app-bitcoin/handler/hash_input_start.c b/lib-app-bitcoin/handler/hash_input_start.c index 787f0bbd..ad662966 100644 --- a/lib-app-bitcoin/handler/hash_input_start.c +++ b/lib-app-bitcoin/handler/hash_input_start.c @@ -40,6 +40,26 @@ (buffer->ptr[0] == 0x01 && buffer->ptr[1] == TRUSTED_INPUT_TOTAL_SIZE && \ buffer->ptr[2] == MAGIC_TRUSTED_INPUT && buffer->ptr[3] == 0x00) +/* + * Function: handler_hash_input_start + * ----------------------------------- + * Handles the start of input hashing for a transaction. + * This function is defined as WEAK and can be overridden in the application own + * sources. + * + * The function manages the initialization and parsing of input data for hashing + * a transaction. It sets transaction parameters based on the instruction + * parameters, including flags for SegWit, CashAddr, Overwinter, and Sapling. It + * handles warnings for SegWit inputs, requests approval if needed, and starts + * parsing the transaction data for signature. Finally, it sends the response + * after parsing is complete. + * + * Parameters: + * - buffer: Pointer to the buffer containing transaction data. + * - p1: Instruction parameter 1. + * - p2: Instruction parameter 2. + * + */ WEAK unsigned short handler_hash_input_start(buffer_t *buffer, uint8_t p1, uint8_t p2) { if (p1 == P1_FIRST) { diff --git a/lib-app-bitcoin/handler/hash_sign.c b/lib-app-bitcoin/handler/hash_sign.c index 50b74e33..33598ef9 100644 --- a/lib-app-bitcoin/handler/hash_sign.c +++ b/lib-app-bitcoin/handler/hash_sign.c @@ -35,6 +35,23 @@ #define COIN_FORKID 0 #endif +/* + * Function: handler_hash_sign + * ---------------------------- + * Handles the signing process for hashing a transaction. + * This function is defined as WEAK and can be overridden in the application own + * sources. + * + * The function verifies parameters handles Zcash-specific scenarios, reads + * transaction parameters, finalizes the hash, checks for path enforcement, and + * initiates signing. It also handles specific cases for Bitcoin Cash and sets + * the appropriate sighash type. After hashing and signing, it sends the + * response. Parameters: + * - buffer: Pointer to the buffer containing transaction data. + * - p1: Instruction parameter 1. + * - p2: Instruction parameter 2. + * + */ WEAK unsigned short handler_hash_sign(buffer_t *buffer, uint8_t p1, uint8_t p2) { unsigned long int lockTime; diff --git a/lib-app-bitcoin/handler/sign_message.c b/lib-app-bitcoin/handler/sign_message.c index 487cf44c..23e0595f 100644 --- a/lib-app-bitcoin/handler/sign_message.c +++ b/lib-app-bitcoin/handler/sign_message.c @@ -246,6 +246,23 @@ static unsigned short sign_message_internal(buffer_t *buffer, uint8_t p1, return io_send_sw(sw); } +/* + * Function: handler_sign_message + * ------------------------------ + * Handles the signing of a message. + * This function is defined as WEAK and can be overridden in the application own + * sources. + * + * The function checks if called from the swap application, in which case it + * sends an error status code indicating security status not satisfied. All the + * logic for message signing is done in the sign_message_internal function. + * + * Parameters: + * - buffer: Pointer to the buffer containing the message data. + * - p1: Instruction parameter 1. + * - p2: Instruction parameter 2. + * + */ WEAK unsigned short handler_sign_message(buffer_t *buffer, uint8_t p1, uint8_t p2) { if (G_called_from_swap) { From 569d640666a3eea552ca0724920a38675f374d68 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 22 Apr 2024 09:54:49 +0200 Subject: [PATCH 76/85] Makefile: harmonize COIN_COINID_NAME with APPNAME --- Makefile | 58 ++++++++++++++++++++-------------------- lib-app-bitcoin/Makefile | 4 ++- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/Makefile b/Makefile index 707c4e1b..cbbeaed3 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ COIN_P2SH_VERSION=196 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOIN\" -COIN_COINID_NAME=\"Bitcoin\" +COIN_COINID_NAME="Bitcoin Test" COIN_COINID_SHORT=\"TEST\" COIN_NATIVE_SEGWIT_PREFIX=\"tb\" COIN_KIND=COIN_KIND_BITCOIN_TESTNET @@ -62,7 +62,7 @@ COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOIN\" -COIN_COINID_NAME=\"Bitcoin\" +COIN_COINID_NAME="Bitcoin" COIN_COINID_SHORT=\"BTC\" COIN_NATIVE_SEGWIT_PREFIX=\"bc\" COIN_KIND=COIN_KIND_BITCOIN @@ -79,7 +79,7 @@ COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" COIN_COINID_HEADER=\"BITCOINCASH\" -COIN_COINID_NAME=\"BitcoinCash\" +COIN_COINID_NAME="Bitcoin Cash" COIN_COINID_SHORT=\"BCH\" COIN_KIND=COIN_KIND_BITCOIN_CASH COIN_FORKID=0 @@ -95,7 +95,7 @@ COIN_P2SH_VERSION=23 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\\x20Gold\" COIN_COINID_HEADER=\"BITCOINGOLD\" -COIN_COINID_NAME=\"BitcoinGold\" +COIN_COINID_NAME="Bitcoin Gold" COIN_COINID_SHORT=\"BTG\" COIN_KIND=COIN_KIND_BITCOIN_GOLD COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT @@ -111,7 +111,7 @@ COIN_P2SH_VERSION=50 COIN_FAMILY=1 COIN_COINID=\"Litecoin\" COIN_COINID_HEADER=\"LITECOIN\" -COIN_COINID_NAME=\"Litecoin\" +COIN_COINID_NAME="Litecoin" COIN_COINID_SHORT=\"LTC\" COIN_NATIVE_SEGWIT_PREFIX=\"ltc\" COIN_KIND=COIN_KIND_LITECOIN @@ -127,7 +127,7 @@ COIN_P2SH_VERSION=22 COIN_FAMILY=1 COIN_COINID=\"Dogecoin\" COIN_COINID_HEADER=\"DOGECOIN\" -COIN_COINID_NAME=\"Dogecoin\" +COIN_COINID_NAME="Doge" COIN_COINID_SHORT=\"DOGE\" COIN_KIND=COIN_KIND_DOGE APPNAME ="Dogecoin" @@ -141,7 +141,7 @@ COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"DarkCoin\" COIN_COINID_HEADER=\"DASH\" -COIN_COINID_NAME=\"Dash\" +COIN_COINID_NAME="Dash" COIN_COINID_SHORT=\"DASH\" COIN_KIND=COIN_KIND_DASH APPNAME ="Dash" @@ -156,7 +156,7 @@ COIN_P2SH_VERSION=7357 COIN_FAMILY=1 COIN_COINID=\"Zcash\" COIN_COINID_HEADER=\"ZCASH\" -COIN_COINID_NAME=\"Zcash\" +COIN_COINID_NAME="Zcash" COIN_COINID_SHORT=\"ZEC\" COIN_KIND=COIN_KIND_ZCASH # Switch to Canopy over Heartwood @@ -172,7 +172,7 @@ COIN_P2SH_VERSION=8342 COIN_FAMILY=4 COIN_COINID=\"Horizen\" COIN_COINID_HEADER=\"HORIZEN\" -COIN_COINID_NAME=\"Horizen\" +COIN_COINID_NAME="Horizen" COIN_COINID_SHORT=\"ZEN\" COIN_KIND=COIN_KIND_HORIZEN APPNAME ="Horizen" @@ -186,7 +186,7 @@ COIN_P2SH_VERSION=85 COIN_FAMILY=1 COIN_COINID=\"Komodo\" COIN_COINID_HEADER=\"KOMODO\" -COIN_COINID_NAME=\"Komodo\" +COIN_COINID_NAME="Komodo" COIN_COINID_SHORT=\"KMD\" COIN_KIND=COIN_KIND_KOMODO APPNAME ="Komodo" @@ -200,7 +200,7 @@ COIN_P2SH_VERSION=140 COIN_FAMILY=2 COIN_COINID=\"Stratis\" COIN_COINID_HEADER=\"STRATIS\" -COIN_COINID_NAME=\"Stratis\" +COIN_COINID_NAME="Stratis" COIN_COINID_SHORT=\"STRAX\" COIN_KIND=COIN_KIND_STRATIS COIN_FLAGS=FLAG_PEERCOIN_SUPPORT @@ -215,7 +215,7 @@ COIN_P2SH_VERSION=123 COIN_FAMILY=1 COIN_COINID=\"xrhodium\" COIN_COINID_HEADER=\"XRHODIUM\" -COIN_COINID_NAME=\"xRhodium\" +COIN_COINID_NAME="xRhodium" COIN_COINID_SHORT=\"XRC\" COIN_KIND=COIN_KIND_XRHODIUM APPNAME ="xRhodium" @@ -229,7 +229,7 @@ COIN_P2SH_VERSION=117 COIN_FAMILY=2 COIN_COINID=\"PPCoin\" COIN_COINID_HEADER=\"PEERCOIN\" -COIN_COINID_NAME=\"Peercoin\" +COIN_COINID_NAME="Peercoin" COIN_COINID_SHORT=\"PPC\" COIN_KIND=COIN_KIND_PEERCOIN COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT @@ -245,7 +245,7 @@ COIN_P2SH_VERSION=13 COIN_FAMILY=1 COIN_COINID=\"DarkNet\" COIN_COINID_HEADER=\"PIVX\" -COIN_COINID_NAME=\"PivX\" +COIN_COINID_NAME="PivX" COIN_COINID_SHORT=\"PIVX\" COIN_KIND=COIN_KIND_PIVX APPNAME ="PivX" @@ -259,7 +259,7 @@ COIN_P2SH_VERSION=85 COIN_FAMILY=4 COIN_COINID=\"Stealth\" COIN_COINID_HEADER=\"STEALTH\" -COIN_COINID_NAME=\"Stealth\" +COIN_COINID_NAME="Stealth" COIN_COINID_SHORT=\"XST\" COIN_KIND=COIN_KIND_STEALTH COIN_FLAGS=FLAG_PEERCOIN_UNITS\|FLAG_PEERCOIN_SUPPORT @@ -274,7 +274,7 @@ COIN_P2SH_VERSION=33 COIN_FAMILY=1 COIN_COINID=\"Viacoin\" COIN_COINID_HEADER=\"VIACOIN\" -COIN_COINID_NAME=\"Viacoin\" +COIN_COINID_NAME="Viacoin" COIN_COINID_SHORT=\"VIA\" COIN_KIND=COIN_KIND_VIACOIN COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT @@ -290,7 +290,7 @@ COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Vertcoin\" COIN_COINID_HEADER=\"VERTCOIN\" -COIN_COINID_NAME=\"Vertcoin\" +COIN_COINID_NAME="Vertcoin" COIN_COINID_SHORT=\"VTC\" COIN_NATIVE_SEGWIT_PREFIX=\"vtc\" COIN_KIND=COIN_KIND_VERTCOIN @@ -305,7 +305,7 @@ COIN_P2SH_VERSION=63 COIN_FAMILY=1 COIN_COINID=\"DigiByte\" COIN_COINID_HEADER=\"DIGIBYTE\" -COIN_COINID_NAME=\"DigiByte\" +COIN_COINID_NAME="Digibyte" COIN_COINID_SHORT=\"DGB\" COIN_NATIVE_SEGWIT_PREFIX=\"dgb\" COIN_KIND=COIN_KIND_DIGIBYTE @@ -322,7 +322,7 @@ COIN_P2SH_VERSION=7 COIN_FAMILY=1 COIN_COINID=\"Zcoin\" COIN_COINID_HEADER=\"FIRO\" -COIN_COINID_NAME=\"Firo\" +COIN_COINID_NAME="Firo" COIN_COINID_SHORT=\"FIRO\" COIN_KIND=COIN_KIND_FIRO APPNAME ="Firo" @@ -338,7 +338,7 @@ COIN_P2SH_VERSION=5039 COIN_FAMILY=1 COIN_COINID=\"BPrivate\" COIN_COINID_HEADER=\"BITCOINPRIVATE\" -COIN_COINID_NAME=\"BPrivate\" +COIN_COINID_NAME="Bitcoin Private" COIN_COINID_SHORT=\"BTCP\" COIN_KIND=COIN_KIND_BITCOIN_PRIVATE COIN_FORKID=42 @@ -353,7 +353,7 @@ COIN_P2SH_VERSION=62 COIN_FAMILY=1 COIN_COINID=\"GameCredits\" COIN_COINID_HEADER=\"GAMECREDITS\" -COIN_COINID_NAME=\"GameCredits\" +COIN_COINID_NAME="GameCredits" COIN_COINID_SHORT=\"GAME\" COIN_KIND=COIN_KIND_GAMECREDITS COIN_FLAGS=FLAG_SEGWIT_CHANGE_SUPPORT @@ -368,7 +368,7 @@ COIN_P2SH_VERSION=7357 COIN_FAMILY=1 COIN_COINID=\"ZClassic\" COIN_COINID_HEADER=\"ZCLASSIC\" -COIN_COINID_NAME=\"ZClassic\" +COIN_COINID_NAME="ZClassic" COIN_COINID_SHORT=\"ZCL\" COIN_KIND=COIN_KIND_ZCLASSIC APPNAME ="ZClassic" @@ -382,7 +382,7 @@ COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"XSN\" COIN_COINID_HEADER=\"XSN\" -COIN_COINID_NAME=\"XSN\" +COIN_COINID_NAME="XSN" COIN_COINID_SHORT=\"XSN\" COIN_NATIVE_SEGWIT_PREFIX=\"xc\" COIN_KIND=COIN_KIND_XSN @@ -398,7 +398,7 @@ COIN_P2SH_VERSION=53 COIN_FAMILY=1 COIN_COINID=\"NIX\" COIN_COINID_HEADER=\"NIX\" -COIN_COINID_NAME=\"NIX\" +COIN_COINID_NAME="NIX" COIN_COINID_SHORT=\"NIX\" COIN_NATIVE_SEGWIT_PREFIX=\"nix\" COIN_KIND=COIN_KIND_NIX @@ -414,7 +414,7 @@ COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"LBRY\" COIN_COINID_HEADER=\"LBRY\" -COIN_COINID_NAME=\"LBRY\" +COIN_COINID_NAME="LBRY" COIN_COINID_SHORT=\"LBC\" COIN_KIND=COIN_KIND_LBRY APPNAME ="LBRY" @@ -428,7 +428,7 @@ COIN_P2SH_VERSION=7068 COIN_FAMILY=1 COIN_COINID=\"Res\" COIN_COINID_HEADER=\"RES\" -COIN_COINID_NAME=\"Res\" +COIN_COINID_NAME="Resistance" COIN_COINID_SHORT=\"RES\" COIN_KIND=COIN_KIND_RESISTANCE APPNAME ="Resistance" @@ -442,7 +442,7 @@ COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"Ravencoin\" COIN_COINID_HEADER=\"RAVENCOIN\" -COIN_COINID_NAME=\"Ravencoin\" +COIN_COINID_NAME="Ravencoin" COIN_COINID_SHORT=\"RVN\" COIN_KIND=COIN_KIND_RAVENCOIN APPNAME ="Ravencoin" @@ -456,7 +456,7 @@ COIN_P2SH_VERSION=128 COIN_FAMILY=3 COIN_COINID=\"Hydra\" COIN_COINID_HEADER=\"HYDRA\" -COIN_COINID_NAME=\"HYDRA\" +COIN_COINID_NAME="Hydra Test" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" COIN_KIND=COIN_KIND_HYDRA @@ -473,7 +473,7 @@ COIN_P2SH_VERSION=63 COIN_FAMILY=3 COIN_COINID=\"Hydra\" COIN_COINID_HEADER=\"HYDRA\" -COIN_COINID_NAME=\"HYDRA\" +COIN_COINID_NAME="Hydra" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" COIN_KIND=COIN_KIND_HYDRA diff --git a/lib-app-bitcoin/Makefile b/lib-app-bitcoin/Makefile index 829f84d9..55afdcbb 100644 --- a/lib-app-bitcoin/Makefile +++ b/lib-app-bitcoin/Makefile @@ -131,11 +131,13 @@ DEFINES +=COIN_P2SH_VERSION=$(COIN_P2SH_VERSION) DEFINES +=COIN_FAMILY=$(COIN_FAMILY) DEFINES +=COIN_COINID=$(COIN_COINID) DEFINES +=COIN_COINID_HEADER=$(COIN_COINID_HEADER) -DEFINES +=COIN_COINID_NAME=$(COIN_COINID_NAME) DEFINES +=COIN_COINID_SHORT=$(COIN_COINID_SHORT) DEFINES +=COIN_NATIVE_SEGWIT_PREFIX=$(COIN_NATIVE_SEGWIT_PREFIX) DEFINES +=COIN_KIND=$(COIN_KIND) DEFINES +=COIN_FLAGS=$(COIN_FLAGS) DEFINES +=COIN_FORKID=$(COIN_FORKID) +# COIN_COINID_NAME exposed to the app as a CFLAG because it might contain spaces +CFLAGS += -DCOIN_COINID_NAME=\"$(COIN_COINID_NAME)\" + include $(BOLOS_SDK)/Makefile.standard_app From fb86e8e6224276799a335c72e8c54263a787719d Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 16 Apr 2024 11:52:24 +0200 Subject: [PATCH 77/85] NBGL: replace deprecated warning icon --- lib-app-bitcoin/ui/ui_nbgl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib-app-bitcoin/ui/ui_nbgl.c b/lib-app-bitcoin/ui/ui_nbgl.c index 23828d56..d8a3d589 100644 --- a/lib-app-bitcoin/ui/ui_nbgl.c +++ b/lib-app-bitcoin/ui/ui_nbgl.c @@ -382,7 +382,7 @@ void ui_request_change_path_approval_flow(void) { ui_transaction_start(ui_request_change_path_approval_flow); } else { - nbgl_useCaseChoice(&C_round_warning_64px, "Unusual\nchange path", + nbgl_useCaseChoice(&C_Important_Circle_64px, "Unusual\nchange path", vars.tmp_warning.derivation_path, "Continue", "Reject if not sure", transaction_review_callback); } @@ -397,7 +397,7 @@ void ui_request_segwit_input_approval_flow(void) { ui_transaction_start(ui_request_segwit_input_approval_flow); } else { - nbgl_useCaseChoice(&C_round_warning_64px, "Unverified inputs", + nbgl_useCaseChoice(&C_Important_Circle_64px, "Unverified inputs", "Update Ledger Live\nor third party software", "Continue", "Reject if not sure", transaction_review_callback); @@ -422,7 +422,7 @@ void ui_request_sign_path_approval_flow(void) { uiContext.approved_cb = approved_user_action_signtx_callback; uiContext.abandon_cb = abandon_user_action_signtx_callback; - nbgl_useCaseChoice(&C_round_warning_64px, "Unusual\nsign path", + nbgl_useCaseChoice(&C_Important_Circle_64px, "Unusual\nsign path", vars.tmp_warning.derivation_path, "Continue", "Reject if not sure", transaction_review_callback); } @@ -458,7 +458,7 @@ static void unusual_derivation_cb(bool status) { } } static void warn_unusual_derivation_path(void) { - nbgl_useCaseChoice(&C_round_warning_64px, "Unusual\nderivation path", NULL, + nbgl_useCaseChoice(&C_Important_Circle_64px, "Unusual\nderivation path", NULL, "Continue", "Reject if not sure", unusual_derivation_cb); } From 7642c5dcd4f074bdc93a29e2a1ba440ce256532d Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 16 Apr 2024 17:18:32 +0200 Subject: [PATCH 78/85] NBGL: change ui for flex porting --- Makefile | 3 + lib-app-bitcoin/Makefile | 8 +- lib-app-bitcoin/ui/ui_menu_nbgl.c | 47 +-- lib-app-bitcoin/ui/ui_nbgl.c | 545 ++++++++++-------------------- 4 files changed, 198 insertions(+), 405 deletions(-) diff --git a/Makefile b/Makefile index cbbeaed3..5e3b4a21 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,9 @@ APPVERSION_M = 2 APPVERSION_N = 4 APPVERSION_P = 0 +APPDEVELOPPER="Ledger" +APPCOPYRIGHT="(c) 2024 Ledger" + VARIANT_VALUES = bitcoin_testnet_legacy bitcoin_legacy bitcoin_cash bitcoin_gold litecoin dogecoin dash horizen komodo stratis peercoin pivx viacoin vertcoin stealth digibyte bitcoin_private firo gamecredits zclassic xsn nix lbry ravencoin hydra hydra_testnet xrhodium # Application source files diff --git a/lib-app-bitcoin/Makefile b/lib-app-bitcoin/Makefile index 55afdcbb..b409ac96 100644 --- a/lib-app-bitcoin/Makefile +++ b/lib-app-bitcoin/Makefile @@ -43,8 +43,10 @@ ICON_NANOS = icons/nanos_app_$(COIN).gif ICON_NANOX = icons/nanox_app_$(COIN).gif ICON_NANOSP = icons/nanox_app_$(COIN).gif ICON_STAX = icons/stax_app_$(COIN).gif +# Temporary reuse of stax icons while waiting for flex icons +ICON_FLEX = icons/stax_app_$(COIN).gif -ifeq ($(TARGET_NAME),TARGET_STAX) +ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_STAX TARGET_FLEX)) DEFINES += COIN_ICON=C_$(COIN)_64px DEFINES += COIN_ICON_BITMAP=C_$(COIN)_64px_bitmap endif @@ -137,7 +139,9 @@ DEFINES +=COIN_KIND=$(COIN_KIND) DEFINES +=COIN_FLAGS=$(COIN_FLAGS) DEFINES +=COIN_FORKID=$(COIN_FORKID) -# COIN_COINID_NAME exposed to the app as a CFLAG because it might contain spaces +# Following defines exposed to the app as a CFLAG because it might contain spaces CFLAGS += -DCOIN_COINID_NAME=\"$(COIN_COINID_NAME)\" +CFLAGS += -DAPPDEVELOPPER=\"$(APPDEVELOPPER)\" +CFLAGS += -DAPPCOPYRIGHT=\"$(APPCOPYRIGHT)\" include $(BOLOS_SDK)/Makefile.standard_app diff --git a/lib-app-bitcoin/ui/ui_menu_nbgl.c b/lib-app-bitcoin/ui/ui_menu_nbgl.c index e767e60c..0b37fee3 100644 --- a/lib-app-bitcoin/ui/ui_menu_nbgl.c +++ b/lib-app-bitcoin/ui/ui_menu_nbgl.c @@ -22,43 +22,22 @@ #include "extensions.h" #include "nbgl_use_case.h" -#define NB_INFO_FIELDS 2 -#define PAGE_START 0 -#define NB_PAGE_SETTING 1 -#define IS_TOUCHABLE true +#define SETTING_INFO_NB 3 +static const char *const INFO_TYPES[SETTING_INFO_NB] = {"Version", "Developer", + "Copyright"}; +static const char *const INFO_CONTENTS[SETTING_INFO_NB] = { + APPVERSION, APPDEVELOPPER, APPCOPYRIGHT}; -#define NB_SETTINGS_SWITCHES 1 -#define SWITCH_PUBLIC_KEY_SET_TOKEN FIRST_USER_TOKEN +static const nbgl_contentInfoList_t infoList = { + .nbInfos = SETTING_INFO_NB, + .infoTypes = INFO_TYPES, + .infoContents = INFO_CONTENTS, +}; -static char text[20]; -static const char *const infoTypes[] = {"Version", "Developer"}; -static const char *const infoContents[] = {APPVERSION, "Ledger"}; - -static void quit_cb(void) { os_sched_exit(-1); } - -static bool settings_navigation_cb(uint8_t page, nbgl_pageContent_t *content) { - if (page == 0) { - content->type = INFOS_LIST; - content->infosList.nbInfos = NB_INFO_FIELDS; - content->infosList.infoTypes = (const char **)infoTypes; - content->infosList.infoContents = (const char **)infoContents; - } else { - return false; - } - return true; -} - -static void display_settings_menu(void); - -static void display_settings_menu(void) { - snprintf(text, sizeof(text), "%s settings", COIN_COINID_NAME); - - nbgl_useCaseSettings(text, PAGE_START, NB_PAGE_SETTING, IS_TOUCHABLE, - ui_idle_flow, settings_navigation_cb, NULL); -} +static void exit(void) { os_sched_exit(-1); } void ui_idle_flow(void) { - nbgl_useCaseHome(COIN_COINID_NAME, &COIN_ICON, NULL, true, - display_settings_menu, quit_cb); + nbgl_useCaseHomeAndSettings(COIN_COINID_NAME, &COIN_ICON, NULL, + INIT_HOME_PAGE, NULL, &infoList, NULL, exit); } #endif // HAVE_NBGL diff --git a/lib-app-bitcoin/ui/ui_nbgl.c b/lib-app-bitcoin/ui/ui_nbgl.c index d8a3d589..4bd409a8 100644 --- a/lib-app-bitcoin/ui/ui_nbgl.c +++ b/lib-app-bitcoin/ui/ui_nbgl.c @@ -23,40 +23,16 @@ #include "extensions.h" -typedef enum { MESSAGE_TYPE, TRANSACTION_TYPE } flow_type_t; - -enum { - CANCEL_TOKEN, - CONFIRM_TOKEN, - BACK_TOKEN, -}; - -typedef struct { - bool transaction_prompt_done; - const char *prompt_cancel_message; - const char *prompt; // text displayed in last transaction page - const char * - approved_status; // text displayed in confirmation page (after long press) - const char *abandon_status; // text displayed in rejection page (after reject - // confirmed) - void (*approved_cb)(void); - void (*abandon_cb)(void); - nbgl_layoutTagValueList_t tagValueList; - nbgl_pageInfoLongPress_t infoLongPress; - nbgl_layoutTagValue_t tagValues[4]; - uint8_t nbPairs; -} UiContext_t; +static nbgl_layoutTagValue_t pairs[3]; +static nbgl_layoutTagValueList_t pairList; +bool transaction_prompt_done; + +static void (*start_transaction_callback)(bool); static char text[40]; -static nbgl_page_t *pageContext; -static UiContext_t uiContext = {.transaction_prompt_done = 0}; // User action callbacks -static void approved_user_action_callback(void) { - if (!user_action(1)) { - ui_idle_flow(); - } -} +static void approved_user_action_callback(void) { user_action(1); } static void approved_user_action_processing_callback(void) { if (!user_action(1)) { @@ -64,460 +40,291 @@ static void approved_user_action_processing_callback(void) { } } -static void abandon_user_action_callback(void) { - if (!user_action(0)) { - ui_idle_flow(); - } -} +static void abandon_user_action_callback(void) { user_action(0); } static void approved_user_action_message_signing_callback(void) { user_action_message_signing(1); - ui_idle_flow(); } static void abandon_user_action_message_signing_callback(void) { user_action_message_signing(0); - ui_idle_flow(); -} - -static void approved_user_action_display_processing_callback(void) { - user_action_display(1); - nbgl_useCaseSpinner("Processing"); } static void approved_user_action_display_callback(void) { user_action_display(1); - ui_idle_flow(); } static void abandon_user_action_display_callback(void) { user_action_display(0); - ui_idle_flow(); } static void approved_user_action_signtx_callback(void) { user_action_signtx(1, 0); - ui_idle_flow(); } static void abandon_user_action_signtx_callback(void) { + transaction_prompt_done = false; user_action_signtx(0, 0); - ui_idle_flow(); + nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_idle_flow); } -static void releaseContext(void) { - if (pageContext != NULL) { - nbgl_pageRelease(pageContext); - pageContext = NULL; +// Flow entry point +static void sign_transaction_callback(bool confirmed) { + if (confirmed) { + approved_user_action_processing_callback(); + } else { + transaction_prompt_done = false; + abandon_user_action_callback(); + nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_idle_flow); } } -// Status -static void abandon_status(void) { - nbgl_useCaseStatus(uiContext.abandon_status, false, uiContext.abandon_cb); - releaseContext(); - uiContext.transaction_prompt_done = false; -} - -static void approved_status(void) { - nbgl_useCaseStatus(uiContext.approved_status, true, uiContext.approved_cb); - releaseContext(); - uiContext.transaction_prompt_done = false; -} - -static void status_callback(bool confirm) { - if (confirm) { - approved_status(); +static void sign_transaction_processing_callback(bool confirmed) { + if (confirmed) { + approved_user_action_processing_callback(); } else { - abandon_status(); + transaction_prompt_done = false; + abandon_user_action_callback(); + nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_idle_flow); } } -// Prompt Cancel -static void prompt_cancel(flow_type_t type) { - switch (type) { - case MESSAGE_TYPE: - nbgl_useCaseConfirm("Reject message", NULL, "Yes, Reject", - "Go back to message", abandon_status); - break; +static void continue_single_flow(bool confirmed) { + if (confirmed) { + snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "#%d", + context.totalOutputs - context.remainingOutputs + 1); - case TRANSACTION_TYPE: - nbgl_useCaseConfirm("Reject transaction", NULL, "Yes, Reject", - "Go back to transaction", abandon_status); - break; - } -} + pairs[0].item = "Output"; + pairs[0].value = vars.tmp.feesAmount; -static void prompt_cancel_message(void) { prompt_cancel(MESSAGE_TYPE); } + pairs[1].item = "Amount"; + pairs[1].value = vars.tmp.fullAmount; -static void prompt_cancel_transaction(void) { prompt_cancel(TRANSACTION_TYPE); } + pairs[2].item = "Address"; + pairs[2].value = vars.tmp.fullAddress; -static void transaction_review_callback(bool token) { - if (token) { - releaseContext(); - uiContext.approved_cb(); + // Setup list + pairList.nbMaxLinesForValue = 0; + pairList.nbPairs = 3; + pairList.pairs = pairs; + + nbgl_useCaseReviewStreamingContinue(&pairList, sign_transaction_callback); } else { - prompt_cancel_transaction(); + sign_transaction_callback(false); } } -static void transaction_finish_callback(int token, uint8_t index) { - (void)index; - switch (token) { - case CANCEL_TOKEN: - prompt_cancel_transaction(); - break; - case CONFIRM_TOKEN: - releaseContext(); - uiContext.approved_cb(); - break; - case BACK_TOKEN: - ui_finalize_flow(); - break; - } +static void start_transaction_flow(void) { + snprintf(text, sizeof(text), "Review transaction\nto send %s?", + COIN_COINID_NAME); + transaction_prompt_done = true; + nbgl_useCaseReviewStreamingStart(TYPE_TRANSACTION, &COIN_ICON, text, NULL, + start_transaction_callback); } -static void transaction_fee_callback(int token, uint8_t index) { - (void)index; - if (token) { - releaseContext(); - snprintf(text, sizeof(text), "Sign transaction\nto send %s?", - COIN_COINID_NAME); - nbgl_pageNavigationInfo_t info = {.activePage = 0, - .nbPages = 0, - .navType = NAV_WITH_TAP, - .progressIndicator = true, - .navWithTap.backButton = true, - .navWithTap.backToken = BACK_TOKEN, - .navWithTap.nextPageText = NULL, - .navWithTap.quitText = - "Reject transaction", - .quitToken = CANCEL_TOKEN, - .tuneId = TUNE_TAP_CASUAL}; - - nbgl_pageContent_t content = {.type = INFO_LONG_PRESS, - .infoLongPress.icon = &COIN_ICON, - .infoLongPress.text = text, - .infoLongPress.longPressText = "Hold to sign", - .infoLongPress.longPressToken = CONFIRM_TOKEN, - .infoLongPress.tuneId = TUNE_TAP_NEXT}; - - pageContext = nbgl_pageDrawGenericContent(&transaction_finish_callback, - &info, &content); - } else { - prompt_cancel_transaction(); +void ui_confirm_single_flow(void) { + if (!transaction_prompt_done) { + start_transaction_callback = continue_single_flow; + start_transaction_flow(); } -} -static void message_review_callback(bool token) { - if (token) { - approved_status(); - } else { - prompt_cancel_message(); + else { + continue_single_flow(true); } } -// Continue Review -static void continue_review(flow_type_t type) { - uiContext.tagValueList.pairs = uiContext.tagValues; - uiContext.tagValueList.nbPairs = uiContext.nbPairs; - - uiContext.infoLongPress.icon = &COIN_ICON; - uiContext.infoLongPress.longPressText = "Hold to sign"; - uiContext.infoLongPress.longPressToken = 1; - uiContext.infoLongPress.tuneId = TUNE_TAP_CASUAL; - uiContext.infoLongPress.text = uiContext.prompt; - - switch (type) { - case MESSAGE_TYPE: - nbgl_useCaseStaticReview(&uiContext.tagValueList, &uiContext.infoLongPress, - "Cancel", message_review_callback); - break; - - case TRANSACTION_TYPE: - nbgl_useCaseStaticReview(&uiContext.tagValueList, &uiContext.infoLongPress, - "Cancel", transaction_review_callback); - break; +static void finish_transaction_flow(bool choice) { + if (choice) { + nbgl_useCaseReviewStreamingFinish("Sign transaction\nto send Bitcoin?", + sign_transaction_processing_callback); + } else { + sign_transaction_processing_callback(false); } } -static void continue_message_review(void) { continue_review(MESSAGE_TYPE); } +static void continue_finalize_flow(bool confirmed) { + if (confirmed) { + pairs[0].item = "Fees"; + pairs[0].value = vars.tmp.feesAmount; -// UI Start -static void ui_start(void (*cb)(void), flow_type_t type) { - switch (type) { - case MESSAGE_TYPE: - nbgl_useCaseReviewStart(&COIN_ICON, "Review\nmessage", NULL, "Cancel", - continue_message_review, prompt_cancel_message); - break; + // Setup list + pairList.nbMaxLinesForValue = 0; + pairList.pairs = pairs; + pairList.nbPairs = 1; - case TRANSACTION_TYPE: - snprintf(text, sizeof(text), "Review transaction\nto send %s", - COIN_COINID_NAME); - nbgl_useCaseReviewStart(&COIN_ICON, text, NULL, "Cancel", cb, - prompt_cancel_transaction); - break; + nbgl_useCaseReviewStreamingContinue(&pairList, finish_transaction_flow); + } else { + finish_transaction_flow(false); } } -static void ui_transaction_start(void (*cb)(void)) { - uiContext.abandon_status = "Transaction\nrejected"; - uiContext.approved_status = "TRANSACTION\nCONFIRMED"; - uiContext.prompt_cancel_message = "Reject\nTransaction ?"; - uiContext.prompt = "Sign transaction"; - ui_start(cb, TRANSACTION_TYPE); -} - -static void ui_message_start(void) { - uiContext.abandon_status = "Message\nrejected"; - uiContext.approved_status = "MESSAGE\nSIGNED"; - uiContext.prompt_cancel_message = "Reject\nMessage ?"; - uiContext.prompt = "Sign message"; - ui_start(NULL, MESSAGE_TYPE); -} - -// Other callbacks -static void display_pubkey_callback(void) { - if (uiContext.nbPairs == 1) { - nbgl_useCaseAddressConfirmation(uiContext.tagValues[0].value, - status_callback); +void ui_finalize_flow(void) { + if (!transaction_prompt_done) { + start_transaction_callback = continue_finalize_flow; + start_transaction_flow(); } else { - uiContext.tagValueList.pairs = &uiContext.tagValues[1]; - uiContext.tagValueList.nbPairs = 1; - - nbgl_useCaseAddressConfirmationExt( - uiContext.tagValues[0].value, status_callback, &uiContext.tagValueList); + continue_finalize_flow(true); } } -// Flow entry point -static void single_flow_callback(int token, uint8_t index) { - UNUSED(index); - transaction_review_callback(token); -} - -void ui_confirm_single_flow(void) { - uiContext.approved_cb = approved_user_action_processing_callback; - uiContext.abandon_cb = abandon_user_action_callback; - - if (!uiContext.transaction_prompt_done) { - uiContext.transaction_prompt_done = true; - - ui_transaction_start(ui_confirm_single_flow); +static void request_approval_callback(bool confirmed) { + if (confirmed) { + approved_user_action_processing_callback(); } else { - snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "#%d", - context.totalOutputs - context.remainingOutputs + 1); - - uiContext.tagValues[0].item = "Output"; - uiContext.tagValues[0].value = vars.tmp.feesAmount; - - uiContext.tagValues[1].item = "Amount"; - uiContext.tagValues[1].value = vars.tmp.fullAmount; - - uiContext.tagValues[2].item = "Address"; - uiContext.tagValues[2].value = vars.tmp.fullAddress; - - uiContext.nbPairs = 3; - - nbgl_pageNavigationInfo_t info = {.activePage = 0, - .nbPages = 0, - .navType = NAV_WITH_TAP, - .progressIndicator = true, - .navWithTap.backButton = false, - .navWithTap.nextPageText = - "Tap to continue", - .navWithTap.nextPageToken = 1, - .navWithTap.quitText = "Cancel", - .quitToken = 0, - .tuneId = TUNE_TAP_CASUAL}; - - nbgl_pageContent_t content = { - .type = TAG_VALUE_LIST, - .tagValueList.nbPairs = uiContext.nbPairs, - .tagValueList.pairs = (nbgl_layoutTagValue_t *)uiContext.tagValues}; - releaseContext(); - pageContext = - nbgl_pageDrawGenericContent(&single_flow_callback, &info, &content); - nbgl_refresh(); + transaction_prompt_done = false; + abandon_user_action_display_callback(); + nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_idle_flow); } } -void ui_finalize_flow(void) { - uiContext.approved_cb = approved_user_action_processing_callback; - uiContext.abandon_cb = abandon_user_action_callback; - - uiContext.tagValues[0].item = "Fees"; - uiContext.tagValues[0].value = vars.tmp.feesAmount; - - uiContext.nbPairs = 1; - - nbgl_pageNavigationInfo_t info = {.activePage = 0, - .nbPages = 0, - .navType = NAV_WITH_TAP, - .progressIndicator = true, - .navWithTap.backButton = false, - .navWithTap.nextPageText = - "Tap to continue", - .navWithTap.nextPageToken = 1, - .navWithTap.quitText = "Reject transaction", - .quitToken = 0, - .tuneId = TUNE_TAP_CASUAL}; - - nbgl_pageContent_t content = { - .type = TAG_VALUE_LIST, - .tagValueList.nbPairs = uiContext.nbPairs, - .tagValueList.pairs = (nbgl_layoutTagValue_t *)uiContext.tagValues}; - - pageContext = - nbgl_pageDrawGenericContent(&transaction_fee_callback, &info, &content); - nbgl_refresh(); +static void continue_change_path_approval_flow(bool confirmed) { + if (confirmed) { + nbgl_useCaseChoice(&C_Important_Circle_64px, "Unusual\nchange path", + vars.tmp_warning.derivation_path, "Continue", + "Reject if not sure", request_approval_callback); + } else { + request_approval_callback(false); + } } void ui_request_change_path_approval_flow(void) { - uiContext.approved_cb = approved_user_action_display_processing_callback; - uiContext.abandon_cb = abandon_user_action_display_callback; - - if (!uiContext.transaction_prompt_done) { - uiContext.transaction_prompt_done = true; - - ui_transaction_start(ui_request_change_path_approval_flow); + if (!transaction_prompt_done) { + start_transaction_callback = continue_change_path_approval_flow; + start_transaction_flow(); } else { - nbgl_useCaseChoice(&C_Important_Circle_64px, "Unusual\nchange path", - vars.tmp_warning.derivation_path, "Continue", - "Reject if not sure", transaction_review_callback); + continue_change_path_approval_flow(false); } } -void ui_request_segwit_input_approval_flow(void) { - uiContext.approved_cb = approved_user_action_processing_callback; - uiContext.abandon_cb = abandon_user_action_display_callback; - - if (!uiContext.transaction_prompt_done) { - uiContext.transaction_prompt_done = true; - - ui_transaction_start(ui_request_segwit_input_approval_flow); - } else { +static void continue_segwit_input_approval_flow(bool confirmed) { + if (confirmed) { nbgl_useCaseChoice(&C_Important_Circle_64px, "Unverified inputs", "Update Ledger Live\nor third party software", "Continue", "Reject if not sure", - transaction_review_callback); + request_approval_callback); + } else { + request_approval_callback(false); } } -void ui_request_pubkey_approval_flow(void) { - uiContext.approved_cb = approved_user_action_processing_callback; - uiContext.abandon_cb = abandon_user_action_display_callback; +void ui_request_segwit_input_approval_flow(void) { + if (!transaction_prompt_done) { + start_transaction_callback = continue_segwit_input_approval_flow; + start_transaction_flow(); + } else { + continue_change_path_approval_flow(false); + } +} - if (!uiContext.transaction_prompt_done) { - uiContext.transaction_prompt_done = true; +void ui_request_pubkey_approval_flow(void) { + nbgl_useCaseChoice(&COIN_ICON, "Export public key", NULL, "Approve", "Reject", + request_approval_callback); +} - ui_transaction_start(ui_request_pubkey_approval_flow); +static void user_action_signtx_callback(bool confirmed) { + if (confirmed) { + nbgl_useCaseSpinner("Processing"); + approved_user_action_signtx_callback(); } else { - nbgl_useCaseChoice(&COIN_ICON, "Export public key", NULL, "Approve", - "Reject", transaction_review_callback); + abandon_user_action_signtx_callback(); } } void ui_request_sign_path_approval_flow(void) { - uiContext.approved_cb = approved_user_action_signtx_callback; - uiContext.abandon_cb = abandon_user_action_signtx_callback; - nbgl_useCaseChoice(&C_Important_Circle_64px, "Unusual\nsign path", vars.tmp_warning.derivation_path, "Continue", - "Reject if not sure", transaction_review_callback); + "Reject if not sure", user_action_signtx_callback); } +static void sign_message_callback(bool confirmed) { + if (confirmed) { + nbgl_useCaseSpinner("Processing"); + approved_user_action_message_signing_callback(); + nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_SIGNED, ui_idle_flow); + } else { + abandon_user_action_message_signing_callback(); + nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_REJECTED, ui_idle_flow); + } +} void ui_sign_message_flow(void) { - uiContext.approved_cb = approved_user_action_message_signing_callback; - uiContext.abandon_cb = abandon_user_action_message_signing_callback; + // Setup data to display + pairs[0].item = "Message hash"; + pairs[0].value = vars.tmp.fullAddress; - uiContext.tagValues[0].item = "Message hash"; - uiContext.tagValues[0].value = vars.tmp.fullAddress; + // Setup list + pairList.nbMaxLinesForValue = 0; + pairList.nbPairs = 1; + pairList.pairs = pairs; - uiContext.nbPairs = 1; + nbgl_useCaseReview(TYPE_MESSAGE, &pairList, &COIN_ICON, "Review\nmessage", + NULL, "Sign message", sign_message_callback); +} - ui_message_start(); +static void token_flow_callback(bool confirmed) { + if (confirmed) { + approved_user_action_display_callback(); + nbgl_useCaseStatus("Token\nconfirmed", true, ui_idle_flow); + } else { + abandon_user_action_display_callback(); + nbgl_useCaseStatus("Token\nrejected", false, ui_idle_flow); + } } void ui_display_token_flow(void) { - uiContext.approved_cb = approved_user_action_display_callback; - uiContext.abandon_cb = abandon_user_action_display_callback; - uiContext.abandon_status = "Token\nrejected"; - uiContext.approved_status = "TOKEN\nCONFIRMED"; - nbgl_useCaseChoice(&COIN_ICON, "Confirm token", (char *)G_io_apdu_buffer + 200, "Approve", "Reject", - status_callback); + token_flow_callback); } -static void unusual_derivation_cb(bool status) { - if (status) { - display_pubkey_callback(); +static void public_flow_callback(bool confirmed) { + if (confirmed) { + approved_user_action_callback(); + nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_VERIFIED, ui_idle_flow); } else { - abandon_status(); + abandon_user_action_callback(); + nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_REJECTED, ui_idle_flow); } } -static void warn_unusual_derivation_path(void) { - nbgl_useCaseChoice(&C_Important_Circle_64px, "Unusual\nderivation path", NULL, - "Continue", "Reject if not sure", unusual_derivation_cb); -} -static void prompt_public_key(bool warning) { - snprintf(text, sizeof(text), "Verify %s\naddress", COIN_COINID_NAME); +static void public_post_warning_flow(bool confirmed) { + if (confirmed) { + pairs[0].item = "Derivation path"; + pairs[0].value = vars.tmp_warning.derivation_path; - if (warning) { - nbgl_useCaseReviewStart(&COIN_ICON, text, NULL, "Cancel", - warn_unusual_derivation_path, abandon_status); - } else { - nbgl_useCaseReviewStart(&COIN_ICON, text, NULL, "Cancel", - display_pubkey_callback, abandon_status); - } -} + // Setup list + pairList.nbMaxLinesForValue = 0; + pairList.nbPairs = 1; + pairList.pairs = pairs; -static void display_show_public_key(bool warning) { - uiContext.abandon_status = "Address verification\ncancelled"; - uiContext.approved_status = "ADDRESS\nVERIFIED"; - uiContext.prompt_cancel_message = "Reject\nAddress?"; - - uiContext.tagValues[0].item = "Address"; - uiContext.tagValues[0].value = (char *)G_io_apdu_buffer + 200; - - uiContext.nbPairs = 1; - - if (warning) { - uiContext.approved_cb = approved_user_action_callback; - uiContext.abandon_cb = abandon_user_action_callback; - - uiContext.tagValues[1].item = "Derivation path"; - uiContext.tagValues[1].value = vars.tmp_warning.derivation_path; - - uiContext.nbPairs = 2; - } - - else { - uiContext.approved_cb = approved_user_action_display_callback; - uiContext.abandon_cb = abandon_user_action_display_callback; + snprintf(text, sizeof(text), "Verify %s\naddress", COIN_COINID_NAME); + nbgl_useCaseAddressReview((char *)G_io_apdu_buffer + 200, &pairList, + &COIN_ICON, text, NULL, public_flow_callback); + } else { + public_flow_callback(false); } - prompt_public_key(warning); } void ui_display_public_with_warning_flow(void) { - display_show_public_key(true); + nbgl_useCaseChoice(&C_Important_Circle_64px, "Unusual\nderivation path", NULL, + "Continue", "Reject if not sure", + public_post_warning_flow); } -void ui_display_public_flow(void) { display_show_public_key(false); } +void ui_display_public_flow(void) { + snprintf(text, sizeof(text), "Verify %s\naddress", COIN_COINID_NAME); + nbgl_useCaseAddressReview((char *)G_io_apdu_buffer + 200, NULL, &COIN_ICON, + text, NULL, public_flow_callback); +} void ui_transaction_finish(void) { - if (uiContext.transaction_prompt_done) { - uiContext.approved_status = "TRANSACTION\nCONFIRMED"; - uiContext.approved_cb = ui_idle_flow; - approved_status(); + if (transaction_prompt_done) { + transaction_prompt_done = false; + nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_SIGNED, ui_idle_flow); } } void ui_transaction_error(void) { - uiContext.abandon_status = "Transaction\nerror"; - uiContext.approved_cb = ui_idle_flow; - abandon_status(); + transaction_prompt_done = false; + nbgl_useCaseStatus("Transaction\nerror", false, ui_idle_flow); } #endif // HAVE_NBGL From 9b5f87709864aa5f09c2c408ab27be8e4c142d10 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Fri, 19 Apr 2024 14:21:48 +0200 Subject: [PATCH 79/85] Tests: update with latest changes --- tests/ragger_bitcoin/ragger_instructions.py | 23 ++++++++++++++------- tests/test_get_pubkey.py | 6 +++--- tests/test_sign.py | 5 ++++- tests/test_sign_message.py | 2 +- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/tests/ragger_bitcoin/ragger_instructions.py b/tests/ragger_bitcoin/ragger_instructions.py index 15af4509..545902e6 100644 --- a/tests/ragger_bitcoin/ragger_instructions.py +++ b/tests/ragger_bitcoin/ragger_instructions.py @@ -42,30 +42,37 @@ def navigate_end_of_flow(self, save_screenshot=True): self.new_request("Processing", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_TAP, save_screenshot=save_screenshot) - def confirm_transaction(self, save_screenshot=True): - self.new_request("Sign", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_CONFIRM, + def review_start(self, output_count: int = 1, save_screenshot=True): + self.new_request("Review", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_TAP, save_screenshot=save_screenshot) - self.new_request("TRANSACTION", NavInsID.USE_CASE_REVIEW_TAP, - NavInsID.USE_CASE_STATUS_DISMISS, + for _ in range(0, output_count): + self.same_request("Amount", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_TAP, + save_screenshot=save_screenshot) + def review_fees(self, fees_on_same_request: bool = True, save_screenshot=True): + if fees_on_same_request: + self.same_request("Fees", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_TAP, + save_screenshot=save_screenshot) + else: + self.new_request("Fees", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_TAP, save_screenshot=save_screenshot) - def same_request_confirm_transaction(self, save_screenshot=True): + def confirm_transaction(self, save_screenshot=True): self.same_request("Sign", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_CONFIRM, save_screenshot=save_screenshot) - self.new_request("TRANSACTION", NavInsID.USE_CASE_REVIEW_TAP, + self.new_request("Transaction", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_STATUS_DISMISS, save_screenshot=save_screenshot) def confirm_message(self, save_screenshot=True): self.new_request("Sign", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_CONFIRM, save_screenshot=save_screenshot) - self.new_request("MESSAGE", NavInsID.USE_CASE_REVIEW_TAP, + self.new_request("Message", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_STATUS_DISMISS, save_screenshot=save_screenshot) def confirm_wallet(self, save_screenshot=True): self.new_request("Approve", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_REVIEW_CONFIRM, save_screenshot=save_screenshot) - self.same_request("WALLET", NavInsID.USE_CASE_REVIEW_TAP, + self.same_request("Wallet", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_STATUS_DISMISS, save_screenshot=save_screenshot) def reject_message(self, save_screenshot=True): diff --git a/tests/test_get_pubkey.py b/tests/test_get_pubkey.py index 199e724e..40c82777 100644 --- a/tests/test_get_pubkey.py +++ b/tests/test_get_pubkey.py @@ -12,7 +12,7 @@ def pubkey_instruction_approve(model: Firmware) -> Instructions: instructions.new_request("Approve") else: instructions.address_confirm() - instructions.same_request("ADDRESS", NavInsID.USE_CASE_REVIEW_TAP, + instructions.same_request("Address", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_STATUS_DISMISS) return instructions @@ -24,11 +24,11 @@ def pubkey_instruction_warning_approve(model: Firmware) -> Instructions: instructions.new_request("Approve") instructions.same_request("Approve") else: - instructions.new_request("Unusual", NavInsID.USE_CASE_REVIEW_TAP, + instructions.new_request("Unusual", NavInsID.USE_CASE_CHOICE_CONFIRM, NavInsID.USE_CASE_CHOICE_CONFIRM) instructions.same_request("Confirm", NavInsID.USE_CASE_ADDRESS_CONFIRMATION_TAP, NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CONFIRM) - instructions.same_request("ADDRESS", NavInsID.USE_CASE_REVIEW_TAP, + instructions.same_request("Address", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_STATUS_DISMISS) return instructions diff --git a/tests/test_sign.py b/tests/test_sign.py index c9749c83..1a58f3b9 100644 --- a/tests/test_sign.py +++ b/tests/test_sign.py @@ -21,6 +21,8 @@ def sign_psbt_instruction_approve(model: Firmware) -> Instructions: instructions.new_request("Accept") instructions.same_request("Accept") else: + instructions.review_start() + instructions.review_fees() instructions.confirm_transaction() return instructions @@ -32,7 +34,8 @@ def sign_psbt_instruction_approve_2(model: Firmware) -> Instructions: instructions.new_request("Accept") instructions.new_request("Accept") else: - instructions.navigate_end_of_flow() + instructions.review_start() + instructions.review_fees(fees_on_same_request=False) instructions.confirm_transaction() return instructions diff --git a/tests/test_sign_message.py b/tests/test_sign_message.py index aed234a9..aceb59f6 100644 --- a/tests/test_sign_message.py +++ b/tests/test_sign_message.py @@ -14,7 +14,7 @@ def message_instruction_approve(model: Firmware) -> Instructions: instructions.same_request("Sign") else: instructions.address_confirm() - instructions.same_request("ADDRESS", NavInsID.USE_CASE_REVIEW_TAP, + instructions.same_request("Address", NavInsID.USE_CASE_REVIEW_TAP, NavInsID.USE_CASE_STATUS_DISMISS) instructions.confirm_message() return instructions From 5e51b8097300f94a0f2448b6c0edea67392670fd Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Mon, 22 Apr 2024 14:39:01 +0200 Subject: [PATCH 80/85] Tests: update snapshots --- .../44'/1'/0'_0_0/00000.png | Bin 0 -> 10476 bytes .../44'/1'/0'_0_1/00000.png | Bin 0 -> 11428 bytes .../44'/1'/0'_0_1/00001.png | Bin 0 -> 14275 bytes .../44'/1'/0'_0_1/00002.png | Bin 0 -> 8551 bytes .../44'/1'/0'_0_2/00000.png | Bin 0 -> 5874 bytes .../44'/1'/10'_0_0/00000.png | Bin 0 -> 10476 bytes .../44'/1'/10'_0_1/00000.png | Bin 0 -> 11428 bytes .../44'/1'/10'_0_1/00001.png | Bin 0 -> 14187 bytes .../44'/1'/10'_0_1/00002.png | Bin 0 -> 8557 bytes .../44'/1'/10'_0_2/00000.png | Bin 0 -> 5874 bytes .../44'/1'/2'/1/42_0_0/00000.png | Bin 0 -> 10476 bytes .../44'/1'/2'/1/42_0_1/00000.png | Bin 0 -> 11428 bytes .../44'/1'/2'/1/42_0_1/00001.png | Bin 0 -> 15157 bytes .../44'/1'/2'/1/42_0_1/00002.png | Bin 0 -> 8819 bytes .../44'/1'/2'/1/42_0_2/00000.png | Bin 0 -> 5874 bytes .../48'/1'/4'/1'/0/7_0_0/00000.png | Bin 0 -> 10476 bytes .../48'/1'/4'/1'/0/7_0_1/00000.png | Bin 0 -> 11428 bytes .../48'/1'/4'/1'/0/7_0_1/00001.png | Bin 0 -> 14468 bytes .../48'/1'/4'/1'/0/7_0_1/00002.png | Bin 0 -> 9380 bytes .../48'/1'/4'/1'/0/7_0_2/00000.png | Bin 0 -> 5874 bytes .../49'/1'/1'/1/3_0_0/00000.png | Bin 0 -> 10476 bytes .../49'/1'/1'/1/3_0_1/00000.png | Bin 0 -> 11428 bytes .../49'/1'/1'/1/3_0_1/00001.png | Bin 0 -> 14439 bytes .../49'/1'/1'/1/3_0_1/00002.png | Bin 0 -> 9090 bytes .../49'/1'/1'/1/3_0_2/00000.png | Bin 0 -> 5874 bytes .../84'/1'/2'/0/10_0_0/00000.png | Bin 0 -> 11369 bytes .../84'/1'/2'/0/10_0_0/00001.png | Bin 0 -> 14114 bytes .../84'/1'/2'/0/10_0_1/00000.png | Bin 0 -> 5874 bytes .../86'/1'/4'/1/12_0_0/00000.png | Bin 0 -> 10476 bytes .../86'/1'/4'/1/12_0_1/00000.png | Bin 0 -> 11428 bytes .../86'/1'/4'/1/12_0_1/00001.png | Bin 0 -> 14869 bytes .../86'/1'/4'/1/12_0_1/00002.png | Bin 0 -> 9450 bytes .../86'/1'/4'/1/12_0_2/00000.png | Bin 0 -> 5874 bytes .../flex/test_sign_message_0_0/00000.png | Bin 0 -> 11369 bytes .../flex/test_sign_message_0_0/00001.png | Bin 0 -> 14925 bytes .../flex/test_sign_message_0_1/00000.png | Bin 0 -> 5874 bytes .../flex/test_sign_message_1_0/00000.png | Bin 0 -> 10297 bytes .../flex/test_sign_message_1_0/00001.png | Bin 0 -> 16441 bytes .../flex/test_sign_message_1_0/00002.png | Bin 0 -> 10301 bytes .../00000.png | Bin 0 -> 11447 bytes .../00000.png | Bin 0 -> 15167 bytes .../00000.png | Bin 0 -> 5730 bytes .../00000.png | Bin 0 -> 11723 bytes .../00000.png | Bin 0 -> 11447 bytes .../00000.png | Bin 0 -> 15878 bytes .../00000.png | Bin 0 -> 6436 bytes .../00000.png | Bin 0 -> 11723 bytes .../00000.png | Bin 0 -> 11447 bytes .../00000.png | Bin 0 -> 14322 bytes .../00000.png | Bin 0 -> 6126 bytes .../00000.png | Bin 0 -> 11723 bytes .../00000.png | Bin 0 -> 11447 bytes .../00000.png | Bin 0 -> 14322 bytes .../00000.png | Bin 0 -> 6126 bytes .../00000.png | Bin 0 -> 11723 bytes .../00000.png | Bin 0 -> 11447 bytes .../00000.png | Bin 0 -> 20456 bytes .../00000.png | Bin 0 -> 6482 bytes .../00000.png | Bin 0 -> 11723 bytes .../44'/1'/0'_0_0/00000.png | Bin 9271 -> 8810 bytes .../44'/1'/0'_0_1/00000.png | Bin 13161 -> 9667 bytes .../44'/1'/0'_0_1/00001.png | Bin 7127 -> 13287 bytes .../44'/1'/0'_0_1/00002.png | Bin 0 -> 7126 bytes .../44'/1'/0'_0_2/00000.png | Bin 5035 -> 4707 bytes .../44'/1'/10'_0_0/00000.png | Bin 9271 -> 8810 bytes .../44'/1'/10'_0_1/00000.png | Bin 13088 -> 9667 bytes .../44'/1'/10'_0_1/00001.png | Bin 7123 -> 13213 bytes .../44'/1'/10'_0_1/00002.png | Bin 0 -> 7123 bytes .../44'/1'/10'_0_2/00000.png | Bin 5035 -> 4707 bytes .../44'/1'/2'/1/42_0_0/00000.png | Bin 9271 -> 8810 bytes .../44'/1'/2'/1/42_0_1/00000.png | Bin 13928 -> 9667 bytes .../44'/1'/2'/1/42_0_1/00001.png | Bin 7393 -> 14056 bytes .../44'/1'/2'/1/42_0_1/00002.png | Bin 0 -> 7394 bytes .../44'/1'/2'/1/42_0_2/00000.png | Bin 5035 -> 4707 bytes .../48'/1'/4'/1'/0/7_0_0/00000.png | Bin 9271 -> 8810 bytes .../48'/1'/4'/1'/0/7_0_1/00000.png | Bin 13385 -> 9667 bytes .../48'/1'/4'/1'/0/7_0_1/00001.png | Bin 7845 -> 13511 bytes .../48'/1'/4'/1'/0/7_0_1/00002.png | Bin 0 -> 7845 bytes .../48'/1'/4'/1'/0/7_0_2/00000.png | Bin 5035 -> 4707 bytes .../49'/1'/1'/1/3_0_0/00000.png | Bin 9271 -> 8810 bytes .../49'/1'/1'/1/3_0_1/00000.png | Bin 13335 -> 9667 bytes .../49'/1'/1'/1/3_0_1/00001.png | Bin 7548 -> 13461 bytes .../49'/1'/1'/1/3_0_1/00002.png | Bin 0 -> 7548 bytes .../49'/1'/1'/1/3_0_2/00000.png | Bin 5035 -> 4707 bytes .../84'/1'/2'/0/10_0_0/00000.png | Bin 9271 -> 9669 bytes .../84'/1'/2'/0/10_0_0/00001.png | Bin 13624 -> 13768 bytes .../84'/1'/2'/0/10_0_1/00000.png | Bin 5035 -> 4707 bytes .../86'/1'/4'/1/12_0_0/00000.png | Bin 9271 -> 8810 bytes .../86'/1'/4'/1/12_0_1/00000.png | Bin 13570 -> 9667 bytes .../86'/1'/4'/1/12_0_1/00001.png | Bin 7795 -> 13695 bytes .../86'/1'/4'/1/12_0_1/00002.png | Bin 0 -> 7795 bytes .../86'/1'/4'/1/12_0_2/00000.png | Bin 5035 -> 4707 bytes .../stax/test_sign_message_0_0/00000.png | Bin 9271 -> 9669 bytes .../stax/test_sign_message_0_0/00001.png | Bin 14119 -> 14260 bytes .../stax/test_sign_message_0_1/00000.png | Bin 5035 -> 4707 bytes .../stax/test_sign_message_1_0/00000.png | Bin 8620 -> 9313 bytes .../stax/test_sign_message_1_0/00001.png | Bin 15024 -> 15777 bytes .../stax/test_sign_message_1_0/00002.png | Bin 9017 -> 9666 bytes .../00000.png | Bin 10255 -> 11036 bytes .../00000.png | Bin 0 -> 15239 bytes .../00000.png | Bin 0 -> 7060 bytes .../00000.png | Bin 0 -> 11581 bytes .../00000.png | Bin 10255 -> 11036 bytes .../00000.png | Bin 0 -> 16326 bytes .../00000.png | Bin 0 -> 11581 bytes .../00000.png | Bin 10255 -> 11036 bytes .../00000.png | Bin 0 -> 14492 bytes .../00000.png | Bin 0 -> 11581 bytes .../00000.png | Bin 10255 -> 11036 bytes .../00000.png | Bin 0 -> 14492 bytes .../00000.png | Bin 0 -> 11581 bytes .../00000.png | Bin 10255 -> 11036 bytes .../00000.png | Bin 0 -> 20010 bytes .../00000.png | Bin 0 -> 7691 bytes .../00000.png | Bin 0 -> 11581 bytes 115 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/0'_0_0/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/0'_0_1/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/0'_0_1/00001.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/0'_0_1/00002.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/0'_0_2/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/10'_0_0/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/10'_0_1/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/10'_0_1/00001.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/10'_0_1/00002.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/10'_0_2/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/2'/1/42_0_0/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/2'/1/42_0_1/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/2'/1/42_0_1/00001.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/2'/1/42_0_1/00002.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/44'/1'/2'/1/42_0_2/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00001.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00002.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/48'/1'/4'/1'/0/7_0_2/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/49'/1'/1'/1/3_0_0/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/49'/1'/1'/1/3_0_1/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/49'/1'/1'/1/3_0_1/00001.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/49'/1'/1'/1/3_0_1/00002.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/49'/1'/1'/1/3_0_2/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/84'/1'/2'/0/10_0_0/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/84'/1'/2'/0/10_0_0/00001.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/84'/1'/2'/0/10_0_1/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/86'/1'/4'/1/12_0_0/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/86'/1'/4'/1/12_0_1/00000.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/86'/1'/4'/1/12_0_1/00001.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/86'/1'/4'/1/12_0_1/00002.png create mode 100644 tests/snapshots/flex/test_get_public_key_m/86'/1'/4'/1/12_0_2/00000.png create mode 100644 tests/snapshots/flex/test_sign_message_0_0/00000.png create mode 100644 tests/snapshots/flex/test_sign_message_0_0/00001.png create mode 100644 tests/snapshots/flex/test_sign_message_0_1/00000.png create mode 100644 tests/snapshots/flex/test_sign_message_1_0/00000.png create mode 100644 tests/snapshots/flex/test_sign_message_1_0/00001.png create mode 100644 tests/snapshots/flex/test_sign_message_1_0/00002.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_0/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_1/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_2/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_3/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_sh_wpkh_1to2_0_1/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_sh_wpkh_1to2_1_0/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_sh_wpkh_1to2_1_1/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_0_0/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_0_1/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_1_0/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_1_1/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_2_0_1/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_2_1_0/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_2_1_1/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_2to2_0_0/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_2to2_0_1/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_2to2_0_2/00000.png create mode 100644 tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_2to2_0_3/00000.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_1/00002.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_1/00002.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_1/00002.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00002.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_1/00002.png create mode 100644 tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_1/00002.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_1/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_2/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_3/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_1/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_1_1/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_0_1/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_1_1/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_0_1/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_1_1/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_1/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_2/00000.png create mode 100644 tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_3/00000.png diff --git a/tests/snapshots/flex/test_get_public_key_m/44'/1'/0'_0_0/00000.png b/tests/snapshots/flex/test_get_public_key_m/44'/1'/0'_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..5a1a78900e72be92d1f5b6a4268fe3c8c7d8e6dd GIT binary patch literal 10476 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/44'/1'/0'_0_1/00002.png b/tests/snapshots/flex/test_get_public_key_m/44'/1'/0'_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..ebd1846fa871c48e034e842907002c97d4c2c4c5 GIT binary patch literal 8551 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/44'/1'/0'_0_2/00000.png b/tests/snapshots/flex/test_get_public_key_m/44'/1'/0'_0_2/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..4321e60181db1ab7e8a7538c25e72daba09d225c GIT binary patch literal 5874 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

d35T<%ZLxEI zW+hOnrl`Lw6^D${zou}Bhw}>AcgNltFc0NKFQGW9Y`PN_2B3P2xr18xC-l_;Nd0TGJ=om}tB?WsXgO-TF zlwdgo5U`bm;1p4R!RJV=4nZbmakP#0%v)5^|HM2nLMmwKkMPlvUtvsVO%wTI5{S1S z^HX{6r1t9oW!|}gqcD1aXv^43j}a%yZosFO`VPW9sW8|u%;cRsZlZNb(j_kmxgm{& znnc$ZBEIE5tFIFV>Ovc)EXHiD2YQ}+)}Gh7kdol8pvTt&te0;TANnqkeX9TM0jcRG z@zZ_O7e(^1bbBr>$Axy(KS$X%?(ucm{i*BN{%!_0YoI(SGpIZrwqgZNJ zbs2wFNq$g^?dC2F;zNRaSa;~1{oN}Xt=52F7ZHwcGji&+iv%dHqUrMmhs(zxXuyne~yP z;X(ADUcRngrSfDGn#0ib@b3)O7nHv|pVmhQSgimR1Y>fY?ZBpn7ojZg?yjlJ=D5dL zrm2mSS=*z<4(PUGXTObB_MH~h!*JqZNiI@*in+X%TX5d>Ug~H^cMMerP2>3T>$wM} z(wxz+1C2YtyB&oRb!Du-KK?v4`1Br|W~?&rqUH85OcG#QonIjpzrP>SQL!rq46ym} z>D#c(LyAc4O}YPPN9M>Tn5WB{NGhAlZ7n!)RjR#2+@A#xi(@~wtZo%yoSY2T)5|Ps zvwG)K|4|*z6nBHV#t^%!{viB~HQX0q+hs_Ad|Y*X-1mK4dj7v}e$_Y!?-zouw+%3` Q%Z8kA_4=mv*rlug0an##761SM literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/44'/1'/10'_0_0/00000.png b/tests/snapshots/flex/test_get_public_key_m/44'/1'/10'_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..5a1a78900e72be92d1f5b6a4268fe3c8c7d8e6dd GIT binary patch literal 10476 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/44'/1'/10'_0_2/00000.png b/tests/snapshots/flex/test_get_public_key_m/44'/1'/10'_0_2/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..4321e60181db1ab7e8a7538c25e72daba09d225c GIT binary patch literal 5874 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

d35T<%ZLxEI zW+hOnrl`Lw6^D${zou}Bhw}>AcgNltFc0NKFQGW9Y`PN_2B3P2xr18xC-l_;Nd0TGJ=om}tB?WsXgO-TF zlwdgo5U`bm;1p4R!RJV=4nZbmakP#0%v)5^|HM2nLMmwKkMPlvUtvsVO%wTI5{S1S z^HX{6r1t9oW!|}gqcD1aXv^43j}a%yZosFO`VPW9sW8|u%;cRsZlZNb(j_kmxgm{& znnc$ZBEIE5tFIFV>Ovc)EXHiD2YQ}+)}Gh7kdol8pvTt&te0;TANnqkeX9TM0jcRG z@zZ_O7e(^1bbBr>$Axy(KS$X%?(ucm{i*BN{%!_0YoI(SGpIZrwqgZNJ zbs2wFNq$g^?dC2F;zNRaSa;~1{oN}Xt=52F7ZHwcGji&+iv%dHqUrMmhs(zxXuyne~yP z;X(ADUcRngrSfDGn#0ib@b3)O7nHv|pVmhQSgimR1Y>fY?ZBpn7ojZg?yjlJ=D5dL zrm2mSS=*z<4(PUGXTObB_MH~h!*JqZNiI@*in+X%TX5d>Ug~H^cMMerP2>3T>$wM} z(wxz+1C2YtyB&oRb!Du-KK?v4`1Br|W~?&rqUH85OcG#QonIjpzrP>SQL!rq46ym} z>D#c(LyAc4O}YPPN9M>Tn5WB{NGhAlZ7n!)RjR#2+@A#xi(@~wtZo%yoSY2T)5|Ps zvwG)K|4|*z6nBHV#t^%!{viB~HQX0q+hs_Ad|Y*X-1mK4dj7v}e$_Y!?-zouw+%3` Q%Z8kA_4=mv*rlug0an##761SM literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/44'/1'/2'/1/42_0_0/00000.png b/tests/snapshots/flex/test_get_public_key_m/44'/1'/2'/1/42_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..5a1a78900e72be92d1f5b6a4268fe3c8c7d8e6dd GIT binary patch literal 10476 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 JUb*w|zX9Mk0*C+r literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/44'/1'/2'/1/42_0_1/00002.png b/tests/snapshots/flex/test_get_public_key_m/44'/1'/2'/1/42_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..e15bba2aff703e1f1bf45bb6c3c78ee25331a63a GIT binary patch literal 8819 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/44'/1'/2'/1/42_0_2/00000.png b/tests/snapshots/flex/test_get_public_key_m/44'/1'/2'/1/42_0_2/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..4321e60181db1ab7e8a7538c25e72daba09d225c GIT binary patch literal 5874 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

d35T<%ZLxEI zW+hOnrl`Lw6^D${zou}Bhw}>AcgNltFc0NKFQGW9Y`PN_2B3P2xr18xC-l_;Nd0TGJ=om}tB?WsXgO-TF zlwdgo5U`bm;1p4R!RJV=4nZbmakP#0%v)5^|HM2nLMmwKkMPlvUtvsVO%wTI5{S1S z^HX{6r1t9oW!|}gqcD1aXv^43j}a%yZosFO`VPW9sW8|u%;cRsZlZNb(j_kmxgm{& znnc$ZBEIE5tFIFV>Ovc)EXHiD2YQ}+)}Gh7kdol8pvTt&te0;TANnqkeX9TM0jcRG z@zZ_O7e(^1bbBr>$Axy(KS$X%?(ucm{i*BN{%!_0YoI(SGpIZrwqgZNJ zbs2wFNq$g^?dC2F;zNRaSa;~1{oN}Xt=52F7ZHwcGji&+iv%dHqUrMmhs(zxXuyne~yP z;X(ADUcRngrSfDGn#0ib@b3)O7nHv|pVmhQSgimR1Y>fY?ZBpn7ojZg?yjlJ=D5dL zrm2mSS=*z<4(PUGXTObB_MH~h!*JqZNiI@*in+X%TX5d>Ug~H^cMMerP2>3T>$wM} z(wxz+1C2YtyB&oRb!Du-KK?v4`1Br|W~?&rqUH85OcG#QonIjpzrP>SQL!rq46ym} z>D#c(LyAc4O}YPPN9M>Tn5WB{NGhAlZ7n!)RjR#2+@A#xi(@~wtZo%yoSY2T)5|Ps zvwG)K|4|*z6nBHV#t^%!{viB~HQX0q+hs_Ad|Y*X-1mK4dj7v}e$_Y!?-zouw+%3` Q%Z8kA_4=mv*rlug0an##761SM literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00000.png b/tests/snapshots/flex/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..5a1a78900e72be92d1f5b6a4268fe3c8c7d8e6dd GIT binary patch literal 10476 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/48'/1'/4'/1'/0/7_0_2/00000.png b/tests/snapshots/flex/test_get_public_key_m/48'/1'/4'/1'/0/7_0_2/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..4321e60181db1ab7e8a7538c25e72daba09d225c GIT binary patch literal 5874 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

d35T<%ZLxEI zW+hOnrl`Lw6^D${zou}Bhw}>AcgNltFc0NKFQGW9Y`PN_2B3P2xr18xC-l_;Nd0TGJ=om}tB?WsXgO-TF zlwdgo5U`bm;1p4R!RJV=4nZbmakP#0%v)5^|HM2nLMmwKkMPlvUtvsVO%wTI5{S1S z^HX{6r1t9oW!|}gqcD1aXv^43j}a%yZosFO`VPW9sW8|u%;cRsZlZNb(j_kmxgm{& znnc$ZBEIE5tFIFV>Ovc)EXHiD2YQ}+)}Gh7kdol8pvTt&te0;TANnqkeX9TM0jcRG z@zZ_O7e(^1bbBr>$Axy(KS$X%?(ucm{i*BN{%!_0YoI(SGpIZrwqgZNJ zbs2wFNq$g^?dC2F;zNRaSa;~1{oN}Xt=52F7ZHwcGji&+iv%dHqUrMmhs(zxXuyne~yP z;X(ADUcRngrSfDGn#0ib@b3)O7nHv|pVmhQSgimR1Y>fY?ZBpn7ojZg?yjlJ=D5dL zrm2mSS=*z<4(PUGXTObB_MH~h!*JqZNiI@*in+X%TX5d>Ug~H^cMMerP2>3T>$wM} z(wxz+1C2YtyB&oRb!Du-KK?v4`1Br|W~?&rqUH85OcG#QonIjpzrP>SQL!rq46ym} z>D#c(LyAc4O}YPPN9M>Tn5WB{NGhAlZ7n!)RjR#2+@A#xi(@~wtZo%yoSY2T)5|Ps zvwG)K|4|*z6nBHV#t^%!{viB~HQX0q+hs_Ad|Y*X-1mK4dj7v}e$_Y!?-zouw+%3` Q%Z8kA_4=mv*rlug0an##761SM literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/49'/1'/1'/1/3_0_0/00000.png b/tests/snapshots/flex/test_get_public_key_m/49'/1'/1'/1/3_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..5a1a78900e72be92d1f5b6a4268fe3c8c7d8e6dd GIT binary patch literal 10476 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 z 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 o{NFbv{tw-hlS1wsKkE62;Ii?<*AFOgVJMF0Q* literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/49'/1'/1'/1/3_0_1/00002.png b/tests/snapshots/flex/test_get_public_key_m/49'/1'/1'/1/3_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..18c18d594e39dd236de5f22ee0e53fef0f5326a6 GIT binary patch literal 9090 zcmeHtcT^MWw{|EB(p6A8_yZM`sz{Zl6cNyqqXC12B3&RDO6UYZK|#O+QUoC!5JZqf z=_G`pC@6@b2M8f(#DF0bDFH&l9nZSo_y70Dx7N99-N{;+cO^4>X7+yHy`TL&^YD)= z_TnP)A|Mb*+~JbVpCAz5EC|GZLzo}<!tJqV=c;9z5YJ?0sU%6eMiq)_keuX2^& zNm!OYE%}(2uzU)z3lu(-a!>V`0q|MpA(mglbjw*MwN^|~pNHr|Pip#0DnxjSIlTtX z0-)rgy|a-5AP`kJ5F}-5C6KJaFAuUgI0#bBNZtx7 zk z3w@{Ol&kJM5^Yqe)n8kiqN&m)Y+qe>auafFtd zIJ9wgD8amtWi1ubN|_6fHCBu)HhATzAecOIZ69lq&FRthgZ_y1fIwhm3d^v+p>=6u ziOs=bxajnx(I^&ACTRFICPWJ4zm<9qp%?)Dv15e9Q}JXC+50KZ{CaJjr{^8D%Inwk zNo$VWp>dz!4gXyA(sut+Dp-1w(DGSNEc9tsJXPCU)}wYBd%heKOn#_n3(i$9EQ427 znBDlPTTgwyKi&mKMmlW_cQ5KM@%ce<$D<7wbM4}n+`c#(UgE5_SjCTop^kM;a7~nR z%oR&1Eaay7dF32e>!-zq~e_V6$ep3YA;{ysd z2W`OxeykG^NHZ0lsv7vHp@tdPN@+G5pc~JG81lNunNjg?c)=k?3wK>vx+fiSsc?p6 ze-aw*WYqf1z?p(w9S+Qk4tcyOdLTvBc|_UbO>)Xtym3N-Dl6&Jd6Hy$DplF`uhUCf z=4KrIy4r@w7J*#Xoo1HK>CY7Qk61Wr>*aMwzS;92Q8v?AG?Kow;Yx0sJG2L(giqIX zCRvSL7zhI*kly{Z&#L&!=7>z%-kvO9!wh#<*b)+tT)kP~C!1C>@Pn-3UhiTH7PNlMh{YQ=4F-w5xpSb|t$w#* z6e(R>+mJgAZ)$-;CNxfBS3H|Nb@3TVfGgN%e^01)wP5y>3XPE0Hf4;~9GN$v!!?Dh zeFc6{XgI*r)E+x(AjL)Ctz2mVNEp)9T-y5o=X?rLmL%r)!S8N<|X7m{SC~B_S-h zyE7=&VCJoHHq~MrZ|}=5(!`G&NR%-WW2gz~8X41fbbKnuQ~EWb5C~X$T>RHm#~q>l z*rxI3ug+_67%ZVNIgz%X&mzyo3SaR#KWHhQx1^g;TwU-{=hv%8EJZJ`i#Aiv85K3? zkUxtiz7apaH4@fyaN}bkS+Em0^`DB*cP|`yZ-{&+5ei$N-J$nQo?+JyK;Q8Bo@g+~SVpDzF6n;EV4$R}_9R@1AR|TkRYOpVM%s zW0VbrSDxOJID|X(d3i0$o`qIv+dPd*NU6uHSv|Fkc%HcIXm_+t`%aKuT8T1u7pK#{ zeql;TFMdL`E8x!qfhA2x1g+@?tfgR-X6-n0BaV>tY4nVd%X1A8$FBI^EW(QG_u&<5 z{7}mn{;JcE$(Jc-G{RDn8zMC;u%R@V-+RU2He(-Bsgo7!H~z`%q}oP0vORXj@EGg( zK;y@VjUdJ?n3kdcc@>HD(*Z^;T~Q~Mck)Ap6gs~h{o8QQY%4l0>*kS-B0Vvxw2e=g zb-b^mrGns=RU+G(^TIE%&45X+u2GT@QaCk;A&1CQ9E$@4DyR;YrYb&bHd@ev{wkWX z*|I(33L)#z0bbQaRm52nZ`rB3mK#ksr|Vke(nuY{o*xh)-9JM5qGm(a)E#!wm?Xeu zchi=?J*d!d9-*(s%&E&5f(H(bsI>UWu!BV%3j1A;;3q@eC+DXQ+kzRN^rvreATtwBD4xfxw)mI?{Ef(CBz4vnM9(UqA3|8Ir!Stea`>Gn4y%wk-l!PiT^=iuPd zh0Dn1YzlVLyU;x9s9qL*i>$h$`;yI6E9|f0CYqKe!Dg%clHSRyc!Wy{+Jf6oC*Aih zQa|A8_4b9aa*pLxXJ@B;C~s$HX9LRNcAnK-jGJ&Ro5u{saJ?-pEqm!h+MAcp?lv#8 zIV5+wfFqB`gL{^azegmPmcpT;dbic)Q;|{QtbeB6QpX>WzpEG0u*4kIN3YOWl#I3x z_JlwhCqoDxmhA;EF{?YdlIh(vB1$s-A|s-|!CmVJg|&HigI}#ec@R&{YKX=pbejl9Z2;vEl2IHg8fk)sF{)>2#_ zyfuQht19eLH^yeO$^UG?U?DPGA4cA|^(Lk*6sTw+ztnmvXu3-tQRkL4>sN1q}?iAY=KzB6&i#bR{}PuPN|ZnuDcFue@+ndWr7nadebO>DqJfsCUWoIp8h3#EwTrv3d6d)G8DP0q-kK zjNOiM6x=fFaLA3cI4*W^Z)LQbTcmSK=bTo50~U+@BH=O~dxWCQ8M|f z?W2oIDWt55Kq8G6uHLr?=g_{U8E02&G{~=f#j^8tt_QD(riRA_cQp7Kz5CvG1E(j} zt=B}TD~!eqnA!+TsiY!aKDxa|tRwfDopkut$Ewg+5-&a-KVLWYQ|TzIbXXp%Wzx3I zs%FZet=?o-)}A6p(C6-ZuMmZrmFLrt2Yu)lckwfk4vT=t`f`_H7iJ;TUF#YygYel# z=Tq(6hZy>Qgi~-B?4lZnw$fwKpyVcoS-OSqd{Vd@lkiU7v&|PJa%-i9cGBvu`#zRr z0#NLuoqulh>k}<;1K45(J|$knLVFYp|Dxl00_WbjPTx;aFck?QRPIpKc14##;J!!* z1U`CQv6p?so_CbjxAN$u5NYS@3`sMox~WH~V3&a=qV{m?FLv~f+g8WQ9Zr`6DD!g0gg>;flSCwWl)yPGx^saYpPKwBkd^V>uhO zwXc4dDoWUbCq{kiUZEFUqqtebPdFC!-(m+MDC}5jmiK7tDRV^O~xaxiGS@o{g|b z=Fbp0sf8rk&a<*<^U{)wevY3LnF`&TZEj*q(lGmEdA0(|1C9ZRI)6Hv2{+`4XDibNPx zBchXNyJZxksDjZ z-o$iHBYh6MYU^BuCcR>hD4nl5*NOa;BzYiRL?3bprii`ODEm3Twom7JAc~eRO(KCi z$xp^(`hPFbd!Gq&~AV zhe5-OtCtv!TKy~}CH73gc@kGZMy#>>x^r!&+7@lZDy)_A;TE`{s&wyfjf|c-k!5)j zgZ*?pPxzV}a7~Hs*NEmP+X-ciSngG@G;?Fh68fiNuaoBc>kiikb(`GkLv&KPtr{8I z2{YRtM;0PoX;rlQQ=|kY5Y^4&%k21)$G7&h`+xQMQR&7lh`cU!=lT?hlybxXu0>Bw zr6}pg{-kvmtaDISwDxv_1uZ?> zX@KdwfN2hp5yozhJtZC)$U4n0FtWyoIe!H&O8TdAJu3WlEm<(-tZaO2Z%y9-K?Xcj&s64>l4Fe~7&@2|^Nj-k>ZwA0CK zb$+*i2#}TP;mh4ZO&`-hAoK+Tam7KA5)jB#T=|cS``2f6l|dKp;-v@Nut+whaRLjwSVrOO8VA&~ptF&1dnCQw+VKimlw z#FzrjM3~{a<9oa>bbLD-g+hfHmUvSN)IU|_RG`SKF^Vmvve@Y3)q4+*m#-!pXA_A; zEOGh8NKn_2q{PJbf`r6GrJP=^{zVMX!^7&vZg<(;8lA~6Qs$SB&a9~U>o+=&GzEZm z59^{|q-+{Sy!2eSv~AtkDTiDhCGAs8bU06HFs5re0U5Rgd?^i{aK2_)EwsQax3iO+ zDSZaCGm7f(6AeqU9KSbcG1g+~e6eM&kSGf@l^%_UF)AuFejSBCAdK$a-nN^IJq=n4 zLh9XmkLVMYdPV9FwcBe?wTif!75YKRQFOcLiNSY-+Ee%{E=WP-R=OQEJc%IMHikbv z|F@@#$7fwMR_xkZj*8*sMOEQpgN;I;FN}!d>MZ-6=GVu==nu0FB{jRjb~HSeQ#Zq$ za^G7%4!jy-Sw4iOZ^{^!IQxvHs+{>y;=c2mAR=S1QCnKORl<#s{1AH`LZvXoM35 zd9dH8I^DHd3Y{V%-|9FrN@&c1+~*zYBoZ67908blhA6+m3?#zO0S+S4TA6|I35vbY zf^!yQPyoIDFx5z^FIO`A6_m58;#F_1oC9=-VeMRCqsEf2l_=+8UeMNr1E=58V#A{C zr{DRFv)Qed&ALFRqZ1vkX2exXLMVFfJcn6cigC1Rt()x;*gdGqE38???LPAV_HBJy zEG*an>Zc z{)^i)^jp{d9Ja^fuc>~Ev`bb3e0*8) z+uaJAoWub8UjN3`09!m9x~Jh8FWZcAI zfQ#_wJ=EQeh!eDy>U|?RkHgqr*_ISzvaS(ONl9(0U*Ctc-o!t6!i{d6bT5XqQQ-=u zGMOLV4eXeqNl5=Hjf~xy+z+=_%hCj}>ubD+G0!pua*9Zd7b6ROhzlh#!zSUe?e4h4 z(5Cn|h5g6p&U(#%>qF4v}-+6TAH_{vnwz_5`AlqDa@sS81EC2+R^bp9dc5ka9 z1&|j61PyErl85Bf+tOZ^e+mStow@G&PZ9*OWkw*VQqSv#IMh0C2=rcD;hI1+;_(p3 z7f7o>29@kQ04jGrR-7g|Z{>3ll&p5>@*zH@k0BDE!G~)3$r4WtMUr!l%h+7tQ+g08 z4?^2%r!?`K4pOW@7WcfiKJJTDZGQ@KD)C?Zof~nJJv(a*(x5n>9-??CMEZ1~eQY;h z5oq=CL11}Y4gxK!Di7G1my7F*&qC}D4)`nbg+2%Zkz~OJCHniC5G6&=_ut7Jnrk@Q znT))28|3=PsIc^)P}4|^!pGp*v(Bo2DO5`hijTzSff7zEAO=AzpZ*0VrG%4{tvgTJ-UWqSI4blnP<6JXZNXwx!C4DI1B-WY1P`qvcq)88&C3e{ znFEBAu|e_n1AJKvH?aVHe@r+95OWIV1_$1H{lv9MT0sjcKL+ySUTXE@FzN7p9z9hN zQi9Ne4~X+2@lSxPUodwM)%{K{QY9JeyNTF_>%8=o}q2=CFbKWd%W(uuL@F zp>a9)z0BW8GG1XetOlS)&nt&bCMtGJk{(n9N+&AOYs!@WHMB4pu7`cD$SEQ+V z$BIS z$*c0VO6Cp8S8|^Zt^FbWA-uim>J2d9u=Ce;dk{|KwTZ0LrLg5twI3;}mvW!)zDO^) z=N-dIjVk7faUUr|ty-bJx<^Dg%U|!ziv?0LUoxj8=pJzj)Apw_D!!1IS^cY!J)6BP z_IOk%8+UU$>~odjYzCsL@lB2mBS15oo}Ml<`S=kI6B^AMW|(ZbT2tuMxb)jd()+V< z>wHSPVJHOW>|cy+cx&)(Q7@u{wyc1DS6lmIt({8%#_<8Iy1kki73M33*>tUb_Y!VC zE?`pI=hIOoAEy8&E|GO6v*P1g$0`hPUE}1IKCGY$)zzK7HAy2XA4AzUrdK>0x@LSS z<^vKB(VM;k?W&=8U1+v5jG54P>&+dL6jwPP)4e_m%V^f6x!9%spC^s4$Ky~= zq$c~9$ffTaBa7ajl+Ql9u#dX+xt&=5qnTK#;Z_f*IuJ;dvErg85FsX$NzS1Q^uM92 zFA?j;`j9)*SpZQXkw8gSzgZmLAr3Bfx<8!iP`w6_OV9D#$ISyi5^fve5C|Y83a3!v zt+Zv9osle@;6aW`Bu_BNhBxo}E1BO<-V|EjLLcDR><22$Du9|=0n|1b;y;O_!co+c zcrO$9EK)X&u{KE<0T@^d^vx(A>KsyPS|XO>b0SZd@bphpis&1)!<#1Ub!XpZy$Te& z*rGK9Zw-@oU-fOY74~2M$Umj)pQ@_SKdj^oaHA^9476mG(pzW&G>tdazuFbPd%_Po zK5^e^WYl8dnLF!v^^-5w%xiDl>ft%pZDpv4H1Zm|M7W zWX7oN+f)C#AYTJMF26(WBEZjH!!@+l)>@)??y+zP#Fc;N?%b9PH*`RVr?O|%Bi=Is zZ*ASJ!3(4oD$jPR8qTjR^zcw50|nPdVbb=SIVc~_u2!o`I>Flla9pW@smkwdVhfQRC zj;51T7TT$BE;{&VHP0?OguyI0xFD(3OIqE$0&sHx#BZE@rGHn7G!bH`#$w*U{!SEq ze=mE+7bu~GuQ3EXj8Wh34;(pG^yTe@fT=M5p2odB#H!J1czcN8Dv+G9WPnUJEP;9Q zfN484u*v>Ey}MwdGb4Whp8qIapvvDTVGvE=yBMxhr^ zzq}RXH+8;Nm-#q;Jox>T!Nn6_o^qe1d&kg64@E~}^y?@;P(piVu2wH5 zyK|ixs=~nA4fb5Qr|^WE#nmjesMs?6(|Cv6t;)Xv5;OmBx>14ub}-85Nu;qy2yLw_=1iCacE~J(nTw*Rg z7b$V#4{IUo$JH-I&CHHB;e(sqN=Xc4$^>*CPOKRd=!e$3czSxWUOW%l+1MDH8EAUK zwj8W91(eA~i4W`1Z zC%xGCTb7ko~ zJI(OXlo@#rm^o#QL=DY6AR(FJi3|}%f#>UXUGMe&{a)Am{MGL-_WONkPQk9#To*cFhIIkq^;kuy9e^iI_MYoTt2V z+-oT$j;&`b_HDz$B(49|1zbFsIP*5p6Mo?PjZ59T2C+WJ2`pvOCv2XHMhLHJix@o z#Kg=Jog-O;o(!RwOT%C=a#E|@@7QFaOLpx^g-|Hm80cI-c%`_w7>+Gs=GUG|%V=;)-cx^6I~rmzG{fH-hhn z^Nd}4KWz2(_T~{HZYZ=`t^Tv891eCUNT1$z#V*pgS;XV!=N9bH=4oX?Rga znICgtTB#P;ewnliB15Bz%6+kzH1iIHLJ?kMlF@O+ZhEzTJ-scc&d+jtCeJqCLhsZy;6&#i zotF;2ma7;m&1U(Y<|`V`p}D8Sv!kP<9J#9`Memf(x4NI~%)}htVc0Mn#ZNW~+LteE5*fhcMRVJ4e|SbY6OP`S9{9!i0x;_6h0K&t0L?hLZ~(r7~fHLyfM^;+7m0 zCOyd-d{j3vhyPNu6`#Tyo`up)!5wkrGW1h3Qkg8*MOe_O4L@Vd785Tap|-U*>b9NA zT9;3~7c$uNZD1DNl$hBOJB&~Hs%N2`kll?KrZ~flW>qF;M(GTOD@}2%Em`jr273QW zGZ&v;wZ9pM#SWQLQXF{p)+U7$r1AwR0Gbj*C6mc2Nn4eG$M?R_u=?1Nrqc$}-gcK@ z#4T51bI|yd9+YjF#VtgwqP@MH&*xVJO4}~=pu_?%BzrSBoeWHG+=`xlBG|NPQ@iBX zaiS@WxCqz17p=>OBNt2MPdCz9J&4Y1og07W5z~C^1|%BQHEz%Di6T-_gY@nAlrMW0 zN)H9acGcW@r&yMYxm;vlYj^#oS$&C-`;6|p~pmA zc`OEst9t1iOE^Kyx;-_~5k%0P1?0-j%~kKhypOVueYK`Q+Q9PON~-1D>}(VpOCy>W z(M*=+If(nc_y>Z8j?Mb)@Fzsp;DWa6Y;}JXA?a6z4)O*dKgNrj5aCd?Sbq?dEX3cA zRFY8^t6h)YidXl&#-L$Fncrw1tWjt#eh+;p)+X(tH^Z@4vAkN%7$F8VU$ny}9?nCx z-KHMNpcmf{S(B2c(;-~3?ycsgQF^;n8mzffX3;QQ(@tOD!;xrH!}SdPv07b3^@@-E zg$O59L04bir~y(_;AzfeGL`O}1tndDN;Q2tFmRshd)KA(=D~t4ub8xjrKP1BX)k~L zLqb9b3g%FMd$ZoDTeGB8hdHMrFNRQ-8(oo50X!A5)VIo-Btf4qnd_bUiIs`9$_1K| zX}Uuc%o=oZb}k;(w5J_?xdC|;D8-;-9Ly*kq!Q?wqYZm_wzy>N@^)`bZ~DYWdpi$U!a)}-_;Jo9I;~~}sMAdUTi`TjvA{(@H}8w6cVItZ)>_=^#Up{$ z_V3OZD~rTaj=n(dL0`CHcfjV~ULQc9X4dG0qovP%L@?=!*V`SLZgRQ&y6ugS8}y5y zVbu9O8kiO^_rWsVhG$7^Y_-jEfZp<6JXZ|V&ui{Sf+uUZ?~ZrrvZG;oyD~*HKM(XS z+Cqs(=68kCw5xYQwL3dYmjitCA&ISl%H1Q%U1|M?+NJYf+gC`f$M-Xr0(>;Hse9j; zem(~I@6Cf#Yh&p9o1$oYm=T6D^jE|DTPNmM_fNP$)8<_Kb3**#IzMCAbQ`8~95@8& zIJjd0wT(I&-Iz+HTJhr!?f}{GxC2TKaLm~PdaE*pqJeSlcgaa0jkG53@;?v=L||7k zSBwaAglDA|8n7!>2`Cs^4tY zoO8p(50TzkCXe#(z88nt75KE78Lnpy&MX)x*=Z5XWzfgKg}VD*20I>VsKzo@ z_y9Dqs07EYUEFXabXK)8wOKsaJ1lKd#G(p4&HKBRVN?hGyMuHNA4IRcX#GJJZ95Wr zaL12s<%=kq`AuU;7#U9@hoWHHT@S&ts*wnz^yzM= z1N^w=i|_)haYrnQOrdCA-W_qu?h1`BoKh<5hqe@WF?cwmDR+tKHs9M>p61!}N#w5L z3(B&7zaBz3Xt|8YnRf=JKxF58<_Px|--S_$J{P%y>Fza0hb{S!hioblMc5i&p=@D^ z*AdivINig8sKDU&3?B?bb+KR-Q&o{o`0ry0MhCiMl6zSh zDJ1Pi*E0zy$!?{2gQp*jmHqrdwGTn#pi6TRD>kVaSLk@Y*d*>71mRVHoW+JXvz4O>EbMxd@jl8`tfm6mI-0R@!(Ake-d%W|^{_FPfPEZiyX$^`4y zYM)+?U|2<)_DBj3jx1?M%geI6vPgQA@)Tp}00}3|NHMF0ZAOWj9P>`>+Mc;dQW1uQ z=04g}UUyuH?qQv8|7+HI>}LtBZ%KYen$<)-6}z>`FMifoqY!*bnP{E7tSB#X5tnfa z$SvX6q2}6Z`Og=dc_}S~#KYNY#uJU=+Y)cSa4LqYO=7cf`($0)s8!AoV!k$q%Z^_| z8`rick(1$NhZ#DuNxl8R*V&owR)KYKFmA2Y&ZdQ9v+kE1@=gTuJ*TV(sOobXlN;)& zol}TD_1=&Y;F5R$fTt8!WyzQRs|Y(zn5e3Z#7&5&1c|-N?|6Il4PtuXlVujS^-D>u zBH1UEYFYJcNq0_m38<=a%DuLhJ9wN@1$f~EC!%0L_^aE40DqCt`od$0ifbicQsf

d35T<%ZLxEI zW+hOnrl`Lw6^D${zou}Bhw}>AcgNltFc0NKFQGW9Y`PN_2B3P2xr18xC-l_;Nd0TGJ=om}tB?WsXgO-TF zlwdgo5U`bm;1p4R!RJV=4nZbmakP#0%v)5^|HM2nLMmwKkMPlvUtvsVO%wTI5{S1S z^HX{6r1t9oW!|}gqcD1aXv^43j}a%yZosFO`VPW9sW8|u%;cRsZlZNb(j_kmxgm{& znnc$ZBEIE5tFIFV>Ovc)EXHiD2YQ}+)}Gh7kdol8pvTt&te0;TANnqkeX9TM0jcRG z@zZ_O7e(^1bbBr>$Axy(KS$X%?(ucm{i*BN{%!_0YoI(SGpIZrwqgZNJ zbs2wFNq$g^?dC2F;zNRaSa;~1{oN}Xt=52F7ZHwcGji&+iv%dHqUrMmhs(zxXuyne~yP z;X(ADUcRngrSfDGn#0ib@b3)O7nHv|pVmhQSgimR1Y>fY?ZBpn7ojZg?yjlJ=D5dL zrm2mSS=*z<4(PUGXTObB_MH~h!*JqZNiI@*in+X%TX5d>Ug~H^cMMerP2>3T>$wM} z(wxz+1C2YtyB&oRb!Du-KK?v4`1Br|W~?&rqUH85OcG#QonIjpzrP>SQL!rq46ym} z>D#c(LyAc4O}YPPN9M>Tn5WB{NGhAlZ7n!)RjR#2+@A#xi(@~wtZo%yoSY2T)5|Ps zvwG)K|4|*z6nBHV#t^%!{viB~HQX0q+hs_Ad|Y*X-1mK4dj7v}e$_Y!?-zouw+%3` Q%Z8kA_4=mv*rlug0an##761SM literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/84'/1'/2'/0/10_0_0/00000.png b/tests/snapshots/flex/test_get_public_key_m/84'/1'/2'/0/10_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..d5b76776c8749a4f59b3faf5af3c1316e5d56150 GIT binary patch literal 11369 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/84'/1'/2'/0/10_0_0/00001.png b/tests/snapshots/flex/test_get_public_key_m/84'/1'/2'/0/10_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..abbcf4a77dcd23a35223fb5fab0f5acf860935cb GIT binary patch literal 14114 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

d35T<%ZLxEI zW+hOnrl`Lw6^D${zou}Bhw}>AcgNltFc0NKFQGW9Y`PN_2B3P2xr18xC-l_;Nd0TGJ=om}tB?WsXgO-TF zlwdgo5U`bm;1p4R!RJV=4nZbmakP#0%v)5^|HM2nLMmwKkMPlvUtvsVO%wTI5{S1S z^HX{6r1t9oW!|}gqcD1aXv^43j}a%yZosFO`VPW9sW8|u%;cRsZlZNb(j_kmxgm{& znnc$ZBEIE5tFIFV>Ovc)EXHiD2YQ}+)}Gh7kdol8pvTt&te0;TANnqkeX9TM0jcRG z@zZ_O7e(^1bbBr>$Axy(KS$X%?(ucm{i*BN{%!_0YoI(SGpIZrwqgZNJ zbs2wFNq$g^?dC2F;zNRaSa;~1{oN}Xt=52F7ZHwcGji&+iv%dHqUrMmhs(zxXuyne~yP z;X(ADUcRngrSfDGn#0ib@b3)O7nHv|pVmhQSgimR1Y>fY?ZBpn7ojZg?yjlJ=D5dL zrm2mSS=*z<4(PUGXTObB_MH~h!*JqZNiI@*in+X%TX5d>Ug~H^cMMerP2>3T>$wM} z(wxz+1C2YtyB&oRb!Du-KK?v4`1Br|W~?&rqUH85OcG#QonIjpzrP>SQL!rq46ym} z>D#c(LyAc4O}YPPN9M>Tn5WB{NGhAlZ7n!)RjR#2+@A#xi(@~wtZo%yoSY2T)5|Ps zvwG)K|4|*z6nBHV#t^%!{viB~HQX0q+hs_Ad|Y*X-1mK4dj7v}e$_Y!?-zouw+%3` Q%Z8kA_4=mv*rlug0an##761SM literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/86'/1'/4'/1/12_0_0/00000.png b/tests/snapshots/flex/test_get_public_key_m/86'/1'/4'/1/12_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..5a1a78900e72be92d1f5b6a4268fe3c8c7d8e6dd GIT binary patch literal 10476 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 p2c48#f8p~${*sk|=?RsC=^*+2_&%^cCRYyCC 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 Fe*nkeH01yQ literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_get_public_key_m/86'/1'/4'/1/12_0_2/00000.png b/tests/snapshots/flex/test_get_public_key_m/86'/1'/4'/1/12_0_2/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..4321e60181db1ab7e8a7538c25e72daba09d225c GIT binary patch literal 5874 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

d35T<%ZLxEI zW+hOnrl`Lw6^D${zou}Bhw}>AcgNltFc0NKFQGW9Y`PN_2B3P2xr18xC-l_;Nd0TGJ=om}tB?WsXgO-TF zlwdgo5U`bm;1p4R!RJV=4nZbmakP#0%v)5^|HM2nLMmwKkMPlvUtvsVO%wTI5{S1S z^HX{6r1t9oW!|}gqcD1aXv^43j}a%yZosFO`VPW9sW8|u%;cRsZlZNb(j_kmxgm{& znnc$ZBEIE5tFIFV>Ovc)EXHiD2YQ}+)}Gh7kdol8pvTt&te0;TANnqkeX9TM0jcRG z@zZ_O7e(^1bbBr>$Axy(KS$X%?(ucm{i*BN{%!_0YoI(SGpIZrwqgZNJ zbs2wFNq$g^?dC2F;zNRaSa;~1{oN}Xt=52F7ZHwcGji&+iv%dHqUrMmhs(zxXuyne~yP z;X(ADUcRngrSfDGn#0ib@b3)O7nHv|pVmhQSgimR1Y>fY?ZBpn7ojZg?yjlJ=D5dL zrm2mSS=*z<4(PUGXTObB_MH~h!*JqZNiI@*in+X%TX5d>Ug~H^cMMerP2>3T>$wM} z(wxz+1C2YtyB&oRb!Du-KK?v4`1Br|W~?&rqUH85OcG#QonIjpzrP>SQL!rq46ym} z>D#c(LyAc4O}YPPN9M>Tn5WB{NGhAlZ7n!)RjR#2+@A#xi(@~wtZo%yoSY2T)5|Ps zvwG)K|4|*z6nBHV#t^%!{viB~HQX0q+hs_Ad|Y*X-1mK4dj7v}e$_Y!?-zouw+%3` Q%Z8kA_4=mv*rlug0an##761SM literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_sign_message_0_0/00000.png b/tests/snapshots/flex/test_sign_message_0_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..d5b76776c8749a4f59b3faf5af3c1316e5d56150 GIT binary patch literal 11369 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_sign_message_0_0/00001.png b/tests/snapshots/flex/test_sign_message_0_0/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..4da45ae31711f481bafbe3881514af95588f8691 GIT binary patch literal 14925 zcmeIZ_g53qyDv;p5EW3tLRY%dYv`b;h*E5Tbd)ZH(0fxOj^9gH?Kbq&0m`&=T@{F?D~xbtg`))Pz3&*ILtVn zynOUBt4P9wQj;ieK>0Wny|y zjd^sDiD@7umW}E22@j_GiT{&N{^~!XZ)}E|WQb$xbo$x*KY2ncD(Ylq5@&-PnPZJj zcm}`(XslVrysyUT0&@%CkT5=1h+svrFlFYHCbXBrDG;VuHB$pz5cmlE7tX}gd5qZ} z7eqi9XUJw_#Er)hV5l4I8B?r3PyO{g^%PapY>cag1(;xIVUe}ar(kK}TCBsk;5ct( zlA?#HQ#Cc^ARyEvw#&SsziAE9Csm?E@FNAJu>IgAdmh$(PRSDvMSfKWFs-1;DH3@ugS0Y;?MGt0H^ zkGkR7={_qI8tsaZG=7NN32tuSA%*$4jUv{bH-x)9V?y`*QS;#GkYvt8SD#$`i=q@y zjn%?s3Et{k0q9hneHnzeC$t9V#n)$?p=#h_H<5OPiU5FE(!VQO|vB1MrAVpfZ5?23IuIfj}#)AKt8xGg9f?w6Bj;xda9ip zi2W*kl4nT?cATQ)Sc^*!Ia-HaYP026D>6;gw0KOIm;o6QMpi2C95hTaJElu4%LG76 zqpUqq5&}tJ7wtv{%R)l_rM6mS2Z8!(!hx|B@2}0!`bk_qn(c2(R1E*d2ffnX#Vq?! zmc#DwR&}1d&YnK{?_y~!F-A=SGws^kao{%Lv`$oKb6RJ~>KWal+tls5UtmvZ`NOJ{ zYr%)~DLbAVy=#laTMsmJQDmTTz_Sd9tE;Q#Dn%DJhPAl}d|DwVAkmm@l%gj=HN~?_ z-TkV5$=rY5F7LqZ<~k~Auc@Z*(QDITjlPZ-6<&_SG-k(TXI8C&P$8#6j(S}ZOPcAF zno?{dXvp*iVW)3fn1a8QF?nS*zO*E--<-hg$N>ilkoiZt^$l}eK}W&zy#Gdttn|gVcdG#U+Ke`sQOlYrQraHfoe9h<115iho# zY5mXL9&w1Yka(H6Ma{FMZ;)Y9uc~=WOiUiNOG$~A6%RBNQ&%O6p+`g5RyMTt@*ZUM zqWh#n+<03@pD&opLe&3tleoB`=5Z+QVA45-?L=Yf-kURxf8l(Ei>-Zi{?^k%7LbJ- z1kL$>+Lp1p9LRo#m?)E&}I+|jC!KzleecqgX2S{IPw zaCu?p>mscwuN3?RzRqdBP-HMD`tj{E?E3mEJ6irJuGYI9#8!veU~E`HXUu~OS9M&i zvo`gwgmerq^Ewt378YU_o}ruVH(Y4>`DbKcUd4&5bkime2cr z*4;=wqjmAJ;j0@{&3$eGtqyZB^<;YCA}3}O9xh5nEUB78vSz|td(IHO)#u(18yOs# z(~|f;9ILNNdzCq&Nj174spDGK%%X)v`%g!?gKTvDEm4mP^Lpa7E<#(bGru=OSM$DCRA8y- zu4r`3K?h-NcW%x(*jB}at>&35U zSN7`tx@0QmHZMsVSXlVOG_s$Gi4`4nu5X7GIKDJ18?L{lHvigX`V!@ccS=p0bR=4u ztL#6!7A#Ou)U6lL;pYYnE9RvKR`LMxg{C?V_WjfopskGxMCkJ?S8Bg(VhC&)E_kn)q8gjp>`F@w2VLQXCf z#u#q6`F5@OT!Uu>{A|Wc%dU{4@$(ZuP3N~z3*zABx-Xtk=t-1B$aK!A^2_ul{AdtZ zAyqvu1s}0{*xK5q77_|e)v&Nw+lz?!Y?hiRwE>PZ9c-b62=>z5f<(U?- zo73K>Cl-H|yJTTO{oon~%OfFM3v`9k7|>*Iq6Z-uO(YQ2Cd+0I+xAmCoxisdXwQ19 z>SPIP!Rfe9{sDmq6$DsDz(lL8d}TbV5BWB_saSed{qMv?-Q&8bb}~^i+Y64LuyY31 z%-ozI)=pTm4t8xKTfU!CC%blq{GR&x?9&{u%dP`FYT@WmhQ>jeRwG4owwf;G zv{B`%+Eg784a)mwYxjV=$yP?M>>{l}b)C%t7Bi1)%9KqF*v;T>tlRVk$fWM2fx1xt z#l;$@&_PjPx&+S}u^f;rRqA!WnEc2;YW1?zZwwcO=2h;-K-lV&$2aaGj;qLFc5Okn zazB~nKz5{DwbBm=$mdqkqL^Y^&7XVcTn30ioeKxq6eJJ0eH`p4bT(r`Y4zJ>tMOMt zg+e^X>aBMcn?f52RIAS2wy!)IwisfiiTR-(_H$y)%MY%KA^9-JUW(2ccBQ>B7e3*t z=f*S7Yw4Mq65Fu&XNfcUEW@hywYa=KH#q*!nuOJOUu-a=5yA|+8U4%vvojp_`!3_W zgD6RB`WCZL4Zpxv$FQbI*ld`kN@Yy^?v!SWmZ;!XsA{ucsC!P&G3K>e)XL6Z_TtPy z?Cqu%9IKT(BU;3}ZMh;%3J>l_Mu{a&U|Gu4520Mx!GRa|~o*sK5V=V?`T3F8b` zyc?XOQT>jX(W?Oc`$N8v0jOjVog=^U6L#%d58(OxCl0}fxwbU@xLZe0K+$_j- zO%WTY97Gz}*5b;ByMu8de@9?fMZP4xJ~{|Bz>JFOH)>brSD&86stts_Oo*(a)kvo1 z5O)aWg#rUF+%7bCd#AnZ&_?z|Nh*?~hevm_J1qQmso}6;VlJ zucvt;)wD5Utk{|})^D)L zPSw*@8wu5qs^u|5!NpY-ch{x2o~~GJXMT|QHtBq*rKZi37j#berQxnW=iX@{#e#W% zWc|uosE$^DErwCOht+&&omKkiE1$ry;J2ufz@GExkDf$AOVbz7RE_4VX=_6cxFCC6 z-K)CxP$E_`q67UBS>lsuMVFBJiljf=Yi2<)-^$I&Mx#p7EGR&aj24g=oM-@HQI-bj>d&YgmcS0JUPgQ@T3=22+@5QLvz1EWkHuBk|7~LnevY0J@WY@!A zcJeK$ksbrfZhJdBYFh?o%#ce1LG~Ca>%!0#vm^ThR^0? z`irbp$&E{Yi`(sCoesJ##;xhDO27`Tu4*Y&zuGm288z4q`5JHwzs8THgMZ;A8L@G2@D!WY|Nc*Xc5Ai>8>a^z_ed)<=)NYZi7B zKVO#dRTiCPPZl1wJzg)Urh{76#3)BFxNjy4s#cPjd~Gx(k!IQV219n_@;*Y$@@dU2 zQKs=`ty>OTv+cqHQDS}i*{2;eU9dk9!c*e8P}ab8z*X2*YjhDX~CrqMdJ%2zS?o$;lmGGuohZ2l$z7png*5mziSG+ z2_RZwmIW>+;7!2dA%n3V0ka?=9335%gX!`^{+7x;bn9;a)R@f~RUbhv_A(|b!2GYhEJK5ofpK1IGA9 zf3R472x}JRGx~SN5^T*^BQiR=$45VgK~suL%Kh`4unU9?wOQzOjmW@WjVkqW#2+BZO^kF?Xp07d zV?K?|UQBzPxo`Ln(f*O=3;E*v8RYuOVxo9a;WIcM=rOjUJ}g{q>shC!_ie8`J6;1X z5@5EvO4gaK_yvEUVvWX30xR-v!FcW~g1f_Yp9a+8gR(nwd$Ga$dn;_bo~;f5j7L$t z3P^cB_RaHEvB~SS@a-$G_Hk(0ja}pL_`05C=BCRbx=zs!I-M-(R z?4$o6W8^O+g}JIS)2}fiykQsXG{`k6c!)_!1+|g#Y|+SWRs*ayhu)@0Qh)mqpnh5~ zlY1{^(UGKs6XOUW3d!Mz>gsK?$bhFw#qS~@Md##>>h0v|mA6T16jy6#<5_4*bgKg_ zyG8aw5{Ki{AkcUb`Jl!xz^?{Zd76m2m8B4tWG$!sj0GYabryM(p@kb@lMC@C!9Kq6 z{vk3@qxFQ?fVCSh;yf~~g=rB_lhEwyrLLN#4K|FsmruIfHj;nKHd5sH?Awz+D|ns$ zLkBl$nX|hVhRi$&NMuY5K>|pfCy77B1kUu-twyvLR0C;E#VpUz!Xmi+gR3UEeMC%D zfko7|a#;1l`S)wVDOmWbQs563ATkF{c-TS_23WT(QcFWBIhUn*-0PJH0P&L$KA|2fDv^i zE@rMFc2o1w@tC}zbO40yPk4{n&QF+pf)*pdhjhA}^W&N?087?b-n;GV*rd}BuryJE zq#64>jrn8NS=~uu=!6n-=(^YK6SAoR{NM4f&JlaAkXG%udt`o~%-~|v`$966LXF&)8TfcNs{+m^e&4@YY;wX-7CG9By{wN!3S&tDmqQNZ zM+=+dvt2!Ts-+WsUo0%&We^~I37hh65?}zau{^I@vA?r~)t%Vh(h=lpp2TW$Q18tg3!K;NHlFW_Wl%%bFPJot^!gRrp1*x-kCDsS==6NZ_d-IZw!58YEsn#=DdHu<>=iJsgg@8Z()u;_jC} zx#Fe`BfHV}7LS1_R`Nm9&<7boQ+Z{AQj-UWx=cT%U+?}g8R8*6VtnOM0)tm$91Q?$ zXFJknpO{lRic%BND9zVxQ4n-B&R^JJJ#ZTbc;pfMx(MD8UMnY!sjHKfiu``$N9GwY z(_+uM7Y+K#-eq!H)@&%~aDR$z%$IH@Z*!UMO8>>Zx#1YKw>y|x>w}p<@4XE4HR#N5 zS-8N>D_fdixPA_cJ;O7wwesS123Tk-fFx|<#N`j`>enWyx*Ym{S9C+J|07gzG3P)g z@j-fp?NKU;#W~Kf1Ji@+AX5sJ>Up&1t8p`UgmdC-20?qm5KlIXAb&YkcPUz`uWP;E zKOI(M1}5|f$Acnp4PcpzA8V})4V-@U_@@qwHPm>y?=7wJUx`q9qy6`F3=oK$?`?Au z0^x0oA~SlC{@AFfruNStVp^%Pm2xJ-s*H}{M+g05oxZ;-S7_pGc3lPi?s(G8ii*D! z%A??_g4ZES>}#j*)DzYUwl4i@g%u?gdl1G1rGo4gE+nByk0QeWZNmp`i)%1BlZ$w9 zO9p^iLe&*_g$c^+&X%dGF9DX1yoMBHa3DRzbOKjC!DE_--imaoP7o~%2+zWeL$E&> z+6?ARlp3G>8i2nZL=@S2|~w=9rgCE!KHyP?3T73yX2Dhtgnr;Xt%Cr^yOp7>IK1rCh$Z<+%J&d zv2&D72R;B@flih573iFNpBQ(7gCjIh|801x7IBy4rq?3Bch9KLBz zuA)#VVY@4?)(-L)k)(c)=?V_0hA6wicdyDEFXQH1tI7|as+S(34!h%#K&9F8_2A$j zvFglc&*z0V)Z1_7Y!O)X7Jr=yD{!}V6I~9~fx;gCruS)fo!x)aP$=1mu%}fj2|vZE zZZ1#k^>8~nu?Gv!t)FH=Y9a{LRC~=kZ<8Mnr|aCmr0Gf`Z4yM^csi=DxHnH8X#a`b z<=Wog-5F*D&A4IX`wq;&r1kCToz~pZ$nF^X!IuT2zqBw=zXBM9$@duv1X$o@fepMx7FFhQH|Ll1!q?R5ng17oXesg6-G98DBj(^v+%Neur zHK%ZeS2)+ahLf-4kj^-)Mb&nW?2jYWs>0W79v976#P)pSCxg4vV}!Huiacg-tWJ<(?!c-2J#w!S2C9oOTeYS(yK%&i6rU zwiqS&iEeanJT`K^;)Hhth1x<`qjCH+=djrlTwQgVac|a+`$N1187pdU*X=xgNe<_( z(UVUPkS_^N{!hxuUHolBaskEj?{iF*1@B@v)(@M2I1kzqwLN|Cw>m_kROS5(y3w?Z zKa5*IqMeK%LPjmvaOxb5<)&@T7D3uM&D>+o3P+AKoA<_D!ww&T3WZD$L>?~_wz0Xr z)`c^%>ygR?eY1AvN!<5AP&{^Y!Q~dQyVv@U5^;2+=mG1vxroXtemM|W{%*XNNLrN& zvOk3qex?kT9IuC;x{Z(uo&q(mydqMyk_|cz7j!z1D@K4qFwBe>Il4ZU(|hk{Z(;sL z^*vqZ#d?-pKPU@r4v!YI%35%Pr`s#fvfum5t9c?guHd`!c@y7Qnqsa~e z4vAm)XKvGP&tOr;jP;q-8M6zAr_Kx4D!JVYs_8Z`Fyh*y@jMtrH4^rdr$TmAqV+u< zl_%s5+2J|Ye_h>+-HfJonZuK1_KsN8XEVJwBIM{_eVM4v@)VRA1Ut|U(~5r; zRXpi~%ig*5pzFaqhqXX0&6NQi*K7J5E%*EG3_q@U9%C!Q70*m>fSLN@)TEXUJolE3chVW>1_v-488A)v~#GnLaVj+P$ul6_58(MtO3xqqxq|Ad~Y$W_3)Nedh7&A4!ibMggt86liwPP{ZLH>N@6RXkn?Ro}OMW zx^O3O))Y)oH+9C{&T@UBh9r`~iQTLd!ak75BD||=lBQGbBiGp<8B?J~FVsSLRybTe zGuG?PHE+@1w6FDLZE|+bGO>9Pf}1C!BO{MJ{7$|uFugqW^!tP9tAJmC8<9Ksj7|$G zfC;FppE;8d%f>KDJ?6p>O)8d7{8=wI5(GBdP+A-nVG6iuzl?^7tcS<++Jw{z|$geR|0iNM^#+YK9_RDj|WiKiI&A3*c|UArqU1%!Dt8b)V@%? zLWS&mq*G(Pg!eJg(Fc->jv^o1m=uwoY^z5H2Nf&hM-wA;puChQuR1b?Lh(l~iEN!^ z5>~x#P-|J)R725egj}kt7BSB7ZnPzoesiepJ7!_gZE(b3=m~N;XA3ahR*&W}0!$YR z4;ee*ty-M?fQVLWrI|tr|9H0NG}AD&^kV#@Bh%rLu%ktv#sCM_Z+LH)x0sL+mNr}H z7oY=AE{u|GC_MPDEI z*G%`+l_KYJnzRqZT%5S_R5JV?`np5EM$w_arX(0f9zUXU8k@?`Wq)lxh|E0bpYhGH zx<*CPLaB~Q=HM<@r(k2sHh+`^+Z7 zz+B)xCB?It@9jsOQj5K~0v(ZsG_EBXJYTgt zh-E4{BhKp}w!l+MfXA&qL+C`P6+hRv1lI7eWp9&=LH=N&={3{nB2&JBOwhC*&Lc^M zYQ{i^E=UnEErBjdg6gjk?dtT|C+L_&3*5W38TmxuZ!%f7|?T{nKUT z*U^5al$48{ZC$rHml|6@OA!Z?H!AvL&xwg759|NsWLi>nFgVKi3*YRxt2*j#@Ii^Y z+j^{sfS~X1?+0KyJBPY7Y(c8>7S|pTn-Q zM=o49_gpB7V!iKC&q~psqxB{on|eRh$i^OdJTzSvQzz?1KzQ=w5th8ShE@A3WSmfo zLIVbW{E@ws30gCl007md0>qu$4|tm=l5Y?F(b^9f+qShmA8cuw_ECZc`*e$8|Vgq9*wBXxuU zyVbm7UMY2dUlBZTOw|qF$F&roA?SS)7euH2JCIKR&hl5x(IF8KXCf48q!Y2~@2oPV z(y%9d{s|qK*gI1tZ1%jr+~D7iq6e*th~ce>Y70pij0525hE+)vycrR93FexcZ{Zk! zQZt3#5%~ny5MZcm`Uu~VPg|=_7f)D)KMlEKyO%98J`L!mk%N)5=J$DDFN;33_(0jW zm^L3+@YSHT49)n49+?06*=epaEz_^;&6y0}A@))u5i<7|i-7v@PdAOg4O9o%PJno3 zz@`8;EV52E00mSg3p7mKDq#ZAbeZHS`iJ^e8gRhmD;)6H0rf*nMD}xQ?|QO?;07a@j&mk3zHn* zeU-(~L^6g{bp^Sw@p*lvo={oLYOVpJ9891`A61>3O#r44t5)$~$eMk3X@xJV51`-4 z31Ak6O5xpA|B4?4%#f;JEpDZ$M!S$p?V~4D&08kkPeahe`JO$Fu%?btw&nv#BtZNS z%igG2BXn*XZ=Li>!h9=XZAewEj~`p8p2x{tJtCN=!D3a*6|oEg#^?r5r^fuR!>_3% zg!MFFoU#oAWGsDrKg|9Y;*Pj+1}TgRn2LZ2HI_0IvZ|@}FuKOenj?s@m#`_- zyb+=$oK~kNpY#n7gZ=TZ!+kh5Z^FH2?+kDIBU=t+_AOjWUJ>73(eI|{=)Abn?7OY2 zrqb4DGzuF#7gpnswcRETK(f?4E_)k94McxdK&+BrDtqXi;{AyEXt4wxZTRUW<`VK@ z%#ORjKF@ZhS|@Y=I^oaSJ%dBdYUWFQvaHa-y_rlLVS;Zap0ZT>2mh3#3db`f*84#zVF_%^E1xf@D4ZC;kSdQ{ ze2%bj#(bE(h|>e*dHv|P>=1Z_@4&&Oxnz`n?{xNg8jW_pTx9z2&~}}5Wv2;Jl>j)s z%Dw>vepf2R%|(Lr1I=NS{zm3PdMI?Jd9;M)M+)+U~U)a`JBg zRw<}hovezGVm`=y&lCE)WuYT-u*JU_($i*v`_Hxewy+q^7zv&0(}0E9Z}iKA_OZZ! ztw>!0g(nXbzuM$nKW`MGWwH(=%FxL*?G>cL?rvTh#Ege$z<+dL5ZI#Q9xYIZ=Ru0f!GE#|kZR5r*o;gsCmBod=S=L!&$xgGAlAc?nAa?dA2?VJ)?@}1 zYz(dqw!M2iwF;wYDYK-S*V^=<26f4AQz;#>Z5Nm&aE{lLx{L zCHODlU$IZVS6c#kB@2W7x;&gzfkepz@@u*7ynVv7Ur(9;(vNxe@$IzmeytKIV|V8* zd-hNWkZ_k-wQ|9?&2zAC-T*21-d!&F^USbb#S$rVcf)RR{z2%O@>5Im z#AM5J!*${(hw=BnM=%F`q-;=uus$N0YCvV^4 z#ZZ6=>E<36`uCVJr793` z(xV-+652wm%_&pwP*p7PP+z<_VCh&H*gLDUHHj1}-z4|p5A%h z(nwvb+bJwRwQ<@fv!*~BFtewcyFX$IYK>C`?}AGaa2NDuaLT7SG3#}-RW{@=e@ z;IF=MhG1Ife-Ip9$~a@eUo%Ka(W-MUoz5P57OKJYUzc$ID>CnY_nJ-H#};ZqXJZe~ z4D6q`tQ>vz4KV#Yx_FGo3%VGpqi(7abiMe@Kxj}>TB$nhGi5V$ zTSgRM8Due5Mh?TOW-F2N3T96hje4a^NM{G0f(g+vF_1v% zh%6G#HStcU<$O{YP}MYy$o{$)atB#FTk?EdS>HpRPZu6*Hay}J1PA>|szZQ*k_Ql| zrgPn`gY^nmn#_g+k#>3?zwZ^z940J&zydw_L=m_E>{-Yw#gq3GIJM#A$x$1Puv`&P zQgQ*_^k=a&R}7$W0j66mn0Ga@qJsUfX)(+pYhiymSqf^UB{h2?$#JC5ZO(+E6=ENC z?J6a%PWDlBzptB`M`6P1uV+sgjpP>a7z&w|4rJi+p(!-Bt|}lVB|mM1_JJ;OG>)jI zR?KXk6)xNg z-(F?aqBfReh*AIw3T_Sx=UNCu5!Ui2D?OpWtD}%7eE>T1EAbguLP z!z!5?5e2yEqoSyEt(7JQjh2i)CZH%nS+XHnT}XP}cUA{u@^6k6OJ`wR9i?-cp3@pe zfb9-Kiza9gWwO-MvhqWVB_*Of*kL~9{$h7IcqKHRzaHL?kIB=jrH1_T971IPHXVZ6 z+Sv(0+WD-fvMxTd_>eqZCri-**_-xBRgU&-U+Sy#2IxT~e%Vx}U@Jnlq89{fU%hc_ z>Y`G=l9WRf(i2K1lf{jJLffZNMFbk9V4N}f+_j?J+#0f%WzF$Z*R7(sKtdg;jqfKm{%MU)}qy7?9K~i)mhTL+!k`02TFC*vVfca9$TiKFYNQ>~(IL z;^iw%71s!3lFgmnoA+sK4SjCT!qG^4kCKyK-5s+|K+gpnK;_RAzmGp^@tOo?!6TB| zMX=IvUMDr9z)KEhjP@C0JgYRV53hxb^^tmL1s%3|Kp%&pXW(H`rF zZu8lYAHJ`jwMDL4J)Uq04GA_^Ogl8U%_##ymD@$-#*#t}5^iB}rAG(Vd=Q5o?}cgr zooo%ihS{2%Ywwr^rfm(dn+oowIZ>|C!pYX#8GXy#9R_kkG$X&OAHjBZ8rHnfcJhT& zDWqE|0t#}JuKd6Pnu`iNHmmn?@M4Z?)apXIC$0*q0NS?#ZXbKp`{*S@y)=<-2gw`+ zHpqO6TXu~k2`#`=&|1etP?tamk}IO3UpND=HX(ZAQ}AUkfIQHd0bh0k0?;x{Jr; z4Ib3|efH3~)giBw1?V0C-5kF?J*fH^Soj23j;5q}P8KcWj7cANMB+#N zr8*up_3P*c1u%f+2ym*2M}ck2f&RO!NM7}Fj-`k`rINKgH-rTO=xJMUh1o!dHN)a0Q|E~ho!EB+z($jPcXW@FGANqNr&w4g+vi*x?Foo8 zF}X-PdG7c)Z;?+tU5ap@l~B6}yjxU@JZ$NZ0k^Ahm==)c0Q$9;KIJ8@Z2%@}U`mg- z(+DCys?mBd$8U4jiTR-p{YYT6V2Ay{_A|9+P(+vFl)d&8q(mQC%xGCTb7ko~ zJI(OXlo@#rm^o#QL=DY6AR(FJi3|}%f#>UXUGMe&{a)Am{MGL-_WONkPQk9#To*cFhIIkq^;kuy9e^iI_MYoTt2V z+-oT$j;&`b_HDz$B(49|1zbFsIP*5p6Mo?PjZ59T2C+WJ2`pvOCv2XHMhLHJix@o z#Kg=Jog-O;o(!RwOT%C=a#E|@@7QFaOLpx^g-|Hm80cI-c%`_w7>+Gs=GUG|%V=;)-cx^6I~rmzG{fH-hhn z^Nd}4KWz2(_T~{HZYZ=`t^Tv891eCUNT1$z#V*pgS;XV!=N9bH=4oX?Rga znICgtTB#P;ewnliB15Bz%6+kzH1iIHLJ?kMlF@O+ZhEzTJ-scc&d+jtCeJqCLhsZy;6&#i zotF;2ma7;m&1U(Y<|`V`p}D8Sv!kP<9J#9`Memf(x4NI~%)}htVc0Mn#ZNW~+LteE5*fhcMRVJ4e|SbY6OP`S9{9!i0x;_6h0K&t0L?hLZ~(r7~fHLyfM^;+7m0 zCOyd-d{j3vhyPNu6`#Tyo`up)!5wkrGW1h3Qkg8*MOe_O4L@Vd785Tap|-U*>b9NA zT9;3~7c$uNZD1DNl$hBOJB&~Hs%N2`kll?KrZ~flW>qF;M(GTOD@}2%Em`jr273QW zGZ&v;wZ9pM#SWQLQXF{p)+U7$r1AwR0Gbj*C6mc2Nn4eG$M?R_u=?1Nrqc$}-gcK@ z#4T51bI|yd9+YjF#VtgwqP@MH&*xVJO4}~=pu_?%BzrSBoeWHG+=`xlBG|NPQ@iBX zaiS@WxCqz17p=>OBNt2MPdCz9J&4Y1og07W5z~C^1|%BQHEz%Di6T-_gY@nAlrMW0 zN)H9acGcW@r&yMYxm;vlYj^#oS$&C-`;6|p~pmA zc`OEst9t1iOE^Kyx;-_~5k%0P1?0-j%~kKhypOVueYK`Q+Q9PON~-1D>}(VpOCy>W z(M*=+If(nc_y>Z8j?Mb)@Fzsp;DWa6Y;}JXA?a6z4)O*dKgNrj5aCd?Sbq?dEX3cA zRFY8^t6h)YidXl&#-L$Fncrw1tWjt#eh+;p)+X(tH^Z@4vAkN%7$F8VU$ny}9?nCx z-KHMNpcmf{S(B2c(;-~3?ycsgQF^;n8mzffX3;QQ(@tOD!;xrH!}SdPv07b3^@@-E zg$O59L04bir~y(_;AzfeGL`O}1tndDN;Q2tFmRshd)KA(=D~t4ub8xjrKP1BX)k~L zLqb9b3g%FMd$ZoDTeGB8hdHMrFNRQ-8(oo50X!A5)VIo-Btf4qnd_bUiIs`9$_1K| zX}Uuc%o=oZb}k;(w5J_?xdC|;D8-;-9Ly*kq!Q?wqYZm_wzy>N@^)`bZ~DYWdpi$U!a)}-_;Jo9I;~~}sMAdUTi`TjvA{(@H}8w6cVItZ)>_=^#Up{$ z_V3OZD~rTaj=n(dL0`CHcfjV~ULQc9X4dG0qovP%L@?=!*V`SLZgRQ&y6ugS8}y5y zVbu9O8kiO^_rWsVhG$7^Y_-jEfZp<6JXZ|V&ui{Sf+uUZ?~ZrrvZG;oyD~*HKM(XS z+Cqs(=68kCw5xYQwL3dYmjitCA&ISl%H1Q%U1|M?+NJYf+gC`f$M-Xr0(>;Hse9j; zem(~I@6Cf#Yh&p9o1$oYm=T6D^jE|DTPNmM_fNP$)8<_Kb3**#IzMCAbQ`8~95@8& zIJjd0wT(I&-Iz+HTJhr!?f}{GxC2TKaLm~PdaE*pqJeSlcgaa0jkG53@;?v=L||7k zSBwaAglDA|8n7!>2`Cs^4tY zoO8p(50TzkCXe#(z88nt75KE78Lnpy&MX)x*=Z5XWzfgKg}VD*20I>VsKzo@ z_y9Dqs07EYUEFXabXK)8wOKsaJ1lKd#G(p4&HKBRVN?hGyMuHNA4IRcX#GJJZ95Wr zaL12s<%=kq`AuU;7#U9@hoWHHT@S&ts*wnz^yzM= z1N^w=i|_)haYrnQOrdCA-W_qu?h1`BoKh<5hqe@WF?cwmDR+tKHs9M>p61!}N#w5L z3(B&7zaBz3Xt|8YnRf=JKxF58<_Px|--S_$J{P%y>Fza0hb{S!hioblMc5i&p=@D^ z*AdivINig8sKDU&3?B?bb+KR-Q&o{o`0ry0MhCiMl6zSh zDJ1Pi*E0zy$!?{2gQp*jmHqrdwGTn#pi6TRD>kVaSLk@Y*d*>71mRVHoW+JXvz4O>EbMxd@jl8`tfm6mI-0R@!(Ake-d%W|^{_FPfPEZiyX$^`4y zYM)+?U|2<)_DBj3jx1?M%geI6vPgQA@)Tp}00}3|NHMF0ZAOWj9P>`>+Mc;dQW1uQ z=04g}UUyuH?qQv8|7+HI>}LtBZ%KYen$<)-6}z>`FMifoqY!*bnP{E7tSB#X5tnfa z$SvX6q2}6Z`Og=dc_}S~#KYNY#uJU=+Y)cSa4LqYO=7cf`($0)s8!AoV!k$q%Z^_| z8`rick(1$NhZ#DuNxl8R*V&owR)KYKFmA2Y&ZdQ9v+kE1@=gTuJ*TV(sOobXlN;)& zol}TD_1=&Y;F5R$fTt8!WyzQRs|Y(zn5e3Z#7&5&1c|-N?|6Il4PtuXlVujS^-D>u zBH1UEYFYJcNq0_m38<=a%DuLhJ9wN@1$f~EC!%0L_^aE40DqCt`od$0ifbicQsf

d35T<%ZLxEI zW+hOnrl`Lw6^D${zou}Bhw}>AcgNltFc0NKFQGW9Y`PN_2B3P2xr18xC-l_;Nd0TGJ=om}tB?WsXgO-TF zlwdgo5U`bm;1p4R!RJV=4nZbmakP#0%v)5^|HM2nLMmwKkMPlvUtvsVO%wTI5{S1S z^HX{6r1t9oW!|}gqcD1aXv^43j}a%yZosFO`VPW9sW8|u%;cRsZlZNb(j_kmxgm{& znnc$ZBEIE5tFIFV>Ovc)EXHiD2YQ}+)}Gh7kdol8pvTt&te0;TANnqkeX9TM0jcRG z@zZ_O7e(^1bbBr>$Axy(KS$X%?(ucm{i*BN{%!_0YoI(SGpIZrwqgZNJ zbs2wFNq$g^?dC2F;zNRaSa;~1{oN}Xt=52F7ZHwcGji&+iv%dHqUrMmhs(zxXuyne~yP z;X(ADUcRngrSfDGn#0ib@b3)O7nHv|pVmhQSgimR1Y>fY?ZBpn7ojZg?yjlJ=D5dL zrm2mSS=*z<4(PUGXTObB_MH~h!*JqZNiI@*in+X%TX5d>Ug~H^cMMerP2>3T>$wM} z(wxz+1C2YtyB&oRb!Du-KK?v4`1Br|W~?&rqUH85OcG#QonIjpzrP>SQL!rq46ym} z>D#c(LyAc4O}YPPN9M>Tn5WB{NGhAlZ7n!)RjR#2+@A#xi(@~wtZo%yoSY2T)5|Ps zvwG)K|4|*z6nBHV#t^%!{viB~HQX0q+hs_Ad|Y*X-1mK4dj7v}e$_Y!?-zouw+%3` Q%Z8kA_4=mv*rlug0an##761SM literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_sign_message_1_0/00000.png b/tests/snapshots/flex/test_sign_message_1_0/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..26f7554552c55bf11bb7bc7888f0ba148e624f85 GIT binary patch literal 10297 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 DX~ish literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_1/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..1ad645a5d37f45aeb52ac499d05a80ab3df06dbc GIT binary patch literal 15167 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_2/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_2/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..684bc40147d8c18359428b5922bb204c067a6a85 GIT binary patch literal 5730 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 U?X7^`vDwi>fd?!1|9ts>0BW=~tN;K2 literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_3/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_3/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..78571a283096b9a72dfa7d06957c2c8c5229cf72 GIT binary patch literal 11723 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 DX~ish literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_sh_wpkh_1to2_0_1/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_sh_wpkh_1to2_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..eb68ef02a99197379de7187265a26384356111b0 GIT binary patch literal 15878 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_sh_wpkh_1to2_1_1/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_sh_wpkh_1to2_1_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..78571a283096b9a72dfa7d06957c2c8c5229cf72 GIT binary patch literal 11723 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 DX~ish literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_0_1/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..feb9222b565fb0afedddb0d6d732115f4e77e060 GIT binary patch literal 14322 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 DX~ish literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_2_0_1/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_2_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..feb9222b565fb0afedddb0d6d732115f4e77e060 GIT binary patch literal 14322 zcmeIZc{Eh<|35w?QMR%aSt>+AWM^y%DN7QvCwt7;jj@-agbA52##&=1gArp=k)^Rk z8H^cZU&c1}^?Q5&zUO;>%OAh<`NV~#>{=)`?|0Dd@Rq$eSP25ko~m4 zX%Gm+Zgl7N0}zN|90X!~#KH)?qtsqt2m+}z7~R%=7@AF^(9#Qx$vEdq7==~ta^HXd zdCVg4`~~Q;C(F6#FD_la!*X~~thAY9q4WBc-^el+-wYtPsCJv@)`~(qPp8KffwS;d4_L8v)t>+>27L7YzUsRy}fN882*D7w7P)2 zu3Ha5%{G(_zM2fhQ+~pT*z(0j2)VTM`K1o*(%O&VXzS{|)1c5`VtO7#-NR<)Lk--& zc`V-f0@JfjPf%#!ne@D}(x+KhS)Pj-rHaj?ud=n!Lhxi7@O`>{+~*SB*99G7pIe$P zwpSli?aF&*wH=Ti7H#xYRC@3K>}%}CGlJyWqT^dGn+$l|01i^gggegJoag8oO{TSF z;<3}Hk1~WDa^2whrQ${PUiu}LgaVe9PY`mq`vAJazBbb?Rm>}E1`dr$(2Q8rO{_sh*D%a5(4&kN+?eJ5M7w#CzUK!dN?i-E?5U;6-j z6fvDOJgjvo*uhu%qTM59y~O1Z4O9SzD*G2Qx~NM~@*oFJ#T|#J`nM29 zEC{j9lYZ3wl5mtnyz|`gE5fse!P6j}s*h!=Adu+UK2RPH13Tz$h0Q4fQZnHJ3u{c& z%7s2~?CG!f@)Az`zo;7}f0*xK%`yeTyt`uWEY&c@yPpJAd85y5xYz9N{Ci0f`{8BM z_vpw7v5+dP^zp$iea#wX1zPPNyrxSww1dycKYdxgU6?(O|m8wN$y2jA_pw9M3Q zyk<|T+jW`Kt%T=9M?}2s0Ywpb@AhE_Kid(PZrE#_oRv(t^Ayzl=d`$Iw0K-(J&JM@ zT_~xJHnl-&LX;RDyIp6ht!Q2S?JH*VH?t+Gx!GR!$O|<7N5=Yx^O@%M$?E-rS((g9 za~@uOUBwfjr_P+*fYuY~qws2JVm{8_(lRn4BBQx?wx$HpgH4m@RD87a2UB0108v}}8E9Tiv`#1}RIe;OuPEs|18Bvi?p%;co^LX+?d$d{2Ab72 zkVa06 z02(ht-Y<0q2U6W3zO>YGP&XC_p*4fXA6?E{Y*bEphwL>Y7U-)Vgj!J)_$I*f ziA5KppcuwTuWV}Zn(^{@M5;sUrHT8E&fGc=|1GLF1^Z&Lfi-`+C4 ze9dnPPQ^h|0RYNq?p|!4ls7uZy$H`Cs&&*0T3QMr42$kwPAH&-kWD7A(kA23db`<* z#!5Pv^Ld`+>3v;=NSI}})JLzUE{za7y8mpm^94SA`3*}@sLH)lwFGg`1(j4WdGWEv z%0n7}Z4O*am>91s)Q66!-Z*E^=MTP2yKbz7*4|SYsE2qM>Xe`Z9MHC?y5K} zlP1csbt{jgVk^k<$D8L57@ANYPmDMcQF1qVSulUl5&(WC6nHj|p^kA7062~747ixE zO{0oQorXmZsftMuxD1hKGLSLXOOHVIds|v!F8Q1{w@mjcx?KOuhv;6zFZJQX*M1dN zlT7o$&aAHWF$ti?V`_G*Oll<)T#bgeBK#NReT2S8HNQV;iQ31!)rf3i@;Hm>7yVq9 z1YAYMJoFy>tgl(@9CSK1^5Z_zB>LhjOzP#G?RedupRSEXQV~s5R03|?*xJj4W`NX@yC7wErfLUg63*3e4b{4A1?UVOo=ZXq;nLsZAB7!KHK!4;5Wqc|Oked6fBOxoM zsUPaq92`g(T>$%PwlNAPUCmCDMdDK4V6HNKW#l{UNhX9BGq(g?V|)H}fEJEbH0eH_ zAsk6z^;z`UEueMwqjO@IKgGN(RdwB7zKq$}`|ynhR#2G?XF?l<;=BvE+e6;6gF;Ki z8Aqt+mLPFH!&sWa-`*e}FLFrDaK~3oVFV^RfxpQpsmnGV;g)musvu$N80F|+Lct3SuvxjKK}j?d~lm+(qw2Go6>9PQ_Pv( zK$U-X%n{#m|G3eq>$kL_xgr+(*WLR4smwiY=2+%S6u#UyxfI=nyOcD~~urM9jg!)hV>o14?W zi-Sa9`yF?Cu&->~`zhDlIj~_Lys{7o&J|{cW+J2bTyAdeJrNrLlYv^8fDIE;d`>kv z9-UN^QfJ>y{$qLn*+rO|rWv;=~L@VAsaOA)_c)T-XF?uyh0Yo#rlri|^*2c^oR z#X4(~PCEA7VxTNWXc6z@)d<{u1AJ1kUu$SLt#D*o_b?SNqk=Y-XecF2M6KM_ayeVm zb-O2DGGUpCv}oCL`v}9>JQRMi)|fk5*SM0Lu|B`VAoJ!UA#;;X4{We^t*yYmYWKKu zLkp~-AJxKBuy&PN#$h{{wr2G%XsK4+{G*-KH4qKyE(N=ES<8j2qql zeXZ^Isp*jtqvLPjxXRn5iRzq0s3{W*KC=(>5Fvp7mSXM*7*1d z;{_1r>Kw7osAebc#GI1}@xTcnGc&>@6v}WAZ7r>AcepMW04@80XAYoMw$G#9&c6!P z%B_)JBq&#vE&z1HBCjQpBR=*J@0Fz;edMEz!b+Ew{-hsFPPQz)nkH*7E{08<+vpqe z8tkU4CA(Nq%t^tU@3X)DHqk&&^F6-z?&o=VQdpKy^{`J@G#N(|lAiWc1?XV=(e@fZ zKnRv*-{l)!{Mmxvrp?fdB(2A1b|3+NU!Ip=3Cro7%}*&bA?d zSJumm6G)j zq)0S8VPZ!2<;+UwSLdbxCeMzKe4Md zPT7g(K4NZas(<=pqPFXzz&3?nI4XTD58Wd`Ikl&DeOQC*3tSEgu!L|pQorjaH@v;7 z9v)}x${gFaA36~uYv3om`YUp&yg}S8>y<+liM~4uanzhCDX%%TVK#fYbW3-VG8?dY z^g{I_dEa|u{K`z$>w#S@qg48?5AZ@-E) zH#Yv*Kwpz%L(fK>@crA|GO^l|gdD+D{8Q^VNQ)d>i(Ik`n(*7lB7Uw)KKCX{IpD9? zn^3B8mvDZk0(B67N)c4N84}zFT9sn)1l>;nsO`u9Y8yxOgU=D|E?i9JJU{%w@c#e_ zufBPzSnoaysQd{!1`u~lz|6+CIIl;P0xv0+=WAXX6QZC`3BjeRKI$6LCqU)FjE#V~ zP=BqL5hQq>38)wlGBZ#v{_jXCe)k(-4ZK4%|4>;M#oQLrH@^_)&JNfu-a}}tmjE4D zVeWgEv89^HF2}S!{8i>v4l5SVw2Z4Ue^o0>?+%7;0H{;KswRve(?Ti{@7#uQkSvTj z&omtB7{u6ED#bk-0GKh5dNS0Q6bzZUrY#&d5!D>+_XN;5^HLmkcNB*`?$$xbVK>!# z125K@^JE4<$v9;rkKH?5OaK97{r>MNCtPV5QP!iebsL7@(OrX=SQZ+4=%c2B?bVr< zWE`q{Cgn9ikU!q*yZXw6kvZC%x9d;jiatTc$OVQ1-%&W|H)KUx1ocRK^4(BcLY$r4@c|YGP8?IuB&Wc1c*k`&cEwug*@YFhXcr-9tDqR zFZAKk%)hM`e))Hg-$8bZoOD8g^u0in$0NlV&1qu(wh?3hIU{?WF`uPTwEL~=6!wO{1C$cjlN9m>rQD2c+_@-f@h_jSn26ut8+!44?LmnH+Me_C@27Vnc0 ztRnnRPK;Qs8Fx9f(h^{|F?tA23cI{4<0S|W7dyi>rP}OYbRW5o0S|6zX zAtT`xAoF|?-4;b>K9{tx-mdu`F2TGCMHa{6DEPydx&vmd^IMRS?97FE3e;mpw7qq1 z5Ny2j%85tc2AS^W#k@GD9HCq&o!Q(i33KNm{Il#H{W}FzglLpe>X73&ro+ckrEpjc%~m5_qc__5dQw$3;rq3-|C#!AKy=U1TFc); zqC-fcPgV{)OfdQhMZWpsx%zS|z?6Kueo_(ClpdU8!~**K`hQNLThZ6rvuO|)7QnOZ zH%T5BdL8Bp9rHkT$6Mv^DVoKl_f`_N8?1o4RAM4)GjVc0kVS3% zskqmhY#s^?Vv6o&I%=xJ{eSH?BDj4PHWX_XTKNm(A>231|uNd~s z()%X4x=(mikrumu@aq3UxjA20-rlb!m&A;k=yLJsPvlayitG3P5L*4qT-z%`xqc!N z$J}P=HnLBaLXt0$BuobQXAi`fHn>ly1HM_!cYk#>nAoTWD3Z49$BT{jvXlWbcOSsW zX9AgiB0ob;;rS)FwNZFy&LN6jC%-34gSnBH=m32Y0_R zoA-$eV&-7iL*VZVcmtj-YFf71Bz|yhFHvVXG2#Bp5}xVed`79J3~-|Z>GcF9C*()3 zZSDgCYNDocDHZ6XeUAo zP-xVuHb-Z66E3!cVyd(*ku_VRr{;a$H1?`fVP|ZY_Q!*d{>yY#Cw!oi6vbx^5J#GZ zf!qBl4Yq}yw>+f(=5ph3l^fI4t#^h6iYPe<_d~ze(Gwb7`%HlZWG*32 zE+e}mheCQ_ep;>5veJ6lMT=9Kap1J@W@j^bnH|)xt!C2~oti^b5(^-YUR1`x`~_Y_Mn!EoZtr%g4c(h}447H}J_u+RxQfX@fn-8~ z-xZ&l;SJg1O7Gp1ZT|K=Kjwn~6E(k(#x)b>f-k1B_bQ7#uD7kI)>Ip%^62}k3T8_cmX=O&U{QGs zm)={CD zky8{BghowyEDO#0&dGT6YkXTc<-GEa61E^u<1oZkY>awEG{iXObL_eEuJ*~at_8Pa zn13E^`>F2u@@pCiwga*%Ld(Nu5Wfz%=}}P}mXx3Cw+0lWj}8E|#{7DeGb%1-!$bx7fQzFGI@$pc96fMQ*I+ANCX$CcHnOWy}PW3OwE$I@#E4IYQ> z4cQg5%ZuKRz9dY#pBl@*d&1@w{h_}qltXIg_k=-wP`vJiJzD_w?(=0_*KN3&b4J}P z^80=7(&g@2`2*hb1Es3ji$P|a-#cty0Zt8Z`lkC`xOLx!hW6PJ|09KmNWYbeo3=BT z-o-sto3dh~y;%$2^4NKcNzg-2uBrYm_W*c_gY0=5TM?;(EM^&uTe{Z+_vO{>UJnau zirb46Ax6Uo{dYTS%TtB!w$~EBcum3FzWD9_>?nQR5Hi}d|Iqg6lHgOH*$orgVR>qy zzjO1a1koL`9?9`NL>YxbL_N|s=fRy17*Ood&z+i|kzI^v-!2x`%klCT41enI5#BtD zgGdzB9KREWuZ4q!(YBl5-uQ(;yzrR+QAH>ihXk{<$kkH5Ok-Wkw(>uYZR%}y(9<98 zq8T8Sj?*#B0FPTw-6~lQvo%W<+nUP`!45-~kek9{vq-Vdrg?1xG7gv**hl&fIo*X3 zaI@hqeam?(D=S``+Wj3uu)x*R``dlEGIf?3>9om!R)1;V3t`Kk&f&dn^ymv~&N-(? zKb(6fS|%=$B|^iJyB94!tF86rTOp_0opLmO&G7rrtPIcIVOVyw<~081t3Sdo0-i5ZtfS}2IXznquLx76=lT{pEFMzR z9m{Xp3UlifRsX`#`dHoLPAN1B!DV&_720OgQl_rG9Sn9rPA9T2HO`Mh9?N~W$UvYs z!{su*@pO;*3l@1vX@qcYCIVp6xf7UCJ-QSyol>=Xsdga4HaR6}_IdOqxn>`#%mNp0 zuHuca(KoFwBY%n9vJx~+b2j5Nh`s@Wf7zt+H^>zf^Z9$C%A7`M^xa%iagv4rij+o8* zgM08dNC}hMr#5<`sp4lg# zwjW1=^P-OqMplbXT_wt0*hj3eMBp7e`Sya^`hL4AFFSKzSh zv-&Ca$nq~|phAB_u3M?Ggl`Ul6Zr$oj)ZR?YjM!R2)0|8`({jJ< z?sgm%;Phz3OzbBOz2irW4`4Q1`BH-ueiyX$x~bxM-GAO5R`I9pmE2QwxfG<~-Dx=j zt*0#BG&JWSSWjcD_of4E@;2=*#LdzhBonCj6$sBX(cMU;&QKr2 z1mN|3TH0Omlgal|KfuE1jk8)ABe8&U;*q}Gh=Qr3w#!C(pw zFj$-~Wa*knv}RtrmZ4VuC#o1?2Z+n^xKjINH^b-eX-rudptUO(-TOzwzk{Gr36Ma= zTRHh#IyW`7mTlw5g1Br$3ZI`%(s@2{!>VFz*jyjQT4Yg0ZN$CIDMc}?mYAd?HnHMuW0X%DVl7KX|PJ_ z0(#DzM{_f0H4(6Le8o&GASSmoi~oK_rJ79ESsMO4vpPn(>nx86JRmCR6bLDTB=vbu z0l#!k#5`d7_t(FT+P^H%qjPVnVGp~z5gF!Q29;l>Dp(H8sEUOXU0=#sYwBW+vV6Vf z@B+KIOPI8=0w0aw>KZ~w^iT1M|LoBF{l@Ozj^c<#hu$J0bG)%EO=pQ@jk+2w`2 z+=A`FgX;lphhbYSAwUy$35%7!xchkin{-7pQNgEHkB}ej>8i;R=j&`0$|kZ_XSz)xxvTz@v4RGiDciIN0JHqbn?&q# zyBotogceM~PYNDxr^?$zrp&-PQ6oE*rYSI}knRJRv?_ z9ASKC@u5Fp<>$NGx!H{Dk0Zg_;o6ek196y?8(QJNb!{H_g>fZ%Q7%XKhMht5D6O~F zWp{3G*V~JfR4y)4H@ve9tf0jLK7kPpN^E-Y&Bw3;3x9CM-r~2v^zChx^ouuKcF)yn zPN#}pOZe-j3W)gZcuGKRWLf>^S)YgXh&@Px8J6nWT9{g5iB7(b=g}@;r$O| zk6*nko;Ffz?-)$jbyluSDPh5x@s1)R1^I8<*BE3}1~dB`-mXOPz9;@D`LtCu)#rEv*5^)!#n+iSU zVq&jc#h=?e`UFcZ)0SC}syK1jbO;_`(=Vck@AD3)l^USy!Mo(ehcQEw##Rezq@$dV z+Jzr3EixJ3O9Z-G1fbjKU9X)}BspQfLR^2mLixSSmvl|{l&;^x(8@N2d+6Eci;5Lq!BXW|F^5KF9^mBJRl!xW8uDgHTT0@H~yn-bLEEy|}Me zV9nrrc)eq=*ZmCQ^aGwB_w{R9 z*$$t*_+~P+6Ju`9;~@Kf`I=^wVlgVIldtko^F2$;w6aL_*_5!^hObXEeoZcUNYr+< z*#16Q8{cIW{&iTnM!9B5MDKEC{AfYGzr=UBAV%ocUo#$kQgmnFBgd-HnQ=I&xgG6D z895C@D5{6pY7!AZe{M{vzhmmpTWg7D&#ma6iKk=5cMO(NGLC)waJl^Q|9O0_uYM9^Y;KHYMWA)ez zZ!|=kx!!qVFG7oatSqA=xq?H}{9F~%Ws6R3+_zpyp=UPl^-6*Q_2Oio#k)VTc07uM zpZjU5@cS0r)!G;C)vsCDX8%cJ^JqXo^u`!RSU};Ve0az~Mo5~qo^bJiL6gE%m{yeI zK_XOx)1|Ij)p)>G1Be{>g^jUymtOorkZ^?gA1N(4f-qiTs)ELxUkB!EDNy_g;iOSV zI+rMYa5}(0d4^i>;y@_id8l#9UF0vUG~QnJJy9PSW5B%8&A}1i_Fe9scpY)NpU@MT z9+P7aO+OFGx%IcB6H^gK7p+-DF|eKGj1C9#R34YX#ZX2r$aaXMzujjeVPgIV-)d-vN>kW`lFH?alMdfhyX$R(>&k^PB z2eQ7-&yIotY~|Arcnw6)_-vgoJYBryPU=3`{-*S<_rYtR*rX_q;FRpDzfO8X^vbA% z=XXxJgKr?gH=TZ;)?^ib+2GTShhAq!`g}U@0lb@;o0IVBsg&Jh48;-2E33|$={k{q0Hk(%>2=nwJd6U(P6LXVzKvV@5@0<`OFTuENGjAp-<(PJKGF@yS1J-HP;18`=c==PfajG1YmoyQ8i;5j zHu+{R9mqb6vsKIX^Aj8;3#0XT4aqn>Ww|$3o72jq<4Rzv7-tnpXasjie}6=*e6OS4 zQYe}5zIZV->0B*uTz*my4&oN+PsRZ|E*kJ!?*j7CxxK*-z%vz?dA71}PN^>*x78;x z?1?V!!y_z%5I6fK{6lo(YVvwSnSe+B77Kz6-AP-r7GD8vAwk zp^!FUC9jeI=Oa9L^`=i`EsnmdGAgz)L<<2<|t3%XL(gn-&lYSX?aI76k<6 z%=wE71xtyYzo`llyHd%QSX>Wd%DGjA5nFGP3nYnH$%HJ-HDZ6n)c*c{K*K0FO`@x) zREqzb4H8J(lIkM;Yld%|zx((22_QAPx=owMR$_nHr8X({^K(A1CFL)i3x4H5rb=<} zy9NX<*$A{()6ecBvnTHJwiD>PySvrR+|Cz%deey0PsUP38XT)aew9{!g7*6z+^>1o z;90g9T79lox{F!&J}KDJ689|2M;HbchIBTPr(J=NY|jl9Z?&skhL!z5ob@AM_Vg<% zHTPRuQbz1Y4Tkv@`mK_IYr=69?_x%>@82Zevs;2>%`_(?5Qyb>1Yi*4-0YAl$ai7$Zr=>E?W(W& z$S5Q&ElFgTH1^W>d&H8VWS`8}(Ma|qzK^>-YkA%7E-ORiS{ve~e>KVD$#s)5Yrs`GHx062@ZEwa7Wd;P1ai#|3 zn%|@EQBChy>D5XXG4CI%+>m_I`zEnXy7pt>>OycInKp<4n)GSnRu?hrvdw>R5E~?B z3>STtdqy;{iTpRRW;o)1dqqXW!{*DoqSzI%&)8{)tUd^jK!7VAHak2ESj^5J9)|S}2m!3sC^S=H|UEKdEP;9fX3sH8&bBx>>_`S8ItapoCkCoQQ?WLf?|4C!{qkJpwnKZZI>45ntF_Qs+ zrU`if2MXBOiw4Da&~ba7i60u5fXc*m08=qUV_pJb8j z2y^=+yDP?iI4{W62NPfji8J5lx`7UFn|9diAdcd{pW0L!TCO)PYRN=Z z(?U>Uon;3PEuJ&4Iy#D@PXO`W-~UA(YTMIpt>HrA7L8g5jVbOrDT>OL*^E<`)L2<= zm^Si`hUAtBBAFFqrf8_-0=Ok80xs+boX6hxFE~G(cYc`Xy0|W`hllTTe?QCp{oMDB z9|FOfO|47~3=B4(K6Ub(fx((_0|UbgCWgSB!;DI>fq`Z7>66F)m02p{j9!_Ht@`Dx ztnT#H4adyZ~R6+ar}Mk%ToWTqQ#3)yUuVSzMV7U2|E|NsAS z0MruV&vGg0nOShj?YMNrh6~3SEOB=ArH8u(q-7R2IIgp*NUQQeuFvgQhci_El58tb zp|Mjt499jGZ&-7jlf4#`Qyn)Xl))Rn-n1S9vE^(@9g+g;$z;vitRprf8_cGEHA956 z$z-yY1&V;dx*O0~EVqQySe;S~ufHI5s1s)I-{wy|kLt`>+e$qGJVL$tAUfnh^k|PP zTf4N>fcn4pCv=mF2VyCyrb#@T=nN zuC1vNX44|r>74b7v03wV5!BK7Eg|$TiFpD?K%V{20!r7uO>*$bRNVIa(^eN9%FCg67AlS-qRl^0x z5s&M@j;rHF2(>jg~KW;pZz#2j!->3K} zc8poRC+a`q2hus1+d$n#huG-~?k9K^r8Ns%BgoYIZEB=LMD&;NhTrwHqM{@NktxC) z*17YLo21;FWw7&~B=*EUBdw54 z<}}BHV(lZktes!^X9N&gk%TlO8qzz@2%|3gW+S3Kbgfz;;niZ)_13rjP{i4ke60_V z34AqA^RahmE65Jd=Qku~BQ(p2_%Zw2S^lL2M8@J?(VqPMh3%Z2G(CuE zDh2i|7fZa`wx{QNd^((}ez&kA*+M`A_D@YpcCoT8!|v@X+Sf#XY@aFCS`IERFZU0Z zYr+b$Q78{}u_tne{_Q{CPrqE{4HQa<-_UC+1$#`IohbFb4q zqS4th9|hxzJ*@_+M=1qow*I&?6elwDDhnLtg>4n+p1a%OHTB+K2y_Y4*A$5#&}1J4 z@}vz1&6v6Z6d>d_W2!2xJ-I@|lrD^(0PTtq-DrRJ&-YQtog(g>&e?e*!cv_P5V#4U z@0q%0^xG3vyJd}y7Zl-5pwm__%*@O2=;G>GtWFU2GFV?)!)CKT2RY`T9UfXcIFV<6 z_>n(_C1Q@Os2yfK7%I>>fS=ywv^Af_xf6q<>dG2Gk!PGO3GK(r+J;^N}d|Ka%Kb|Euu20-s{LwgrilfZd| z=CWAlTkhcl*_uod{lmBlGW=jRJ=53;kjr>YAj0FGTZbzA8XWSnkAwXm?i zq(|-C>x>*S9@MQR;H-#`!scoqZ#fk}JXrne|BFW*_%HS`O|r6=lO78-p^t31V{ zt*68lGcL;uEc~kahXQGzNqkAER03;0^6wofEE#vcKRE}$s{+oAMArnIomrmc{JvRZ z^-E%>{8L(oRqACoO2`M^Pm2$cpE&>^A(A;!)J}I5LLflFvYg*h>a6FT+5k+`6aWQf z$hoL{<4hl}c2{?*ixmVinEWHzHy%NXzY~)5xpL;oOjo!`b5*DA4<%bS;2s zX(?5cK830gQmoVbiLCD44nbW)8IxZ-81G&d3^}}Q)B4&CF+RH^U(yBi_BiTVZ`=Yi+%LHXjKb14H|O&QCK&;akgOdbGP$tnZW>Sys-S3 z=_!_+dej3acz%0_J{Mu+Wn;$ldWp$Q<~Y&cL>>UnHp}>McK(~m*HoT%^Xh?ow~|Rv zXWs{yAf~OY4S{md$+Hx|5x24FOT>#5O8(SU`SD!rT`EZh?{zmwAFhzBro1-Rc#Vk3 zFIS=;={o*FO#5z&K&w_Xg_7BB-Ww#+?x5#prkqTGvOEem`tK~%;dgx?0VOOuO| z&AlrVd&KFMjA(V4SN1P{5D2Gs@~t({8k}d^1=I=slb0;X0G0$m68k&#+210h{-cYZ zH>wq>=3u374`XUecE||I{u@k+dHEx|goxh;1{4paq4Pzb~u5C4Gd_DLzLWMefKHN?UA=H?`8 zZ$6dnLx@$#`e1_Hfh!kp(!Uh&^d8^1Uy|(25H_p(x2WE)lA6DJ%ONmm5ZmQ~A4XQav^!kQ#==De632{Z=&p+=0x1%c7 zL}I9zJ_E(^zr^hNmm8-42J}~yIDcp5@2vbq)%Sl`n!4RLCuK5OE!600lHS7ifYt5x z?87ghfWm%muRJq9Y4G2)8&poNB|T8G;g`kLsyWD!`##J2fMJzV#}>+-b?v}m>Y|Q8x z(aMXTCvrKT8Y>0CXoe117z{_F>A3X6syzS=c?WLI-oaB98_H_F;ygZ z6D)n}FF4+;j0Lj*O$BQUw5Q^IKwe(9O5vsbnOLlDg`SGD|CHz&>QqE1-3~ibHY_Z# z(!xHzsUJ=R;OMjpUXZw0VEzb@XwvMm9~*~PG+-U0j#|-cv!B3}M8X)DTNNI;9TjKz zz@#T}<|euZ1qG#~q*yZB9J>_?MRgo7Ysb1!Ud@$v7D)Dzz=QPWY!i- zwaf^4klQgnsgjcPyYvEmI^b{ML|7J$fo?Lhspu`;LF@1Sw1jL+P6Ai;Pi&~E8BwzU zHEwGG2si*2X*aYM;?{xore}JWwY0R*%(DPhRh@;y=>@nRguB-iPmq5y2?Wf)Dh41_ z=LRQ|5t=Gi1XBNV?sa2e5cTx(5=E5vx%5m;O@U)1;nCiOUDJFf0cF3m%xB7NOZFbj zn2D@sY?5Ft!DlVBS|csS5U5QK2odsNYVn0*w=A0mSQ>f2LZsl@D)RKkne*&)P{-6_ z<`Em$0G2lO;G=udA*+4>FzuFwx@i&a`;xIcyTZ@Mc<)BQzysg`JR*ULv;>2qv_ux| z`@GJHp%WC4EJoSyRFKAB)+i)mOyvG;QcwapxK1s*9paIn{~5SR$=~`t@y2Q7BLdBl8SIlsTPWpJ+|f zBrflRsQFf1Q*B2GVp{t$I=w%{YOS+xhbRnQ+hfSKHe zXPBFtCvA;s93FDG+u%qwr{|@h5Xui78)sNvuSF9n75f_e(*6;eu3Or2RP5M?5e3YT zT#>>XhvN~7JxTcP@V0xvqoUzh@>gS`pSR1?<6NM3gZYzO#W4^FgglJS%9_Prpgxr2 zmykf`N7l!ZN4?vA1^y#ZioccswJ`Dd0u<>&< zGPZ6UDU^Q1o}j|)yv)_FRV(5$<8TXK{VTC9YbQ`78jRjkz^NT9^i2W<{yK9ojtD}E zGcCahE>@e@=Vk;+g~9}VY3rxd;evAj(*RO7)+PS@D5zO=PtgTnq2pLg0%-Km%ja*$ zwRwPs6Ne0>YbA93R^NI>u$|2%n6agatw&3xpO5|QP=@6Gb?q_f(8BV<*No6KkDnT! zG|r^GJE88J6wjW^pZ4OV~*8rKh7XmwC^z$1Xu<@TXAwxfJFtk zHM-w}E#Jp@+5vUP$pefmKo6h@xBFw8!kjc3zxh+NTiX88UD@+t7QSa!E;tpn=;e2u z`?-u(rP8}wWOqx>*KtU_WlU}!LXqq3zK99uFR9hVt=boBOFNf@VPmqm48FViD-os{}9|A2S>K0JQmTo-sE=+!GBRzD-(IZOx&+pru;H>FL zC<-O&Y(=nvn~&`s5IQ0wEGcyUe;5CuNf_R0(-P9T2nHvY;DNuD2p>8RM2Vg}A|5|2 zefQeCQjxN~1HV=Vnk!`zXZ%0UTD;Y{l65clqfN1-{16x%ZLA=5|J@?8Ah$nb2BehPo3I6Z zkX0>$y?D;5g}dH0z8Gcq!Q1r;j>3#}-%Wm)nBoKmFCshHybf>h8mfC!z|Xuaw(R3 zRBW?UQc)kcU3>k}7C07N_$csp!}#KfkEQ+B4L*${o~zjY0wr|&R#2<9P)V`*Rs6$lxUliVo|3k`+Mq_8{c>1-aVD)<%5K;-+oYkKN&I#bR>)qzMUas9g(dtx+Mp&P zKc2h!_*q>dZP=UA7n5FEx#hOP4Z6eIJMi`6%5e4esE~vp1A64*hmzYLb^_rfel$Em zD>kQ8N7v2uzAc$?19JQKA|qekmc45Znj|Ki?)c{1fzW{OT(N>anH&**mAzn>t=0x%fN#n9ck4^BwM7ePg%93fcX zIF6D;HSYa;Wrvx88EnrstVKU@=85yk-x}NWEgbcV>*>|-+irSmHqOJ|Cv3Cu`0}-0 zF*mFIJKA&u#g5rY!weEw-);iGhSq|(I(B*Rn8J}BnDd=eK;!{Y^SlM&+Wdk7MV*!7 zfjhzwb6$xMAa5TZFvHX%Y+^!crK!8_UYna1gAaV&C7d26v1^XXdRATqhxB-BwN88H zXP;bcbIWa3_WE|>Xq&EnaUT;|u#lbUe%c$+XN16<7NzKSZK+jG0p;4(7m)UWtbrP@VcQ{=qXauyKg#k znsw|RUu_=u+f66*!paZid@n=s67R+maYpyLCvz~8A>0g97_X~+Uy>L^9kb9%vH|hn zM+C@jI_Unq-nQaY(Zik7oTOV$em|=$4rdHX_D`KeRqjoCdnXn+Rk`dAE9K_eTM#42 zTw)QT+|)oHTGuK(Gax3p7uh*k{G}c~=M*uh`2nFY9p27L)-531ksJix`~`|AjIVo` z$KVSv7rciC;Kp zRZ3;8#9O$3f>F3dl#`47k5hpfiP!set530xUAGz}BzHeC1(rja<)Qj4u&2fEGP$IA7dDwqaZ|}}4Rcq4{!EEnuq40WZcmI@Z z(oiQg;ZGA0AfO0R*3hJ1*3Llh!Q;K@_SE4X9Ub|gF(Pmz&dRA$xJSf2Gx5yW3Mz|- zYV8^PQ}ny1_g3R_+|6>dDSY7g2Sj}5WCz9z3*@xhw>~%@nf%)(4x}`{V|vY;GTx@s zdl2__txU}PdHK<$ZrD_x|4u@lM*STCSsyj-1wFb<4P}9YUi7P{k6rerOWr*<5}r5TShC$*GEGsKFp^=OR6*|m|zem(; zy*0;C7#pOfuF3E~2tNE_9UI@BQCeAjiMv#Py6tr0j4_^gLoOx4tTJ6KmRJg$5(V^MizsIqdq1EP*OI)oa%dD17c>%A zUoFS@!u{KNeWn}h?7hBHRJm^1kVpFVTu{BHw-=YqYx2(UxNJt>EDwh7JWlE!7*sVf z3QO&01Vcx$RKcmJ1IH# zgO!2+NOpka9OEqmt~nh>Wkoe9lLz_Zo^RzT-28~=SARj*JBK@T#$}ac2B22Y1BqS~ zF7O4^^brzeS|+@aSxm2E){QCtOsns)A|{LULxbe{khmPPKsXH^){y`o?F;cGBEB0d zMQz9TP$1Ym^y_KN=RTSo_>pHjR)DFOu42aGTZ))ff|2b#zV*&Bkh|9=Hr@V0s+9z= zS=QKPY#^#I5b_b>O`@i%8Wo&SAR>I+jVffUOQdf(%K+$2nTf!if9hGgS#L^R$zW&a z1QMn>Tu}S-lg+r`-)D!5@53?sL6lB!Eqt?&G8UB%F+h%KMHEDv+ewZES8on`9=_-r zwz2X$>|j~7avk9Y8)np;+zmNU*wf39_pI)KHuQV^!r_$l8s6&E2v*nQ^LGzR{WIWL zLYQG-3@9yQA1ov99O&2IGY}BvgT~2gwcP?|KZBSGEZk=mWd>A>}GX;~Eej1zD7O%Q;rq;e1X;tRGVdSEWg$7q}>JJSx zOSd;ao9NPojfTru`^%;H8%LZgsCYa}sffL)m19T$B5O)LcXsYc{B(i^4j(>}KMX*C zwYW%EJ7s86`ODzWpz8KOT_0$3JMH|5wn27}Uw`LN#<-uJT3<#Yb=0mdNEjSo+u@d_ z@>zg!w<=|v&J9?ZYj^B{iM7mr5;vjtNE_`uxs3KhhozN%+SHYGLZ9bH?Yp@dCpKQq z^aDlQ0E6+`4Q(q?AN}R#&7uP#N>V#`bm!=q#j`sHi?a%Fyp5y=Vqvh#!iM- z;X*|FIHuQVzxR08kD1{Plk*xPs8fvRNb`DXpLTP1+b?@*T~nYQDC>+ActqzpDT-cP z`KkDZ3yMCh`4@EO_envpBWFA>eYTNX*)i3n-E;*pka{A+pL`>Je2>DmJ3UvIT!PjM zg~OoUSt^2)^&SuMg{=hMG9Q34xOQOJTud;2O4Z1*h%;~sK`{EAN8yYXb3 zmeIWIaMF0tLU4m-q>V!bmBI3!;rHO3*zPNHuToWS`?$LY06*@jXoZ%Yd>Stg8<_WU z)#>oCsk`vNeqr-Ru^D40_txUSfCzD`ojUb3eU`7wp?*&|13UrFsKAq6AN~WW2i?QmP`$WOqevVT=(Ui_3uDV6N>k9y`9;L*1@Sq5a^y-32swhr2?~t|UF*lw!Y25Cd{C4xf%qw+OuQ=~3+60q5U2IAc9Qfqi znD0cmk)CR_%g2?h0_ruBj7Vbza(1O?wV$)&d{wRgmx_Ujj#%qTH;=d&C)~(&s02?5 zZ_?UWh{oV(hi)uL<`*&ZnkT(dP+sK~tbC!$3fjJWRTktCZmVDI#~=1?|NbWtP*`&d zb*+8<&ivfl0u8xIAbe7!N_bqquy#c6{#58WqmGl8F@^KpK2EP7GuCZ zPgyUP6^!Zkj$2iv(HA6FTGtmsIE8@;dhT$&v+C|sqXI<-a{+be2Bystm49BDPRK8%!)71cTKQ8I;20(q+h02{4`@!I< zlY@jhHh**IxL~+elh>TTGjgzRvldTE^XPo@X@l+`C_`xu z&XQC3`_!D?Xsl7vJ~yj#2`bInM24{BwWIoo2QJ_d9%^zCiPdUhNZwA77Me~gnQF=f z&%FCKuu;kKtf=$!6A|)DO2mGMSF44?+yvd^9jW;S?7Ds>p&p^If$x>NQfM(F>V`zT z(OB^Zgb#hH`OEs+~HOcky$o;_S9xRMJ)m;_05!Jnlis!aJX)a=L;Xb4%5RH8$(mv~p>IcnEfD zIVLw#s3PvGM6R^_^*oBI_`90}aeb$nHSZp2aC8qlkxh>sQm45~va}^9+ck9?t*Hp<1UT z!`av=Z^!&{e6Y2_UXQk8T>XZegi=~XvcZn4u|-B4WP)_~zVH013S-)fV9x^ahSn36 zMW?gMS*8?Z-el>lQKpAn3P8aDk$`iXSHG@5#paoE$`f|O2WCFio1*U!-~(9s=Y*X^ zL<&tefg60y4d<2lbA0>Hg9flaaNwLrI;3N2zH8r5s-_XT$rslxn)OOk3+^R-KrH-O zy9ea9d(PNl&o-aiEhA)`jVHH(7M>hLNEq@aaQOamt1P!{L787_shY&Qy6`Y-=Q(wn zitX@q0BTJGP^&crZTb<=O@L}%YY6^jfIEN9_qS2x1&aHuv4f2DMvMbUk{l$BKjgmg zT5Ar)O<=H*R$I)_Sd>{gjWj_C~Dj-Ll+IbXuJmMHLn>3A4klna`Abl=zyr z_|ZT(*lq5P2P4i@KaVZy^{uZH`5Mq{O0R5^hj})AEYvMhUsIKMrdX%MJei& z{M&C^wXIz`jNTQUy%j{GG(IG}MTGpGg?;y!m|1Rce2ohn#q_#6x+q;XKSt`gCHTY1 zA75;n=4b|x0m%i^o8Tozn)-kUwJ5A+#DIz@OqyTSw*wJI=DWE={)F+w_VLA=#vU1M z8^)dqt#hYdq;D#84u7n@a%#NZdOz{n8h;Y;9MCgd+`7NI$|T2DjB~rx(uP07>q<08 z0t}A1Ui{`37@T+N;I=ocs3CRWOKl875DIkYns(ZGzf7|XpbtQF(6e5D`$!we!!ANq z!YVtQVbD5bj8JIzJ?>ZU9;y2mT@SgB;`hEDdV|!O-`l;>yUJ9_6)O~jvhU9r*Rkhm zCwX#uypFNivC9X|lUoLH0Xd$Hd}WV6JM0x^R=Us;ZVLJIhSrB)O5W9x$zfp`4c^!C z>0^DnztY)(T2AaE-Xs)-3#Zdtml|u?M!oZWDalMOgmhOm-x#0)(#|2WQg-{_IC7}h z2Ks4fy2~>2qwjT>A{Vam4_nD*42sV^*@)NcqqcjFiX+7MC zr`>K1V|%`h$#zCl8E5(~ovHreGm}ZxH)ubDC{Cka+jNUQ816$^Ni?Jn1O@dyF2wBO zNzd)Y1yqks4nmj8&WfO3SWI7Owrq}mmVceGFnf#TC&o=rGX0s~8bG=Zb>GG175RB` z)#0ZSU;bcRC#9=Myc_t%x*|PSWLAypzvmAVTUl|b3_6#|S15q9$leP35l?SgZY({W zH>I`at}n_DOVhoB6o`W9>Im>?Tyx$CxvtX-+X=^7G@!!j*q*e8{wUb|!HMv8ugdyx zN}+w$4@@sWe`uJ|-G%4JUQrquK%wcQwW8mMPpEjO#Tt%B_!szfSsvP(Qqse7#m)kP zfnor7ZKN(ee{F*={krh0)$1EeW!?1m-jM8 zih(X5-l#I_-T^z^{fmpYr??=+{Q{$s@?KrDTh9W6k*6P&RvH?X5K@Z{na|LBw(wB$ z7Y2Skb+LdCJ(>&Y%KUk2>>Q0zf{ght@U(-p}bog*XnZKG>z zqt$#Xu9=TU26<;TmcXeSpAIc*&Ob$wG&ETtS@?k6AsH=~4Q}_Y1U=OoCA z0dRV!*EG@3?e#2D-%Z%WMMt#WGc9!JXjCJeIoeFCMegdm{-srr?sZnfCFSRXQ3p`Yt?<&_<6Pq)lvNAS*ejMgJs~PDbJ?(}AWg)HDZ@t(%j8=z;+IL29%jSttWNS|c z7O_}sX11aan}l!;>j~Mc3Ma~)(=!%CsIBXkWQtUOa-tHYYwA(yCG$&FNO-;JyE6>AH79`nm?_PEX<99ogJKA;9M7Q{< zAu9Y7SBFO9B7^Q1iM8^E9g?7596`x$yXOYMk{){oW?GTqAsJy|Q#!%@+rLRD{HSfQ zXlmy5_^}_1L&Z0GrZ=uHrZ>kohHzC+wYrnjR(DCKhZP!pU+iB6N#^fxGjOE)hEBeJ z<^pR?tjn$l3EwYq{+#2`A4ZGAr=P3kt8!Aki0#Usx9FInwRj813YW0`@OwXY`G^c}C$gdd zf^JV8j2q+XJ4L#*C@tzpXo_Y$R|ODWr5KDCN$>h9H!p3)2yzBz&tDGYh&lnU9*nMn zP3Sg3r702NO;>FBg~tP0?RJ;$PB*2HYyG=c2#(WoQSx&^`=rLEtsP5PX{C?dUSwYU zi&6ex#PWZj%l|I^Zy@&{oDJStA_9;jX&;1yh6NPFa~+9xEis|uj1y8qd(slcgi6F= z|9=b z2j>EeP{{3=o}{Y#%PLDzk0f#w?Z&}O;3md-%kIY;9s{=s+$qtcHI#PwoT$g+mQQhZ zu6KZk+wDDo6ns8q2+)PSx2}h8JDPm5SeWd1>9ze)e_0?%dSPHCyMDLX*&c3K2=mH7Cr|IV_v)Z`Jvrt)Al0r zLidgp3t#zVho^k`VrKW>lpt{#1Li>>kvTvl!2Wzxv33si+4fIJ?V2m6Nn=F1j@?mb zHm8{}6I0ag{iM7m{yheLzf?`?z7-h!ck(gM-=wL&9mDwZQ+_cixa=Ykpu;C%fmz?m zLG-lWoMw`WZ7Ch6^7&OZ2id=4&s--6j&a|l&N&+kc zo+iA9_CR{TV1}Rk$Y!xSrrQ^M1{-*Y*a&HC?ewh&G@>sxnEs|KtuZSgRELDW96l}! z%1-->)~PgMCVOZUVL?cJ*TtyyIa1v|F5BQ&((9|u-8~)J6JvpEy&$KXH84S>LGM9U zhx_n?wv3z!0CEFIaWy*PVIHzBazvH-mgP%1oo3180}%(3F&K|O;_74}$B*hNBM zA)^ig&{WatoMljb!e`yd&iaLz<87_b<*9I#FAnw8sXYQ;cg^Qv9xK2wwdW-}d$m!{ zr|=uJWu+*e{b(j;Ag(i)y3I4gmtv`f{jlOELQ-^y$3pw)O0W8+F}9PVi0Ag<`|zD% zXzZ}Lf5?WT6};SWi_<`OVSWKy6cEWWk5)J-VKwRG^e^JB!kfxx&iR_xkrQdp8Q&|) zYG*pBqoXRojFzp}?f?e+2!|mlsDdMa5{?l!xBHs#`6UzQg>nQYCe0=VeQyFG`RShk zY4T%ZVuF-L0P<(exOCl5t}`;N7KM?f0b zU*`O>`up#Tt-KOiRQ7^ujL~~nx~pEUwb=5~Tzs^DfsCGdO6tURiiybU%|}vxdQnH$ z2NID!?iJ^-fmnEGn2y&LkNrq1?QPTM%N>WbyDN}Aoa$Yzm=6lQLH@|PhRh>4kMp5{ zeRZL$ersiyP6 z@JdalsKf1D35ZF^`f#Elv8xbZ%zcIlq0EW zVi9@&-O-GhIu(QVug&%o3oip4%HTb(7_KhAMfx;0H=>XhM#X)fZz~W@6r>m&WH1*~|7myk&;gJimujl}tK##x_S0^PzyTE%7$t+jmQf|^af-!vZH z{P9;Q^o>Jat2cl76WJ+P=bp@%0V)!48DL&4GSx%p6K-p)!?^nQ#OEx`rkR_E?tYsP z#f=HmjR}P&?*eVxs_yF!8+z9(*C+`#o*{js$>j@GK4G+@Oh3ggf;9=YKqI6r1TV!F znG~!JWUKq^H}T(&m0rv7_;w@#F6n7YZNVPz>%6+g?~ax_LXR$}r)x0_B3E(`kV&&= z&>Dbn+@}`W7I05VeMuSdQ?YiG@h6^XXg z6-;ltuST^@!^BL7x0Y>|M@Mp%=M*anZ=EWSHd?N7&!0c#A70w}Iqpl*SXD)16gVd7 z$R}<*%v2q|d9^j^%j_*6Dw9dI#PYMi#5MU)f*Sy9m-YqW+$-6OtGfzgWy4E!zktE4 zU*oa`O%+J!hl%J(>k5)nyV?llIDGEwL`1N7c(a4#MiQ>_Y5)#dM;Tw-U31fhw2%Bw2n?>O(@zY)$Ms~DUsbyLKsv>^62tKHl_8r-oXTY|gQqGtAef`o1UCZVW zY{i}b^|PQo^9bg@S>kiE17hjcuj)eb0z8*N+V(C(>r??=YEYe{VF1(6BAtmo>jbU@ z+dR>cAn5)!z&NU+W)sUL@gKaN|s9~aI?EV?)f;D?z#d%By8oU=BIA1z{T$`w)?5yNd^#2jpemJc>t_pT@
os+~G40nQqzYW#^AgQepd?n$6zB&NCG;0r0m1X*N z0U^Yhn&w=Z&m;u`VCl%GN45e2p$3?VtKdI`;JP;NUZ^`-EF7Q6**$GBx8py@_w^S` z6K5Kub%lhYw<3XZ{jT<*uux^$|Ln(KsQ2&2{AVndN7G6HhZFm%(8J%;wC%5D0en|m z-&x0wEn>zthrYz)fliBkIb$4K#P2yvf(rvS3Nj}KijwReB%bd83tHUfDy?_L;GAXt< z%jw=84t3>`_Qi7n;L}ag_meg_i^vekxl*++O*Qy0f1NU&OX>%$OE5qG`s@bTy4hPX zTY!*&zbtU;E#3MUl`SmC0jx4Y%|k)%aw)6Z?;fcX%mY(4^$$H9W~{H*ul4x(?O7^^ zx|M(#8m;|BFh1uqw~JjJMer6=I9|LXeBb%U-1T@sgzENCPrKebeVaE`5NM82P?ow+ zYX@|x@kLrB_4Omz_t#_ORpDlPKwh6y+FQi5cK#9T3&FOJ+jq~#fGlv7_CA^8w5Nf2 zhu%2LtoQiIBx7_l0w~ROy$O8s!#^a}?*;29IuCQ6TMy2LUfMu%&5?3UfQi9hAf~TAK1y};p zSKBA0YGaGY(+7d+L|Bswg&W1bhaNl5A9%BuJs81KUV3dR4y(Cff4yRU5DW$;n{?k1 zG-1%|P@~dhQ_01hhU`Jt#>N9<#f?Q&)(a{?JPHil6w3o4hBgmf|Em1Mufq5zF4hpq z%Z%YDgaQX}ABDG1a~2E47&d2NWCxs2A7%jBY_-@9ouw~4`orZ0Kr1oJVQ1%x*z39* zmS!0NQVWLsybI1R{EYaPMmE)=ktM03)w|veMEi{F6U2bX7LjXwpOLHoVgvw5R~mF0 zuH`Wj-lNFt1pv&?cdK&SVKn`{qi*V<25ECsz&3VZyDGg_87|f}LnB)=RP@ycTjwjf ziHNW;?B^`8+6syn86F*}Et4X19ob?T5C$Y_a0-4ICa6|R0~}IQ6I}FJ+pJCLR{6#v zwX`Bi5LeS*4me*7&|!Z$VC>QycF*BR?j(*c=-H&ICAJTP`W@ClB>Z+O0bs6-+;fe> zYw5A3><}RRKN7B)v{+hIwts_Vcr@OddC-GMQZjeY3NX<}{Bs=GehahbN?(3o9xh&f zLiYV!#2iG6_@&D0TL5Ub#eT`(Fv1wz~9azo};PiCu@ZPfvci^p?qBHh=T*_63L>-7!+kiv}g}@c8XS ztpIyZ?j!OXk>(ZWIro1L|91%gD=lFx)n0~2whB!jxk`pY$Q(}!`|gpSaEt6pt-V#J zyx!Ek3l`9uwS$loOUo|TB9XZBkv$D+_5@~j<<-1H;j`?J{IotkCCXwXSI zz_TEr5T+uMzR$0FYE_oZdlY#6#tU^~pz`Yt=#%!PM9%_<#`CGwf|`)s#W5&%d)uU1 z<=r)rV6~{=s@BA+wjvojF5I|eOzBKBoT6lWtr2;~xaue`Z*GS8>hw?eE+BN|S^ZoG zDS^_Z*Qp1`(NM4;cM2wsI2IeDQ+nQAk0++V$ zY}XjHdm{Yn5|enAPxn}P(<>|*ns@#R{<92TF;8o+=5u=|Y3!i?hN+^B(~BWqpS-kz z{7i!~Gs4trT!7~Vr!jrUNZCy4_gpL*5RU8{ZCnCKet)aH=>-;@nv!y%7ouN~)MH3s z?ps(&ru6zWIwrMbyU=O zmb%xE2Vz22VY3XjwJvPFT|`TeH@E+xEH^N8Q={Hj#BnEw|q)$#v(<; z^dN6;fWz+Nr|2}&*fjz^!7=~UuGa>Gz}IMN=`T0xLJ(aht$z(g2hrbGxcBb~R?A2m z&^ggoe)q^5A@>d6@5F64K!?AJ)FOF1y6AFXmJn}l{QKN99s?gKhr{Dsez3QXh-6pR zAup+$?(NfaEOs)Fy)GoPr%5`}^}Wu{pDo?R)%K}~X|D3Z8lr>3P$mgFoR<-vy@KJ# z)>fW!s~`Wd$Xj|(L!zsU%44E$5-e?l(EeJC&+NSX(?=w@t1Qq`NkVv>(Ga+HCI8h{ zk=hUqTWY=|pCE@deDmNS$XXj9@J1^X%ZLE6_2V41{{`-ql<)eCLWdvkU zVlTy;V2pis64B=N0;6Ou6oB6OnZ74bqN=>yKdzH&VbVJl)#kr=xK-NRr27nIUS6&&B1I!L$9Iyag; zkPe*k3B-aqFJOVm6v;lV>|=wdQxN!(0_u;d$h#-W>O8Ziw5W0s&$z__*nt4;_)M`=H+O%R^D*u)K@Hh`= zCutyT5WNBOn~9_`STNMUx0TPUW2t!6N3`c1S87M^hm_b73Wag$=D})qP*uqyr9RM` z3LSD+`>oEIuR5C(Ra<*`m*?MoKnyOFgT_uKhvG7W_TG)jd!QKl(Q)pt%d6qo+zJZ} z>b7UR=W<$Ubd51I40p|*f1pBA{#b)sy;ZL7_;AH+Wl}a^7^O?2V*YV4{9={B%WE3X zNuQUnFG6+z*RRy<%wcSk=}^w?w3X%gG!a_nyJ!Xqd4|Bm2kP1jZ>03r#_*q$B0f51 zm#^peT-~~;X4+W9NF-RKnZl64E$cbjw$I-QIsybPXE{e>>mz*f^K}y|KBRp=wo?iM zUg`dgX--8ofb9s%DG0o0!Kx{8I{S!Hm&7lm_{3*1wl%lqc?OP_ADv9;1NMVTrkwTr;+KUMhE;zogj_p%n!vP*$wHQqoh_U$ zYAobx0Y(r08w3y8RGetijXJ=F`*JT8T+moh_!siP|C<01_wtwKYgm!rKCZpwZ2+Kk zT?T^@L2wEiz8jDshg2J4!64*T#`Y4^Xm4M&{XNZdEblL63+u9j>m&UMKz0J+onnt# zcIBz;5k0uoW1%fBcYO8v-zYlNy!hU|f}_5e<3)r^+c-(vlrDJ|*f_PsMw?SsVx3d( z`N;~rZ_e2AN*2AXkT^vK%B^l6O61w23ZqWakVbN|TA!A*vr4iglH%N> zU2aCed|enz1v8kiZqoAuOw;G1N~_!E-5MUE<5BzeVzzCi1Uw5?c8kPAc@mm5Bdko$ zJ4p-N2|e!)uFgEv+SB~o-Xi~R+D0{6fF!VfJrst*(gReZTJ|~L&vyAAwZDeMzQ#qJ zK>f|3wYyWCqGmPLSx;#jxR78(yElV!C(p*IP8gN(;&5rrYh&_6WIK$%ksKDY1qLrB z`hcJ92;4n#zw(q_KKj_RfJ8&kMj&#gTG5qX_JfwIAUy`rn2i$sp6DYb;3qo}{pVKN z^7{lR_W{$?V)B88*%Dc;x}K7=TtGoU{%MXsa1m;M;##< zt~h%zHM5McMCECuO2npG$F7>i*gPLvjO&C3Tq5s(%G~-PqCD7296o;5eYK9qE+6;n zv>~!Asn1)L0Piu|eJrwkXe})=!p7@^R?BR_iJU4P>Ib|sZEl}Vw=2r`u-nZR(jn$8 z+N4HK=SxIdWY4#24GZ54T2tITwdZ^;yF0fO5JxyGS57Bl{y-W;zo)F1r?vHb>NM!m zuL_!AmSv|!`nm0^zvQX@R%)pYIe~ro&9nfNGmc{jVf1O{=W3pQ>Gp2uQ%3mH z1s5{E0LHek9$eCfwXwmBhsEHRP&cBita^ADKDt4})Q6=GPP0?i^`e-r&?^AlCAPHd? zu27gt57XKTq1{`Tn9|LjE>Z2pTYU87T|dpNsz+!Sm><`zi;4tbP4g=aNm>lK#3w$KdIeULuUL<#D#yZ9go7Z zw|nsts>e9wXc+QZ>+ItVsjY?QgaijK-Eh zK}QeR2dv4_iQ|hC3^pfeh(jeZ;NPOh^z`IwlnMh+etvtKFEN;vlun>%Sq7bHCpWRyU_oTEX zuo+lLe<*4zDUy zZov0e&jh-WTjj+X%#w^33=ym>Z}2#*+pQ{XTx)jciIn)64x{WXmeQS$IJQs`_>x=1=YNeQ>R>ChJlamYVELvoVNNR)XfN8~aty{LAj-hoJGaA3r_`kgSv>!Fv0 z7?iX_I<~jK;Le%Lg3~$fs1y6W8p(lvxMHXAPfySa`sjbCIlie%SzC^~KM#NE+NF2& zbB<6F>f5mn;W~|(uib7kAt*`2^~^@OFUCJOwajbPI?C2Eb|-U;e%Wy=azZnH&jVmO zwADGjS-%WQAsC41zrIR7`C@5{!DuY}J~@9}DF}U+57N^j7}2UfqNg8~H@g~#_uHj< zf6xk7m?MsbYrH-k&-#-{yKXS$dAF!C=Ghs9|3N&B0>EnL<;~WV+#>5Qri=n9B7iGQ z?_7;{ukR5w6P^lfg~e&R?s^miaB6~>rhUw=%2OnIt5L(bi=S;}#{$Xvm#EKk9em}9 zj%TXIDQD8Wg1TJB{t>DoS8pdnH3#4BVOf?e`KDZPuqyEX>5Cvl3fPNG) z!Hl_ZYUp9Y8p3#1O4BJ9?120 zzT@3L|L?W|Q0w*rTgT}t-zslz;C;>h=}kRHnJYo|vYAWFj@J0F8=vu%kyzoD#PMk2 zndz{z_4ld<`=%ZEuoirrR9s|k<*6c;ha~pY&`7ja-NXz?Q!CZu6X#jlzRx=LuW`!i zgc!J?r=vf_RDWS|S;qoQUbl!cXw~qAM?v8(=08N_-EYS<;WIPZI72T>Zy94U4QrP4 z%kqgwHw}7jfm;0E)fDREwJWF|U(v-q*qSQLi;{jsl9b+{$8g7`@yXQHZ~R^axgTCD z8L_!@t40?|poCF<#c5iiQhOzO_-!CB)_jnZWM2DxT0VBncxSTV8y;2s>$FE$RLPl- z$W^XPBh;Gd4+)r>u2L5iFB?WW`&PPB3 zDHroqLPL)-O=@;?&jh}1aQDJIK1G_U9lQrMdk441$lW|(pR#*46_qg^dA7a`xwZMA zEWP8;5fR+QCem6fyyO5;LZAhYjKIsZNZ^9uM98bG_<~|Zw|UP?0VOxuNx6ZwSxLGx zUY)i=cns2$xhZH>z7|e0vBLW_`d;sb!yNQ_=QeI`A;e$$+^*j8ES?!%b1dFDt=B$$ z1~W1#aI{?EZ!S7BK3Ugf7}!1BaN=1K`fJv+gaT(z;ZS-GsxY;dTt;m&i$x~jyM-IJ zexTT2_aA^$??!Sj6+7Qv^`oHuJ8M!!C2fDjf)Dad-pRSAj?=(Up^_9fP&5_=hzO0K6PYhCh2HhlbZqN;1ro6Wmk9rYc_+{~S2qJI8RC8}1oyAFSN<#)! z(UBq2HZ`nWX|Qm=DGDYH6CQk%g_(2iNoU~HQ)EQ+fCff?j|Z?s~R{61aRO3x4} z1`pJ25MIzfE$#!DK-}xahB8@Kbw^`$ zE7=XAip+V}bf|Fr9b{)|EA3FrAIW%)vWfJ8PLcHTEnTP35l-J+xza?q0jbe8DK)jW zN^PjR=AW|Q*S}8MjleEAOZUfhf>VJCj-$#*(B_jD3o9){QoJ1VZ?<~9wspOE*1w<4 zmHG2%oT&!hA(`{i&n%u~AMTROoUp0`Z1&0eu!XBgS7TnNRs8|I7?H<`q(e4NYIf*$FsmDw%Ji!< zKoN`pDk-s)UayV(C#1+cdEpw46cBUs#bgtWp<=hO^U^~c=gZ6iaCW8n`1SJ#X=i%R zvX_3#Tho!O+0wyJ%aUvee8lD)yP(a-;q5gIg!M)4MdtFamxLhp2L(nqup)3}w1ou; ze8RllF&){C=6h@VW`@B=Ykbn$8`VB_O=i!GOv!YZ_F2;OOLPhK+v=L%C%b$@Q6sD< z^x3XCed!xz@pkl&2=-yyF>t`L_6X|>n%vvjD6zb-zMPV?lxQXOaA=v@+DOW1?`bDM zH%X5%q&usT93wv1~Pr;*I*b&{?Q zLCT~Ug2s%zz~HG>5^_GkljdSTV1Cfj6RRO44>eD(#v$xiVd~MK`W`;!%SmR}YTOh| z2xbVvJ>TjnQ+Z%M)8}bo}Q9zrJxWP)5ywwK6KnJUu~$tf5#8iDjHZ~ z>Lt9{r%R_s2OGq|N((P{IUNtyDg)om@P4jqR*pZuG2x+mv(~+0hu3UA2ILoPd8MJg zD(|rgFPFqgPN4owBXy2RVighHdIACkM4tm=J7!`~GN-g-Kn zJi%O3dARUxeZ@g?x%6=T1?7*?;X)f5XU25P2jK|iz2eIcpwJEN+q*SsJ0sCVnARhC z;wVc8BOxxI6{Zo>IkTDCSeiUyR)h}^jKjOHyyZXF+ieu*sELP5_J;}SmRzo-P$=V} z`T?8zS*3@I118oJOcnD`3(aM&87>59@C9Fx@Z#ZLGWj{^$L z{o0S!oXQ569Kt$29YE_b#!Yg?vQz_XagwHeot`7>!7X~ST~31M!Tn)qtntSG=&^7k z_{(s0P3+awdaG^hA>@kK7>0TV*WUFoajb)l8~RF`8I5-E!^5?gyBizNjo^ITlN6OH zQ~(?$Q^@1>r$lZ2iGOs;=*yyiS>NJXD7JVUH)wNt3GXYTHZ;-{gzNcG3-fWAne-S` zRlS?SNC#g`uO)#8wSPqbrFVDgQ~;tuyG&m1jYG-n#l%@~d}l$8t=hAIm5bs~nP0jo zQj^oV5cd=sHf4gH<(WCb|MibF&bvUpzBjJ3B<1G>_+rn$*7OTv&baWbQ#*~q=8|MQ z7I?iFVBOAfp&60u8eN3gi&TgQ70(ws`<9x7I&6kLM1RXAM;}0qPmp24ccA}t1vaY? z5*u&P2P9BJsKa4x3%FK?#&c#-u5xT6gx1D|XQ!diFWQx+e{Nay1qrnz?mScZ3^4D2 zp9<zA68wC{H zi6ucdEQ2C8x{RoiEd|V5{#kDPVMcEH!9wppp4nLAg_pUx*MgMUDN1X?zj0}i3U5bW zqG}Q+DvV_Ao&9+ts=sJxVB4gvy<>nB@}lUdY^ERmF6nTP(HqoOzBGLwrh=QUlp9gf z#GD)0Y!JdLgvDLybl0vHg>*Y5c=~?=V+6zt$PJQWO*3MGGCSLVDH?b zOb!Zda8t+_*-q8<^@MP<0T8o}HD*fCm)UtUr2=pWNTp0avX#lg9eC%=h+b=4Id+@A z6ZOelxg6|&#&LA`$?*`gdMolQV&S)+zN~u&@Z#A%D7Y};;l`g^6f(dn{hn~Qr(@l! z%BTH#Xjl^e(DW$f;q_die9KQPx*q8)=u*|`W2)b2q)ObDkUs1xz7e%wVsf_Dt)gA4 z8hzRH0w?(`W0}b>&oevr9C25OXG&}SJ_mTZfvepdoxApSDxgGy zJARpJW}o9K2;5<8moAM%QF;Gh(W81L@zs8^oE~2?R5p{Tk(iwq1^F_)>H*?acZHD8 zlmHoa)U_IuLc3+?3I-PhI7wsT<8OKbHEzd1|Ld6h)WVM^_r0BJGSt{F`fRC#;}3A= z!YIZz$7<$dsf>1$NSujUOL>MfR~B(#))0Y;b=w7>9Ku(F!3PDbqy!|(&J2y{8iT!* z)P|fbMr!voay-Cd+S!#mcCSd4lV54C-ft&Ww`|>DrDM@|j|9(1!b#QbPOP2n9;Lx` zB0l;#h9!vVgcC0IfGREywiZikX;=wnB5D+grUR)zxvS%-3#syT#KQ$ck@UVfA{Je$>Re_cB>=D( z9hFEV5O~;(l(3mqWjEt)K1&I#;XP-(96UOe=-n^~weCcR(T}*R>u_hyT}6NQC}mcp zxI0N34?FxNgJZfyXG~r9u-;tp)Yrl{3#LL*Hr+Oj0YK8D+_?k>hXR~@d(k`YS=(-V z#w<0`DRtxX#|l+=oZvgv;r^qpph4P2pwVRJeb!0(wY5|0%*FzBUy^YN&Su5Bed*Z+ z7OdVhtIvv+;Nh+YxP;wJeHCcZ&s&Bq23n3ZK?HM8jCx>>bGtJDqcIc9R|~2c+aX0> zh5ErU`6^D^Unb{ZPNkUL(CJIQS9yQl0Ip0l-BRhIjZ?TmF~D7VJ42#Ex^LGZt{fD` z3q2)ko^GMGXMEL}(Q+Mwex-)=&`z#DG+#U&8%D+!A<5q4)}HyvQGoGkJCzlQn5@Td zc1E^re*S2s3U>q)+DE)?h>xEO?Uxy0L-(SGAsyBY9 zM2B@JoB4FIL~W&QkaY)aE0$w6NpD=9i*~nRQnE-n;mQWK2kju~y1orP1FlMsJ5`k3 zIO(Ek?#Ie)T$UyW7o3!GXDLTVit#mtk$AUaMF$kj6(3~#ayCxkGbbAUr#{2v#zji} zXv{cj<3ucEIWock+v?*AYBDljMja4q-QC{ULU_Ms<3!VBsw6pPFJ=^A_lrYqi*4P3 z;>>DBA>80GK(?Co2l|H+$Bz!)zYnB@YsB_~7N8v(h-IJmm5qIRiR%Xi62veO?_@GP ztsW{}PUhz7L{}5gJPF!f#HbV5l|Z5fYt}=lTr+8?y_-TA&7-x*om+gHyYfbBH&}n+ zk^&XW@}H(Imnzi{PsR|}-#*ju=GD>!er*RmjSS0V^|FPFYnzNE#$1qz)uki0zq_iw zL+v({BnLxG$FETY77T0!o8%u<43zEt@-bQ!(#Ch)N1){@%+i}I7Tf#kATc!Ud1$LX z!4K>sZBy~&#?`~4+BM%`moztDi??JcOi)F#R#fGiK&^e_Ux&Ge&7$_mwU5-g@pQ>T zK>H8cJYMQBDuz5klu~(XG}nr2+o>*C|JdN^SixB4jS`=gCxK#3ZsZ>{rwxVi1MYgT z7~Hx#$L&W@<3{2^9?c7u_OJ5l(9`P=hrJ-YsHrfjRo$<1N@dC#ly=0=(X%cuARyG; zDt&z)V$&TnqfC11i7~^fv$lEfue!$z9}L{MROZF|^AeyB?UR%HPt?X|W-?~N&{zsu zj}L1h<1FJH7DxNp@Nq0TZw!ixGHesAy8O?$7;dheqqvA=Zwwko7bzEkDdYZ>W83gQCnDyB)^mKK5@MF^dd>)~ztY!S_?`1Qnw_`GPJ*+u zBuZ55yu=RJJno5@1j*G<@ynDq;Hj{$nBmq#3<~3++E8GZhyg4ncH%!0?S7C;^IiJp2EVTcKvv0;n$aqdTfqA^_T1lk6Z9GSWazG+EoEP;6X_bwkQ32fG&vlsz~t0$ZmTWFD^qv z;(twk{qIKr|9?oh!!%{Y8mmM0@}#X=5Sa6ZK3LfV_uA119DdV1{~`1AAJJ6**~dNh zo(1+Y6`FkV?_`WX61}~>S$%#h=^N)P`F{gc&W|_~0u#tr-Z%AlBUFc)(e!G2-s>rU zaaiR}O3uT-(`*~JjZ3_g*l-Jx^dlmHp7szjunQQRSQ_7P?St0KfF_=QJ~iW*U8V#x zf(vQ|V30Lj+Sww@_`rn(5}T{%Sj$+fJmva#uE!7rwAnuj@<}b{>TnKV4QW__Ww)@f zIM8_lcOpjG=E;!0C4_8|`q^TYZx&Jz5H(C*S5yziv*8LQP)ISi9}0;wC}wV%!se`` zfbM#;8k~~1kdQeqVKsR6=cTA&L<%MiQTd6Mcq;n_W}+@u^>54ebS_0}?+Q$)=iZ-( z!23w&$3VF=p2{?h5?^ix&;^n{$>wV9?L@26_WiJu`rTszGpeCAe%AzAZ0Kv=%{IwYD9nr*JRE+-86%mDi-I?|7`>3u)fe)NZ&^R6U&Ri0C~<*Ut)Up zQg3&}!u5dhhu?M>Fq=Z;nMMYd0c8{kb$hMNCyxvTQsXNPXLO|8PZ zBjG~;(@6Qoqau}r|GC;}XiCuC7RH(18C`i5AN#k9Ct!6I3@%-w0Z@<%>o)&UBir<{ z@)S7@-fggGx3K#JE7y$lj^+LJTQz*V{ByZQlcd?sYY$f4{I1>*-QLb;; zy_ba*ocCD^FOZqBq{i5M2f?YxnTS(xnVP*}(!7diwtZ DX~ish literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_2to2_0_1/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_2to2_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..7dbc71631d2fa19a36097a236684a499325138ef GIT binary patch literal 20456 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
t;jmzKd!yRoOIb** z;p9komjKU>&lg3gBIsTX=s4fNY~IdJ&8g0wY)EpU+ySI;^Ftn-q7s06*yN2o>EqpR z_8c?r67ysHj=!R0_{(XSzc=(ZO#Y(s`fq6de}<+B-w@|fg;B+sJ)6Tqq3iOxiQ(%A zL+KtWT@JR#&f>pm;*{eqlP;iD`@XmY!C_VVto&=V>mM*8KUoiQeDDn?wOkGd^nhG0 zAF_vknIqPR0v&A4^iMYfm;Mnj0CdDqs7k3!-&C-93Zc-BBPZsc;L|>t9H#i-n?%6> z0Gd<10t(h)BRZD(mIc;_V);_l43!|&?est2bdF3W%gBP!1Tk}IUE`4UjMF9pTPlr* zLIDG(p&sfwCTIERO$ z7UD=$8V!p=d7{J!7|@dd0!OL>)XK_pnlD|lBkp;m^+WH}5*_*hnU%;mIsgWm-9&DA zU2M5{S1unzOCC^=&PLxY=1LLQ%?1NOf2u@vAF^m8$o1yq9DI~ zs@$Roz~s=g=UlnbZwZKtAcXkq>4NH0cGyWoyr-3gCg{M{wZlem*(n$ER|X8$rJ^Z- z65>Ez6CM%4st%IKWQo$FfC{C?Mm3KTOosq5y=Q4V`u+8>Cs3FyLV79Y6%~Urh=;wRg1OfU|bjz?Le#0f?JHJ~8o# zAO%z#TcuE>d6JWK5{YDHpzv!-+{|0^e3*X6lUqYwQ;T=l;{r8~GL1eSG;RE$ zFNJM)_pAia`?$HZ$82c{pR^_an5JI7128VQk83+GSr>oQJ&(-w_u~wwM(&z|9|(mG z0sT&So#){uFRvtzs*GJy=Gnk%9F9{IVUZ+qy8;pI^Y-y6t));2dEJ-vdjXH`Q9a|* z>%OqlV{W?MWiW#wnA703n(Ae9MG+7>*H*!jpe&j^uRtOj8K4it02=i>1v>}J7#HG| z>{Yso*{`kEuF8M)_-&-?EX=W#<}yA$o)AbG+NRj+t1P_+{|$sd@0!Xmzo6njN^c`K zRn9Kjo92A}HGfB&4mwz)Um@eMXXa0j(cEp7A3yfXp3lcApah5h?ulpm*9R>NK1m>l z&i3|3^u}MMRK2{-^ukvkWbJhY!aW*hW8BzsY&gd8a#LRf<|}&1O6p*E55d|O@I^_- zk@N2}Xyc>)?!eRs1!{*bX86|25f6^1t&c?z2l=l_dvsUIXC^YjjGPCkc40r|;VPoEr*_!p@DZ6m_WA~u3309Roujiem zMIPV>b2oTb1v0LP?TY+7PXaM?b#(SF_7K-U9OO!|x0NO!A6-xnSkNyiF)%$Od|ke1yLeU+8CNHN_Kk|;7t$a_D9yLgA_ zS(f5_%VWqJ_brD)|WcX7?pzD-z{5H5XL-E(Y+r=EkKOJ&{PH^9N_{ zXzv`aeRcV{_8#D5g*dnnn-5x9>?!i2B=+1KRE*d#??0yZL7~tgpe2`Uks$2`8KM%; zWuH$XUu^Ly4JLaaAfdMJVIZBLhmELaqzVb-o+L z+%!b__B!tew#qkYU0^vWRmmo-jlj1T9miDJ=gh6m>sGt{bY<@O?}%wjS^hhaD_}xP zZDGf%>?_sy#8-uAR%M` literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_2to2_0_3/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_2to2_0_3/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..78571a283096b9a72dfa7d06957c2c8c5229cf72 GIT binary patch literal 11723 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 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_1/00000.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_1/00000.png index 1b793845c470db158e15747666dd71a33b0782e6..55a58f0da3ec93dddfae520e47b5b69de5eae052 100644 GIT binary patch literal 9667 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 literal 13161 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 VyH|PRfRE7dfDFy=pl`eV{a>X>YK8y+ diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_1/00001.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_1/00001.png index 746852babe56dd942b18f9e440877cf9bdfd83f6..24a035249be4145e1a01d7846ac512bb87e87028 100644 GIT binary patch literal 13287 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 D7d^Gx literal 7127 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 J;tA-@{{rt_E?fWr diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_1/00002.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/0'_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..dac6211874f0cad55d682f35a6489c30d93ab422 GIT binary patch literal 7126 zcmeHMeLR!v|3?p;gzALyc&bwr(a}O4D@PBAig}u$P6&BO9*6BjrB1OEhhbRdDVv#S zmWQ^+k=B}>XqK3H8qLC(VIF^1=lu2i@B7E^`+A)}e)m7ucHh^1-Ph;7uFw1Pe!uVg z7hKP%Y|+{xCnu+J?(EN(zlv3fg(QVO6mK${xROL_o3Vv==xE*-v#GYDBvO8gW{+otvDT_sf$gO85B45Gx zZ&?g)^vgP3sxUaUii1tdy)NIVtmIJp>yiIrv!vP+fLi59G;U>l2(P_FgeWhTtfiH^ zzgCm(tPUosW;obuZ_;zor(ZI9{Joc2p07N-F|zjKmM?#)r zqg7A|YY)}@2=|;Bo$KnBPm{%gl?-T{O)Fy1SKfjvP$EciFv>cYq5oH}lF{%5oqOf= z+k1wh6BmPR2MpQUw>x9pTRrPny5*ZVGmZ6^q6X`62E@jkKZU){_kP}~;Q*8I6~qBr!wBU+hFybIm& z&2VE4$BXaBC87v{9c6$PTRSqd*kj!q_3=h+k4So>_P3{rD3mEP#;joL=JZI)r~WVT z%|tw2GR|)3n+!Z+$ecX@o9<<#^Csg((j_g_{pkBy>A4xeB?-mZF$WziK8F zf43n*7n!?e(&Tm^=VR5v!UB7$p7(7~##g=Ta<}({9LQmaMB!Gqu<6xJ zHJT3`B`!wH7#lqc)5l-qn<*3uq^N)uEc{s)-O)C5WZf`e9+{j>5Lp@238hkUjcDvW zB%jABA5mt7pl#9%N_4e@xV4TKTmczPi#n3dCL%=~ceV}JR|ClGIwB-(Oi5(fmgK|sHlHfMgT_=*4US(f@R?ed(hDm+;oPXGDB+GMC^&M13S8TB((iZ> z>WpFBbTp;Tp9G^+-XzQLg6rna`^b=s=e_t{J(AL{ECEYUY;!YT_!um#=y7m;FGD`K z>E`E*k6BVgYOvww?66$5J-VTiZC3W5UbL}r=FW;sTNgJksNnRqvyg{_n_K{O4kS#D{jnIcVZ+?(j&Fvq#=f@dy z6fK}sGTM3`>>#E)$@`MHn3fZdRO^oyxdio3#>=)f*?t<)bwveW-k%;ah&ikOi^NJpVPUtE4O2UtQlk|oP!pMx}{!dclnu#|?Ja@FKD=EtW?RXJv zU1d%Aa!GA(vyJ}sl0G8eJk{DeMDQ+dOvAsCMTHFhjLB!{Nd8HpYOsGky z{R`dqu-4ZAY><{WSQP@^iAe?<$so)pkL6O$71?}!M=C7uLz^B=g(9|3F3#sLrsz;L zjU@oJvqlNW-DEAV-h5}Hl{vuYcWbzHDt2dLsuP#8k797$nLNF(AtU4$#FYE1PKwH@ z6Vp$V5tA*~icZP62JA_jy^Htp_=%>@UaR9-)_RJo;&(Fz=}yjsPSViQ-4S(|O#N<8 zgO$Da7k7QSQlS{~fln;Fc3&p@o4GMjAjKI$-J!RF3Y*Kl`X$!BR!LF5T0upA zX@3k9QQ!mu}1k;-{6r%&UwTszv_kW@cD1Sk3*VuM9Q2w&g zf7~o47Ob11Hub2{@Z)+73Ti@=G|tMUJZ0MMA!jvqf~90M4sLI6ujzO(PteiP!B{RM zSh42Go$4J8L$<|+9&K#?rlXg-NiSBxpItITq^XzPG$<#NE65_|W)w#LYm2wG# z`S-z2kUQ0UqZa9X%XM$|sIxQiKIgi5G6FF%f&JOO&*|b$Hk-|2@UEKqm|$3>>{JwL zTAaA2OxyK4SbgK@?7<;{+WJV@!2s7VUS&Zp9$yIi8f}!(_GEVj<7(H+2P7?O>J5m@ zi=wPH61=Z^G9DXplgM3b||EW?ZJ7P0MO z87$A(TlS|mx&sFfr4F>gI*pG#!%vKilpa@@NHJoGJPk&ycWs^h2^s%L8JXUKX6p>1o+VxCzGAex-igg|;Xo*G666Z(3}+_QJzX>M99Y^`(!Qq6ZF3&>x#OS@jTT-oRE|(iSpb8$@GBw|pf%}-k^fz!z zY$LvI6PbD^kj00>si(M{o5)b3)6nR~wX|H*JaorM)W@L=wRIQj-gu6(w`OGdaodeq zfZ^F-mj~We>D#Rw1##I=N>5vjQ@UCNE7lsOKC5zQB05MV4nE%N=aVOkF!YfGkwDRl zJ(bll5^J_D9t!Da7|f?O_&*V}a@53c5s4B>aJ}qJR)jg$RS$XEuEU#ST3jgsPHoO#e~J;&jn_hwi{aYd(|k_@tdI#^AzQ%HZYxcFcwTKjDY3?aDk|`oU186p*3ywFO%2 z`dCPey5n;{6Jp=6#rM@B>X&$#XC5<1QlF1D4L*M$htQxt#W#KR1!;ikgPCJlAnE)y zU{FpNc_KR1eq)^GzG^%kkY$|O`anvwjUGz)eI50AF2uqm{Jf}1Z|i0#v|#h87)|;_ zKuI(_?zVK2=qD}R_d^Zea(|2L%sV;0MEi_)9K2F=(rfkhU1Wm-?Ogy<&=u}>LWy?6 zNonK$e>+kA*E8w=pWwe=?fm~5{ok(@uwS!w&B(NR-}VF}xftJ0F=?R%SU)Rt{| z`ZD7>FGe@d_oOAoHX`b1YxbdgqPq@6?T5e?(0hH}b(9L60r8O~`{HDkJYRacP*yf& z>K(R8t%~j5TnUTAGe%e7w31cpe>4&yeXMM2F@`F+MeJe*1oO5C)Qd+rwCV5d9i zW-SVJo#}zM|55kw&CHbF*?$Cqz?pULDWH<$@sTf`=SusG``b0EVpQ6OYVr8~d%Q>s zENh9MS!X;hkwsg&(BLF4;5ThU(PUpx8oZ7D0|J)$Mo)cBFd13>OBWVVo73rGWGh($ z1jkMu$mvmaIgsc4G}+N{2DjXHJ{FqaHuQrxI@nTYYGL^(>U`+6ZZzX+HpN;8 z)bAl6!+(2f%tWKnpswkmllyi@mJ?caHj3zAl756$qz4qcSKbk4h5kIn&Ps{cuI8z%qTC+L<^Gl11mL;Ujj*+=;VXSXn zkVxO{W+}_ky!?e=9MHQCc7GA40clm>g2#t-CP}V6KYqJ^df@;zK@fgSR^;`a{uw(* zQIkK3YcPEj%j!Zm^hHns0T;ydYV9xgS^(u%B9SmEt*HJ~Ut&o~Ng;bhr79h#GV`v^ zkLbz50ZPG(^n!A(LEc$Z(1BU7{FQy{*~41B(|T7@q&uKZYpIqx=GgPTTOXZ)WVBtj zDjrKVkFsB})+%(Zl;zo6aZ)DDK08dj{??)P=)UTd=C$0$CCC)TElef#u$!nn(cRpwz*2da} zHuFjfI*43RQw=tubGf_4ZK+*gs=Mt@plw$0NfXS`gp|pHUW3U8S4t#jK2)pIeg_v) z@Te+N*22`vj9oM=O=>y2txAUQVFH3p^dxW&1$Z?5c$2T)d~$rF=*FnXTIjf%vv4k) z4_-$NEbGGzf~jLiA9hvhabRe6c8tt0%AW|WVsAe2q+Z}Op(Ndb)xrN<6`gwUG~cyy zc@=4gV~y_+8!gnznZj@*`)TK%y^&81d9H($&PxiXb5* zG8-a7f9qyq!ZV;3W@o#!etOl?QkFaQP5;4axFWz1_2RLL@n0f~E4KG+K%}OoB9W2M zsv1%Il^M4Ex(<69(5~)ochNjA5>qlh(X5P-%$T7Mr#8G7I2+QILRG|P;Ob+8lGal`aSFzAE1ycj;Ts-^c}j z=%xwfO1mxtI57hEiNoR3a~9ynmse`H)(vVlP25NEw&w-YNimb|1AlB&8kwM*z5N@5 zUZKC8Zxf9}rbC^c`G{X5tm(_mcguamzc1O4lV5$Q@ev0i?5dWLxfkjOFVCT@_<=s@ z!SoF;8Tb2pE$mU}tUUNTRkrh@-``-~DZT5vtuw-{510gI4u|gz>z&?Zq3XF87R{d8 z17*NB8a+Dv(qbV8Kbn=6`&OerJ=qx=lR$Tx)z6DLiJPi-?=9YJ6uvqm)QlB%Dsy6{ z>0$S!8OpKDZ$SB<3(fza=L&ph`||QKF=4|Xd(GsxD-bOn!a{ECJ$N_&W&inqTia_? zsp?+@DdH6`GNBp16ycMX!x(L7o^xpCMZWU?TM7fKMLHD?Pm{v_-hSDgli!TEnM4~L zJF3php5jjm2ncxa6fpcWso3Q^)Ey~e_1muF9`Z5P0Q=W=dPhonpe+^BfEP6x{svTF zv8xw>gQNuzJ%J6yGeEl!mK5x;qk>WW2mqYvfxk!Uf5YoqVI0TFuzjg3l@5?J>0m{7 zs1**_tRV{k6S{?v^Xih!q=v-m-I(B7*MX$^UI>NUd)-buiTs;nW@e`MTU8p--B!&% zQLE=S)tP8RUAc&5RTNaNBG+eT9^vr4)E?%89L80$@39fi#Mv6C5AaH2>U&4aG}d*e z$LYLlkk8l6_4V~x5rT#-J*2(fY9?M4$9UFJ^}S$hV3QVh3!Kj;^?!W$7Sugzh-7|5 zn^||=E`kaWyCE_($Pn`aIL`~Cdm6v24bEzPFa=@9Nhi?20lHZOTncnRdh!@8j!JXnI)ioKpZ*;{Tpb=0(EjzQ!6t&Ctkv6OZzY6ls{2+I!edy@1ZYt~}2N zrm{XKZgpj)h)W+=FB9es(@OK3YEYIZnS>Lt=6~pgq_*aoUso8f-tf1|%1RKy3oBee zN8MfiW7$uDYy{fq0U_TLq7CsnGJ5j7|I^0a>xKJ@M}ky32wP^0u@?SRRU>{r_cACJ zW5d<46hTY@I@}IN>8Y9x+$f@0*2knC*_ASX7u&;&F{SEOGrgKDG)WB}Pyqkky!qu+ z$zBY{8_oJdOvz`D6FB%|c&Ab#NP(V7AZH8rJj3I2L_WeKS1RTRI(OC<%`fua*?!fm z_qur!A51W&@%{eQfu^HRzkSEjTgMJQFDG1tLRV+n)VdrA&UT0)Z7M)_ug@w9+l_zN n>VE2nt@OXq{J-2R(hByLZnIpTaRA@zBdSW@HMeh?q*|1yQ_}h`h(`Iscu{`8>bp_kEt{`#DvRk^dI#4m02D zf5I;~^N~vaK76=;{q6HyQNp^jLxtBJ4>|64y!LGj_!OA43|$S*7MPbAs>wc(48_r7 zCXeU%5v_3rwj0nt{JL!h+YoV%-fevyHVE)=8`mwH*Etw4*HgY)KMu4~V;hWRS;Z2s&^r^yXh|x9|-mApl59W!$Z^!T(6SP2~h;<{%mH&shg7gic zGSn0aRIS`dy3hoB+;qirbB|Un6XU zhbQs70RFHcR#q1JC^x3-iGKT&Kflkts$6F&UtONI7!qk_XAeBHT17dG#cj#kz(ZFF zK3EuUvOK5I7^8Vg_`;9l6;zYXquTu5q>Zsi-3p7NZ(S|(+Q}W%`lhC)*~|gJ1(KG} z??-!b1l1)aC5Dq7zCJz-=_D5hz7xatP+liivjr)~q?vEIz+j72{;9doEy)fu0(QGA zgMF^95A9i`Th(ble2C-7c`YqIK0Y=!tD3b4Ft z0`~_1kMBuM^e(ou;bdey&L)>@U5jFolNGSy0L9>7$JpX@|1`n6iXA7=hGOpRA`6m| zlIT|NzE{-DX8KHd)3~*S>DS9xF%?KtD?8)r0!!_@rj%eI0M9gA&{4y zVG_lZ+PYm8iA1(_@iV=e1WB*C6K$tjt(F@PfhY&#+xRcB90RNUm!zl$?@ZnD=6vm? z-h5Rmyu=BSYhR2kA9%uM$B43TzSE(XRXuttr1|oZ| zI~d#F;ldk9e{AKfU5?uo&Xi6ruz&b;$vs?O#rWvr{wAUS9{@In}?ghpF}ZZ(~@ z0PaV|aww%yQ_~itU6FQM6L7YmUm47xP)1{&qEGTj9jHhcS9k>Vyufq81FyD= zCcLz_vkOQ;Y6mE`T^06!HQF@g+qS$Ad{?vudx2jWAA;<^SBFvu*LWG5zLCoNQvY5f zhb=3u!8HFExVOo)L&%|PL7fAM8Ac`vLC~-x#Pdj^DQ~UxRKu$?o9#U?`+CziRuQjT z)7r)don2@V9JgONQm1&)0VM1$JzU0cmA0s|5J}pB6}=x@H2v3B>vz9nn5+SN7dP04 zcDoh`?9Da?-x)tz-y9Q`7I8eQJY)o;nYeRm!Dun18Qt=G5b;l-UiC3SrWE{)VZ0v{ z3O!;bDb`0Mv2}etT@O3s#IO568-V+6W@gqsUa#%BX>i>8@3A>lf>8M<{=~%T%Gyz6 zB3k7P|6*s$3;J)K)G@2v5Z`zCX3wM^+J%LN16{%d=>hp9oN|w}OZMyqcm$oV(-8#b zdzDEKMPp(h!Ou%y@^!Ey&c`l{{)OuPmFESf;8B|;adl4Wx#co?`#Vx|Z3ELpGGqZ2 z*Ejn}Q_8hiPBp}@A^q+5w2sVfq6D`T1yjJ`PY<+$9lu!Ht9z{O?(P=RVBnNyG;IL^ zd)SdD&xpq!OY~1Yakzab<}=9L^k%(7H}FA}>>7!@{Dd0F%OKQDz zn)nwUN)wHRBv(>|Lg{BvaD~R`XcG<)xY9|cIs4xt5AuX3aIE%6xXHj7q1jbzPHxQsdnnr}d%(9elrO1H|!pQhDn z{i;^YEyXq+H#QkBC7!r1ysSH;B0Mls^s3!6Z;5;{ITv1LAr_qVe6knS*s5bLx4LhepppFKiXDmn49Kw(dFv@;1eI7KPA$ zy}B}ZYGVftlyuw0+K6h)ypvg3BdH!6ZqIiiMD2oPaA#Yc5xHTRONpO*3OT_5)t;d_ z57R7T)ZQSyrKP3mJ`Xfn6ho*7aQ+zerf#{qRHb7-FgR|C!aKd-A3i+PPDFw(xu$&J zl<~_x{mxJVqHN6HS2=*P*@Iw8!SZVL?!^I|R-@5RwS-`WH!FiEimL-tbJc+%kPwxx zExr~prPFA@oZq5WZnWl-dsx=m{C^w$NG3+5kB(=BJypRIN^od) delta 3140 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 OCpakd2>oz;!T$hx@V%n| diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_0/00000.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_0/00000.png index 00c634ffe88af03190fd5e8f27080725368bf29a..538f3218042a9c109feb262a20e2e64009b25057 100644 GIT binary patch literal 8810 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 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_1/00000.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_1/00000.png index 5f744aa0331b32f874184a5495c4c3697b280778..55a58f0da3ec93dddfae520e47b5b69de5eae052 100644 GIT binary patch literal 9667 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 literal 13088 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 bJ%n^@z4q>7pB3=s3!9;y>D{tB&f)(9{b41a diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_1/00001.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_1/00001.png index f82843b86d59ccc8753f0d1c4c13a3cf5d67d832..c6220afd09be1fb01959001d0a7c4d5a20173026 100644 GIT binary patch literal 13213 zcmeHuX*`tu-?oaVEG0?S5>dud30bd->_o=cmxPe98#@uM2-%BJ$TEzvk1+=2LQG7I zC1ycrFpR>O(D0o8pZmrAd0srP?*IRJbDuB#=5x;JcmDS8@jZ@XUOX_<=Q$~Sl8udx z$Iw96l8x=iD>k;H@3@Wvcht>0YS`FrJ~q_7V-@yxjZAw3H_1tIji^&R63P|KC3IBm zXj0szCtSkuN$)NhaPh}Kzj$fuk4@9$m;$e4eESwUHbl;I?gLzQ)~9Qx(o2}F8@E^D zsmR8*rRQ=)DWUtQ%kgI%-P}h{#a&<*WV^`)V)Hm{!}jH3J=^O$|ML%I@YW)cNKX8j zZerLI7el*DTehTd2bau;Z1k;n-GPJ^CX;#nCdW??@iR8%=i)3(#1D%G6OqH>jH%FJ z5ny`muoyArKP;~PQQZ}oQA2=2rD^*oD1K?Y$vr)Jk3n7q+L33z2%(=d`n))1m-|4j z;gz%iJmnvWxDg{8LAmp6PcI;zGxqlOw%;&fK6EhcFHa{>h_AtS6`LsQE^I#?E~~a< zE-|(_6xjGwVst<^PIc>ESynUhIP&_F73#+;TekbEb3^#Yf9c*8LplMy*|UTo$FY5BdPW$qVAG#mHk5@bBvn(cUGu*;Edm;b=P z|9fBY^59C*E);bt{-P;CiQ7-O0S@n(JI#J4&wZYkySwhhF`B>HLby2l9WWTTxKR;+ zYy7g=;rWHEti*=7Qp+!>H^(}{#(b?*KiJ3}|JO-vU{LpfSsslzr)QBRb?3B!$irkf zJf(E$jgKmi=pV#QYcTl0sDki2S2eLzRw{m7g1cMkVT-F_LAjT3|F1d!CAB16BWW#^ z&SsePPe2sD+ugR#x<-jRAGheyl&Lw`Xfk?}D;^FH#T1EzTL`$@3hHI5Ru6g1OS@%B zF(z2W2}j!crJjKgFIOR>99;{myu~?x1HzbyWtKEoyb`xGNZsh3Di25s(IEtfd$-sP z@DD=3;DLYgaUVoth41aUS_lM6f8;4UtcoD@>;vP@j%vD_VP1rbuZqZpZtP1NMFh8y z8rRVm<*XRz5;HKE5*&(gET&?}Pz-rc#ZQ$hsU^rXY|X?n`Mjj{T%rFR7M1r`KQu>OhwJV$4V8E1fT_-66;}pHd+$%=hhR6%1!r`OJzJ)Ge z@F+i0EJs)a2?6Iyz0kaV9}_@PuBQ~tr_&YgyO}fJO;~D|;1~H`Oltr$TM3*?Sz^x! z&dp{T_r1cUQc4*S@>(hk?FA`AVT>Y4**{r{dy*C++OJ;J2wJ=^sp#BFM1&5Hrp6g& zaf@(w7XgPHxko%5<3O#fFuZKJ~zJI%V-x*=8 zqocDc2sO9O13n~BDZbhzC{wg-%KG}cy|Jp`S}10H-ETc{PSGq6?OQUn7TPrR^smMF zD^@2&+Bm=LL~Wn^X(_jLKNHqCIHTGUIzH17swTR%KICy$&qCjN!da50@W-R+MEpCa zx3&oDja-EU6McAcyCj6F-R<2ndhX@Cn(4#vo6utF?hYQ0UknU~rn;7(Hror^*Brws z!6cRx*HN#au%BrE*P3{;U=|4XT`j%TV3^)$sb}%$&!4wul_&BOuDKRUu{x@(;V z;l?$N71aln1VB7Tg;}4$cggrt*(?KXQC>ZZ9QUgwVbY!~6|Q(?Q`(}p*0(GvFP}BJ zl)EU4`MS&JZ!N@I2_-cOF@%%31=Z|3WKWXcd{^t-Ed6HM2qN%@+2)~!?NVuXRznMvFm#3joqe-LFwY( zR0wM6?tA9Mm$#s~4ORuD}RgK^cAf@JiBQ65ZOp@ zWYRmiZUB!rv+ir@Pd@mmVoaoJg$Ma*I?Ss~zDl%!aIKy4zB1WxxJQ$%efXZg+UKk-r}xQ$xbgYC z)!@otd{0jpPXk;wW$LN5;=2!C?G6e+Fddh)In9ooGGz`A&YJ$%438FBsUW}&i>!k? zvTBu6RMT&j;MYkPNU3H_6Kcu}Bbz`gDZ|E@b@R$>CMIHr&Wu!Ld zP$ITjEGWO^iYa0KSD1QHdVg8u^XIN%gq+x-lG@G*MaxftWv#yXOSknMZDBHF%eYpa zo(ICpC?Z187?Z&Tqf_dZ#N8vd#4_}!f}#2I_Qp2!hET%asDf+tD|>J4r}@0Aw`fm? z3gJq=dkuR{<8l}2ckFc@NrdPA1X?KO)Yc#1pmS|kl#hOLLNx^Ia8X~cr0%7YSbZmh z~xriCi65O^#Vad>$8Wv481ppT)^;ErPa!g=}dP{7B2hyh|yi zi-A)k#uTvz#O5>TpZ!D-%C)MvzDx164fLO8`FjVq+x1g0Eqgh$B;WA>-7qS@yp|(5 z?oLKGeEqgK znx-7EvnWc?(B2EO{duvwyD~SBVNoPQ1v{f>; zKY+BIt(C9hnCNP=o;`Bkt{}$&78<#Ua*U=g#k`d=B%XP%VIq`7N0u?49$)L4E@DAa zOT+&1%&CrO&mcYm*4v^-IvGk8ciY_@6FJXVZ!H`4h33;RmlgbD(=spVL|F)=_DbS6 z(|gJ^9_HcP`#(zPWjZwBHXV>bG*n>zOVT=7B{5x&w96dF2?u`A(+^JNL%KChJ^5#q zxwnr&)!AJ}dp7;5q1!H<2~ZOyIU1ZF-SZ+jx8jkZxx-fKE$p$dNix*4x)Kv<(YlYQ zd+g?u6KNCSj9znwUTE``hpq|FkH-~L2rTBzN)x1Yy(u)!@f#9oI&p0RM{g~rlgF{G ziAa0{=2T0>quj4#)~-X-I(kpq&=PqsMB+|b>H<_b?KYA;q2(8166%jSuBwa(^%2Sp z_RH>S`BokKIX5S=;vl|AWP1-=XXQ3|WUgh3Mt90vjJsPmc6pfE6!|$^Y;n)rXn*Nj zD;SJcbwP!kiBKo+y9!b49MgQVq%vtD{qq6-db%1OoMzQVyZM8Gt>?S=O4e2{=9X61Cbl+UZGErDpP)aR#;`Z+g8xNS$i?^qOeXrVvieaw*0)S@pkL? zfulN2-wQTKL;30(Xd#?7Awmup1PJ39Th`CXP?-^0dD0gHtEsJ; zc$xMxqLYi^yt{y2gc9tJ=AAAg-8ma0sAWI3kSEMjP%7IY&=x_sA59nYG+w7)SZuwd zqR^UeEoS~>#V@5P!a`tI>MaQ8x9DL@Lp%KeP49(W1^BTB(WW{JV}6?pLXE+ zdbMtQr3I(NolL%|CI-V#?(rn#+3S+!N!v9c4)cXW9?t)|#3oOR6Y3sasXtn&TTfgI zo>vh(OR`3^diE}cYZneJwD+-}(l`nm*gOB%LU_vtYR|uBH(0%(k7PV1)&wQC+TD86 zp|V~v9@DjM`*gXp>`Bwq%b0GE;Hjb?vxAIs(&f^%6!hpCX!%F99Qnz#NBQ1g{j9&} z!%D6eWB-8ff@k)Kb#iE5PDbK#j1nOT$?v3)4FV!hZC7C8Nv)rixXD)|O`n!INC$huXzs|!I^*pQqpJ9VRx%zl{ut|2 zg7-w*`eL1uU6;fiDB!z(4(rJn2L&+{CJkrf67HEn=k0fzGZw$wOon1#jK$7EmX_(l zKe@D2b63!_;0xss@+!QrO5pWidZ^DU`Kz(DlRkbu6U=9Y3O_GGQ-j6chB4BM&yTxbn#vYc=xwZT94e z+P?f7q}||x-HGkNJHEnxnE}UY=I`{S71Af_UQm{(o9KX0SD|)PZ3e#$E5Avbe)$*< z!xhu=bw%sRUxs%>m_6;gPg1T@E`4tpOFB0;ty@>zuqe*#o7aU#M^w|ajTE*AhPDzg zSC(BL=6#s_CZ+#76ys}rI(&I}TwC8&s2K0L4tX_f^w42AzyCwHj%}8dB2oJL5fU-D zgBTz@;MNLkQ-`gb$_^DuIaubN%CKbm{95Q|ERy0d)IuZs72o5qlVv`RC9ZnAj-Z6XWcNg70me#NF{+o z7AJ~SxhuxYxm+X7+(pCC5O9kfqFDw4bijVH!iY<#iMZBbnYC4kQU8v|XAs?+fBiUu zZv0iiH^x`RfAmKfYiuzKT5^W*YwfOtTvf?u>B)T4nmB$zmvl;i^qMuwdS)Rra`)&z zv+Hua8cwVo^+RImfi(O7n{9HNE-Xpyitkd~S!#RlAZ|Opjo8y9+4m!YBDYou?@V-L ze16)IwgM|HBJRQtY&N1k6qhk=#iQqXb;)ghiAc*-1m)M={4-nAXh~)b=003`K`8@Zj zP5vZJHiLco=KMhFG~>g?G(RDpxBdJr=bDJezZTgjTpN%H6#6VfsUY|zTzsWkylqP> z_PK5oy|!?crDRI@2sVJ}EC+cM40%w9FZ?7U|8}~QeaoBZ@Nj*BS%{~q&lIkdqr|V8 zD?xL=YF(d59lXo=^Wxy#Q8enaw|5jeQms0y|hEFImU_> zSd6Fk`OzR>k0X0$ue~3(@D@$WB-`k$0SJ*}9kN-+zcQ1?$kzscYCZc`mQ)%&#s6)GirlX4$x$+NG zGVNh;BZzDUJ66##^)wIthBv&QmcKXNg`K{#@w??oVVQz=zi5|F zXJ;oVpMGmwq$;SX%)I8!UPMi6Dw9rSI0BnLO30C>#ElhCg-kuco{V=XEvD0X^WEQ& zhV29rJ8TW04zekw^CYJkZ+BaxW1jzoTx+^g_MdA-=4kE@Q?EL)!SHs$8N|F?U$@?X zsFw4Vum~XKN{7;m=YRcXvBdshZ&qLymReI$j6ZpMYa)>{FB`Kn00^RvnUz8y1Wg{8t&IBgiFe^CNCMcoNZD(FB?-F^ge|n%_k|{GVW1Gi7`}B*jCN3|& zxL?QLPJW!x?-mXD21T{sL2kR$1h!#f`(kekMx}D$8fA8>MC#d#^YwbAg(lXOr*Y5zVAngiKP1) z2HqP*Jml(mP?!cVto9!0wE!`l?7bVXo%!J+5;+oCM;@=dBA^#w?yeN}=JJQGYVk}` zrY@}5rmj_6bG7`vhBHxIXErRs{v=#eq=xHzpo?w_!`zq`&Y`y5zFz$-VVwf`xFiii zHD!=^s5}?7_!kaOV+b1HdMh8Sh?By24C>@?GY?CYNn!!oC6VUE^9@xA=)}a2C`l*Z zn295gof(~u2y45IjVmEkGkP7_y9GXDva&{HRKnQryrQD}7V8IRFK6UjPoogXL}2y} z&XD&yV&*>~+^747`+ZsHJ&-?<^@6^P+Z)tK!&J^FaU-{b{oa<*wbE+7wkjn|eyuU{b>`thr|K9UU-v7v_`O}Dp;YikaKu`wQI^5zY%N8Rs_P%F}G(f9)_g$@S zQfQif7t<0z#<(rRzGiNm>|0lh&=e;}GDSpq7mr*`*jxY1qs|zSh#gfE&!8uqg~PMD zdXzN9Gx+GVKV}oO7VCVK!lC+;xKKVM0QO$}gmKOuPYEXk$cZ#zkQ0HT7pCl`y zutS`>+2-!A3T|KI6AOHhunQSYsvngZwsD-N;58^>|o3 zfisAyo?;i0Q@<~f#uawPZo0H;@%?i~tbtsIFmRvU`t&R7F!1BNg$E-iFka3|^4J$L`apvWfm(67ZZ0?;8dhkSyQw@qkhwN-I65Y)gb} zB=+3qi=uu&|Gao6E$j5L%A68{&iCgBvNW+7fPdo^;_vRyt$%|3B=Y-PUTwxH5L;-p zb?(n!y)~{aUGz&BU@S^y57noODWy_|SyI1}uHtUsH!pGlS;Tn_81IK;}E?dms0v7U)g|QRjjjVJD$jjIoP|ty~lE!fT$w(*P_*2KG$sT zMGGY{N`RUGs+AW_hA!3sye_q%Gi`H+6uRJPYb~)KtR5n29UxkQr&j0hxbAJz0EYDn zpk+pBBjNCUu!TU=RIO}EzhW*RiABZ6qHdi4qVZ0YwoCle&5<)U+1WRH+U`xr3!d7! zZ2C~%9N@ALzn0m4T7f@=3+RnRV6}_PsGB=sn(Y~ePjEm@!?8tXm206jjF0wiypz#p znH!mlRJyPB)6cwnET<&Cp09f=f#{{N<}Ay@wDSCIBjhmckdLbb_HEEqpQQ0O&k24} zme1n?BMX6XnL6S%uK4+1RV6;TN-3qgN5@b*y4nb9gA+8dC#Ln336Z3^Utu}q_6F%T zIDG2qHWgn2`~`S>;6q=51sDv_?Z9j`O_?Me?C(Yppx^cFierc`~6Gjc{FRrS75Iz_noswHXpk_#HrYM8xWcsiYUYfm4xcGMj-Q{zf!-2s`@@$8bH<%Y*~|Z zJk1W!He!wQpB(hxo2cqx-<1OzN3?~8kqrQf?9P@%K6^{{DFjJMV=WO+2I~m$%wcwwYbZkv*7= z<#4dH1hEiE6!dN-t}O=MF2M`C(xXD6%Ve{zbl?_CrOVQ{HRO+sYs8L0jI1ktmB8R! zv+W}+5p5jxpUudURI|#5*jj<4xj=NSYFXRb4LS;Hh|sQw zjdp85A6N_oXky6Iv0LM~Q|c{@h&5icgMxHA(c}I5A8AV?q!DQ^IoBdHnY7t-OQH=0 zh>w@+?}zSPop0X{a#qMs18XV@DC>S#gWAU+?tATgs)=W*i1khPA%_mKxJHXci^{~u zog^Bx)sGt2O)*NwSkK1ij_eUDIRwFRRJj&?<*pGSx3wkL-S$xKwLw^W6{tAvpA8VjZD}Y_!QgT1 z8D)jV*5Zp?JY$ny7SUj1Q1IOKwfhthqtsp8RtL#Sl>{%W6DC_rl-CJ%(hnqNq628x zmL}PJj2hXLm5=B3Mz$3ZZxjSm>2v|1r0xh#;M~ya)`U4#tt?qCh!5<(k9_~YuOYN+ zMZ!isx_ZIGHniorP=7;fBkdg9y3q$YLw?6F>}%PZ07I)?a$fKKq>09^%@UjXEvDp^ z`5TmOjnH%wALWAiF``k*=>KTAfsm8zq(fD^Zu4>t1LjVIn4Ol7l~ zHO#t7d!?7%I=t>)X!Adq$?N0_nBo!*a!f=AHkr9sqOT8Z{G~U}bToi90D%xX#oF1) zL;~W>w9A-E!0ljMV~)a)Q7xm&)zDdf%FAY(1&*ol#gQ{D&6Wa*!;{kT){W0C`Exch zqiCU8ehzmW>&LyNdA1pK_B2L&q?cYnMf*3Bv07(F3bkLysluY90a{cB3H$Zjb*XsG z@0u%%GD>i4OT4(geII28Yq^&&nQSa$v(6uYc2JkBHpjo94|+x43)u>WMQU;{HIK|x zot$dS!rHh(vr8`(3MC2C6zV=?fqI*eY`|9Z=YCsFG0B(vqox^ zO2b|khUl0QfccR>++L` zwyLP_`_X*9ZoEDITlV+LKaGcBpQ=xL)!>zn zwwk=DeuAwy!zVbl<$U|V+0})0&gP+cttgLQ*M4^c&Ywx@@rm-pT6(9H@4eROqis%= zF+al&gQ?A{zP+6<(Bu*# zo{tZt=kc##4TNni=Z1T;?#shFbG|Lw(p0)7AQZ2nJ}4*O#9PI0I}HBmUcUEQXj!c|Dy zC0yIuLI6Wn;ED%W_EqN6%HmtYk&I2LinwO)pBHV4ZYg=x4p`t3kN( z=X!S73rBrSoY2euY65y^4y|tHcBOph4k1|7wxvrH`-E{791g;z@7jUE)2q_QI8_BD zcE`Z(fS;&TR(N9Y%8}@hEjrr3*Q^r`H`@0l-4K&oG+US$nCM^Ici3`(krKKi015^o zkVv$W&>IOv2g7z7K>%{J0w8djs1VTV8od+Ms>|hv!uvmPIB+-ekG@4tg%{qWHbXqg zHP4;06#YX|P9*7lZLNlXmXw|Kn$y*yzg60qZ=cS$0j4!DxCIbyL~|rY9D#08Y7sy6 zz9Qz{05vJ|>01Ego@l?T(BKh*N{4dFK=+-~Kq{e9f3oMRuS0eKwzU-q$$FZsRuFE; zBS=lOt}aod9b_+*lx0eHjiNa`b}4c>%^qG%dj)~OO_`7Vq~)Y}4(LV$$vqV>cysED zD?rA+bAg3(=Tj5kHe>S?uL^+jjpZ{wk2vMIN4w+;Of^ThJ4pgg4E_QrfiZ`aGHj=* zS<-*r&u^Yy3$-&tdns6QP}Z3g_D#+Fq)#<+<4Y@tZ&^GCfgL*O=n;?mmRN{*Db`<-MWP)O#Hx0E)f7SHOS312M-G$&)80xpHgykMuE-e)Y z_Adcm4Zy+&K@ETSwVTkI4+EK_0%V8{mK&E^K8;vNM|GCUmcK0(=Jct_*RznyEpRQ8 zQCG+tNG9tyMn$%GP89`(n>K#2yzcjB@VgOK?I`WdNvyzQhtKd#(Z%gy!;5-hBel4vkLG5MrP0l;b%r(U zylLdbElKh$G$kuI%|fz?cG$(5aqkA3ws7?@g^Y4vZzs)h#hsAa9Kn+73P)*P%}>9_ zyaw1Sm+%=QzS?&)TI#;;qRTW{v5RDUB!#Ow|0;H*MHMZ20K9J^w>{g$dN+SSCauVr z+=--9-EGBzEGq35J^tCXIl^PxRvS=CsSQXl!a6@jD^35MKv{W7xu`|Nrd>&yV;^9? z)Gh(^$<_{F@hl&#$s2xMA918HrbQf~=eYON-fK_;X-4GBrUYOwfyW;;d^O`U%nE}T z1bwpKk{zUOm`HliDqruafjovDWqv%WADe`{_o8Om*?|*AtPf z82qht>NT7tbE6ed1_P3{5FZO&>>4A06}G|>&-`s!#jowmIuT1& zFGU=Paz>5o<2eeyzbbxI;3~A8VHLP?1W@1p%eC#^V;XXH)^Q}sJx=rQA5+FhG$o|} zz3%P*4iA1Sa>e(|{ao#3i=*xT%lPZ5c%02aKlk*1#7O?%oAQ5q)&IqAg;i^?~_S`EdNl$3BP@++}DW9*kd1-!wh*$;C*8X%yc9RPA5 z&;7>ByoYg+`?)_^fMwORW^+e0>3vl3A){m=fUvH)$OT9!5!eYo;D1Md0HKLRY(LCV zPxb($3H?%P>C$c6Hy(J7ZVlo(vn$LQusg*9wSQB4slozQAaipqRHVNFgZd|6)l^rc zD-XB06JPjbp0+88>y8L2&;VF|34r-Q z{|ZJs01gwg!6EJSjqibIfOUn2h2JjqI;S@h)1^~nCS3ioYcX1$^ua4ay$EyzB1WBnVJ$A!|&1GdtY7g z67477`z}ASwEv?yW6AWp+O{3C&WJFEpt;*xcddr0i7xOV_m}d>3w&$O=JL9NKcL=O<$;c&rJJvR@)483d%H#N3vU0F(0iaQPf z6DOCoP>r2?D@mgdq{~Rt1xc!Xh}-MtZck7|;Av(J91iHp%@Q5k7jwm@;LCZxM8TU|0=Cj&;7rA>txJJ-svG44*%h$VU zp(C0_W>CXQ3gSJb<}c1roz)pWW1X=WoBsKcwYSm60i&O@eCzy zBDC$-aYBcXs0}N!9a97W^fqUO^A}bF(QRoCTYV9JRws0NLor(78BWzkM)uUrsXd3{ zSBuB*i1wE?dkzE(uS<_LX7So~-M-Eh5Ad7nMZr^_lt}B$g7Ti-qK_%SN$5Ny^OI73 z>l%Pu_;g;~uhGtM5}KW;yk*iXr1bporzqgN|KGB-mj@gn?1EYs?ApHrKf7Tw)HBnq JyXzAFe*j#?O!fc( literal 7123 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_2/00000.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/10'_0_2/00000.png index 13499fcc9366bb214269b05db05ce8ae4380ce24..3f906b2b76be79fc321634fc00b2785ca627789c 100644 GIT binary patch delta 2731 zcmXArdt6d?8^E(nSDBXYwDLOFYs}Ov?bR}c?Cx5!yyB&)QJMsrH@t8;rPW$aaKoZz zN}DFBC^&Bkf>BdSW@HMeh?q*|1yQ_}h`h(`Iscu{`8>bp_kEt{`#DvRk^dI#4m02D zf5I;~^N~vaK76=;{q6HyQNp^jLxtBJ4>|64y!LGj_!OA43|$S*7MPbAs>wc(48_r7 zCXeU%5v_3rwj0nt{JL!h+YoV%-fevyHVE)=8`mwH*Etw4*HgY)KMu4~V;hWRS;Z2s&^r^yXh|x9|-mApl59W!$Z^!T(6SP2~h;<{%mH&shg7gic zGSn0aRIS`dy3hoB+;qirbB|Un6XU zhbQs70RFHcR#q1JC^x3-iGKT&Kflkts$6F&UtONI7!qk_XAeBHT17dG#cj#kz(ZFF zK3EuUvOK5I7^8Vg_`;9l6;zYXquTu5q>Zsi-3p7NZ(S|(+Q}W%`lhC)*~|gJ1(KG} z??-!b1l1)aC5Dq7zCJz-=_D5hz7xatP+liivjr)~q?vEIz+j72{;9doEy)fu0(QGA zgMF^95A9i`Th(ble2C-7c`YqIK0Y=!tD3b4Ft z0`~_1kMBuM^e(ou;bdey&L)>@U5jFolNGSy0L9>7$JpX@|1`n6iXA7=hGOpRA`6m| zlIT|NzE{-DX8KHd)3~*S>DS9xF%?KtD?8)r0!!_@rj%eI0M9gA&{4y zVG_lZ+PYm8iA1(_@iV=e1WB*C6K$tjt(F@PfhY&#+xRcB90RNUm!zl$?@ZnD=6vm? z-h5Rmyu=BSYhR2kA9%uM$B43TzSE(XRXuttr1|oZ| zI~d#F;ldk9e{AKfU5?uo&Xi6ruz&b;$vs?O#rWvr{wAUS9{@In}?ghpF}ZZ(~@ z0PaV|aww%yQ_~itU6FQM6L7YmUm47xP)1{&qEGTj9jHhcS9k>Vyufq81FyD= zCcLz_vkOQ;Y6mE`T^06!HQF@g+qS$Ad{?vudx2jWAA;<^SBFvu*LWG5zLCoNQvY5f zhb=3u!8HFExVOo)L&%|PL7fAM8Ac`vLC~-x#Pdj^DQ~UxRKu$?o9#U?`+CziRuQjT z)7r)don2@V9JgONQm1&)0VM1$JzU0cmA0s|5J}pB6}=x@H2v3B>vz9nn5+SN7dP04 zcDoh`?9Da?-x)tz-y9Q`7I8eQJY)o;nYeRm!Dun18Qt=G5b;l-UiC3SrWE{)VZ0v{ z3O!;bDb`0Mv2}etT@O3s#IO568-V+6W@gqsUa#%BX>i>8@3A>lf>8M<{=~%T%Gyz6 zB3k7P|6*s$3;J)K)G@2v5Z`zCX3wM^+J%LN16{%d=>hp9oN|w}OZMyqcm$oV(-8#b zdzDEKMPp(h!Ou%y@^!Ey&c`l{{)OuPmFESf;8B|;adl4Wx#co?`#Vx|Z3ELpGGqZ2 z*Ejn}Q_8hiPBp}@A^q+5w2sVfq6D`T1yjJ`PY<+$9lu!Ht9z{O?(P=RVBnNyG;IL^ zd)SdD&xpq!OY~1Yakzab<}=9L^k%(7H}FA}>>7!@{Dd0F%OKQDz zn)nwUN)wHRBv(>|Lg{BvaD~R`XcG<)xY9|cIs4xt5AuX3aIE%6xXHj7q1jbzPHxQsdnnr}d%(9elrO1H|!pQhDn z{i;^YEyXq+H#QkBC7!r1ysSH;B0Mls^s3!6Z;5;{ITv1LAr_qVe6knS*s5bLx4LhepppFKiXDmn49Kw(dFv@;1eI7KPA$ zy}B}ZYGVftlyuw0+K6h)ypvg3BdH!6ZqIiiMD2oPaA#Yc5xHTRONpO*3OT_5)t;d_ z57R7T)ZQSyrKP3mJ`Xfn6ho*7aQ+zerf#{qRHb7-FgR|C!aKd-A3i+PPDFw(xu$&J zl<~_x{mxJVqHN6HS2=*P*@Iw8!SZVL?!^I|R-@5RwS-`WH!FiEimL-tbJc+%kPwxx zExr~prPFA@oZq5WZnWl-dsx=m{C^w$NG3+5kB(=BJypRIN^od) delta 3140 zcmXArZCui47suN&OYgL@rJ0r6Y+4g_trQ<&WmcAHX(*b4&eYNb!^A1dzjVVbHmhlx z&y|`60vZ{S4}`3oasz9ML_UQEq=2TRD1zMo?Y>@}H`n?6&N;v9d#=enRF|7h$gQ~G zBZtoZP^}r2WxYYxlg_NrFJ3LZTN-~No$c6x2&JSvtxzHOoyvf9gyg_=DTxkw-9TAUxAmfHLEr(7Rw6I z&&}-ro;=#6K*X?R7Y~vn>iQCeX$kt|L?Z;rTjCh{R^qvyhyCbNK;V%HF z6C~zhL|G!QQIT%dej%*Yn|9AT{cr?K@tTgoVm-+vAr?L|pNh)VeexJFX;8;GUiJ0qeW zLONZALaNKP%X|QU-*vtd>PKkm6^9_KnO``N4lg z%)HqM_}-wsy&3=Nj8>U1Ph4!?_HQSaJHu#Cy}1*Y(qXd^uH6Okm!Fi_je*h6@vnjc znS<9EPRJ{RtDp9!zG&QFd#on5J!2-I+kL*lP!5V4&^(DNAC2ZruV~j^Mas~ z#O3!=2sFIWfjjXdDLL!UNM2ZE>WkpWXPGg)dELBjWn=H)buTk=B>vD;#*OMS0?7-U zULp2B-?}?NgagUVVj?`lmV2KJlm7m-FK83jfq|VKwh-?*Pz(l>%#^m(JeGDo zkzTUaeJ~jEAm%GO8#fmGRZ~+BWs{vAqkW^JadAJ+^ZtTO^Y&&FmpYl! z77B%Afn^Eo@5INE7jokOI)^|QY@+8{Kf?F>L@9SIjt3jdr)>r10_vA#e0ef+U+*vF zqtyu;hT5B(j+gYE*U{-k2ka_H>N4Q7g%Md09v8jPoRVFf_xAru^`qe?2NZFLcgC^lD?K3x#eZKyh zKAQST|E8(_ZAzZH!T5-j47S208%3q0wjmEPUd?iR3itOsvs_rd+vQmz|FO~JQ}2bg z==?LZ+wo~vms`|fh%K4CGb9~WhxMxBty2wa7G<&o-`**hjkB ziV){4roIk!5in^cYW*(O_PW`UNl7zMC=^jo!WxXrTIJ;A^dQ6ubq23YZ#`a@H4LLe*00{H*@X}7n5ZjeF;0e`tJd&ot>Sf zil=3=doYC~oY>jb<>`nQ36{f;BAo~T05IU*|D?Arb?qToKk9F$LT^I~T)!_iq zD25f-J?v7_hoMK+-cRN9bSo8k>$p3l(b%iCTwnYH^@N|4wu5nd>vQYzsVOY1PI5qH z-SjB|BV1QuQ``b``?eya*a|sK9@dZ&-8{xxQ`%$15mocCt84tE`Rz%7E)q?PtT9;@ z^^0o-X@Bw8-7kMry#+b+&3)W2&ztIoB-2HLWahl?9R2tY1cGbYQ(ebfZv9z!gI>s1S1e~v@Co) z&;3}cRfzy}E@u#sJA;qU4D1C(^xf=lRn`G;xCH(P2g$gUGzBssnHlX~PDrU#XqRO| zkM5E%lcii-x2bnu4WkI*ZpQBD@QZ!NmJD^R|2R^8&0^?6zqzMqeKw3X9PLyS7O36k z=d&2KSJkSEf~mGIQrfa-u+YjXL2^<3y)XvpbtaHW+Jmg$7Z#IE%;W2F5C|*yd-809 z40~pV#@nw}uTyC>G(m_4iOIzXZ&vemoXU@BkoTs`gXv`|2fXC-@i_iNtxKVuG?->R zfbTFGSF%N2nh@s_iA2)d+nYEl9i=H>&+BWe4m1qQaZ;1%@YCJ$#?5?J)JCQc+N$3d zvg#GEwf?l^zonZ?WS_VJ895bO23hgV6pH+}piR(+vqtgJoW4>J%p?NB(=lB8L57l z`Yx;t5~r9u3Hz)8PPJQiXJ<&$fKsVUtU9ncqUX$DN_eQyl8-9QED=KI{n#?pcl`XGTDiV^t~a*}(`|*z5y=wVq1}FI5hf+3dSU!vmB6d& zQ~=0ZmKF5pLgyYV0H?lKwk+_h^kVklU>8pP^>e=ngi<;P+uxGgkb|7n zkB*u)MWLTOTzsug?<uL?N_~uC=>GnT2wO6)=t%JVygYxE0g!+im!pwBHtIy* zn%yh)edp&F7xA}J*y@v)e+_C#+|siDHg%`YJX-z>4d?cE(ys0<-O;_|7d>p|E(XtY zbIYw=Rolw6Tp^W}y+d(Du(kQc_m{bm)(48F4dK=2&t_SfrJa{cuAsn0?p0&(4ZX;e z#x8<(d$uGw?M?)4u7#hp&#tGnEtO`Rm+Kew4G14c!{4IyXfzu7lW+O3W{7|bV}Ja^ zUe~r^XlZ(nIFQCv6y~cVA4~cz?#|v-KQ#H+D+=uMPPD#^3f1GIoSO?h4bzLyYN_J> za$G7^OsTc8<~SEuf;cu*3Q^AH)sxYqh z-dO}9{~Hev5A$en_50Qg@u*BXrvHV-5Mt@$gjM3HfPUROkhRBrNV3~hTf8I}q#9`5 zy=k6xA}hwruaHsqs<#cj;XpBAK52IkR)kE8H63YY65yjs!pN$5{wGn& z@`+&Wt))|Rw3){)E+{(;i!h`|bEfK@Ka64n)K}Ml OCpakd2>oz;!T$hx@V%n| diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_0/00000.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_0/00000.png index 00c634ffe88af03190fd5e8f27080725368bf29a..538f3218042a9c109feb262a20e2e64009b25057 100644 GIT binary patch literal 8810 zcmeHtcTiJXzcx)p1;Ha71W{B}q(~J42#SbO4hKR}T0lTrLWdZFpaMq_IigYp6s4EY zLkmQrASMu$P7(rAB7`JB4552B=Y8+Jf4_I`_kHutynE(1nYGu-FSFPBt!F*Yv-9M4 zYjfd4GKYA0c!Vu(T>FEEhxacY9=~d^Z739A0 z1zvpteE}ift5{Jj0b!G?1EMDc4)U7Di7E;FN|~r|u(B>Jywuvs^)xbkbv3^4hkm@f zMf%5(C0^{(PN$6|4^Q{W8lKN5{vH3GgMZh+|5^>K6H5-qxqqkA1Ewf+&Sq2kl;o+J z<>u+X7Vo4lci{w8K%O!7oT^)a)4T!_Otz(cBl>FKv}$(Vb& zki$jO5oP`m5Z__6uu^~4n~=-}($MIrWOhRCz2CkkcKq4mh7!3(z~0sp2{{&@pvdpX zA^7yFfD*B$sQ&fnN>A-rgS!&@MV*>)vlPppccxVZBw8B-^wkb!uKASReJc{5a0GU% zq9gT%^N)`W`z;sxERs4CWh8Qpe$%(FQ{Nw-AUo+`R;ZeoE2y&V<-o~t7T+Is#RKv= zH^30+e~RTh@#yd9`bDTA-b*y=I&jqK2j{u`>DF5Hxc}he~mWXNi;VpXuD zzf&_Yt9)dg!4suev;3#8XG-bc3*MiaKfQeNz4}4E!-FT%m-mOa^8aPx!TbM3tP}tz zh3-&bPHlGnlD2vV0fQjmEG~lE zS*`bsL~6Ko-FB#DkaOR#=8CU6JYQ14#5rS-Nsk7t^;tWiM)|$zpkRWiRafV|78f7q zkyt~k!C`;x>1Prt2~|$o_FxX1?L{{sk^*&d`-)+YN(TLEoh%#GVh+V~Xs@kHRPYZ^ zjIp>h_C}0R+p9NPRwaj?2?a_)GqObc$=MwEqrN$WF)6=U{O5#<7%7p5=GT==W=# zR5I~{3qxbYy*(Cd57SQ7yi{J3hM`ILxj!=IVmo0!HN?$oT~yDG<3n2-?34*lQ*5KazNt22f}vO6yFN0IJCYaTQEr>^={t?)8(mLi(a#tph%XAN z@G?O}3KZ?4Dl7h%mX#z>ME9~Zn#8U4{=FJQD(I}fnwWwE|`*})F#xtEqDLyns#INI)fyP((>P9%#!Wmfjthw#1(c!l*vXh3H)vL${ozzV4@mP8-l5?@f4TY~;x`XHL z)TvM!@5%O)9n+Ow*ywdvWGBguv4#%gmV?-%Ru2X+Xx>)Lt@$VK)Fv`Fe7ak!DIb!b zUs$#Ows8ue9&aoJuk7E0{C_F5qas{y#Uwqvd08 zcbgKs4DSfno{+$fI27h74ZfE0@}2VH*8By{?Yps)P;?$b*Bu|YOLDYlpJp*L-N#YL zw8GD^1y;V7NoQ%{`oj@HM8=g3tCc0sHSsM^xt=Iwu65gEFgVZpEZbAej5#d?^X+1f zIEb0$6gQQI$ca37K2d;Ee*20Br@_*tCE73Fyw^EX{~@Np0|AeET)M)DjwF1Jef!)X z`L1K&gPDaa?`J(;)P41CD9ULPRdZ2aJ}t7hKeTnTBl}!(VZYj)ra4{THcbJRjC1|I zF(`VJ-l+L;%cyKL58bT{p*j0MFl4x2f3f`QLb7LzOQdzuI3u#D>04Pf{gWr;*JGXc zeyuL5NxrZuhl&;VX}=d=V+FP-p{L7+1l8U zHp1ZN>cZl+tQ;$b`OPMPtQiwyQ=YXyw%<<%PdZe9Y0h8j0$W^+T2`o!WHP3ASDwzS z#~9Jzu|@@b3Wi)tq%gipu4TgW9N+?{(>t&)o0*62WaqSA>cH$jr=~76`t5ac~_&Nf+-L}Wi zK8P$+xDnM!&E3%{SIiS{&}qxqQAU%3oHM+gb;_+7SEDKL00p0PC7;^vjcI*ty`!V_ zPT|Lq0`HV4Z2V0vxmFW>F?ff2^9Zh{UgMjj0CR5C4G(Sknp5NGXkdu4 zzKfiLr-BO&S=GU5mc1Oz)y8PXc7}ac#Ma9XjZgD%iCyB&PnDy5Ph9 zYUozf_xNv-65U+nmPO-Mx*KwG^T;3r6%#$vd2mn$gnrQo6NG!L#qG4P9KTRv!C(dz z-^27Choa}LX9gE$=gTllTl?o-&Qw;EpHD7?4NO6py$iYYsXg8@KNPVR$rUCfK-R~8 zu5_elp#y!}v$MXTXJ=`Q>T@y=q~kfn2<>G9e^_Q%i=wvA>r!@3j7rUSJ)L;(^Ou+} zmD{e+lIQoMbwP?)$}UzT5ppkMNrgBYb>@g=K&aij<4$UZFml}G-{LvOxK6FS_z2WN z1uHL^qx0V_28ZnH0*i23kO_plYG&TW!4rZpR0ZS4@8UjNdR5s4XyXLzX2JB~`T4ma zDa$1-M&%smKINYH1a>iSz1h)KRDjNzc%Of6cp-cuQ0JHgObOvhwZlu5DsV8`ME08Q zQKw&zZ`g|EWq;%9S)q?=3|wA4sZ$eJF|gkO@e(_^^c_AK+sTr>p7j^vjDZ1b>CSu- z_vehzP$C%{nmYzFf=OYOr;SI!?#58}p7J*4ayY|r8A&a^3qZ*7T3RQ*>QuN}#0&Ii zvH;7VmU-hl0-7V+Y=||CU;D%@&;{5uC@iyXW1O5vaw}G=Ay*f6l<@mHH#w;Qlxh|i zoUggWFbXe&9r;k>C`R;gpmtMU==eB={gzkovSnc>KE3^WJ0MQx;QeCf2Qd?$D*=8s zurh63?@yg@0KZz`)v)o*Y8c9=!6QR|2ZMEL^ijHZ0@NR^q(&Wpz6_{DjM|PJ3+TT( zL!m%@@!S0eLW})?EZ0}aIYZ|CvYP`*a{wi-g!#CgpH0Iwi-?D0 zn-63e*ZbwfB9T?20e0T?HlMZK!mX~`&N7Qw3#XyU7bQ}F^@#qGd^~K4oUj9Lamis6 z5NWv>YlsvSeMht99KH^PQe(G^vE}63+LV(gM|8!^Y{B3poT8Oom^ImaB|1L}Bu`=f zN_(yQ^ZSTg1xnh?GzAUI`x-{*1=yrAk#M*&GJ1V`7~W~ za^EQl{ZlZE8&Ghgsfs$xCFvgzG(;{zB||Z8nckP%Gk0RC(d8f3d(G!f4l^`83O=ZZ z8rW%wO#9o15%|UR13nb!!|rX}OrH(P%R9eBNf05=`7+1UE4Y*sYa#OzH#D=iCY6vr z5)a#`x&?Au4P|=If*LK8dZ7(jU*Ory9zX?goU;t2mLr}+2ye~p9vpP8@j2S%=O zTQNu^vQ-d^0!q}_^|1lLu;zyHRFO>P7=ay79B*dLs{m2Mz|V{>@uigV&0}4jgr!tT z?~}0IN9ZGa21vx4+4F|!6pU>KdmIJFC13tHa+U^p?hyBy=+;zF1_AC>i#RkI{f;|X z73V&6N^-T0Kc#^$HkIq%4-*CqgLUu87~4*@nj06U9PiVLc8alk1DAp%*A4jg24c7_ z^J*e{15Zr`*Rpwxc`muhI@zP*jOT_kw-4_n+kKPiwyt%M_j5GZ!xqE0TRG~wI|T6E zXp6s_&5{W`+A2JkibYh)9eLVEukr4+&K%imRrd17%K#q9o=;-8UxH!sa|LNEgtN)y zQ&105A$(7QfRnItrAYl=TlqU`UJ%{2Z6d4Q&DC zS^H!Ikmo}5uP9%n(EyhPpK&O9z+Su3Mxn?3Ztm?&e9_lKY!D0(uQnw+)nCUS%8Cla zlkDbKk<=>4Mh6Spv_frb+7_xGUpernWVX`X>SH9dm;qpG2toz3jllD0k&aYj!b5vtK> zt9Xg;-Q)7Wj-iM=Z)e)2B;1E~uvh|8LkOp2Arp~(LJ(lQay@(O(vGpa%HC*qQXyY7 z_F27{t6JZkGG8i^goC0Hf%RGY{GAE|5zCXR=LdfwF>Y*-?h8fo=5vz!WT`HLyQQ2Q z*v4A4hsRI>&c3S(2y(OMRm#FcHBe|vSVRSTRE-$c*6!!i+D5NP{az&h=SypWjPtTi zsq>TShy|U+6SiWF#y7e8Q2}?EbmsNV>j#tg>GK(^LzNu~ICU))4Q|A=hukFIO-Zpe z1*dUrNU^WG8@{RF%gZkrqv#XaW?leV=*hW{Dh#q0b*T`@762KEc1&bcQP**f8*U5&V{2+<$>bo zp3QW~{sa`a-$`$0pNTj?-h&Q3d;^nWMhzJOq}z2g54Q7+e;cq2!Oj_gJUMe0;L-hr z2`Jj<%u7aXUA%ZAUg7dOsHX2}9oH7<1Q#{03<}O7UCAOHKlgo-LuskWOAk!rb}X3=in%x4p-)I#6#{J+TU+b#!s* zTYBVmr1QsD*XP`S ziVBjw%OAIVQxaJA2R7=fGm1Ql04Tgt;SnC}=Gy}e!G8e9?S%gVj==+a{gVNOaeFYL zc2MQKGgg6HDEcOG-<9qPzLc91%f1-qYRO&`04tz*0Q0l!L6C3?fp7Pvqx4V>t*9Gdu(z`V zcsMuZu`%7aKs7GEwR%u1sFS%BE0t&>3TmJG+hzm(!!hki(F0tD415s{4!lDEyw1^z za)9hRXJr4nZX0e?U~G47`?SCah0r*`g-Rt_q=O{xtZhDsI9*X4V0ZD*Lo9bE{&bKQ zsV;jM(9Gmdh06C$G+#MTYdm0G^b!}F=23V6P8llP18o|%wU&o*F7pQA;#9e1l! z!ACw{+rk)r+p{?L?8{q+$$s0mQ=@MZIn5^o0}Vch|CBp&fUWzW@%AfkIBP#nJ;tLd z6F>o1C6Zqwm1X<~x~ss%2i`CB1cr z8ZWFP(HzC;zq*Y4Hl63su?z0OA-8Y?>&ER~2fC|c0x&3VkNv+6n_IKi60zX|aK zaybt%qK0Y&dyHRSB(fTxbb$?ge-jis=3a8XEi=Twx|weZhO~V&bVX5IgWEb$c@b6o^s^w2I;h-(C&e9 z4-Ig5By!t!?6mAYougiA@k#s@c}6qFdgKIaZVwpD;c$jGGVV0i3ctR7;P*X}Az`MW zPWRt#ZCd#HqpWs%b(}e=_l#oA1msgbek4lJR&1Y%N8*`!6@-t=YPf#O=>>XvTZ(j` zU;8>C=^3xU$j86EcBo?o<_PJy#TvQ^b|YlFHL~0U@$!q$2tioRRIaD^z+x>a4xj+8 zJ2cu^LB3;hsZvP73kC8E#IFFs%91ga8uU;Qn$(T`i$hQt&ZSRWaOTQLg$btZ%UEc= zUFF~tp}C-BHAsO<_N=T#$GCD{Eaumc2to}2N8QtXEsFMA(Z+bx%HpgaOd zBZUQ3_Kq=!0ZU^ynUr;p$bVZ!0#_f}jS3*WO+9Tj467dxH-dONY##Z5eAwq@$ZVrP z8*lGyZ#P@aHj(@2I>NFaHt< z0}%~arvpJp2Dr$moC@xbAEa4=V)*2(vDhn9>+jTWH4!0lJ>Jf(chrgJ8hnSjJ2NZm zPE;!J)SEGMCsD3z=Z}02(`{(=5=emB^_51#Qf4uk4z1`RLdfu;l&%@(z$J{qDJbdWH zAs!x{!;ssz9`Nw&dB?-U`+=VqIHPs1sg#H3EEjT1|6xE5oxGTt*TP<3UI-02VSlIf zXeA$LkI_E|{X6fD7VydM0S>dQ$t`yVXy?|C?}R|S^nyw$U*uV;-09ZbL7JGs`#mq} zSUa{hdw4S9T6sV0kJxwpFt5Oi6MW)4*Z4s^t|FE^KV&O;{?@nOb3f|eFZ_ES{>_K~ zv%2UEuPEp7eNMu9*T6|wbm#~ZOkwE|1=^MQBb5d1ETJJhyaGlw@N6d-ifTMqe{jgI ztmKm8T~o1@J0g5uQii6}ffK?*$7H67G~d{~KSM(=P8a~^P}I#^CcQ@tzAp#JVLe4V zE0rxs*zDe?)niX!2-JxP#vj{%Ev>B?m49d7ONg zgb!GnfN8Q;ge3LY0deQowoqA^>7r- z69|%Pr5%N$+9;+IX3nJNZ?$;DzYmYDsf?7Z#62ZhGj*n~$c6|qhF|QA(GlvGJxIo; zV&B%7?wGIWr}2X~-AITwz8_e49f`gf(o!p{do*I7W4sG#czyEe9A&zletN(D{WK?2 zG3@L54XrPE^5bih>SrtMd+5Cijy+-cijqr$?NubvefpCqDL2wEv&o6m2qqo`NibgT zbG%E!+S%E~#Thxe&VGiaUCyYO479Zw83zjpHnflblw6RIx+4=;ppoE#q}X#OCVe3@ zOE7*=hIVzUj;j2$qDASDYa>}m$mWwv(DSF{%#sa3KJm03HP1D}bh(18!f(uw>M_BI z`Af!w*@gIf6tFa&FJg^E4j27i)ry(6wcympOa*Yw7nq=>>?4+VGUsCd!LqhZbMK1M zzPLIR{dDDZdk(@MTRB}7MKBMT2S4By;2ZW}{cVIqSGCUh^Be??$HwI2$w=1oMgRGM zt81Zn`Pf32Co}pYa*%;Utku13l|Mq~6S#x0po znXSE+s>ckf9-*aeWkSFWFD=XUKI${}i@y5xMXHpJAb{?JZrVHG!t7589gwU`(%$Uw z8n>Gb0Au0orPsHo)IS()kjOp;%U=XRIJ@1vcT+>Qc@vp^RG*zlRFV0y+=$jKx_D7* zkEG=l>mj{1XBktkL2-}Ek-|5D-Nngt`mM!EJztt7I7m!nrPlnjXZ3yNNpdSaZOVd! zSLsdKDj+|qn^K$3cIyYWhyQbX9I?a8n1bP)hWQYaVat-w95@Ju8NATI^lI~yB)O<| zplsJF2ri`c;mmnpMS=M`CYZ?LXr|MQ?T-8kw9P7X$?6WZcawhGF^)E?dS=@uVyWDD z%k=7nN-POY4b&HT>7b!<&9{s=>NPL=z@s5hT=$sGjSP(h=k-HQpQ&MZyNZ$Bl~(0f(FqvP0grO!PUE_@pk{lJ zTRb(;&xV4R4msNJa^v+~OFMI{OBRTLCDCv0uN=7gNp-hH*my}@fUNw~l7oEyfml6a zDeZ^;jj9MaA~T`utV{GkKJh|1$b*qJ;U{T} zY(E=S_h=VB@$z@y?i1&wgHSBTDtfz3 zUEq27oYH2bZt+(gAj?Mnd4=I+tYrxpy>M>X$oxO0*wWGxn-}nx@lPze^O~`$&GuYE zldu7lBT_U-JE=N)55ym-Nhor0jmsfYoh=r(ofluoq32bhYb zI^paMCtl~3gb6;f^cmY5_B8Gy(TD9L@rqb7Y=@$b*~YM|pJkmVTwzl-Dx61LZ=k62 zYYi0T%!&7T@`y$mHUBo;LOeLnj9OUT588)|?^*AA>uk@w;SU=gQE>WYO+z;EEp+UVhF?nAP*V2SVD>H^Y zqcjre{g5;#$D0K2gu7u3){F6u6>$0y6(TcI_D$Y1H>m>oLz=i*c1!#lCz!dI0SODt zre_bsCC6SiotrN%=@xoArd(Sw8X0OlIGPH6vZRnOMRs?#U~~qB8@in%KdT-RYVT)p zxaWUjFUNj1C$Tv4vHQ~(Qo1o^aI4~*B76=K37jFxvXUl6XzK6vW9;8KS@t|OpR;>t z#~L_oRjP)LT_IuyQ3eZbA_k^5BaCHHgZCiE_U|pf6B^gX+OAo7J}#OCIoi;V##Sjg zgd1v6r?j^6?I}~ao)WJ_^8*~i?K|(Rm0ns{R4_JU;mb{q^ysHAsrdv&yN6d&9=nnd z&9;ry1uZA_?A}$_S2}_{s+*#dbN)PJ44L&zb>a(>cYV~>hlB+N-GZoM?BnXORe!TP zI4VN>lX>Y7#^pHxbSmvpR1zK0b}0PXBg;CB40)2KS9e)9+(vsmN;P2$15!#ivKeuY z`#_1U$~<%MPasNg@2Nz?;4s&vicnaZ6YOW|0sZ^j8MPU=N}=J+;pBJ=E6a33N0<=j zRp(>^kQ>ZRH~%jz4$}^)R!qt{*uLbeHRMN6yLQuY-Mv^o78o=(Bfv5aVc*Awhs4uX z*&&pBgAZLvkZlyxPo#T7u*N=p84yHY%x!OxQepX&6^9=II zxNc8g2+?gcbfl7L`igAE=rpMA;&cl`n#XbKF^ey)(Ts!NTt~Nk&uh_CB}d6huo+}g zON3mbjOgdEBu2%gYjG9+rVsD)%ENwsaS~r7hI_{sA3J~ea%$8Y|NFB}@MyTj=w5HP zlsSk6=(WQ$3zB4475h)%#NG>C7EnJ8sm{N$(p<7Sg-qT;p+Rr_Y)FYgCKp+2*>ekQ z?&R2YcG3J?YO1FS+95_GVaAG-IX)Sd%D(VwT<`=ttD&84Jh+OVCpL1=LXKwEyr<$w z&#U)#5)_r^;`c~8W);4_TUO#)M>=NkJ=3rugMBb@2pfL5x9362BEf@RXf)O}tH`IX ztk#-%kZ<^?T4lV7foZ+-*a9!-f%|Rr$b6}lBv=`B+|pDGV*d?yBe;O9$#E^aj3c|x zyy<0v37FS4B4!$!Ye|Ddx)$jDEi6m-a8{#+c%28Zg{WdZiCYKe%5vJmipkv%}VRyNeVS1 zmrgiF$_8|rHn@FtiDWz5KknQ5<*6Yhgox1mG_D$B-OIhfH|&l5{@w|;6Z=~?6Q!t^ zNDeQTj|IjpFxi7!!gaH;3=^IFKqoFoL^_q1(J>GeW$ewwbHWz6y??A9>(~rk2tAPz z)%wWY)4gxCZVdT!2%k{qlGXe4top+MsAx}f)m(dpjF`7@46x{=R5bh#&Ogx;S6zxF z!7o%J8j)~$+{xOaD>D}TFaW{S$#jfD?rjTpR;DG}Iyk?guF^JT`4>{&fQdWXo1$G+ zR~2LPJlSWJz{+{@-p{?A!LOJ-zj%$~eqMwmwf~a+#08czFcslTLSr8S(?VnO#U_7QV}Z*YS0AN%xY_59SEcZ8 z=?FcdPN1{2FRN6=JECuU4~W8oV>0mh_CQ9ZHfSP*hae zbiBmG;a#rs4O6C?4((gTm*}?2HoR0W^e?_IW-xefe2;CUxOluuXP;fFmqK6MFP$R* z0L@Sql(g$&=Ns|=2Ng)vF#KBZyf%g95$fKn;}qcpAYfOZ88_QjjLh#7rs0Y}m4g3W zOY%&+pP46LQi2hVe@}I?(ScZqMTf@!4es&d1~yv}eny8<(yfNSMwOAUZ}a}%=~oW4 zEDpWX+oN-3M_21UYCUMp>ykk1WOI&5k;k+CK#5#n;8i_v6y_QYuCm#r*~o3yX(xJU zEf8b=XXy50F$1J=yw0j}Y#w3e3f9c=;uJf~W+d@ar1~v;n&+BJp}xqfQL2;X_lKIf zMA3-a`m&Rj$k!bW5q>!9{W9m~8Q<-n8mC|BT;2Oj|47pXUZXuM)54a;T%xmP5&`2Y z+`+9FfXf(|`s(HqFyLI`z_=%ceqi`FMy*orJD3=k_a^|{J(xj%?A|-2p-5Qq#{KZ4 z|K+0>Jrl8lHCKBEpat}Uq92iG0<8GbfJr9}F7HgxVr8mxz;ob$W`N~6k*zK#)+Qx% z<=b=`tNha4`5gcjVz}Y`VI#GN@6>hFeBhrDkNDI+u-TRND7 z!jxC31P2e*0Letm`1|JIRW;w=8fgbw%%N*QRlafn^36@N6vm?QC1uBCDl6l~MBqqhGbPGLPo9mo1@1sRC7IV<>x);27Sg21EUR!p%ag>9 zj6^<($&-g14Q8gv$GVMi+nVYZa$2_-25_k^?`8+*Mx@IhMx(w+fy*VCXm*fu=g$Ai zPSK))5Q=~HK@P?-SvrJ*w^rOOn1!C!EtHo)Y+K;^;Go8SkK@%qLW(+C9(w68ic^Vt zGqo}IZ36>JmZRO(kIj3w#ZY0TBX2S&${FXqr0f)rvoN>n%&~s76|j==U_&|Eu=lLV|CCXY`BZP20x7ALY^~|OuDI`xj<3j(a#!jMl z`P7I1*tGt8Kl)eO{#WDwAM`r7!G8O6@1Uq~lC2FW_6(63_CXhK4u!(fBpnmFrb_1{ z4bN0c7nhV2x|A!<2HJ`l=-tmvC@BFGnV~yWU?@asL&c)EXZ|j^#28=^!_EH{BjuY4>9|X{!bAmSW7i z<+@Bm-}W$>a3z^@wKu-qT}Ww6va%p4X>%GfaEtW^BGw+m(xA{8p&@olu3QZJlSkH5 zJjJLB03}}|PDjet|4exomTWVGXrv!^BdvRC)OX<**`{K>Jzv7Sh|J#_46)qmV`DHP z^NBM#x?Q;jK14%e6sn>asutRo!+=^1CrKxEnFw_&eJ2CE(sL_YGFC?aN)>t?B`C~p zk>S%9;X_fs?NP-x3C4c=+?i2Q(kYGw6MYVh6u3E;!GVhrCAN^R_Wttx%G{o_t?&5c zj-o=;aIcrqR_~+fhu#7VV)R@E<3|Q-aKNI8gG@U4XPLYFOp#)5B8yNcMCF#zcNNE5Q5hDSSSkh|U^42$XuplME6 zr1zkCfdJ5swG=?HH})R_qI@VVZBAWyScJ=Rf|-gjTBb~aF!77*t|=8rQXk~zxBRwE zYX^yj<_okS0E}KBe0?ZLQ@~Y_P+2+d+471P`!Ay8Vru;5oR7PGO4eVo(_XI`-D{zs zJ(Orf6UM@=#5#1K1~L(AcLowALY^;e(A4wYcAn2>1m#LSj6z;?@x5CSm=};$*fnK3 z(cq^LMU`0y*t`{5sDr2#)jp>*pb(6Xj9!2= zbPS4}qwUYXrKa9I8}pmZ39BRF0viGp^u8q&`~5Bs@Ai0Hp^fA|E;Kz*C(7`{)%+)@0x8q=-?f^CjVXZY(MS$L zQ4^ZvAZM6(?Q1GbcXDc>OHsY`rDxo?AGPbe=S|3GWAi|SpI9;-ff%?c@d~LbhbY>@ z-*UVw!l#70+~u4fy>`XhaF6E1lcxaSa*!|yAvk3<-hH25b12fDOMg6Ywe~l z&Hyjw+WXCSJ_$QvUbIgQ$t#PLZnU z892l*hw2HoTUZ<*8rX9HMC4v)rHQp+b957?rj|F79+4~LV*$-CJ|^!?>sEm8!SLuj zdGk`J9{N_A6Cm`zF69GVw-42Iu>##bP(BoF`ze8q*uiN!Tm1GwiS(a!aAhPwd*Rk3ldEH{A_m`kbA@V7SL#}46?%h%QR>*9%@C8phYhjo1|+KmpY{$w zUX2DwR~KKxt%0&D0U4>I6n6zb1k`=q&qV1w z#9KF)yfioc##n*Ex>sZdOH+H$i>HT@>f`eM1`!&{$?!3^bCqGoc<0;4QfR)c!c?bB zIS9ZVb&;oTVCd)7Z_PDejT$OgcB`Qj8+53SV0)heQUU`x!PmB$v~gRoAzVY-aP_>t zi0@w&<*|8R>GOa?rAN=8;F%Ad-y^RQ)5Iv^$HF zM59^GFO7*|ClIfC+-d-?u`daG!gz4J+P@$8Q$5$;wbT~ZlHK91;MibDf6tkkg2^+L zx;b#dbf7MR1I)5_ik1?u24H{)nq-cm8kmZ0*VVF3>s=q*v1fQI+vY4NE?7WtpFj)-gFg^k*QwP*Pw z0dqIbM)A1+ySOpST!1inc!8yfRG%W~IW)SVT)TpB3NsEU{FA4rU>H=}^Mi1!Z;E4h zjqei4au8S=761WAlMC4egjuA1oF1Ur>>yj6lfVBh%U?dReSJTAc09--!fJ7NslfI6 mkzK^-dvMSHvnN5g!tXrS(rPk8M}Y@|cpwHQx5{tWNB$Rr`r<+W diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_1/00000.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_1/00000.png index 84d9c832580ff71c7953cbc8cb2183641be1a6be..55a58f0da3ec93dddfae520e47b5b69de5eae052 100644 GIT binary patch literal 9667 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 literal 13928 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 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_1/00001.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_1/00001.png index 1d4e1de778297ffe7ec6b06a8ba109b30d639942..e84bf60fa421e34f09daed761b4a19c637fa61c7 100644 GIT binary patch literal 14056 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 literal 7393 zcmeHMXH-+$wnh&KD#ZfGL5ds;9;p^OBq|3uh=L%YgcejfQbS3EfS__M7!?7Lsz^%$ zp$7;dMh+k%M7j_l1PCoslL!eUyzRYjyx;eZao-#7$Nja(*lX^+)|zY1Z_e*qkFMKV zN$peICn6#uW&P(L4k9AEo{Na=E|Ay_yfLX+Gmfn>jqBeQpnCRi8y}KTKaR0tw7I^RM9_v*`U4^>>T!d9#{>$oc zM57YA9`R}Sp+cXs|c5S1$m3}|nU^JP^V zoU~7xFgQU=WhM-YewuBa=||)wbeF;KtORzA>`&Y&`>gtPRHEy(>O3^)I8K1tS?xae znfSWonNw|}%{TuHvVDPvmMR=?wa5^6zepV=OWV{WK7&UvN_}^E%rBN3y%DReXf*%_ z$$zZ~0ef23B+5q#ccFl{MQHS&Lz)G0X7PI;`0g5Jtpv5WZ%VtD4eK~u>vqtdJQtq; zAwhQ?VVSsy969{I=hJ`NaXlr|a>ur|?m{4`M^joEv8Ew0mQmT=zEv)gdy;u^6XWj7 zk;?)b4U?>^A*5s5mRjOLBu~{nLAnafWbzSfkP!oAn*;?v;}2yH2vINs9S{Ip|w$jU9P^Mrsvk1C&- zn0Wl|b+@m8O7in6*BoC2UgJ7itnRe+E{?U zG3E+|!ohfbV9_;3O*clK|G2hphQ(mOm^JFdLNW#uSThn#pdF4hJxe)ULkl6OJ7I+1 zOl1Xu4pyq3J4R;r=1do-(#@LZ(DDiuy`2&)js67=lX>#a2ks>&2;@oIyOtt3i?dl* z7sapF)0SAQAjO_$5~)Zk>Ri@S%ffAJ+_x<*w+@5J`P7t|nTf$H-YpIo;%bq@8?=^G znQgHsl#1jYAJ^i0gN!lu6%vUwXfXTkbo+F8{EPKlel@PsJ%zpVv|nfojDQX;DHt2S zKBed0SRIAODTN7zLLj7;mSXc}AJ+^YS6PcuS+umgL;2%({z@{S zoGv6OWGt_Kknh?>AP_D%*qC4z=H1@hML9w%O^MCV)t%0l4@491;06GP_U`g+iiAEK zc*aG>-#k6~JTTo^tvn!J4(c^h`+-XzvJqEah`O(*APM~Z`_uO#dcp)xO?eg>W6 z?e?&h5z%OBmf7nMhi9tG>4u^La0Z((?=x01EWMw!{gxWur*J|w1>~pn0t*HE3xxPy z{{h3_dtJ(83xElG_CBtC!)4q)GaXIr#(rJ?tfC!;B=w9OeGoL}dq2Ghrxc&6W3kQ&TPr_!6S4FwH6q)uec*y2Lrx2fRAU*_8Fdm#|~+NS3iqwE|$hAZoaRYNUzx}TXvG? zhi4yjx^+t>)zYJRq*AjB-st3-5n!(M_+8#3E;2X8gNJi%60GX>+ZCnxrw~-HMavj_ zxXxSQDWCn8Bl6axX>EHr^YklId>^maZ8P2s2n&xkLF`a)oI`+|8oCB1j3I(e!~K=f;yXzvWqu z*W{F;VMUHbtoZd`H{PQxd<1H=r5^%;na6l!H|~Z>-{8v>THu5_hQ2w-{bMe_-cBRE zLb;p{WNjY)K7S-IuB7VA!af`&fj!Xs`EtJT$Vr^);WE`JGyZZakl)&Y2?#`|dT(E` zLx#`vySMqD{WgGO9XXlSIm2W!!-lNT<|Wf!5QrHVER)jO-!a~IrAVgKA2;w5%rbSQ z3j3n+xIz0BcMRZ!>aW?hmM*C`W*64;7vM-v^#c5!&uEN|-x%8j3PprM6@8RQqQ8^Q zpY^)=#@9?SwFNU1tlyQ*Uob1HbqL5wFUhGuFWv02%WN#U@h*V!xjNXresuiv%A$HiAy5)}3qCOgmE5r))RXZ?-nEt?)8}Hg0Kp54vC8zV} z1tv{wy`JFfB^vv4*H6k`R7euLujW#fyAu)?E3y$K`9#$^Um=oJlqgj2-sLSJf8ZhP zpMIb-c{}UQFb^KYY(qD*!Vj5Nmq^?^^q8Mnox|&v03%~tS|2@fhH%L{f>2!rS&KCu z55WN~uuinRadeBcrpvwdb(C%MzhJypwkW`jiXGk#G@@n+CsXWplRrf?j?o>b-7I2= z9xNHV{7zTdwnqyyb|15^p0Zl`x;cc?p6z>W;grFgo15$1`=cfhoC|A3drs}o6Gfqq ziU&2i>kG9LWO3(JQ9Vw%2AILX!Og*rjt)ja0k<*Eq{l4o&roc%P*g@Rf3oGf_2foF zc%^g)54>+EO9t$R?MVx~%E0cd(sFGC8n^mm3bZr3fP(ccQD(RzA7T=jRI;+YWD~cR z_F*Nw3#Ru&7R8^76}FPcG3MNni+pt^Wiu`3!#ti9%0e~ zeZd#78=E!!j2qyCJ>&w072dwYZnw;|{;)StEQ-im91Eai)>BhdjhhZir?m3oQ1FuC zwnm^ruf^uU_&4t}{|vMt1{sTBc4h zhY$+!!m#|1YnWVD?0(O}L2Fq(WGcBO!zY;dUn)gFe@k{oi&%>&aeDz0K=`uUfWj%<=HsXEon=TZYz7)+p?f#>f4tSNew|+~pZvDh647tw<^a#aS z?I0v{JA<}0z{t!_VINEY*G`qT*1Ne`pF3hRMwUza(KL!;6A?xK~$L*l1*uR*R(;Xs>CWmmq67M(<;wq=plAP|rq= zbN&S_{!pxG{P#oh7UBGyUI3L$iLcO;p1jq==qq4&lXVU_lmD>ET^sL;`NtNyiglYO zR$qq*4|Z;J5c{e>-U!sm;wT077r}FMLkG_yU9oOOl#vwp;?{ ze@`a@t_(Mh4;?j%M4(U=`F;HMVskV1$!vyU?W%AJ-jj&=u z?&RB{d{LD?9jPG?`> z0jsGd#&y=7?gE`OSA}63WO_Xl!&wx_Q7bE+Ze|HHKlfeNd=y0ZDeczku~&~9(IoMx-WW?d6) zJGC-V*LZIRLvA}l+2Vu5eu+W>>{riS$srD~`(pQdBPu2Fi8$`D|L#dGvnkc!PtK3u z0Ud;e{S3elyzu(&fcBF}T(W|N{g*j*um3AyqbEK; zFVC{DH?U4oa?g{tDJHXMr|35fGomrHv)uW?j-R1Yg%h?A-x~*7L0Bv9*UhyBXj>e} zZfARY`+Fp!;Zgm*8v2SDs~6znKl>J+E9Tj#t0n!W^j`l9im3oqh3TGtJjG^5lIeD* z(kA2|x&>f$?^2Mutqk4aKmzSrN&mp#fVGJ0ZK-s)B8mfGZ7Ty#-aoYVu!g96lP_r< zAdYLN`YbL^=eE*M{iNQ!!B81F3wyAGlYx>ni=rrwx#gCsMrC;8sZ?sKpbp@oD3k1NfLd>_4fsLPw>+-6<@ErJIwv9? zU%y6MfI~BU;`0sA@+|XD;~{>2?22vNDX++k)$o~XwHORQp*f(?(9i|v?Cw)^mkhvJ z!B1cIjgZ!2w>ca*+##i-%NaYE4^CLT(Q@G(+Bvr_}Y z2;(7Sq{`nuOR&6W)Y|Q2?2D%9TLR(q^l=Z#7giUx1StJ%=G~!C`i_a>n{HoThUv{K zM?9JKZcWu{G8EgVmFr72BbwAEA?*V4&DB$>YTln&aO3W2JjhNbY*a3QCqqFhWhygz zwEUmG2F{rA#7)L3{tqXzAjiU38P_Tp;fJzXv17%^!j9?irf>o+cgOT=8Q?nl3Q2D+ zT*+)*P~NOQ*noqRJVOaI4%_?E1f9+f1tQ>PRRe6u>W+T);jM5Mw+Vyc=d#xaR?<+0 zI|IAyC5EO;kIcjwMW%G*MTlwJFnnzB79^+b%Sl|r^%A*vP%g>nX;7_GVc`c zQBUjawK4AxpXWb-@-9NAg>{qrS#qD#bIyelh+~ZZ!d&7201saY}{3yjFHL9%bR5*nik^?mGmdxIzR@2 zPj3Ci0b2A5xK3Afcoh>#LdC}~c~>D|TR$rLFMLE^)X~uaI?2>C5J;VirjR$6-zp$> z`?BY#`Rz-zCH-q9?6wDNUTjuJ2FPu8+vaovKR{}=9LSvwgv-U@(KBBr+#(Y%j!I@+ zlK=WOME)s||Dr(FGhrhdqSZsmf6sbUrDS#DC4=8}KkoiGf5K&t>uOh&?5^XQ$DURs z`8*dRJH=#^56T~~Orf0nl;l;~FGZ#u%^qkNz*JNMHFAbd!$3_jn zJAXnUbXlo`<6&RIyY^d2)g8;Bh13&%_4auPJU#O=E%G#z@(B+vIe;JdhwMdK~dq5x{Jzsyz1s56}l0 z3G;ur;otL^UZKDM{)l3=iEK{LlPNG$6*}^)NQ)ofn}5#?|KwkUE!^E-v0Nl+B)Fb- zhwo=E3n-rTPvAv>F6)UGPrhU?3n-F9Ps|CTEJ7(}k;gN-L;ER50`LLKr{6BCAb8>d zTDB*d5^E}tOYzHGb#}oI?`*TF-sLabZmw}S1MJ@@Vxp|IqACak0&LY#smHfwFtCoc z1mxK5bJiQ3)3ObI(R)?tfSy`02uK8BhF1w_03`eY#ev0Q!E{|TR)4j5u1FWmDy#64kFN)!^k?QGRY3aIiKCVNC2`9 z;P?qzKCb$wUdo^Vpa<}GE!Lg9(`&RGO>7?r^k(YZ+*plfSG!lRXCeTf(|#%bqAUua zCD)n(Y7&0A23qc0<2nlYVlYc;Gv_u8Bu8<2R8>{Ei1@g;IKA~i**P|wjTL)sTavQ> zm<#zH%&cK7xAS&{un+_SEh2!N&(F_CIB%s*Vy&f=y2IO3`iTpa3(*@aC=e8AeG4UbXUT$@o>CX^XT;q zW(dJ12Dk#@Cc9U(BZH&&COqNAwLr@i3o#c)`P zp@=yr4w*aMTT)USazGp+R6zp9yKeaSd_NF_mje!%Y_KE; zbQ-+(n(Eq0_rZvX3y2~YlArcv`$$T1(aorP18WQlYm4_q^~SAx2XE`E{Lwd}c(aua zPO8>MKDmy2P|_Xv-l=+HR)!xYewJu|Q58HPiyGXFffdR}zsy!TcS>pIv=6eo*XUV{ zR*TrTIyp9GebKB?zUGxsb%AO0%ov??w(8n8%FL{*zPVCE5Ed@vypNkW-;Bu$3(LK; zEpK+cY;Isz1B~4!+mMggc3Dwv&;5VvVS_dQWt`0}BZrMyX{vNi-=>`;kA_>Mf4Fj7 z<0Dr%|MdH6*0t%Q8)eRDUpNF4e=e^DlH?AMAVP+S2&yyJMDUhkwUj) zv#rvKo1&E!?*kvgEqK^@`}MGp$vT^zgE!1=#!&3>af>2%P*^SPmTFr2Z1l*K-1crQ zOwOiCqX&uE|9W+Gl{#NN9Bxt6-HY$KUxWNz;0uLHJ#knIO(_%#E$Y5TV-@F5KipZI z&x)nlzqu&t{Q7*xC)-A{AYshzwBvfJQ@>5xV{6_;;vh~icmafDYHAv~y+XB$O!hNU z6B$$VAN_UpA~?B<6#<9CnUP=leB)cMvj4hj4&uN$?c-D`6$<5?9c*rD@`6IyC*7+n zkYZf>tdq_sB*NHXYjAU0>yg@|dh=cWMrxtIWp^AFTP<5p zKL{9*{K8ws;+%*bE)P4-m&j0tcu|lGF9*t1^)CHTKYA!W!9m2fHg&RJQSagta#Wx?N z@W+lM$+&KKcv+~e3+*^Au@oK{fLn}j3Zn9=UA3$mKYXpu9u7I_-q-HowbnIjnFL*^ zS#1uY9S&h5F9AO14W>+pQuUVTk`*T>|Y&p8hBogPk9 z@$`d7Onud-%+cQ}L5GAl%;%=M?}zx7(rde_+zy3#9uTw0$|KP{~QV}L(v z+a$eFmH274>ogd(+uI>3Pxz#M)Wl+9F@9rnv-oR#H1;?vzUQC^_|DWqRO1^~jx?+( z_iK*oo4A^)Pb46oNKxF>kz-G=4vn|Cd)rQRRh5$suJdNB<|8$uIa$;D4RcH=Ht5|$ z@+#ENUDq{0!Z38ma}TtfVTnPYAe+&kCo(kPsSZcf3j~7Mx#FAG@FQ6jxprgTLI+Q2 z2em@aW~&D6_d1$?L%ITlZIW(3!+Y8m7XtA??A|OQWq7Me`u{SyEX{Y8?h*9HA>ByK zXwP*z-PPe?u0>9j(INHSQZEM@cunx9NrBrjAWGA!9Z;G!T3bM9h{Xw3n#B(Dx!wlo zpB;lsIsh@F-3!&osSuXK{Xea>KBwjUIv#EIKJ2NPN8T22ZDO7~Ny&)W;%_ru%$ zN@VuwPtWK&&*C47_c6_Ry*HMjy4S0H$NN15E+skVr_1d)(dck>e@x>?d;C6kCGXsj z>8gQwZ#9$0C#KJ3{+5X!@i*d9+qXARgJB!al0WkOP34z66_pgv zR3;yn`-g|5rjJ{Bt+Ko>>fGD3x6$^@qH_7M4|x~*Tc2<~BAwQH+l5*XwjmjH;@Pz+iADq>=z#pOrg=S>6X< zIJ%HHW(A{jsuttKL!3O~IH)MdQy84l+w+rWQ2w<-z4)1Pri&pS zvaOxC)EKLtEzioHq%~{*m}0NsU2tg{dp=+e{zFmA_L#Q;JzQbOj--ZIY57ROemgW5 z37<+Q$YC=5ca*&$Eil2ILY+;%H(vD*^Z83U=qDk*gy8h3*E%~unVqTb+jNc5Y}}(#kJa4;!haFAIIP2I5v1?gL)Cd`1cuE_VwO)XuFIR}fsKD{Y9# zhV7?7xTRf#f`o22s&6fIaOzWL5D`L<)9&a_5lJM4n0&Wm>Q76XmL_-WLHbC+&7$U< zLGJIPivy4P1q22s(3;s+QWm=@zZ;Cg*`W8uYt+A0;Q@I@$|9M5Pnl?kjZeL}NGna? zEs3_LjC(?kYy8$ZZT?OimLJt^san?(c6|qrMD-+j$f{27Xd{yiw%Cbn<6}9h;N<}| zAiF2N8klH8mq{)Lf|=<){EvQt3!s?QqYKUvd&;?7?sEGL^F{=6J|#^MOWWUii}!** z|8;3)B^P5Az{Ys+pI$cMeL_zxCn&mp( zB^4MOtPMWak{RXA|G2Ym6BH;sx`060yRI!Q{jSoI;Y3vGp#_Q;h)Y>n5cVI5!vR3P zXEHBItOK2g+uf*75j<*d4)E%wtq9h@uRgvluee<|%l!!SSejJG^}u+cpY*c+zD@)@ zO=*4L`zBK4TE=kHih4!TTD@yb&vw&s-HqOWm33)Eec8FmDoZI~RW_uOHS{V+@2&## zQst7%GBFL@BE8wNGzk~?(%e?^0Ha5RhQG?w3XVVzwBQjms;41veNrYJL?(A7?sD|} zB4qkX$?u1ThL&|iSIu1VMgznP`{x(-uan6r6sqf7x(Nn+fuU|*vks~i9bHI9X#NYwIwx`EedNw}&PIrQF86_vm8@>{~{NT0B{o#wJ!WLa77B}V?(XC~By@O$I z{3sQ^Rxxdwo@+XH&lH^vq(g^WhlIKkKsg1Y&mi?SN3EdZK z|K}AcL$5yQ-R+DPW;%~=#idQ9(4Uzm#*c^34Ote)wwX*8M7Lfr+_XLMoIC_fHY&##;vc{x(YU(RT)qourn@|E$oDE zD3c+qU61_9X1<(i?dH*i$C%K{`MJn-Jfq)d&mHjmRJs?vYD};S_0eiuh?!Y7 zQ6_nT`y)AShalyChU=;97AL;LPCGK(=6x43ofqBzi4o9PJnKFvn<2q{_k67r|Mlnv zE!9l=v4mGJe${xwFz$`(=V~&!FF^ufFZBNJ@|Gn)x0eg5e^zY0owrBv{6D3y|F{zW zXXQVUw*F(R{}}6^DRcfU{AII6B)jnuj+Msn9FxLF35iw|X5Md5#<0aP+^dAZek6$GqOU<#dBZ~&NSUnCU8 zdH~EM9?^Vj0u5l3iAhm)L7Xv1s$5L3^b{POH?S^a6#_=z<%DH}Rrv0<`k%0UW z%Md>VwNVFHUy=9Z@AbM=DpM!&c>1zVu%9*f3iO3t8qwLZM~n{tmYW(9FMpMy(DwJ5 zbVNB<`b*2j10Qaf8$9}n4fKcfs;0@GdNX6IBh}$A&#OBTJ$-ZE?giR@p#9zYp#SKK z10mCixXcitq|3|ZAe?vE0OB~zNDasvQqzN;#(8wKYecib2Dp7Pver)vjr%H0V7T_d zk^$nNp$z26ukWol6_fZ%|B)oCsu4gPs)LbMQKhLD(5M!fZ=gc_L6>G@b&+oCwm^;6=)>U)_-kT0N6poJ!`CL|`h zwvL2bh&!r`^5`MKPoDJ5<2t8FBoZ;(#xAJEkFvQTzC>7(zo^g(nmXtRR0eacc(-Gt z{5m80V*FF2TPlqoyFMWN*~`qXOy>c%HN$9?oFeqY|_A;-Ug(~m76hvZ%YGXwSsJqMx zXF67KaJu1}VqC;8!G8dItO6fHSuIUJCli{vF10p zcOkX=3ZxhT#X56(CQE?i*uU-wDdCAwG*&4=RcQ%mWU;my%4+E!+YZWpU~Q)0Wwzv;AiDysgL8TtVeOPQ z8nGef5RT?%B-DisU*t*oG7e~ReBQq1$zHiShH;FRJd z2Li*VY#^eZuD4!HAPCQ>r8|OtKIrJ#s$vNLBRX5Pu^ap}fGJQ0s~Q#HMN`)GX}zI5;4c2q(_0tyx8^_oon zaAlDJ-qM_B11JuR-87G2N7RSf;7v`QGCJvYb<4wMT=;1*)8l3`vKE@(%xITw9Q3}t zGG4e{uJ2l&HM`tfnCw%qrqUr7ylEU(PlPK9Lx?cUECcm?`lCCo!@ zixmeafViqs3EfSkz|-9+3WK9N#@Q!~x>M5nxuq=LFLA)!cR^eA1&*fmZhcKkrGw0s zwBNZ~d>L#Ji_i6uC8akW%-j#o@DH*IdnG?P7F*rit!Q|%KSh83^1a*B2;D0A)o
h0aiH?@#pPM`8eWgm0HE1n z4@6&N`Agd{KWn7?%?$sV0js(r73d%RO?SLo-PBgzF}=7pn7(bn{=04dHFx;OuClmF zQBMv6RHXY_H7kM%PJfXPA=L-IG`v+mDni+7C_j3kfpe-4(rna)wK_tf02K%wtpIQ& zARj{U#xd8JWhU@|(VCDP2E+x4TT<^kTE9x9*r}rKzKSa?Cj`dYzf2|vwJ&C!z(-U8U|R7B`i{k$3@I&<~QkJdAr6HBLFfG+}g zYG$Aw0AXl2(yTzUI5r83^#Gf%=Hq30UmboYWGDM24z|n}bU5wRw4YUS*S!R@#|#tW+%I7N#6<%qpy9MKH!V z0Va9yz{HSvkKKpkGQR8^(QFfpb(!;L+ z&OpD6iuY}wgvyJ1M28rFbhGoR?Lf*9rC0Z{a_J#KRB_UH10+Y`2(0zPL&Kr8_DLUP zL+F_C>eLhhk1a`*P7U0zGK!-GHjV;(LFdbzQ-i@k4EO^`dmwB;16tBM2oyEbE6Y25 zMSGrv40kP-o8yTB-H*W~NsM+&J(V4)v(b{p#jLzrR+=Vx^ngBkh3%0?t=~%rwp^yM z7S4daG^z@AR-p8VXMR=MSZ0E3{FG()0$=z3-$Z5+yRA@aJ;$vbQvtqR%D6Z}&Q_d8 Gr2IGR1i07$ literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_2/00000.png b/tests/snapshots/stax/test_get_public_key_m/44'/1'/2'/1/42_0_2/00000.png index 13499fcc9366bb214269b05db05ce8ae4380ce24..3f906b2b76be79fc321634fc00b2785ca627789c 100644 GIT binary patch delta 2731 zcmXArdt6d?8^E(nSDBXYwDLOFYs}Ov?bR}c?Cx5!yyB&)QJMsrH@t8;rPW$aaKoZz zN}DFBC^&Bkf>BdSW@HMeh?q*|1yQ_}h`h(`Iscu{`8>bp_kEt{`#DvRk^dI#4m02D zf5I;~^N~vaK76=;{q6HyQNp^jLxtBJ4>|64y!LGj_!OA43|$S*7MPbAs>wc(48_r7 zCXeU%5v_3rwj0nt{JL!h+YoV%-fevyHVE)=8`mwH*Etw4*HgY)KMu4~V;hWRS;Z2s&^r^yXh|x9|-mApl59W!$Z^!T(6SP2~h;<{%mH&shg7gic zGSn0aRIS`dy3hoB+;qirbB|Un6XU zhbQs70RFHcR#q1JC^x3-iGKT&Kflkts$6F&UtONI7!qk_XAeBHT17dG#cj#kz(ZFF zK3EuUvOK5I7^8Vg_`;9l6;zYXquTu5q>Zsi-3p7NZ(S|(+Q}W%`lhC)*~|gJ1(KG} z??-!b1l1)aC5Dq7zCJz-=_D5hz7xatP+liivjr)~q?vEIz+j72{;9doEy)fu0(QGA zgMF^95A9i`Th(ble2C-7c`YqIK0Y=!tD3b4Ft z0`~_1kMBuM^e(ou;bdey&L)>@U5jFolNGSy0L9>7$JpX@|1`n6iXA7=hGOpRA`6m| zlIT|NzE{-DX8KHd)3~*S>DS9xF%?KtD?8)r0!!_@rj%eI0M9gA&{4y zVG_lZ+PYm8iA1(_@iV=e1WB*C6K$tjt(F@PfhY&#+xRcB90RNUm!zl$?@ZnD=6vm? z-h5Rmyu=BSYhR2kA9%uM$B43TzSE(XRXuttr1|oZ| zI~d#F;ldk9e{AKfU5?uo&Xi6ruz&b;$vs?O#rWvr{wAUS9{@In}?ghpF}ZZ(~@ z0PaV|aww%yQ_~itU6FQM6L7YmUm47xP)1{&qEGTj9jHhcS9k>Vyufq81FyD= zCcLz_vkOQ;Y6mE`T^06!HQF@g+qS$Ad{?vudx2jWAA;<^SBFvu*LWG5zLCoNQvY5f zhb=3u!8HFExVOo)L&%|PL7fAM8Ac`vLC~-x#Pdj^DQ~UxRKu$?o9#U?`+CziRuQjT z)7r)don2@V9JgONQm1&)0VM1$JzU0cmA0s|5J}pB6}=x@H2v3B>vz9nn5+SN7dP04 zcDoh`?9Da?-x)tz-y9Q`7I8eQJY)o;nYeRm!Dun18Qt=G5b;l-UiC3SrWE{)VZ0v{ z3O!;bDb`0Mv2}etT@O3s#IO568-V+6W@gqsUa#%BX>i>8@3A>lf>8M<{=~%T%Gyz6 zB3k7P|6*s$3;J)K)G@2v5Z`zCX3wM^+J%LN16{%d=>hp9oN|w}OZMyqcm$oV(-8#b zdzDEKMPp(h!Ou%y@^!Ey&c`l{{)OuPmFESf;8B|;adl4Wx#co?`#Vx|Z3ELpGGqZ2 z*Ejn}Q_8hiPBp}@A^q+5w2sVfq6D`T1yjJ`PY<+$9lu!Ht9z{O?(P=RVBnNyG;IL^ zd)SdD&xpq!OY~1Yakzab<}=9L^k%(7H}FA}>>7!@{Dd0F%OKQDz zn)nwUN)wHRBv(>|Lg{BvaD~R`XcG<)xY9|cIs4xt5AuX3aIE%6xXHj7q1jbzPHxQsdnnr}d%(9elrO1H|!pQhDn z{i;^YEyXq+H#QkBC7!r1ysSH;B0Mls^s3!6Z;5;{ITv1LAr_qVe6knS*s5bLx4LhepppFKiXDmn49Kw(dFv@;1eI7KPA$ zy}B}ZYGVftlyuw0+K6h)ypvg3BdH!6ZqIiiMD2oPaA#Yc5xHTRONpO*3OT_5)t;d_ z57R7T)ZQSyrKP3mJ`Xfn6ho*7aQ+zerf#{qRHb7-FgR|C!aKd-A3i+PPDFw(xu$&J zl<~_x{mxJVqHN6HS2=*P*@Iw8!SZVL?!^I|R-@5RwS-`WH!FiEimL-tbJc+%kPwxx zExr~prPFA@oZq5WZnWl-dsx=m{C^w$NG3+5kB(=BJypRIN^od) delta 3140 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 OCpakd2>oz;!T$hx@V%n| diff --git a/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00000.png b/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_0/00000.png index 00c634ffe88af03190fd5e8f27080725368bf29a..538f3218042a9c109feb262a20e2e64009b25057 100644 GIT binary patch literal 8810 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 diff --git a/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00000.png b/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00000.png index c623aa7a753d3e129a95e047f4436eebcd006a69..55a58f0da3ec93dddfae520e47b5b69de5eae052 100644 GIT binary patch literal 9667 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 literal 13385 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 MdM0Hvj+t diff --git a/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00001.png b/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00001.png index a5d6f39400111fe3147779f50066e5c3e0e04273..aa4adfeab49cc26243389508707ad0db54e05eb9 100644 GIT binary patch literal 13511 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

FaT4q8`kSREE?bwIhNRmtxU%20;12J~FgC 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 S0+4IXVP$^r2GYzc?Y{u%|HC{0 delta 9569 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 Ov$48*5p({Z)c*mW{I`<; diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_sh_wpkh_1to2_1_1/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_sh_wpkh_1to2_1_1/00000.png index 78571a283096b9a72dfa7d06957c2c8c5229cf72..a19a87d4a2dac3687a81bb15ac2750bc32e4e67a 100644 GIT binary patch literal 11942 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 literal 11723 zcmeHt=~t5N*S15Ml|zH2nL~q?<(#vkWoBmPl%nF8nTR+=Dk%zDrlqBpB~B?0<$&`X zj?Gk{s3_!omkA;&8KNnn&(-}r>s{}9|A2S>K0JQmTo-sE=+!GBRzD-(IZOx&+pru;H>FL zC<-O&Y(=nvn~&`s5IQ0wEGcyUe;5CuNf_R0(-P9T2nHvY;DNuD2p>8RM2Vg}A|5|2 zefQeCQjxN~1HV=Vnk!`zXZ%0UTD;Y{l65clqfN1-{16x%ZLA=5|J@?8Ah$nb2BehPo3I6Z zkX0>$y?D;5g}dH0z8Gcq!Q1r;j>3#}-%Wm)nBoKmFCshHybf>h8mfC!z|Xuaw(R3 zRBW?UQc)kcU3>k}7C07N_$csp!}#KfkEQ+B4L*${o~zjY0wr|&R#2<9P)V`*Rs6$lxUliVo|3k`+Mq_8{c>1-aVD)<%5K;-+oYkKN&I#bR>)qzMUas9g(dtx+Mp&P zKc2h!_*q>dZP=UA7n5FEx#hOP4Z6eIJMi`6%5e4esE~vp1A64*hmzYLb^_rfel$Em zD>kQ8N7v2uzAc$?19JQKA|qekmc45Znj|Ki?)c{1fzW{OT(N>anH&**mAzn>t=0x%fN#n9ck4^BwM7ePg%93fcX zIF6D;HSYa;Wrvx88EnrstVKU@=85yk-x}NWEgbcV>*>|-+irSmHqOJ|Cv3Cu`0}-0 zF*mFIJKA&u#g5rY!weEw-);iGhSq|(I(B*Rn8J}BnDd=eK;!{Y^SlM&+Wdk7MV*!7 zfjhzwb6$xMAa5TZFvHX%Y+^!crK!8_UYna1gAaV&C7d26v1^XXdRATqhxB-BwN88H zXP;bcbIWa3_WE|>Xq&EnaUT;|u#lbUe%c$+XN16<7NzKSZK+jG0p;4(7m)UWtbrP@VcQ{=qXauyKg#k znsw|RUu_=u+f66*!paZid@n=s67R+maYpyLCvz~8A>0g97_X~+Uy>L^9kb9%vH|hn zM+C@jI_Unq-nQaY(Zik7oTOV$em|=$4rdHX_D`KeRqjoCdnXn+Rk`dAE9K_eTM#42 zTw)QT+|)oHTGuK(Gax3p7uh*k{G}c~=M*uh`2nFY9p27L)-531ksJix`~`|AjIVo` z$KVSv7rciC;Kp zRZ3;8#9O$3f>F3dl#`47k5hpfiP!set530xUAGz}BzHeC1(rja<)Qj4u&2fEGP$IA7dDwqaZ|}}4Rcq4{!EEnuq40WZcmI@Z z(oiQg;ZGA0AfO0R*3hJ1*3Llh!Q;K@_SE4X9Ub|gF(Pmz&dRA$xJSf2Gx5yW3Mz|- zYV8^PQ}ny1_g3R_+|6>dDSY7g2Sj}5WCz9z3*@xhw>~%@nf%)(4x}`{V|vY;GTx@s zdl2__txU}PdHK<$ZrD_x|4u@lM*STCSsyj-1wFb<4P}9YUi7P{k6rerOWr*<5}r5TShC$*GEGsKFp^=OR6*|m|zem(; zy*0;C7#pOfuF3E~2tNE_9UI@BQCeAjiMv#Py6tr0j4_^gLoOx4tTJ6KmRJg$5(V^MizsIqdq1EP*OI)oa%dD17c>%A zUoFS@!u{KNeWn}h?7hBHRJm^1kVpFVTu{BHw-=YqYx2(UxNJt>EDwh7JWlE!7*sVf z3QO&01Vcx$RKcmJ1IH# zgO!2+NOpka9OEqmt~nh>Wkoe9lLz_Zo^RzT-28~=SARj*JBK@T#$}ac2B22Y1BqS~ zF7O4^^brzeS|+@aSxm2E){QCtOsns)A|{LULxbe{khmPPKsXH^){y`o?F;cGBEB0d zMQz9TP$1Ym^y_KN=RTSo_>pHjR)DFOu42aGTZ))ff|2b#zV*&Bkh|9=Hr@V0s+9z= zS=QKPY#^#I5b_b>O`@i%8Wo&SAR>I+jVffUOQdf(%K+$2nTf!if9hGgS#L^R$zW&a z1QMn>Tu}S-lg+r`-)D!5@53?sL6lB!Eqt?&G8UB%F+h%KMHEDv+ewZES8on`9=_-r zwz2X$>|j~7avk9Y8)np;+zmNU*wf39_pI)KHuQV^!r_$l8s6&E2v*nQ^LGzR{WIWL zLYQG-3@9yQA1ov99O&2IGY}BvgT~2gwcP?|KZBSGEZk=mWd>A>}GX;~Eej1zD7O%Q;rq;e1X;tRGVdSEWg$7q}>JJSx zOSd;ao9NPojfTru`^%;H8%LZgsCYa}sffL)m19T$B5O)LcXsYc{B(i^4j(>}KMX*C zwYW%EJ7s86`ODzWpz8KOT_0$3JMH|5wn27}Uw`LN#<-uJT3<#Yb=0mdNEjSo+u@d_ z@>zg!w<=|v&J9?ZYj^B{iM7mr5;vjtNE_`uxs3KhhozN%+SHYGLZ9bH?Yp@dCpKQq z^aDlQ0E6+`4Q(q?AN}R#&7uP#N>V#`bm!=q#j`sHi?a%Fyp5y=Vqvh#!iM- z;X*|FIHuQVzxR08kD1{Plk*xPs8fvRNb`DXpLTP1+b?@*T~nYQDC>+ActqzpDT-cP z`KkDZ3yMCh`4@EO_envpBWFA>eYTNX*)i3n-E;*pka{A+pL`>Je2>DmJ3UvIT!PjM zg~OoUSt^2)^&SuMg{=hMG9Q34xOQOJTud;2O4Z1*h%;~sK`{EAN8yYXb3 zmeIWIaMF0tLU4m-q>V!bmBI3!;rHO3*zPNHuToWS`?$LY06*@jXoZ%Yd>Stg8<_WU z)#>oCsk`vNeqr-Ru^D40_txUSfCzD`ojUb3eU`7wp?*&|13UrFsKAq6AN~WW2i?QmP`$WOqevVT=(Ui_3uDV6N>k9y`9;L*1@Sq5a^y-32swhr2?~t|UF*lw!Y25Cd{C4xf%qw+OuQ=~3+60q5U2IAc9Qfqi znD0cmk)CR_%g2?h0_ruBj7Vbza(1O?wV$)&d{wRgmx_Ujj#%qTH;=d&C)~(&s02?5 zZ_?UWh{oV(hi)uL<`*&ZnkT(dP+sK~tbC!$3fjJWRTktCZmVDI#~=1?|NbWtP*`&d zb*+8<&ivfl0u8xIAbe7!N_bqquy#c6{#58WqmGl8F@^KpK2EP7GuCZ zPgyUP6^!Zkj$2iv(HA6FTGtmsIE8@;dhT$&v+C|sqXI<-a{+be2Bystm49BDPRK8%!)71cTKQ8I;20(q+h02{4`@!I< zlY@jhHh**IxL~+elh>TTGjgzRvldTE^XPo@X@l+`C_`xu z&XQC3`_!D?Xsl7vJ~yj#2`bInM24{BwWIoo2QJ_d9%^zCiPdUhNZwA77Me~gnQF=f z&%FCKuu;kKtf=$!6A|)DO2mGMSF44?+yvd^9jW;S?7Ds>p&p^If$x>NQfM(F>V`zT z(OB^Zgb#hH`OEs+~HOcky$o;_S9xRMJ)m;_05!Jnlis!aJX)a=L;Xb4%5RH8$(mv~p>IcnEfD zIVLw#s3PvGM6R^_^*oBI_`90}aeb$nHSZp2aC8qlkxh>sQm45~va}^9+ck9?t*Hp<1UT z!`av=Z^!&{e6Y2_UXQk8T>XZegi=~XvcZn4u|-B4WP)_~zVH013S-)fV9x^ahSn36 zMW?gMS*8?Z-el>lQKpAn3P8aDk$`iXSHG@5#paoE$`f|O2WCFio1*U!-~(9s=Y*X^ zL<&tefg60y4d<2lbA0>Hg9flaaNwLrI;3N2zH8r5s-_XT$rslxn)OOk3+^R-KrH-O zy9ea9d(PNl&o-aiEhA)`jVHH(7M>hLNEq@aaQOamt1P!{L787_shY&Qy6`Y-=Q(wn zitX@q0BTJGP^&crZTb<=O@L}%YY6^jfIEN9_qS2x1&aHuv4f2DMvMbUk{l$BKjgmg zT5Ar)O<=H*R$I)_Sd>{gjWj_C~Dj-Ll+IbXuJmMHLn>3A4klna`Abl=zyr z_|ZT(*lq5P2P4i@KaVZy^{uZH`5Mq{O0R5^hj})AEYvMhUsIKMrdX%MJei& z{M&C^wXIz`jNTQUy%j{GG(IG}MTGpGg?;y!m|1Rce2ohn#q_#6x+q;XKSt`gCHTY1 zA75;n=4b|x0m%i^o8Tozn)-kUwJ5A+#DIz@OqyTSw*wJI=DWE={)F+w_VLA=#vU1M z8^)dqt#hYdq;D#84u7n@a%#NZdOz{n8h;Y;9MCgd+`7NI$|T2DjB~rx(uP07>q<08 z0t}A1Ui{`37@T+N;I=ocs3CRWOKl875DIkYns(ZGzf7|XpbtQF(6e5D`$!we!!ANq z!YVtQVbD5bj8JIzJ?>ZU9;y2mT@SgB;`hEDdV|!O-`l;>yUJ9_6)O~jvhU9r*Rkhm zCwX#uypFNivC9X|lUoLH0Xd$Hd}WV6JM0x^R=Us;ZVLJIhSrB)O5W9x$zfp`4c^!C z>0^DnztY)(T2AaE-Xs)-3#Zdtml|u?M!oZWDalMOgmhOm-x#0)(#|2WQg-{_IC7}h z2Ks4fy2~>2qwjT>A{Vam4_nD*42sV^*@)NcqqcjFiX+7MC zr`>K1V|%`h$#zCl8E5(~ovHreGm}ZxH)ubDC{Cka+jNUQ816$^Ni?Jn1O@dyF2wBO zNzd)Y1yqks4nmj8&WfO3SWI7Owrq}mmVceGFnf#TC&o=rGX0s~8bG=Zb>GG175RB` z)#0ZSU;bcRC#9=Myc_t%x*|PSWLAypzvmAVTUl|b3_6#|S15q9$leP35l?SgZY({W zH>I`at}n_DOVhoB6o`W9>Im>?Tyx$CxvtX-+X=^7G@!!j*q*e8{wUb|!HMv8ugdyx zN}+w$4@@sWe`uJ|-G%4JUQrquK%wcQwW8mMPpEjO#Tt%B_!szfSsvP(Qqse7#m)kP zfnor7ZKN(ee{F*={krh0)$1EeW!?1m-jM8 zih(X5-l#I_-T^z^{fmpYr??=+{Q{$s@?KrDTh9W6k*6P&RvH?X5K@Z{na|LBw(wB$ z7Y2Skb+LdCJ(>&Y%KUk2>>Q0zf{ght@U(-p}bog*XnZKG>z zqt$#Xu9=TU26<;TmcXeSpAIc*&Ob$wG&ETtS@?k6AsH=~4Q}_Y1U=OoCA z0dRV!*EG@3?e#2D-%Z%WMMt#WGc9!JXjCJeIoeFCMegdm{-srr?sZnfCFSRXQ3p`Yt?<&_<6Pq)lvNAS*ejMgJs~PDbJ?(}AWg)HDZ@t(%j8=z;+IL29%jSttWNS|c z7O_}sX11aan}l!;>j~Mc3Ma~)(=!%CsIBXkWQtUOa-tHYYwA(yCG$&FNO-;JyE6>AH79`nm?_PEX<99ogJKA;9M7Q{< zAu9Y7SBFO9B7^Q1iM8^E9g?7596`x$yXOYMk{){oW?GTqAsJy|Q#!%@+rLRD{HSfQ zXlmy5_^}_1L&Z0GrZ=uHrZ>kohHzC+wYrnjR(DCKhZP!pU+iB6N#^fxGjOE)hEBeJ z<^pR?tjn$l3EwYq{+#2`A4ZGAr=P3kt8!Aki0#Usx9FInwRj813YW0`@OwXY`G^c}C$gdd zf^JV8j2q+XJ4L#*C@tzpXo_Y$R|ODWr5KDCN$>h9H!p3)2yzBz&tDGYh&lnU9*nMn zP3Sg3r702NO;>FBg~tP0?RJ;$PB*2HYyG=c2#(WoQSx&^`=rLEtsP5PX{C?dUSwYU zi&6ex#PWZj%l|I^Zy@&{oDJStA_9;jX&;1yh6NPFa~+9xEis|uj1y8qd(slcgi6F= z|9=b z2j>EeP{{3=o}{Y#%PLDzk0f#w?Z&}O;3md-%kIY;9s{=s+$qtcHI#PwoT$g+mQQhZ zu6KZk+wDDo6ns8q2+)PSx2}h8JDPm5SeWd1>9ze)e_0?%dSPHCyMDLX*&c3K2=mH7Cr|IV_v)Z`Jvrt)Al0r zLidgp3t#zVho^k`VrKW>lpt{#1Li>>kvTvl!2Wzxv33si+4fIJ?V2m6Nn=F1j@?mb zHm8{}6I0ag{iM7m{yheLzf?`?z7-h!ck(gM-=wL&9mDwZQ+_cixa=Ykpu;C%fmz?m zLG-lWoMw`WZ7Ch6^7&OZ2id=4&s--6j&a|l&N&+kc zo+iA9_CR{TV1}Rk$Y!xSrrQ^M1{-*Y*a&HC?ewh&G@>sxnEs|KtuZSgRELDW96l}! z%1-->)~PgMCVOZUVL?cJ*TtyyIa1v|F5BQ&((9|u-8~)J6JvpEy&$KXH84S>LGM9U zhx_n?wv3z!0CEFIaWy*PVIHzBazvH-mgP%1oo3180}%(3F&K|O;_74}$B*hNBM zA)^ig&{WatoMljb!e`yd&iaLz<87_b<*9I#FAnw8sXYQ;cg^Qv9xK2wwdW-}d$m!{ zr|=uJWu+*e{b(j;Ag(i)y3I4gmtv`f{jlOELQ-^y$3pw)O0W8+F}9PVi0Ag<`|zD% zXzZ}Lf5?WT6};SWi_<`OVSWKy6cEWWk5)J-VKwRG^e^JB!kfxx&iR_xkrQdp8Q&|) zYG*pBqoXRojFzp}?f?e+2!|mlsDdMa5{?l!xBHs#`6UzQg>nQYCe0=VeQyFG`RShk zY4T%ZVuF-L0P<(exOCl5t}`;N7KM?f0b zU*`O>`up#Tt-KOiRQ7^ujL~~nx~pEUwb=5~Tzs^DfsCGdO6tURiiybU%|}vxdQnH$ z2NID!?iJ^-fmnEGn2y&LkNrq1?QPTM%N>WbyDN}Aoa$Yzm=6lQLH@|PhRh>4kMp5{ zeRZL$ersiyP6 z@JdalsKf1D35ZF^`f#Elv8xbZ%zcIlq0EW zVi9@&-O-GhIu(QVug&%o3oip4%HTb(7_KhAMfx;0H=>XhM#X)fZz~W@6r>m&WH1*~|7myk&;gJimujl}tK##x_S0^PzyTE%7$t+jmQf|^af-!vZH z{P9;Q^o>Jat2cl76WJ+P=bp@%0V)!48DL&4GSx%p6K-p)!?^nQ#OEx`rkR_E?tYsP z#f=HmjR}P&?*eVxs_yF!8+z9(*C+`#o*{js$>j@GK4G+@Oh3ggf;9=YKqI6r1TV!F znG~!JWUKq^H}T(&m0rv7_;w@#F6n7YZNVPz>%6+g?~ax_LXR$}r)x0_B3E(`kV&&= z&>Dbn+@}`W7I05VeMuSdQ?YiG@h6^XXg z6-;ltuST^@!^BL7x0Y>|M@Mp%=M*anZ=EWSHd?N7&!0c#A70w}Iqpl*SXD)16gVd7 z$R}<*%v2q|d9^j^%j_*6Dw9dI#PYMi#5MU)f*Sy9m-YqW+$-6OtGfzgWy4E!zktE4 zU*oa`O%+J!hl%J(>k5)nyV?llIDGEwL`1N7c(a4#MiQ>_Y5)#dM;Tw-U31fhw2%Bw2n?>O(@zY)$Ms~DUsbyLKsv>^62tKHl_8r-oXTY|gQqGtAef`o1UCZVW zY{i}b^|PQo^9bg@S>kiE17hjcuj)eb0z8*N+V(C(>r??=YEYe{VF1(6BAtmo>jbU@ z+dR>cAn5)!z&NU+W)sUL@gKaN|s9~aI?EV?)f;D?z#d%By8oU=BIA1z{T$`w)?5yNd^#2jpemJc>t_pT@
os+~G40nQqzYW#^AgQepd?n$6zB&NCG;0r0m1X*N z0U^Yhn&w=Z&m;u`VCl%GN45e2p$3?VtKdI`;JP;NUZ^`-EF7Q6**$GBx8py@_w^S` z6K5Kub%lhYw<3XZ{jT<*uux^$|Ln(KsQ2&2{AVndN7G6HhZFm%(8J%;wC%5D0en|m z-&x0wEn>zthrYz)fliBkIb$4K#P2yvf(rvS3Nj}KijwReB%bd83tHUfDy?_L;GAXt< z%jw=84t3>`_Qi7n;L}ag_meg_i^vekxl*++O*Qy0f1NU&OX>%$OE5qG`s@bTy4hPX zTY!*&zbtU;E#3MUl`SmC0jx4Y%|k)%aw)6Z?;fcX%mY(4^$$H9W~{H*ul4x(?O7^^ zx|M(#8m;|BFh1uqw~JjJMer6=I9|LXeBb%U-1T@sgzENCPrKebeVaE`5NM82P?ow+ zYX@|x@kLrB_4Omz_t#_ORpDlPKwh6y+FQi5cK#9T3&FOJ+jq~#fGlv7_CA^8w5Nf2 zhu%2LtoQiIBx7_l0w~ROy$O8s!#^a}?*;29IuCQ6TMy2LUfMu%&5?3UfQi9hAf~TAK1y};p zSKBA0YGaGY(+7d+L|Bswg&W1bhaNl5A9%BuJs81KUV3dR4y(Cff4yRU5DW$;n{?k1 zG-1%|P@~dhQ_01hhU`Jt#>N9<#f?Q&)(a{?JPHil6w3o4hBgmf|Em1Mufq5zF4hpq z%Z%YDgaQX}ABDG1a~2E47&d2NWCxs2A7%jBY_-@9ouw~4`orZ0Kr1oJVQ1%x*z39* zmS!0NQVWLsybI1R{EYaPMmE)=ktM03)w|veMEi{F6U2bX7LjXwpOLHoVgvw5R~mF0 zuH`Wj-lNFt1pv&?cdK&SVKn`{qi*V<25ECsz&3VZyDGg_87|f}LnB)=RP@ycTjwjf ziHNW;?B^`8+6syn86F*}Et4X19ob?T5C$Y_a0-4ICa6|R0~}IQ6I}FJ+pJCLR{6#v zwX`Bi5LeS*4me*7&|!Z$VC>QycF*BR?j(*c=-H&ICAJTP`W@ClB>Z+O0bs6-+;fe> zYw5A3><}RRKN7B)v{+hIwts_Vcr@OddC-GMQZjeY3NX<}{Bs=GehahbN?(3o9xh&f zLiYV!#2iG6_@&D0TL5U%{|U(x z92^|{RyS`v;Nal=%E7_q#LETLXk)4^IXG0Et!|jw#lGB}+w83Flidp6YCqstzuwoOd>Jaa=Zx( z`PGUi2NiQfRW7MZa^`6_(hTr)?8*cCf|8H8q5{8lsE3U(^{M*F=L*@&Uzlvc0+Hg4 ze^1BG_z;JOV$M=TkDHp9r5aNR6JF@|LCYc4B=DvqnGxMP2kwGaSlQ54qXhkrl{-it&v+Ny)qqaSzogn^@l+sM}hP+NVqYIe;Rdi^W{ceaz*cayq}U8z2}|8$deKv;~kw;z+>Kh7Jd5)w$s+-ButmUm(s zf*z*HeKWFVH#LYxiDw#MAY~}DGgz7D4<8*vl@RoTU|c^~3=`hGx_9Nd-CbjUg7D<}}$Mkz-4G0wrapqkhLJ;u^al!Wn0)NE*=^fiUms3qJmZ_oaDCYd_Ch!f) ztyQSiv9|%8Ukp>kUdgFO21N|2Yw?6mLV%C!KFGnY0AFr8!jm^N31L(4m1Cifc`Fr{ zN9hS4e(EnUx0!~|Eq#^T6h8Q5MuVMPF0&!#Vb2t#b!JsCU@}#48Ziw-a>Zds8 zY;A@4(?h;o@wUe%wq%{+g*=(z#a`=Jy5VJZTZyJ zjHInEx1{F3dU6C?eC5bfU+#`lbky(D;7VJn*k+MwozV23u1`+;|lXJ zHH_vOSLjk8C_|ssDy(+eN80fi;=d6o70iQ@?d5K=w3Z#)~T$6omeB8{9up!V#I9DIFZLEXw-zN6Zk#Q%Ofh>OT+5f?#9Y}-C`+$EZ}fl zO+LsSI2ZO|d-#eizvvCX8V0uWAEQx7NVBJ!801Jy)LCwtfJ(wGU+Dmm|ULM?9qN~8+tekS_ zY3@~tx`x-YEk|klBWpRA2|WBlI%T-3;TG!J{m?PvAr{*NPhZc_=lispuxY~YbZ{dZAO;n%n!*S~f%9qbDzd*H6J+9Uh1M&mu4=K%Nf6tIjs zY~i`PwqWT$rMR`Y^=0z;{G&?iYFu~T8J;5i<=2?|NBKFxg@sRUM9I>4ec{)Y=|+Dh1n z_48ku)%%I_hlOhID0cQMu_R{V0`sav@vF~mv*0d>J8K}h-(yhS4RzzEc|+3ez3l`O zOn6_E#yk>918lP|!CBbcMz}U;KlMEScRIah=CZf=Jh;mbo9>xG?Rw!knYLA*W8q60u#a*5rTGn8>)4fNl%Axp-Z>K)!E@3RHo|k; z%r=!lb>RmJzhvytwZDc_ei-2m@@)_8`|&fI4xaZ$=x+CtJGNQ7C@&>Dw7L4omaOTi zht73}Ae{!zuY*ZJeADN0s^xg?%->bRpm!ui=?=8w+Adz4AHKIRND^fKT1JMidhXM&IIcCOzsvl;*Y279E zj3%MUXJgR|W!M(@B|IGt-@OQUS7CFjXHg=JD%gqj*SfZwYK$t$cc(I6U2>|7Ot25J z=fKm`kB8Z)7<^r^iFuG%^FpE$ef$F zP2BJFHn#vh(h#giZnkw}*Ll}gpWucJV2^BRF$E%LwpOApn1hb1A}SAFJk!N448b|J z!~{=`o)M6aZG1I>kvZ*KyG0@hc9PhYRzefv`WsJQ- zD;s9_H+f3^24uLduB0^5l(n#V@FtwYf2uTZO6fwf&VYErg7vc-1+&wiR%OmImHL{K zOixMWV@MfY{=2)zheN!9WzOWX7A@;@W!j9L*y77?Mwy;JBJ@tIo0!$T`26cuSn^pV z(%-nc2?A>J;w&QbmE`%o?*+KX3<^Cc$x$2KP^uiUowu5#Q$(1a+%zB-JADUQqDOVm zH@2C*dt4wM0k&}I*{y@E)_Ve_mx~7|XmL(-4NOYaY{3zu#2F8Lt zD-(Iw>Oqtj#_aTQ&JmT!ZoNq*H9Hz$d~&O&Bq33YhD!Pzj#!=QUK?Y)u)jNp$zJ9y z@qi=K7ZUoxcgy_Zp?PDE_CGP?NGW~c$`NitohWR;NMOt-#xihcI{o}${eJc##$^QV zgYet0IP}R)2fqS4wn_p}o`z<;!4-|fKr4zAvSk8Xgfph##N|82%MU(Ptyn7+NN$9{ zSUMLEwPylXc|r8hpso@CISzAywkt;UV7}}{2m8)BFj3Jq+d5TM)zh~)IWsC^9*%KGT?sGC1?VGayd^>}17N`5$X@7qWvdmNN*;~RdV7!wi z(7%pd**=U5Z5{X++DCMC|3jz5anMe=Z4XJ}u~Z)OIP^y>CjB|Qvb!5RMn6C(qx&R=Q2Wvk%lk!Th ze>U1KJVnSFd~cL`KgO|X;HWXrjDI^cM#JvVsnBn~E`V+{Nbjpw1SY57YMgXG6-&5)#GPF7gM@oqJxp0jJP44N?jio@p+OmP^ znv%SuO?S0?-1kF8o-FU{`l}QW`R80@w8Qh0^1zI;a|6PWGZR|wM&+vB;vOwz(mW#j zf^PEd32DNrJ;t;ttYxnGG)zV?QuFxQ0q@!&euD&Dc+UBZswZtK(md&m8;yTAB4<4(YLSL)HIaF0bXSPH4W_MOOdAnUGRVO8N5bj4;uoC3?x zBkRZOH9?Pk<2>j}$EAImcK9%+hQ~rmohPKu1jAM~Q0q+~1A`}1&Kuo4rjfZKSP#EIwb6{t%a{>%RORQNavXrb_04M5}0#A^nudxK9XEOT=;uE@y5Q zrBs>L`GeGG);v9*yjZuOFHoAYmEa6=*R@n@qC3!?L4R9g%H&+n&gr2z)^70|Bu{r}piX*-&!@`6)t1h` zFw5QyTkQpt9b5GxS?*K`CDL^N+m=YK>C}|B&Yg(8G*YSrLJ;+2_xotX1ooEE?Z#%? z4H9Z>V>c|c&K1P`SOs;^2F(x1@lKZG;x0B!(HMNqUDo;8tGX{MR2EuOCvGFPu7cX* zr~88@u4b(2xcE7^l*w^-9O0b%+r8H1thOkoS+|t~hN8*i5Mx^3^Km^aq_gCtvz{&pv z5#lc1a;iUANd8>YMQ~tK+Ia5ZS#^%?4t7#3>sAowSgy*xEwQ-|E zwuLJ|d~p>4!l8Oj@D(P1-i}A?1{@*c8=BC>j%jRRz%leglfYcBgHjt>OOsy5!NWVY z!sc7f6}TJmduMsMRP7H)R(In|e=6%&Qi`!rOMKTLCoey)yjQP+ z9mbLGX#ey{G?~S&w9Ray3agR^nQ{HdPH;2en{)`XX!Eo&6GEC!=fTenMx4F7GW^NA zR?!mTJNEE=aOHLm}^WH3pYLU+KrmcpWHkPbg*FR5s*fryPRcMpV z)_}FC6qUv#SJ!^7RIs8+SlI}(*dA8*cH%i8eX;3m~1=Tp%R#=8VE`A z-vZN{RRJP`)?;qdV53LvhaV+xASLU2zNw#F*4xr-hX1^M^_hZ|6vjQ^gP$|Cf-~`6 zy^P)Rqd|4MG7{w_3Q04u(jkC6Q6iVqAO*yRe@^Oa|sQum%G+5mulvR*Q` z!OVSyxq2XV)i=<+bAE;{zP`73%(O~5n5=(GJTp$8dS<)pl~425`B(9gE|>q91?ysX zYLc>{QP5ej$8(NIAbyj7KcV#~v1sa_zBw=uXg6_e35DP(?M-}FP7Y$0HOS^>%nOoC zmytYe-Fi^HespiVcw4*?Y3e4zSFdFy&DBTX>5V=m}127ME0{6E?}5E z9YjsyCEm1fiMhTXMASDD^GDCxX;LThf7p8SnW>_|JF@S4Y$Qu?g$3i&sTWoJq zIxbCKt+GsprRVakDaD6=&{#?eKTOfN+Fc;PD znE%{P3O0n4kDMa4=UTB6=IpMoYfOo zU4LIaVQ#@>Q1-G@`AP|8vVyY7WRWxp6YCELMwn~`t6k@}RPL~om&;->AjK?!933%&!D8f^P0~c;EcolJ+hM>OW^Bfb+kH z*PO`Kg>&<-wgq>AiEmhU!Ed3EX=J5+&Mm= zUxnlAMZ`2J`AZwf9}1L1_bKK@SzcdkS#X6(h{(@D)$FfP4Y;DL?AnA5}I8$YA! zc%txm_BBFFdOAnq;zXzt|IQ-w*zO0E!M->Y#viC$PBsz4=;o)B(o-i>Dv(7bkU)Z- zTVx4~J#ZM$_~-f7Sct!7J80k*M*0*?s46aKD_+q=Q{u}?#NOWCRESQfWaD(CZ@Y?N zC7wd>fw=uBga4(o75OXW-w9k9U5U^z+(KAK=8djvj@|<+ zz9T5wyr!(7Ym7BUBSV`xRK-jhIANt3@4gAm%{{}NdT>JMyY$sLa&-95ftDsm8)4XR z)t;XTc}yg8krAhDO^eztF3ErLaqo2%|lt2nOU`R>(t#93pMD6N}K4nKn+PLbnyQX&5&__rzG zp)FywVFAQ3#97eW<&n-iEoR1{b`nf|m^#q45(M&Dqq^@`*zfp0Z^3CBkzOdm(*Zpw zQ24}7LN9ESczk7Isk&mjwt!ziwQY3UHy04EQ@Sx-(2%mh17c6bUbA**jeU54{u|s1 zYan#~Fd85Z0v?|^VgRb4;51@tI$su@HSCad!nVRqHF^JVc-6_X8|mU+9+7LrO6;Cq z8!mjP3cN6*M@NycO}Fp?JJvu-nn#E*o{KGbnBZnrSmN{A1+7}+#~0iQ(r2GU;Se0eFI=f zvjrhS4UHN(t?_+>y=Zc_G8BLJ40w){onXRH8Qv0HO)%+_@r6MrF=pdgoGlHvW3``QGwm0n={f=h;j_bvDG*xcQ{Fl^heI>D9O0C*d~13v6nioN{*9vStw zX7&zbZx8UIc2v3y7ERPukCN7W#sek2VPkwi-7dU2K`Jj;3x(kiQFQvHJnvVIv`2SG&vFa(DwJA1`XwRCz|50);c zSAGvcqxPI!{O90z1YL8F4CNdPwj*<$3In1t}7B>j)^gO`iJ7&bUSFM zw*nEw^Ap>f*K1R@S>EE*7!mVVXK+zHZa~P|M8I7yxPO`T!v4sFit9H=vdg6FuFDTr z;-Pedoqg@wA!cIJ@!90a$==uo_tCSH4d)vHt| z`@B_zC^MoAw9E1Y{G9g(D(e~xoYQqKTAl7}X_iKct?08_h7r3*L^xzE_*@#~cz09n zgonUghEf8k3q(dCNjZ!9(=MD4at+FUW(G=fT~nFhzi#eM38`3ZN;-{Sv#l`eibgaw z#`Ob~kTTL(Iv?ZzBw}r~p?^9AO|t+26Y3bp+W`~eRCN?KcP?B{x16&EG!rH((Q#=_ z6U2VJKf_EcfIG;+^h{i5zF$(IqDWZsa;Ixc*bST4IR@dvIVJ(2{DzQ50?3dS6WISz z$0yS6>Es1H`VbX#hauE+`-)GkYy-zn1uhpY2r|*6k}$vYPaHgVy^jv~}fncR}2C zGsjQ${VMYNjV;3USv$jNBUH8G13~JRS9`WFcPdp$=d5iyQb6D02Dho#YT7{OYlwKJ z?nM8^{lBYf?5KiGuFN{0 zd4E#X8Il0^B?fyiLO(O=2mk(6L(El%6w^rg;bk@PNzE1@yeVec0TpueU0_^vEh0)@UmeWPDo(FQOid^ zIIF3=hNT-ffBFizHWUFY3rbJnQqFmNWTZ~-AJWFSBX>M!b*)2j^--8LLihTKwbdbm z{&8KLs1E`;MXXsfgkMAk?yeRuyY3>sYK48#7CSYgYGtjTZF=7(qAFB1TKxN6%2H8eSHqh zXYy$c@~i9m^WO?sWRx7$p^O~ZQj)q={JH+gHVY1Ek!_^8EQE!KSd@Qk5-T1IWf*^k zY_I1-mb5Ijng-lEYetR@psu?VKnua7v9cPITXTi78q|cfTMLey-@JEC`3e-W4K5>T zE|3^4&okyWAikT@e)XWRE^AA35g}XFBw++`*NNp}m{ll3xbYfK=zv3lh$S zxLBc(-PN_Wyg+Qe>%VleaaZ**7Ehx&Tr6|KdNY1tt5rO~18Dz&I4S zwc^$fXF54n0jZjU*ZkU%l>6LT|0(=u5q?|3A>C*@qDRI3BuC0-as_4Rw+i~kp$MC? zf28lYyA+3l|7#bJY6L)l z3IKXJJRRfiK&W6*$Rf3)DSPHNFBG!(<3%Lc=vqDkb|oSxarSp^Q<_|{pDM&12nhjk z7&^Zh%{LfUIK=grJoXBn{@sXaWZhW@aO2%~=14-n^BQ)Vw^>1@_ZF}KITiK8XgkUP zKs4EW+;W7REBj|rdQ=pkA0!|AD*2-Aty5B?Sn7u4q@oV!MZYH0yf)iZT+KZ(1}=os zZI*!n4W+|+LPG(Al4+3LztiOa5%c%8FN@hZIV7D13;p`sVGQQse9hA4A;U=6yme;N z4h5i0;h`79q2ifQ#z)Y9{>lZ~bsIkdk~9?!t>`)yfQPXw}ek^sqzEW+UZ@f%Od z_Dk6^9KRLqg}9Tc&g{nru=PtvQhILU*XVn{gsqEoV7^SgYQ?q+gGxNkB3wMPYX%p$ z!cHPz{@50>8__{yOz#&0`6Ql^y>lp&QXo0UOIG!v2!khVf;~14>kaL`xfZ4;72WGj zA02H|Nlr>aS#0ClUIL-n92h`&fOe#-!*TqBho)PiSQZ89f0#0LF|5aJ7bcJ?C9;J0U{hrExK^ynLC461j`S65yU`$8Pjh|{3cp~MRgD0j< zTG}(>sd`Q|AXX07ZWSZpRCFfJe5dzaX%#;|PH9Z5$@0x-4*@O9$*BAuspRG3!-_Kz#Q3b!s>6BLj;itd+bZ`>NQp)vqfsdADyN$*K_U24i|Ga zC+g-s3MGbnm%h;3kJte6sc=u?y~TC5cOvor3Y@f9mT=0e`Z)eVR1MHBm?#y7t!JA==^ln6s|$#Hoa?5;?>E7rq0*x z%qABCc(vglIo_XsW?z*Nisi;GguAAv?(7AHarl&=U!S{LZp`KK1V}Vorti&CbR9UF z0k%5$pvL}nyQNsxY6b7{cQH37v~sFDcfH5cj(zKGz5u)-$?@U;leFV~G`~JanSrE= S0+4IXVP$^r2GYzc?Y{u%|HC{0 delta 9569 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 Ov$48*5p({Z)c*mW{I`<; diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_1_1/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_1_1/00000.png index 78571a283096b9a72dfa7d06957c2c8c5229cf72..a19a87d4a2dac3687a81bb15ac2750bc32e4e67a 100644 GIT binary patch literal 11942 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 literal 11723 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 S0+4IXVP$^r2GYzc?Y{u%|HC{0 delta 9569 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 Ov$48*5p({Z)c*mW{I`<; diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_2_1_1/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_1to2_2_1_1/00000.png index 78571a283096b9a72dfa7d06957c2c8c5229cf72..a19a87d4a2dac3687a81bb15ac2750bc32e4e67a 100644 GIT binary patch literal 11942 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 literal 11723 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 S0+4IXVP$^r2GYzc?Y{u%|HC{0 delta 9569 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 Ov$48*5p({Z)c*mW{I`<; diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_2to2_0_3/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_wpkh_2to2_0_3/00000.png index 78571a283096b9a72dfa7d06957c2c8c5229cf72..a19a87d4a2dac3687a81bb15ac2750bc32e4e67a 100644 GIT binary patch literal 11942 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 literal 11723 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 literal 11036 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 U<9G+?dSw9{S=^|;=KSn`0Z?_bBme*a diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_3/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_3/00000.png index 066a141c36cf945611b85bd89d55612e677a6a54..945e95e9b033490050de60c6af8e9110d59cecac 100644 GIT binary patch delta 9685 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 delta 9511 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 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00000.png index 9c787171418c01c3841788905a02d133e49e41e2..495e4e67d84569a07419edf1e3deffa87dac5b20 100644 GIT binary patch literal 11179 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 literal 11036 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 U<9G+?dSw9{S=^|;=KSn`0Z?_bBme*a diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_1_1/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_1_1/00000.png index 066a141c36cf945611b85bd89d55612e677a6a54..945e95e9b033490050de60c6af8e9110d59cecac 100644 GIT binary patch delta 9685 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 delta 9511 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 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_0_0/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_0_0/00000.png index 9c787171418c01c3841788905a02d133e49e41e2..495e4e67d84569a07419edf1e3deffa87dac5b20 100644 GIT binary patch literal 11179 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 literal 11036 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 U<9G+?dSw9{S=^|;=KSn`0Z?_bBme*a diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_1_1/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_1_1/00000.png index 066a141c36cf945611b85bd89d55612e677a6a54..945e95e9b033490050de60c6af8e9110d59cecac 100644 GIT binary patch delta 9685 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 delta 9511 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 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00000.png index 9c787171418c01c3841788905a02d133e49e41e2..495e4e67d84569a07419edf1e3deffa87dac5b20 100644 GIT binary patch literal 11179 zcmeHt`9GBX+rA`GqD7XnmA%H6eNTnPdP}zKWl4m{GRBY!H-#iS<4%?=*#;AXnUKjk zF*GraAu(CT7{d(4@?71|>-!HpKRn;(htKuf%Q)ALn_T$8o0oWn+Hg*tugI z92_UWH*ehH;5hV(gM;%Q9!}sJJ==~N4vx!V;2S2lql>5{YId~+vCexz;_@LqEYy^V8vER|t{wX9YbUrSk7MYh z8*)TL4nnA$92jRVAr4I*5XXa)&K%=X4IJ-Hybk^K48!>kcfygYCpeEkIrpC%{<9DN zIS>CsTR*iu*PdF)OXR2n#{1{1Wmm~%c5@Ja&VZ3c(~-OgGG|SuX`V@u=fSB&xZW6g;O4h)w}b(x61)wY--2%Yh2`!m}G|e z-Q!tblM@>YDzEl$6wH2^CIAyikc>WH1nQ%l;}~dVeB>xh8l(8&fnE zinNM7XJn0EVL@#K)Sh6jA@}0Y7Ens4&MTMS*S+5M+zF8V0@}FHFat!(D02`=qA+y9 zuT}XZ6?+yR7wkp+S@ht3!NR9j2QjRjpm+v$j;>I`WuhwG!DJf}PRvR*tYzSExTE*F zeX@SMnS)HzqdVM`kwhhHJe?6x;D?wrxOKWi5{Tme;9UjmUfK@|=s-F3+Wv)83+(;z z*;5hj`1~X16A};dW3K#W?^7dDq~I|92Pe7Ul>Yd{=7w%njW)k2w>hP-^CzddZ38g} zE0HKLzA(~W3>$XPQ4CstFN)K<9#r7h$1z?J&`P9k$HI3^J7hVJ!zmDJe4hHp%qfBG z2HeRWRp7~dT?*8DCs`MAd;@St(V_`QaD~$y>joicvXjGEQ#OQh!nFH?G|oS;0Qlg?<;GbIp&I@2L)BW`Ztm4Mly=Cn^t{ytvI(|5a=Pq-oHtOQLD->YpUD!sd^CXkT0J(Uol zBUVPXfd9&s0YeMs=-)Mlf2w5mgW^)NQAxDFCNfh-2=}V_4@aD&AnBgp9(JkFFmO;*A6vLAKhM?S4ge!lU4fnrOPlD z_}kOEBBlV?Mm&$UmrICIWuucMe?LB;R&eL+d596$q=~})1?JO3zyimYkqGhwbx``; ztRh~6y5g5Q_Yvl4gV(S(ufun9D%FxlSbI`DeLpI+W6ht_*e*G~E^@d8HORPdxP9{7 z(T=C)UY{5pI_X%hZ;_}?m@!|ELMnGs60=xcucGTh#8?kvtxiYwd9FE>r=|xQFel1J;Qk-0AjN|)Tn8{je1l*;m^%L z;7&R71OlO~{!7i$JQ>)mD;1v%I!yKntE0KvWIYp(P%uTD9)S-kT(fUbptr zw6@=bwitGjX~sr>E+%_#$~S@Yc3$JU!NIqgXoG3@T%B~4+`%c?y)II4WK}SdI3?R{ z`L6pVi`>19tS(hZExn1?7;HNGVwT-SV~_pLim!Lhs~TtmrFJt6$SeZsCCw+grn*km z*vi+-)b3a8t(@|0)@D2cuD?b4Qr>}^3>AbVQsZ7kKbQU6a`yXvfaV2zoXoyTsWpv280|-RQaAs zy(2R{mqUONqQs}rG>RxGPM&-@}~T#uD&8)1{87Qfu=WixlFzq zB^2M`(=B{;Hc0q-UDg0POGb1nM$pvceE58urh)Syy^|4;I@1%yc7?#Qjq(z79 zSX0NhA)3Ax`DP2Cl01Pq9SH^Wt2iq}trX8s9f|#ctt=A`qN~1tisi$h+|3u9%Rpk<6H8I$D{c@8Z!Y95 z^V9i!pO7N@S#^1py?^zP0nQRXzFiZr5fMjFp17L1!#U`33hK+|4}fYGU-^!8_PpG) ztUHvXT}5bN`@Q)~Ydo~4cLZz7xx9MX5T{>)J03jb#0*aGjeIC*I#RNtrzGxyBvNBK zr_LhX&4;TJip|YDOHYiWMLz>@U9hz|KcI|RyCa}2+J#2rD2(k`t2q`RXak91?|Zox3)0~q-ISS2`VqL`nwWT%_uxZC%)~4sX0~PkEB|iZ&P>o4 zM0R%{S#{df4o)E~PfQ0-qm6TYW1<_J+O?yN5|Ps`#ueWoPU|c%GWDm18fc*JMsZVVCf@1W zBW4z!f9tr+#17iXQm{Qk4Y20IS{96KbcK@rHNA}~khkaLA4n!u!_NA7eLx?4P#qEW z4;d0>870i~B}Va=p-!A&oc}#;hq7sof3b7vzUN+{J0GLXetU?|`bdlAUCC?3F9Hh% zoe$q@3PHNUDaB{<-hFm?Zb%s^+3Q+htTje;dgxQM-aS7|jq*QRw5PA%u&O+o4j)Nc z8&BK*d7Inu>(9Nx0FOy`UKlnHHZ{LnMXL>!;@4XyOMm|DmXrUssIZyPsj|TRQlNIE zwO@p(_Dz?9GLP^~A5tF6J3WP}puNvTup@7b9Iwr^)WCn=4F9udmy$K}E`KeaLN0t4 z&SrN7l8xL6E#glBY$^Q0FZz@`&0oexsT3J|@Ig;GIDmTw-0U;vzFT<->}U&bndgMQ z2G520ZkV|f931kg-zw`fbos6$%vxo@K1UrKHtF-6wn z@DXzkD^i|{jjz{cro=E)q6zPfnEX+kftZ`q$(ef#@a`Kc9U}G}M_&NH2Q?}jlW!=~ z8szfxa&jm5@z-$W{J83GCZeR{Z(dMwrF59B-)_zSS&GL8V@F=Hz4X>_8296bT3Cv= z$iSQ8K)PR)T(#I@T$@{+5M$1suz3-M1s`MA;&&DDkg%rvAo?3-t_SRI7 zP>2QCP7q-BRpQQvhpaEaDF8){V}ma8a3Xr!>yX3`{ZVbQagn@KozNKFlHR($!Ygl9(?xPj96J3+2D12Vc|#zT21?& z3u00!cLcQ6sGcjuqn!JK_ndtLM7BBp-cEZBP$tCqlY6`~_gB;`-+2DDjT}>-1W(H} ztU%qUWLxhj^-aU4t)RhSKLnAwQ|Fz3ffLyKaX1PY1#;zML@Zun-cizIp#AoZe{`Ii zTXpCLmx;Da1{oO}>&xejuKvFKcCurEg=r*Gfl3&ME@3^>=;$5cT}j<|%8r4Y!+J;9 zcnRDL5Ks~oIkUS*dy<=gs+odu!H}98X@_GwL~KO4&5DMJ=$?CY^g(BCLpXn=P3Im;yqJ;Jc(3&?~)Z%wU}h^_#14xFBV2S<4itS zHKqvV&>T&zUf)=Kay~vVTYVmLe<;DVM*@_@*ksZdii9_^8!}+K(D?dSQ;BU*nb-rU zapY?m2+-8Pee>JuKOmwJ8EQ~`qIaHeK4@hB$M!(S>9{Cr7ih2yH@zRaY(y236Y} z2@$B0n{b7%E^S#dZKU8HVOr54YXpio?IDU_M91orFEINE_KLuWqF=+=Fo^i z+F#=cdHFw3MP5#5q~&On6)#ql(rWb{mZP)|K-4Q~jZNuO6TwZ?pDZE*d=&LrR`LAjKdP z8S9C;>-S8HH@an%l8G36Fi{2U{CPkL#E3J5yrH%yCUk@~l2qw1Pmj?D`wtH`%Oih= z+QlPKsH(c<`uh4VzpY^8<#J9T;`1A7mSbkdh6S9dZ~nSd$+YwK=o2@!qh!CS2>5k&wyD2c^=0Y(t;EMY zWrJq>N+Hf|Y$N`*CwHgaPA7SbVPQ%KO(5SRTe}b}opk+rv;23aBU5_yXugj0jj*=I z62@1MpKW;)^ZTkqsM@fR?!bX{=e{96z=5(~!nz-=rpy%GdV+ZRb!LQwvbBWZ*P7f-%kBPME z_Z?XsxS`?j zHbmhnw6*)T3;R~1+of}Dy}k|(fZov;)JN}IxuJW#!=t`97neJ=*;huQ%Vdn#R7FI? zsgZ%LJ@jZd*h^IOVqpn&Z=7IxDJp9qM?CzKCit`{x4Xjx7HckO`bbRRrC-C~SEmf> z{I>{FoigmK0$)#LF@o}qfZX}w#b1A!w$z^U`nE$0kvh=yxG!@=D@q~~g3@+0hTW$woBL~x9oodtK2 z{Z&8h-N|?mji7j^89Y(RwaoFg`H(Hw2WWUfS{X&BKsvR-TOVWk>~bk>Rm*-{RmVaO zHZJ=gDY=tuc-c1h;YY*Oa#v^Re3I#<%}r z{j7Y>>|0ts(V`-6IM&Yl6eHmlY%J4jb#L_v^b#}$7TCFxXh7^xt~_)v@~%rxa?fn2 z&UbhDD0Itso#$uuB?nJ&_=TOo%%@7f%MTACE(Mb>T*|fVB{3du^G*e60fI{LndbQS zFtRqHCD-@zU>IT&kSt8YZmhzx;|Imj)Bw1!GgD7Fo0Dm?;#Le~5HgL$?u7kTMlE{| zuf%A+w0`L0rB#uTG0Z4r z^MQx>zC>eTkld!nul_H60}1mR#|QF|U9QK5Mh2Te)_6!yDD|BoUk_+--2m4#wBOKpkT-7g%!DH6)ZO9%S`U+KhHJdZ1 z#+*i^cvi3?APHx0kya$;suwJSn9_5;Aw+)U`(`Q-&ara`?h3@KpvBh=)ExP?19NuC z5zjDZYa>W53Q-eC6vyxhR#uL}J!d^sO%n(OAhweuEb5xSDfqR|OoTL|->}~XhwS*i zAnHW-9rA`#V7S?Hs($hV+$%p)AaEA7*EeeKc!5*>!o;i^3Y-%tq}SrT9~8gR_;mSP zc*>ns%lW+b3H2!9t|{n=DLC>>E@@NczQ=#RdW9)> z3urZw^EgM+hjarpk@bp9VTbm`=&Bhi;l?KG^zqndQm0Rc8)efN%oL$M9u zSEpm=rhGrW=Bbr+aBv`OlKNxG8FO1l2j<>a5B$;9zOMiVX&w%d$W%A#7r{@8C5mh?a6pIW5V)qM898Ydm0G z)#qAs?yM4$b1(XbuU7(GG+rM$gt3@Z&(|X|qmqqG%ze>8at9w5KCALB+^)8z3TBFmUlvR0MZbp zv{G+58B5L$Y7&^Mvdl~w<}<`y9vriRM3wLG;UX`&C@yXxoh*!sv~BtRNo*--ud^1& zC7nPMslUvLi`%cwObRM03@@5P-3io`hhskKdw8nQ>b7aD8>q;4Qslw7T1sC`7S^<3K%XA8z0zXv&<-DvF7YhuSV=z7+|p^N9~08UGbV#1LeU6xCM-T%wBiPl{STx^i=$ zuwgjdIuqnuKJ`eE^2{3l#&`Rs9bg)K0FOxP9gIVEn+xq0b_0D%VhY7>7t7m^{T6{U zFa!ihUm|0@vdVI?W8Z6M@aTYg(Bve4?VH#yF0(&%WZgU+9L8+a^yHWIRgOQsYV%;> z1YG2!vz#QqWdAw=B|RwNHW2vw%3unFQle2e{zAIp+j!Rv1?wl1!{w8JOi{k=Cr}+~ zr6=dFGM~M-JF+v(Q#$y-m5sDmDACDkG!t@N*zpx86aUKJgUzFa@KK~(3 zo-IH7;2S;tM>vE$B+k9>kqsYWL-St?zMe8(t^Catub+R6jrx^F1R(33v#Xg}Ox_c;J+8u*doE z=0RjZ#bhuNVEKkBfGD^XQYkb2(fm)VAL|}`c4I&7?SC(E3JZ9q4+{K%FeU_=^i_Xnh|IG-^0gFWM`}J@5>gOJv!U5AW z;dPH{Yw7~+2ibBBA=qM8Gq-;d3}#lp)|>?4c6^|<*ndvf)uoCBz46m>_Dv{^D!+T; z{NJr~%OZNEnwijwX!3^o!XkTr>!xgF97pBz|2K8BsJi%rE81zpTTx1&)CDDo*}3oi zzcz`}7Z0bLHEoPkFu=W-i>BV?z`%-5bN+vx1^Q-3h;VQS%;n6|wC+iF9gPnZ zo{0c_C_z(pIGNR>%JIqfqd_AFk$cA<)p6`#AFE*Gp+V1_)Cw>D%7>thgy5;s&1GU=a_J9INrPCbxvV3;2 zy_Pk8pWG$NZ@aQv57OZ4VOq%*-yV3d(`6j%XBgH5wk+u+C27xLg7nkeG-v_QS1u7rx+vK#pTn09Y<|DVH>nxP_YO& zCCR1gN9EDoss<&vVoNZ7Bc@YtK1xn#VSMQCxsRR4?&WlSi9G-P5rCVaNT$$}XP6~T zG3N!IM(r8Q_EXaNF&CP79E-Tb8K|xvYv%R&QINLS5Ftxu@iN3;sQKPa9r34!)A*rE zX3DTk>bJHzZol(@P7^87cI2y>*XB8%S|atEOTSg>=SQ)CN=~SOapaYJ9f>hsN0Gl} z0;LL0$sLp(yrN#d@)b}R{zwziVpzb?r)kGV-=&D8&*@m(XT4>XrvL^IiUb7UJw;{> z-zwU^2^}_iO#R?(2IVr5a{V4Gmam9a`R`{K3MzMrYI9rBr0%{whdA;z1+z3E> z&tL3Sb}^2q17;w*qKNKZd3zz8?F7rLc@Ap}umDPp*mowSLdlPl1jlX0P>bSGsxCRY ziB|aW+f$;J@jj>%D?0wI3zyP5Z)LS|=#4JMdAbwg_jea}v-ZwB>|6LQ83PvvYHyN* z!-<#e=MLP}1;6NiXed0(a=b6sHuZJCfy6cfrQc(VT>`&Opa%nOHoPmG{nF)kR;w#H z=$*o`r&pB$3vn?B33lbs;tT|=x+V~UZEZ~gnz@l)x!@gT#q@(ZvBMq&)AoevB2&J{ zm-^igIXLu}w_}g?%7Mdl#0+pX%R3B)IuB>R9OW-bfcrc|CQJf$fTK5a7x2-|)FRqJ zmR0d#a$~x5>EvY+tzhavPq-UNd`L00%6L^*Lyf$=e7VOwwe&lU_3zvfUg})ipD=0& z*#@B-UL^V4_w(chEet7`;-;y-Za~vVe}p#w*sBZhnTRmlbXyUPL>2!^q_H1~CC5M1 zDm+Sbxzf=JFd|S*^_41_G{v^}dU1=kQ^EKA*m}lFAx|&`W;PCG>8mU#3Uynr&;Xak z$OR+B58T6_-*%X{g6I`nU65DWJ0)k%UAJo7y;^=L^_oroaP%PEGJY)beBKAe^9e0d z5-RHXi!8%po5(=&?Wo1J24HDmD2PmBFX-;077WJoZxzHiDwzQEt=s{DhyIR&HK-9ZlOIe;ocJY4J3 zG-ARhjbGlvAcMGEMXu)`JDSQhlh-w(Y7LeCaUlal2n z_-jYr&aQt^^=Dh@xrHE!nEcz6?{%}~Dov!EbBi`!fKxOp7Ku$Yd}_9nLUadArxALPJ3`1Ui&ikM?*R+z?UlE+@ByxX!T1R#_fO*xt zPV!LJNoV6>2{~)Lrv>`d@7P=mY=& literal 11036 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 U<9G+?dSw9{S=^|;=KSn`0Z?_bBme*a diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_1_1/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_1_1/00000.png index 066a141c36cf945611b85bd89d55612e677a6a54..945e95e9b033490050de60c6af8e9110d59cecac 100644 GIT binary patch delta 9685 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 delta 9511 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 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_0/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_0/00000.png index 9c787171418c01c3841788905a02d133e49e41e2..495e4e67d84569a07419edf1e3deffa87dac5b20 100644 GIT binary patch literal 11179 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 literal 11036 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 U<9G+?dSw9{S=^|;=KSn`0Z?_bBme*a diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_3/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_3/00000.png index 066a141c36cf945611b85bd89d55612e677a6a54..945e95e9b033490050de60c6af8e9110d59cecac 100644 GIT binary patch delta 9685 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 delta 9511 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 From 4d86f7428fc26f070191228b3708e6e75262a56a Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 2 May 2024 13:40:23 +0200 Subject: [PATCH 84/85] coding_style_checks: remove now that all sources are in submodule --- .github/workflows/coding_style_checks.yml | 25 ----------------------- 1 file changed, 25 deletions(-) delete mode 100644 .github/workflows/coding_style_checks.yml diff --git a/.github/workflows/coding_style_checks.yml b/.github/workflows/coding_style_checks.yml deleted file mode 100644 index 797dfee4..00000000 --- a/.github/workflows/coding_style_checks.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Run coding style check through reusable workflow - -# This workflow will run linting checks to ensure a level of uniformization among all Ledger applications. -# -# The presence of this workflow is mandatory as a minimal level of linting is required. -# You are however free to modify the content of the .clang-format file and thus the coding style of your application. -# We simply ask you to not diverge too much from the linting of the Boilerplate application. - -on: - workflow_dispatch: - push: - branches: - - master - - main - - develop - pull_request: - -jobs: - check_linting: - name: Check linting using the reusable workflow - uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_lint.yml@v1 - with: - source: './lib-app-bitcoin/' - extensions: 'h,c' - version: 11 From b01037a8563268094691da786f40e8978493484e Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 2 May 2024 13:54:39 +0200 Subject: [PATCH 85/85] Makefile: bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dca95310..aa9d0c02 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ # Application version APPVERSION_M = 2 APPVERSION_N = 4 -APPVERSION_P = 0 +APPVERSION_P = 1 APPDEVELOPPER="Ledger" APPCOPYRIGHT="(c) 2024 Ledger"

e<>8+PV+c37lwd*_8Z z06L!su*^O0g|*ob)2|$cZ!0@pKg?mdVxC%UazE%Dr8cP#?qDnFcDUxi?9h|A%M8?d zU4eD-qEc=g?~m~YsejxD1nd@NW_`-v)J*ZxA= z>iPG?nSb`6f5Kx|s?|+jK#2#W3LrZ`l$sY8j^Lq1+5kQPD(#AH3!%@IYorUdmkqrR z$p_%GHXIKq$`8)G;m0DfiWdo7n1xm*kl|70>SgJ{xl0$zyW&)^0$L`bVbYO!q!hn5t-Q>KqL#*Bq9KTU}h(d9y=m)^uO`R`UfoucH z43`^tVpmrX4!A_lE(^(z?ZWC&*rG`wJZBnETXMM5$O?Dt4sBDLv3n}5hYF}XZ!LNd zu49?L(rF~myg~z)N`y3iEe0crbOM7>${orrN3uGAnM9d~4W)|yEa)zY!Pn>kTT@3` zhQWyU6lnMZy{C+EK(h@I1qgQ`NQ3*|za#_U0%$!5?lK!AeS``dYSZeZJ%ENGthTka zRqbxF{J0>OTi342>bM49y-r}ZwM;peXsr3rW%*rZW@db$X+bwIxs*q5a?Zs_TjVhpCI z7i$OrzNDFR-DJ>4xFY2?|C|8T^CI{eNlIssifoOrIp@YC0C1xomuLuA<^BBD}Xt>dG+OezX z`VJs!o)K_^bl+65M3NKVHs0uB6*@X?-j6wUeVq5!+=k8c>%G_Rc;6~l}x=_=CV#B`X z0LzQnDL;sgv;=>kT+GAn0=+hq=`HhirU4Mj6%31iDdOj}r3RmLrpcp}_5G9vArJnd z7~h78;I^y?wVS2i^ zkU!x&P=y5BHOI(4(JI?J&Bg>(fOsbRUKWdANGhahDj1&HJRTL1t6 diff --git a/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00002.png b/tests/snapshots/stax/test_get_public_key_m/48'/1'/4'/1'/0/7_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..e06d6335cfeeec48f797807973be3a5614d40107 GIT binary patch literal 7845 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 delta 3140 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 OCpakd2>oz;!T$hx@V%n| diff --git a/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_0/00000.png b/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_0/00000.png index 00c634ffe88af03190fd5e8f27080725368bf29a..538f3218042a9c109feb262a20e2e64009b25057 100644 GIT binary patch literal 8810 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 diff --git a/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_1/00000.png b/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_1/00000.png index 9039782df20d0aee45baa8532126dcb0e5544214..55a58f0da3ec93dddfae520e47b5b69de5eae052 100644 GIT binary patch literal 9667 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 literal 13335 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 diff --git a/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_1/00001.png b/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_1/00001.png index 97d95bf286dacb200942c23bf032c259cbca15db..11533ffcce0f0bce74596a1dcc9c69aef66ec6dc 100644 GIT binary patch literal 13461 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 a>Nz)>YhLk5I0trBRZcm$o~$~Kyz)P^UNF!A diff --git a/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_1/00002.png b/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..5b55721953c578f3916c8bc9cf3a24c0ea121ee6 GIT binary patch literal 7548 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_2/00000.png b/tests/snapshots/stax/test_get_public_key_m/49'/1'/1'/1/3_0_2/00000.png index 13499fcc9366bb214269b05db05ce8ae4380ce24..3f906b2b76be79fc321634fc00b2785ca627789c 100644 GIT binary patch delta 2731 zcmXArdt6d?8^E(nSDBXYwDLOFYs}Ov?bR}c?Cx5!yyB&)QJMsrH@t8;rPW$aaKoZz zN}DFBC^&Bkf>BdSW@HMeh?q*|1yQ_}h`h(`Iscu{`8>bp_kEt{`#DvRk^dI#4m02D zf5I;~^N~vaK76=;{q6HyQNp^jLxtBJ4>|64y!LGj_!OA43|$S*7MPbAs>wc(48_r7 zCXeU%5v_3rwj0nt{JL!h+YoV%-fevyHVE)=8`mwH*Etw4*HgY)KMu4~V;hWRS;Z2s&^r^yXh|x9|-mApl59W!$Z^!T(6SP2~h;<{%mH&shg7gic zGSn0aRIS`dy3hoB+;qirbB|Un6XU zhbQs70RFHcR#q1JC^x3-iGKT&Kflkts$6F&UtONI7!qk_XAeBHT17dG#cj#kz(ZFF zK3EuUvOK5I7^8Vg_`;9l6;zYXquTu5q>Zsi-3p7NZ(S|(+Q}W%`lhC)*~|gJ1(KG} z??-!b1l1)aC5Dq7zCJz-=_D5hz7xatP+liivjr)~q?vEIz+j72{;9doEy)fu0(QGA zgMF^95A9i`Th(ble2C-7c`YqIK0Y=!tD3b4Ft z0`~_1kMBuM^e(ou;bdey&L)>@U5jFolNGSy0L9>7$JpX@|1`n6iXA7=hGOpRA`6m| zlIT|NzE{-DX8KHd)3~*S>DS9xF%?KtD?8)r0!!_@rj%eI0M9gA&{4y zVG_lZ+PYm8iA1(_@iV=e1WB*C6K$tjt(F@PfhY&#+xRcB90RNUm!zl$?@ZnD=6vm? z-h5Rmyu=BSYhR2kA9%uM$B43TzSE(XRXuttr1|oZ| zI~d#F;ldk9e{AKfU5?uo&Xi6ruz&b;$vs?O#rWvr{wAUS9{@In}?ghpF}ZZ(~@ z0PaV|aww%yQ_~itU6FQM6L7YmUm47xP)1{&qEGTj9jHhcS9k>Vyufq81FyD= zCcLz_vkOQ;Y6mE`T^06!HQF@g+qS$Ad{?vudx2jWAA;<^SBFvu*LWG5zLCoNQvY5f zhb=3u!8HFExVOo)L&%|PL7fAM8Ac`vLC~-x#Pdj^DQ~UxRKu$?o9#U?`+CziRuQjT z)7r)don2@V9JgONQm1&)0VM1$JzU0cmA0s|5J}pB6}=x@H2v3B>vz9nn5+SN7dP04 zcDoh`?9Da?-x)tz-y9Q`7I8eQJY)o;nYeRm!Dun18Qt=G5b;l-UiC3SrWE{)VZ0v{ z3O!;bDb`0Mv2}etT@O3s#IO568-V+6W@gqsUa#%BX>i>8@3A>lf>8M<{=~%T%Gyz6 zB3k7P|6*s$3;J)K)G@2v5Z`zCX3wM^+J%LN16{%d=>hp9oN|w}OZMyqcm$oV(-8#b zdzDEKMPp(h!Ou%y@^!Ey&c`l{{)OuPmFESf;8B|;adl4Wx#co?`#Vx|Z3ELpGGqZ2 z*Ejn}Q_8hiPBp}@A^q+5w2sVfq6D`T1yjJ`PY<+$9lu!Ht9z{O?(P=RVBnNyG;IL^ zd)SdD&xpq!OY~1Yakzab<}=9L^k%(7H}FA}>>7!@{Dd0F%OKQDz zn)nwUN)wHRBv(>|Lg{BvaD~R`XcG<)xY9|cIs4xt5AuX3aIE%6xXHj7q1jbzPHxQsdnnr}d%(9elrO1H|!pQhDn z{i;^YEyXq+H#QkBC7!r1ysSH;B0Mls^s3!6Z;5;{ITv1LAr_qVe6knS*s5bLx4LhepppFKiXDmn49Kw(dFv@;1eI7KPA$ zy}B}ZYGVftlyuw0+K6h)ypvg3BdH!6ZqIiiMD2oPaA#Yc5xHTRONpO*3OT_5)t;d_ z57R7T)ZQSyrKP3mJ`Xfn6ho*7aQ+zerf#{qRHb7-FgR|C!aKd-A3i+PPDFw(xu$&J zl<~_x{mxJVqHN6HS2=*P*@Iw8!SZVL?!^I|R-@5RwS-`WH!FiEimL-tbJc+%kPwxx zExr~prPFA@oZq5WZnWl-dsx=m{C^w$NG3+5kB(=BJypRIN^od) delta 3140 zcmXArZCui47suN&OYgL@rJ0r6Y+4g_trQ<&WmcAHX(*b4&eYNb!^A1dzjVVbHmhlx z&y|`60vZ{S4}`3oasz9ML_UQEq=2TRD1zMo?Y>@}H`n?6&N;v9d#=enRF|7h$gQ~G zBZtoZP^}r2WxYYxlg_NrFJ3LZTN-~No$c6x2&JSvtxzHOoyvf9gyg_=DTxkw-9TAUxAmfHLEr(7Rw6I z&&}-ro;=#6K*X?R7Y~vn>iQCeX$kt|L?Z;rTjCh{R^qvyhyCbNK;V%HF z6C~zhL|G!QQIT%dej%*Yn|9AT{cr?K@tTgoVm-+vAr?L|pNh)VeexJFX;8;GUiJ0qeW zLONZALaNKP%X|QU-*vtd>PKkm6^9_KnO``N4lg z%)HqM_}-wsy&3=Nj8>U1Ph4!?_HQSaJHu#Cy}1*Y(qXd^uH6Okm!Fi_je*h6@vnjc znS<9EPRJ{RtDp9!zG&QFd#on5J!2-I+kL*lP!5V4&^(DNAC2ZruV~j^Mas~ z#O3!=2sFIWfjjXdDLL!UNM2ZE>WkpWXPGg)dELBjWn=H)buTk=B>vD;#*OMS0?7-U zULp2B-?}?NgagUVVj?`lmV2KJlm7m-FK83jfq|VKwh-?*Pz(l>%#^m(JeGDo zkzTUaeJ~jEAm%GO8#fmGRZ~+BWs{vAqkW^JadAJ+^ZtTO^Y&&FmpYl! z77B%Afn^Eo@5INE7jokOI)^|QY@+8{Kf?F>L@9SIjt3jdr)>r10_vA#e0ef+U+*vF zqtyu;hT5B(j+gYE*U{-k2ka_H>N4Q7g%Md09v8jPoRVFf_xAru^`qe?2NZFLcgC^lD?K3x#eZKyh zKAQST|E8(_ZAzZH!T5-j47S208%3q0wjmEPUd?iR3itOsvs_rd+vQmz|FO~JQ}2bg z==?LZ+wo~vms`|fh%K4CGb9~WhxMxBty2wa7G<&o-`**hjkB ziV){4roIk!5in^cYW*(O_PW`UNl7zMC=^jo!WxXrTIJ;A^dQ6ubq23YZ#`a@H4LLe*00{H*@X}7n5ZjeF;0e`tJd&ot>Sf zil=3=doYC~oY>jb<>`nQ36{f;BAo~T05IU*|D?Arb?qToKk9F$LT^I~T)!_iq zD25f-J?v7_hoMK+-cRN9bSo8k>$p3l(b%iCTwnYH^@N|4wu5nd>vQYzsVOY1PI5qH z-SjB|BV1QuQ``b``?eya*a|sK9@dZ&-8{xxQ`%$15mocCt84tE`Rz%7E)q?PtT9;@ z^^0o-X@Bw8-7kMry#+b+&3)W2&ztIoB-2HLWahl?9R2tY1cGbYQ(ebfZv9z!gI>s1S1e~v@Co) z&;3}cRfzy}E@u#sJA;qU4D1C(^xf=lRn`G;xCH(P2g$gUGzBssnHlX~PDrU#XqRO| zkM5E%lcii-x2bnu4WkI*ZpQBD@QZ!NmJD^R|2R^8&0^?6zqzMqeKw3X9PLyS7O36k z=d&2KSJkSEf~mGIQrfa-u+YjXL2^<3y)XvpbtaHW+Jmg$7Z#IE%;W2F5C|*yd-809 z40~pV#@nw}uTyC>G(m_4iOIzXZ&vemoXU@BkoTs`gXv`|2fXC-@i_iNtxKVuG?->R zfbTFGSF%N2nh@s_iA2)d+nYEl9i=H>&+BWe4m1qQaZ;1%@YCJ$#?5?J)JCQc+N$3d zvg#GEwf?l^zonZ?WS_VJ895bO23hgV6pH+}piR(+vqtgJoW4>J%p?NB(=lB8L57l z`Yx;t5~r9u3Hz)8PPJQiXJ<&$fKsVUtU9ncqUX$DN_eQyl8-9QED=KI{n#?pcl`XGTDiV^t~a*}(`|*z5y=wVq1}FI5hf+3dSU!vmB6d& zQ~=0ZmKF5pLgyYV0H?lKwk+_h^kVklU>8pP^>e=ngi<;P+uxGgkb|7n zkB*u)MWLTOTzsug?<uL?N_~uC=>GnT2wO6)=t%JVygYxE0g!+im!pwBHtIy* zn%yh)edp&F7xA}J*y@v)e+_C#+|siDHg%`YJX-z>4d?cE(ys0<-O;_|7d>p|E(XtY zbIYw=Rolw6Tp^W}y+d(Du(kQc_m{bm)(48F4dK=2&t_SfrJa{cuAsn0?p0&(4ZX;e z#x8<(d$uGw?M?)4u7#hp&#tGnEtO`Rm+Kew4G14c!{4IyXfzu7lW+O3W{7|bV}Ja^ zUe~r^XlZ(nIFQCv6y~cVA4~cz?#|v-KQ#H+D+=uMPPD#^3f1GIoSO?h4bzLyYN_J> za$G7^OsTc8<~SEuf;cu*3Q^AH)sxYqh z-dO}9{~Hev5A$en_50Qg@u*BXrvHV-5Mt@$gjM3HfPUROkhRBrNV3~hTf8I}q#9`5 zy=k6xA}hwruaHsqs<#cj;XpBAK52IkR)kE8H63YY65yjs!pN$5{wGn& z@`+&Wt))|Rw3){)E+{(;i!h`|bEfK@Ka64n)K}Ml OCpakd2>oz;!T$hx@V%n| diff --git a/tests/snapshots/stax/test_get_public_key_m/84'/1'/2'/0/10_0_0/00000.png b/tests/snapshots/stax/test_get_public_key_m/84'/1'/2'/0/10_0_0/00000.png index 00c634ffe88af03190fd5e8f27080725368bf29a..0d6d65baca3e3f744c16d57063ab9a240991d391 100644 GIT binary patch delta 7523 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 diff --git a/tests/snapshots/stax/test_get_public_key_m/84'/1'/2'/0/10_0_0/00001.png b/tests/snapshots/stax/test_get_public_key_m/84'/1'/2'/0/10_0_0/00001.png index 0ba005e17c141adb6d507f12ee201932a0fa0ebe..ed29648d3eca123daaf36ce824e2da54ae031eba 100644 GIT binary patch literal 13768 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�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 delta 3140 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 OCpakd2>oz;!T$hx@V%n| diff --git a/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_0/00000.png b/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_0/00000.png index 00c634ffe88af03190fd5e8f27080725368bf29a..538f3218042a9c109feb262a20e2e64009b25057 100644 GIT binary patch literal 8810 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 diff --git a/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_1/00000.png b/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_1/00000.png index 4ff8395ed52990697faf973e5db8ecea409a7d3e..55a58f0da3ec93dddfae520e47b5b69de5eae052 100644 GIT binary patch literal 9667 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 literal 13570 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˹KY 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 E1BN$182|tP diff --git a/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_1/00001.png b/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_1/00001.png index 7df57e9e77399eb7829336ab46ba34f62b6e2394..4786788f6f63e24a1dd29bdc1a32aafb5631f8b2 100644 GIT binary patch literal 13695 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 G`#%7oK)o3N diff --git a/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_1/00002.png b/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_1/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..5d9f15f7390a6d7a8abb5046b822097d0bd0c81b GIT binary patch literal 7795 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 TbA*7HyzRP$%@y<|_r(7Jv0?;Q literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_2/00000.png b/tests/snapshots/stax/test_get_public_key_m/86'/1'/4'/1/12_0_2/00000.png index 13499fcc9366bb214269b05db05ce8ae4380ce24..3f906b2b76be79fc321634fc00b2785ca627789c 100644 GIT binary patch delta 2731 zcmXArdt6d?8^E(nSDBXYwDLOFYs}Ov?bR}c?Cx5!yyB&)QJMsrH@t8;rPW$aaKoZz zN}DFBC^&Bkf>BdSW@HMeh?q*|1yQ_}h`h(`Iscu{`8>bp_kEt{`#DvRk^dI#4m02D zf5I;~^N~vaK76=;{q6HyQNp^jLxtBJ4>|64y!LGj_!OA43|$S*7MPbAs>wc(48_r7 zCXeU%5v_3rwj0nt{JL!h+YoV%-fevyHVE)=8`mwH*Etw4*HgY)KMu4~V;hWRS;Z2s&^r^yXh|x9|-mApl59W!$Z^!T(6SP2~h;<{%mH&shg7gic zGSn0aRIS`dy3hoB+;qirbB|Un6XU zhbQs70RFHcR#q1JC^x3-iGKT&Kflkts$6F&UtONI7!qk_XAeBHT17dG#cj#kz(ZFF zK3EuUvOK5I7^8Vg_`;9l6;zYXquTu5q>Zsi-3p7NZ(S|(+Q}W%`lhC)*~|gJ1(KG} z??-!b1l1)aC5Dq7zCJz-=_D5hz7xatP+liivjr)~q?vEIz+j72{;9doEy)fu0(QGA zgMF^95A9i`Th(ble2C-7c`YqIK0Y=!tD3b4Ft z0`~_1kMBuM^e(ou;bdey&L)>@U5jFolNGSy0L9>7$JpX@|1`n6iXA7=hGOpRA`6m| zlIT|NzE{-DX8KHd)3~*S>DS9xF%?KtD?8)r0!!_@rj%eI0M9gA&{4y zVG_lZ+PYm8iA1(_@iV=e1WB*C6K$tjt(F@PfhY&#+xRcB90RNUm!zl$?@ZnD=6vm? z-h5Rmyu=BSYhR2kA9%uM$B43TzSE(XRXuttr1|oZ| zI~d#F;ldk9e{AKfU5?uo&Xi6ruz&b;$vs?O#rWvr{wAUS9{@In}?ghpF}ZZ(~@ z0PaV|aww%yQ_~itU6FQM6L7YmUm47xP)1{&qEGTj9jHhcS9k>Vyufq81FyD= zCcLz_vkOQ;Y6mE`T^06!HQF@g+qS$Ad{?vudx2jWAA;<^SBFvu*LWG5zLCoNQvY5f zhb=3u!8HFExVOo)L&%|PL7fAM8Ac`vLC~-x#Pdj^DQ~UxRKu$?o9#U?`+CziRuQjT z)7r)don2@V9JgONQm1&)0VM1$JzU0cmA0s|5J}pB6}=x@H2v3B>vz9nn5+SN7dP04 zcDoh`?9Da?-x)tz-y9Q`7I8eQJY)o;nYeRm!Dun18Qt=G5b;l-UiC3SrWE{)VZ0v{ z3O!;bDb`0Mv2}etT@O3s#IO568-V+6W@gqsUa#%BX>i>8@3A>lf>8M<{=~%T%Gyz6 zB3k7P|6*s$3;J)K)G@2v5Z`zCX3wM^+J%LN16{%d=>hp9oN|w}OZMyqcm$oV(-8#b zdzDEKMPp(h!Ou%y@^!Ey&c`l{{)OuPmFESf;8B|;adl4Wx#co?`#Vx|Z3ELpGGqZ2 z*Ejn}Q_8hiPBp}@A^q+5w2sVfq6D`T1yjJ`PY<+$9lu!Ht9z{O?(P=RVBnNyG;IL^ zd)SdD&xpq!OY~1Yakzab<}=9L^k%(7H}FA}>>7!@{Dd0F%OKQDz zn)nwUN)wHRBv(>|Lg{BvaD~R`XcG<)xY9|cIs4xt5AuX3aIE%6xXHj7q1jbzPHxQsdnnr}d%(9elrO1H|!pQhDn z{i;^YEyXq+H#QkBC7!r1ysSH;B0Mls^s3!6Z;5;{ITv1LAr_qVe6knS*s5bLx4LhepppFKiXDmn49Kw(dFv@;1eI7KPA$ zy}B}ZYGVftlyuw0+K6h)ypvg3BdH!6ZqIiiMD2oPaA#Yc5xHTRONpO*3OT_5)t;d_ z57R7T)ZQSyrKP3mJ`Xfn6ho*7aQ+zerf#{qRHb7-FgR|C!aKd-A3i+PPDFw(xu$&J zl<~_x{mxJVqHN6HS2=*P*@Iw8!SZVL?!^I|R-@5RwS-`WH!FiEimL-tbJc+%kPwxx zExr~prPFA@oZq5WZnWl-dsx=m{C^w$NG3+5kB(=BJypRIN^od) delta 3140 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 OCpakd2>oz;!T$hx@V%n| diff --git a/tests/snapshots/stax/test_sign_message_0_0/00000.png b/tests/snapshots/stax/test_sign_message_0_0/00000.png index 00c634ffe88af03190fd5e8f27080725368bf29a..0d6d65baca3e3f744c16d57063ab9a240991d391 100644 GIT binary patch delta 7523 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 diff --git a/tests/snapshots/stax/test_sign_message_0_0/00001.png b/tests/snapshots/stax/test_sign_message_0_0/00001.png index 6b7c4de4283c4cbc3a83181fb1434f647894ed54..475185ed48c6393233b606af1afd09064844d985 100644 GIT binary patch literal 14260 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 literal 14119 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 diff --git a/tests/snapshots/stax/test_sign_message_0_1/00000.png b/tests/snapshots/stax/test_sign_message_0_1/00000.png index 13499fcc9366bb214269b05db05ce8ae4380ce24..3f906b2b76be79fc321634fc00b2785ca627789c 100644 GIT binary patch delta 2731 zcmXArdt6d?8^E(nSDBXYwDLOFYs}Ov?bR}c?Cx5!yyB&)QJMsrH@t8;rPW$aaKoZz zN}DFBC^&Bkf>BdSW@HMeh?q*|1yQ_}h`h(`Iscu{`8>bp_kEt{`#DvRk^dI#4m02D zf5I;~^N~vaK76=;{q6HyQNp^jLxtBJ4>|64y!LGj_!OA43|$S*7MPbAs>wc(48_r7 zCXeU%5v_3rwj0nt{JL!h+YoV%-fevyHVE)=8`mwH*Etw4*HgY)KMu4~V;hWRS;Z2s&^r^yXh|x9|-mApl59W!$Z^!T(6SP2~h;<{%mH&shg7gic zGSn0aRIS`dy3hoB+;qirbB|Un6XU zhbQs70RFHcR#q1JC^x3-iGKT&Kflkts$6F&UtONI7!qk_XAeBHT17dG#cj#kz(ZFF zK3EuUvOK5I7^8Vg_`;9l6;zYXquTu5q>Zsi-3p7NZ(S|(+Q}W%`lhC)*~|gJ1(KG} z??-!b1l1)aC5Dq7zCJz-=_D5hz7xatP+liivjr)~q?vEIz+j72{;9doEy)fu0(QGA zgMF^95A9i`Th(ble2C-7c`YqIK0Y=!tD3b4Ft z0`~_1kMBuM^e(ou;bdey&L)>@U5jFolNGSy0L9>7$JpX@|1`n6iXA7=hGOpRA`6m| zlIT|NzE{-DX8KHd)3~*S>DS9xF%?KtD?8)r0!!_@rj%eI0M9gA&{4y zVG_lZ+PYm8iA1(_@iV=e1WB*C6K$tjt(F@PfhY&#+xRcB90RNUm!zl$?@ZnD=6vm? z-h5Rmyu=BSYhR2kA9%uM$B43TzSE(XRXuttr1|oZ| zI~d#F;ldk9e{AKfU5?uo&Xi6ruz&b;$vs?O#rWvr{wAUS9{@In}?ghpF}ZZ(~@ z0PaV|aww%yQ_~itU6FQM6L7YmUm47xP)1{&qEGTj9jHhcS9k>Vyufq81FyD= zCcLz_vkOQ;Y6mE`T^06!HQF@g+qS$Ad{?vudx2jWAA;<^SBFvu*LWG5zLCoNQvY5f zhb=3u!8HFExVOo)L&%|PL7fAM8Ac`vLC~-x#Pdj^DQ~UxRKu$?o9#U?`+CziRuQjT z)7r)don2@V9JgONQm1&)0VM1$JzU0cmA0s|5J}pB6}=x@H2v3B>vz9nn5+SN7dP04 zcDoh`?9Da?-x)tz-y9Q`7I8eQJY)o;nYeRm!Dun18Qt=G5b;l-UiC3SrWE{)VZ0v{ z3O!;bDb`0Mv2}etT@O3s#IO568-V+6W@gqsUa#%BX>i>8@3A>lf>8M<{=~%T%Gyz6 zB3k7P|6*s$3;J)K)G@2v5Z`zCX3wM^+J%LN16{%d=>hp9oN|w}OZMyqcm$oV(-8#b zdzDEKMPp(h!Ou%y@^!Ey&c`l{{)OuPmFESf;8B|;adl4Wx#co?`#Vx|Z3ELpGGqZ2 z*Ejn}Q_8hiPBp}@A^q+5w2sVfq6D`T1yjJ`PY<+$9lu!Ht9z{O?(P=RVBnNyG;IL^ zd)SdD&xpq!OY~1Yakzab<}=9L^k%(7H}FA}>>7!@{Dd0F%OKQDz zn)nwUN)wHRBv(>|Lg{BvaD~R`XcG<)xY9|cIs4xt5AuX3aIE%6xXHj7q1jbzPHxQsdnnr}d%(9elrO1H|!pQhDn z{i;^YEyXq+H#QkBC7!r1ysSH;B0Mls^s3!6Z;5;{ITv1LAr_qVe6knS*s5bLx4LhepppFKiXDmn49Kw(dFv@;1eI7KPA$ zy}B}ZYGVftlyuw0+K6h)ypvg3BdH!6ZqIiiMD2oPaA#Yc5xHTRONpO*3OT_5)t;d_ z57R7T)ZQSyrKP3mJ`Xfn6ho*7aQ+zerf#{qRHb7-FgR|C!aKd-A3i+PPDFw(xu$&J zl<~_x{mxJVqHN6HS2=*P*@Iw8!SZVL?!^I|R-@5RwS-`WH!FiEimL-tbJc+%kPwxx zExr~prPFA@oZq5WZnWl-dsx=m{C^w$NG3+5kB(=BJypRIN^od) delta 3140 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 OCpakd2>oz;!T$hx@V%n| diff --git a/tests/snapshots/stax/test_sign_message_1_0/00000.png b/tests/snapshots/stax/test_sign_message_1_0/00000.png index 25b48b6b1ad0dde224bc7e7f0dffcac5f1de12f6..a78662e3e325b39b90755f939f8503c57c596667 100644 GIT binary patch literal 9313 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�xWweNUjNfTRb64)+xzNXV_W|Ft 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 diff --git a/tests/snapshots/stax/test_sign_message_1_0/00001.png b/tests/snapshots/stax/test_sign_message_1_0/00001.png index bbf4f05a8c9259cc3f951f26f2447a14c0645742..a08f0e8b186faf0536de9fc3b925de38ae05c594 100644 GIT binary patch literal 15777 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 Bs!IR> diff --git a/tests/snapshots/stax/test_sign_message_1_0/00002.png b/tests/snapshots/stax/test_sign_message_1_0/00002.png index 45566d4ec16b906960c67010f64ba5d4c3ee02ae..97ecbfeae8ae1ee25f1e9f31bafcdca2cc1d3306 100644 GIT binary patch literal 9666 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 U<9G+?dSw9{S=^|;=KSn`0Z?_bBme*a literal 10255 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 WMf+JCmw-k;7E>e3TeUabp8Y>hhU?b= diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_1/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..1bcae3c7744911416a4bde5ab4f06ee77ccdb864 GIT binary patch literal 15239 zcmeHuc{r5s|F0;ms3?`~Q-)L`vSt4yWG9V%h7y`&#x};xSn^4HQ^;V1vSrCSA_ila zsAS7Bm@+eDUnVow#x|VC_jk_u@BDMF-}O7^kKg>^ay{3x-S>0f@B6jg&uy(ug^rv% z!pFxaWOn=39X`H&ulV@*a}MzXN3?AkOZoV8tj%uyeK+*Y0+XIzVkus64+Dwh?>atv z{Mvr){m1?`q5%I0{cZH>IB5Ujzi-YWuMJ6-Hu0O^?UmNc-g@u)69FxaJ7Q>cExLnCy2yKfOQRAX_))fh93wQ%+ z59(ZhH*+Y5wi*Sdt%ZG>kN=hyZsq&pcjGLg$O0^QOowB8a=7EozM@iX4Kh~g3tUe;c`{5A# zl^=Zw385i9e$C7r`t{{MhMK(`Q z8Z`G0S$dT|tnLug4rc|X^v5Lga3)oCZ)l71-Gw`A@~bwFX$lI zb_c$^`K%$MFo|-Gy1^Rhn6O3Jrcb=ao|!4F;13=7?B{gS2n-g2q$XFq?mw=SecP@y zQ$11rhE$>{M|AGy*a%s7L2_SX*XO8Iuk_EKLP%>J&S0>a!Ln8YS>Ng;G_%`8G{2+- zzB>CV%B3hRwO`=MrYq#FX96G8d)zhXvv+mhbp{J5M?8zU$_9gB4Redmc(bwF@RYtN zxwQx16gwY`t-&)vX8A>=mlwtc$)Z~uH~2%z&JF4*UiB{JYKPRys}xtN3=L4RG@BUt z3SGb&GU(_rAp!d!=VxFAC{6CH%y=ns|?Ff&($z zV)@s-B5V#Hr4UU2uS-(bx~^il=q;|0nCFOPpIUqqe5T@HtH64>x8gmi#I`T@KR78i z5?>7=uV!h3-!(tCP(zPPVk1@RdHr_5!JlGD0pOL>@1D3E&+yR6v9dn$p@c2Y&wZ=%58FeIWMG& zu5a9i;HNgi3Uj5N_*9%6vNZz#_3gp0)-lRa{JzzUy674wMg4#Onwpv>lh-i3vGtXi z#IUAO&Xj2Vp)+kuaH39jPyVSV=S2?=2`o(EYy%_-4y7=0L5lKquhdFEx^B-Dr=(=K zHhw~@Qx$b)LpSb%6z&cGwf>Z-Q*BFQ{;!$~<}do)VPA81cL#&(jrb|ItKH;|eJo>H z-3aOur*JeZJm$z+MrnuUs`!5GtKL6kn;nz;m%tO1X`wO_`@;SwmF?%4^jhBb_CWKL z2=DWj8y1%8)egSNCu?=u2?_C)E@odGnfcfxa0bx<7wVrX@pC1Uf0k~x3-~a4iY55Z zAgU-GRhIk~Sv}&&609HHe5Opd2SsAuT{*DGdEM0a)*_nETh-G;2y!8xd4%FwC{mUw za;_lyz%P}c)XJDFI&H5C!Nw^^7-6lDXuhn~04>Q?GiAQTM z<`0cJD`4TiCdnJ=;$JimI)G2n!GYSV6yx$HmVW5GZj^UXi$u4sM*J95vx3mr`^jh5 zA_jR3UcMil!e~=G_2h8(V2qq`iEa;7O;0+JJQG4y%j}j2Dig72d9Bi1Piy_v7&y2Wt5a)L~jND z9e1~HR5fA$-_CgLBwmC&IF)v~mI){Ky;IQMN%i{a$-D&GCldQq=Uqbu@)QnqDeh*6 z^DHny8BNrnotko z^KtZPDW26Un2zS{kX1o^t&f$K4j)1@TmqlsJKq2$&_*2l&Gq~yR(l7=wT5bU5BnVa z6)&%J4^}`}SQLESVN14|zU{KFx&5=8V)5!)$ZMSMBhjHFH8Xd)SBS~sX9i6uuP#|Q z4J#LCI_&lQ<-@Ar^A?-ETtR%-P2U&8`BPt#)#w71_d6)d_wy`BG1jU&bKJkeP03$g zIoH)+a-REBL@1eWpFJkF#MgDN<8tojXjFJ_>I@nT7R?$nw!5uNUBfK=2~N}&8S7XH zYaS)~k)VW{r#JClQFIXmE@IJ-u9ViPl~ApSEkx)&$&|lxubp=#iR%8*g5+kkcKh_4 z`sJyzhKhnK#ld>q(?%JCjHbI}AwO<^(|Q%3jkS>BkG3)Yb*U+SGs{bB`vsHnW$m1; z%tn&nlM1v<(zdzmN*?{gPHND>#beN$`~EYrV_{e!sYz=_DL|4X(8tNR`78Xs6}65d zYJmfFR^_%;7&QNot?_dOr#87=>{LaI|6a*@vz+`67`v`IW;orRHblB+!j%UMHLIdw z@z*q<6Y2&D!JZ4A@2&xvg^-xt;ICL-3FUI!__UL;on_OHdo-51?U|Q(3Oy@r8tcjS z5rM0j^m0Xupb2m1(@tKE%oK2oVrK&a88Uh;qi}BB@i9{|58Ira+3ihY&Nrj8I>qua z?>j4*@MKVc2m>ZgVzF4AZ|~y0U>QTmato}kv}UH2GhR7s`T9FxE#mss0r0Cf1PtEX z@UBkE7#2B;Y93`>3p{okN<)%?CF9Kdl1F6d=vwRZw2aE=L6*PPY$N7MfD+fR-WM1P z#-^6Ie4TeI8@~k^YnZqG9|RaTvmNVJj%abePqkk%xZXgjp{lJ3*10KVZ~`QEUj;Nb zH?Q&C#^q!A>I`0Kiik9JDj!zlu1aKdZiEfpgV#D(o^oOz9^(DMkmvch4#%?J0Iy1# zqK?E*$iHy>8%wLx|!QPXP>O!%Tkclkoi;%au{3)kD@t1pq5=Mtat}y-{^Vf0%nlZKPWVA(2XnVJP zqV5q}$qWo8qyt}{Wg`6X`n)3&LeiOnOeDab4HS0yWGJeXx}S7{+f*zS@feH*52Mz) znUQt5$iR-Cm+V5yw+I_;5-MJTN2Fy<*H{n?ZhcaU2qo-Y!kYrV2Km*h2}U^D=9->f zgZLGnjJ@U+BpS9fyj#V)L2p#_cD`k;4aXNL#0}R%l+u=oZdau;^ha1Tf)1jSLT?I- z>Fg#b!9ZUh-&p{yh|nY6IJ8dFX!WODAH6w1> zSq(3`O2d$)A6bUc>c)e$7eaIn-+z92;YTXS%oz_KJ+y6Tpjjzh=~AwgWRUwpaA-FZ}lyR!lOIiFdWq)HQ&5WK!6#jE76pp_2s4;;lbkiwN)CD0EpRuvcO z4*v7DXD0V|a{GKUQv&C1P(fE#>#Sn$`xP>gGclXE7G&XM|9rx!Bo2P=Pwf*+eRrM? zBTS<(`BSug)}v4TYGf!Ow)Jmz&C3ZbD{7S@Fpsik#_(0NMAFa4!4T^rdsG#PX`MOg z?jQQ=@8+iHss0N_IMCSni*s`oYeS2En%eK!$sq5H<*=iLjFa6qXB-WVt=>nmGBsuF zpAug$!-P2FA*Y2<_nL_UpOSH)qzjh6R2%6z8arnLZLBxi`)b5Q9|}{4d=ZI_UW_Dh z6DC1Av``j0CZ1BskQvO?nfUy|!ilZ?r#B?xH?##PL6fsCh7ym0kE$h;z1+AfNpfY2 zQPHRkp{TV5v2_8n$?4&4Q(4Qkk1>lkrnAl)4OUR+2C&b6{d)p$MVF0~B;(-?iD)#f zj$Q55AbTY1+R6$KM+w}5uIXQ-vFx>{&o?IT$LmPJt_~3xwzGOhtAS3EZOj7^-W@gx z?9)z-UcgEMhm>K1$-Zuyzu{21$@+H&Lp?%enT*phEJeXlO z>(8J+`L<9tL+0I4SNppun9z>om(mf1LBEo~2uV~|5YenO`!{z#-um7wsB0x`yJj9H zU?KklQmJMo5KqFmyGpi2d4+m(*vCicXOq&rsA^I{wq#!h&>a%4&iFp})tN0VNns;p zjB0myMCM(|5t8mrY4yI^a>f2{MIG^Twwsici;~Q6XnbzK)S-P@O}Pk=Agjh>v{lDSuN|@P*+2B1;39K!v1WLbqw)d zMu>5#8~*9z}6WuSHeSgGVv2*b6h&&7?$ zzGi=Y72!myaWnI8eK_gCm!79Te1Le3py6IR&6xbQhoKv$(20ho5Di*2ryCNqGc>ywG%oV|0@C6e8$O3)T2q4Jh zFXjJgAB9p$w~UBC6$0lS5``4Uwbmen#|IIBqS73B$ z`_;Nq`ldiQ!}O1?Lg$@82gl3vYI*T8$0*72!iwdqLXdhL=|oTKiA3oQKH# zy%u-}rE_Xlvf$=!?}?g(c*$dw>%iHU+*U*W#vS#6m)n|~fWgQsw#=iEC?Uz5FCR!9 zUi}tVHt97tm){dHTHe?A64R^tAdkZO3}@b{S;@(M6q6UaL$0ZY3o_OH4L!60s_1u* zX6Fy-Wc|CA!PW5g)+al^PeAkW6bL?>nyzZ!EjV7$cGHC2oe$erD7mg z$@feCKN+{mN35(!PA+IAt%UR^twK)qmD9j=g!@*w$%?d_SSs4XjyWaS3K0)??jy@u z!?%YbUX!Y-D=esLVDQ{L$PDM@>=E0+N}J?la{SL3EOrjjaIIsDyy`jY?v?F|6U?-e zf`UQrUjg>S60hMJ{{&X5fVPG3rSVq)D(V`3Hb;_wrvR{*WSeG13lu~?yGiSV-uMy5^8MZnm1A(Yn@1krxG+l6oh@NuJ~(~T3HGV^`54e57~{32 zunYo$Ag=foc#8`H;FgU6dWkX{?P zvz^o|fJoj6|I+&9ey&+kA)uygeqV&CTTPt$NcJbNF!gTcr9&9<_m!}OcYAlD8Mw$j zriawK%{R}iY+TfQG;hN$YhEw_^i9kkyw?queqd1Ue=x6kjebD+X-^wV1ug^F8Z*fZ z_ib8VIuQxcw35vZMWhcQ-YEbSYEtJts{uH!>VN~Gvqnk2;xC>-1%?+wG))bp6B{1E zGCC~XtKa+4=jX%}piGOj%Zi;_bctQwyDvpO^HN5d&%y={zN+w_T_Uf4l;?#rM z>Lb8-FU~(}@X1X1dh<})<~;kTqCe*v`#jL+j7q8ny+M6ak3hoF~T!9FRMpR4OByh;Oh&nfE zHRPJc7D>_B?yk7QR?gj)Y@cEG7s9mL^MntJ6EL)Z{MIpBVSlbMks|RrCt;AcfIJ$E z&dRnf>YVD=yVhbbtm!xe3Dj$_E=qoELbRxKY*|)1KB|ZsC3#dN@haigArB$ZBppV7 zDf`e_y@ZK>>sfFj73vK~+wTC&U|>B!RhaM@_#~EOqK~Mc%vW?x1qLJ@R!(ht`>tE( z1``&-vS$~la9k0Qq}_z#w7KPAZd`?hWEyXq#V)Zj3K1sT|iQsn^k6g;)!ZXQdx73K-K2?7s?O!&^tk1{ow* zij>Fu>kF3N$I945HYTJQnfN*v_D5RJXbp{u#Ok%QZAS|VvpF2jh*)T-9hRvG4Iiaa z!@DlK6C8QWCSv*3<4)&zM%3V*F~jq|51xBIRDyTEM`a89b%D&{@(zh z>(KecGzzw~_vGB0*hy)sd!_Cu;eg1jaE+Odz^*(R=oP}i!y_KLE&NroJ5m7(57WqJXu zoJo*g@J&C#Q~ubjPcrI;xTu3^f3CZfY_ncmD?i)27$IE^inqIDF{a0+0?+Cj#pTsO32B`LiWVGU)w#9n8+rP`B#o&s#(_|J1n-*-;?fpx zlGHnV`g`M-4L3HwJX7ZBQTeNs=--+??TZ?nK-Em~u0&0phEHe>QLA7XneonjqpVv1 zqU^-fvsB&WW-5I-UjAAaRH8 zP4gX=uY`--5h|OBT;OMo!=oHW3RejG@ol`C#-FdJl4`H%85NT2e}DN>3Vg(BfWVIR z#}E7yD?O+-5I4E={UBT-bQxCQIjy>irq{BXTVSdwC2ZB$ND70u6?Rx5E>9}~sm+!m zcq&yh#AZ!6-)GzF8B;PsWwXszoy@O_m(W*FzW^BRNT1KJ4M7nK7&BMxUp{UqVKr2+ zMsWYa2Gwy>v+RtF&uH$GfrkXl^mo5)sEEz`4Dldrz0iD?iww4ZS5ji=UH@gH_z%JL z%7EOPN8@AzYcMz-M$2vmRzSNVmCh}PY*3%x&g7L1Y>U(o7R$5DDC|qV-dUw$<;YgI zM+Et4WKsnCDsX`pi@5-X?xS{Ll@=ik@cQQFFr0YjV2a)uxZgneRaA9|MfVnOBpl;{ z;?xDDT};DxiPmp?4`&SCHBHbc@0j|F=Z||XlW3}3-S~EW-qp=#er|-m3#OG5S+x=} z6Gdmw1X%8RqRt>T*-AFlkBS!cyWe?Xvr2hb@j;33?dt;UN3y7`M_9Sfp-+e)IK)Qj zCR+Rg0E!{joXYPjjfxh8chv5tHBHoe)NXv+ReKb+0V@GAJLybK>?_d`%Oc9avRS?T>L4d*&EV<`#C&@K{l6QenfEb*FN+qSJl&JN*`= zBPDeuon%dy_`mrzvZS>9cg@#}Lc87?dWOu}UQ{)EZ|DJ-G%E4>MzDgQ<{QtFVCsS4 z&rmfW|2w0noB}g9Ju~mi?*^yZ*2S)4$RVWy{UW7U{@aliBc>R=uFsyvRJGJh$HpHx zta=O6zOzdAtu+(xJ?Ewm9>t(5zK;1jl{+lIzwy&v(^m;s8&z}zSfksFLfJGH^5Ge@ zmb=!f%mmZt`n~JVbW6%yw}H!h21aH60PaMDJEy9>K9L}#o3fleF24m4&!7Af23Q}d zE2$FpGWX<9^;2H4yPpS08u)*)Qu+W(OG@IhdHXT4rdcyC-UC-+lt;X>BDr#6C^W}< zGhMpr5gTfc{jfwPXK_RqI}_4ns@kSkIfk_IC;VBCIQZ_6;`Yh@a!cvX ziM7kGDsqR-*T16_e%;tRRm?b7>fF@%B{HfXWTrapA{`-b?zFDAy0nnDVPVi-^*G^0 zaOhd!5IBScamELt66l|mAd(Lo&KZ?qW_m@jf5=K|n>F!J#pc7T}FK-8KV7mhKw+&0v@g0yXkQp>gAYR|f zVEb1|n_wn#+~_IKnyPG)M_5Y)w9CAIO;_ZybjrSl!$@ zdQ#5@Ql?0AI-s2zNHp=V-#^0lD=<5&fxh7Vc6}YWEp_bR5OKvidITl&5}j@Oi!adq zG;fQ)6MH5sqwxCGK{A2=>@I%-Y_3W8@ez)EZSE(AfKABfGSS_lAHs@glTZLURo&sL zUnMc&MEWV?u`jlqo&nnfD{`f4IVAql%r8+~Q{4$~k9uX>+qg-{#at}qn9ziu3g;B4 zM8c-pdOQ2RPGyXnk~mj#mc0c?u(kKl7oTHQi(vEmA10q&2_P;-O~GZ7~H46{s`y9v36IOG4BJj{b!O9jw5TTSysL`d;QDO3!QclTbbUJpG_)y+LDcjUeEEGgt z3Jo5OR#IMW^kq-fBi_50I|LTg_|Z#BVnW_j+{`E>w=yJid_OqNX3d8;4}nZm6klU+ zACs~JByXidvBnvNRfTMh8>(`)IbD_YnS2jWKd5TU!-w<^O|>e79zS>OUaGB4rOMS8 znk~NGf8s{FQdvK^K1lt<>?H4E3?@UF}!mA@hz*E-C`$;tEE1X?Q$H?Ja+1 zcFIy***~D;s^Y3}&enGckB6)SBkrYHx_N+z-)r;zQO&&d<;HhwrT#ql`*_&U^P_}Z zqxKupq0h_C+Y91J7BSz|q$u=9nxiE8Rudza5=hr-TZNoyhLQ!Mvm00;<+IXPG$UDG zeTKeK`mehwmnXnZW@%J1UP_}2c1L9Ar#l~#W*X_QCZ#mkj_hTWIP~DkozS7@k%?M| zB27K4e#R6$>v@=C$g0JKeu*Oxl*`|iJCv?$gpr}jX)mNhkdVmm@OZbAsByru4I+LI z3lE3&+(DDL8)5oyt*g!e5H-B44)CGpT{^G4@FLXJ*b!5GPBM?ANH{4!Y#)BCfeD>N zOV2KCEuN4=^d>bIw7vz^xgM`z4QCd*>MmV|ZxXtUC$JAI-`jfuGtExyYMO=Kp=!ls zM@yCwP~6s(>(4(JE{z^j-R>o_MPNk3Nr!ulGWgt+Ln!x)igQ2x9py?%p-cpGrF@G% zMUG-h7>bOumste3WSeXn+VXHGL>g74>HEw+wUQCp7JNMX_rH!fz74KMHA`jWL@1f& z(8UL&6x|%&BF4v__F^qw&7B|HhLW!y9sS<^YhljNBOJA9QnCj% z&qN;3lXP;~f98=-K;#D5Q!eZnpt-lxE5B}gM`s?*KCFmHd^z`?_v6GGj~7mcio_am z8fNF1e&dqEG^SVY(;?n-p_!d9QQFhR>5;SAKgwP=$>8BS2-57xGNypke9@>V-Lc(q zjDkBMz+(b>V)CIVN}xrgQM?!XlIGo(jC|2wuPOce8vmR?DX&g{14Rw07iP|qO$V&t z==?1|RP4NTFe+Kvk&QowXib-AOGg_ORqMQ*qh#zo$d?dh==%%0MqhCHD?F!xp^=mO zCkG0!QTC0u*2Z?BG~4-xo$c-4XEEXj3lz!Ez0w?H$-pk%4{e&Z zg0=)&7{ND;BQKJ1x7Wq%I?FqliuaIagagX;EzK)YCmq&_4J5WK;iUP+GAydQ`y`%T z6|~?lTjsj>rX*TUbF^-y;iu=;h^)C;a!}oM2ucy6admmsp||Png`VDj5z^PcJ$+Rg z%>!sC?`%@bZOJy9KfU40_e~|+N(biy>+3G!R^NmLRwc%V>SuRWt(qV*rbBi2ya?Z^ zWI#=9DHEI3Wt+Svyh3V8j%z7(-VqVt-hmMgCcLlp1Gu=`Uw<@mbZVg5>Zl;J`(Z@! z*OYajx;HPrPj`lQ&p9ZqCN7GKS<702>mcP04R3lJKW9Df%Tve~F?Gg6Fa9QJ2Sqba zbzDDyrO z#+e^O#%+ z16=vnrc=>#8bIvnJw8A2a?1D*NVAY!K9&q>YxMw*WGBDo*^3X9ZdbL;5~7{XHp?&biQ+>ZsuzFWPh zEa%tZkN4`28Vsl%XUmG_9L%eLWX4p_7wS6|U0rwBa$EZA-%5RyKP%etVm0?cLgPo8wY3SUPZ3p zRf-Q+IFu$ynIcE``W6UsCgml}7tyC1En;bQzM^UbPY-h?jF$Hg6XRWy$j+veU$HvyW z63^)r`uv;}Ji`PXXb3ysf14?fIseM+;Gl{%1r zYeH(jrgG`1?o{Kml&y)68w@{FZo(1C8&?jTPSCldNUbYf`v>BA= z`<~YFsHTC1b}He1@YnA6Mn7zt706`Y-8@4u^l1MVbHY;l%G&qa+EC02&L{Q{Tn>f) zT87BE1qg7BFKmH?S-$>RCjb>&dJe72mT(Vy^~>wYS2n#}IIT3S`$zHJhJ1vUq(fP%e+TR-E*V$NLzbd&pnL+(9DZVD{yh?PT_dIRG5I ziYCpPUoz@izX0YQYjkD?b)QgB*2$L1veU{adP`e@%7FWfOvP>#FvJfxqs+2YCM*4 z;8xrdFOqxs4L5#A zjebrzIUios-*L@-EU5bDZFgHy9YfdS{e7I@Pk|e*>3rO?Zq~xz_KiAf4@ZdSdXB(_ z_^#!SZj@m7nos_B%=f?J&i}Qs@2|TfWWMH(rO?OpKhqxQthRvdf2KBk2KO>6?-T%m zodZ2>`J9q*2ST%=G9(rEU+2`y{f4aXb|mTQ(oLW*FUg~qL`hsrJ$ zz~-}V>;;eCf}W$a0S2^e{9?Xg1Wq)=rFd;@*7rPkSOAoql*-$s?lF`MoFg32kC6~l zJHU1r`FLyhy;j1Dyio2P56u3d#NJvzs#?^h3%z#ux14|}>a@()0kBtPtzR+-U6yLa zzX|Az^|$@3n;y{}b{3ebQK^9!133>!6EOzjvNWllzbZ!_H;>Yg3mStL&F+Xj!}bE% z>YtDE$AM_})aT={j1fii+hntgHEv2I*;+qi6uw9Qve*DhaRWeKG5srCoq0~KrM<3-2_@mU-%QMJK}Z}73^HA zl^~bNpstV9f1_xBQiv-l=|7LC7V8K-A?{|UY+x;r5|sKOXRP6u&BlKN?BnP{dT{vmmCh=EDbo(Aky)I>77yBa z3Ds>}LWyntl<5Hm_uGaB6=0Zeev=;*G>*^jCCxh^D9dLjhXAjrioOt+x2SZ^Tzc)# z3{X4E^~?rkH|dz=Gjnn0k#gLi^5XWXTFNYre`FR&!J$n9|3uY?o(1hbqElPt-;|Zz z)l@3b|557)2KOjlZa7qi!eMT49LX~_#4`nJge1RtNZ_3{hr;~c6Ip>Ct5u3XuZAHx zZWw~WLoC_@-BS4Wu}8tA(W7U{@66XDkPwR-#%sbFca<%0w=SzEBC`&;DJF}w`c#Es zt9^bZ2W_N3NH4fQvX%NJb#n}O+C20^$^}a6mx5R!bw`V(?uEN!^{h8xp-KinS*W4r zmlRB9NlCtS(oTVRc}urR(8G*EV&FM8T8!77Q9rYs3=CwvMEQ=@{vkTxpuc^>AJg&I z^3mPJ1%1^|BlrIaJM;a7&`Ok7zuRVlQ)R|>ReccVkf_8eQ;2k(lX8gmXQ$YX6cN_+^LsSpX<3K_ZQ^koXCyo zZBBwx&0V7X&dR?VabD;Je77vO(8PH!Q<{onBXyPT3(Lf|M)^u|2G!!Fr;G&Zh!gsM zJ_;iKG4eAp7=sBV9xfYb&6o3?eBf0OF)Dj9QmiDJLkn+lclvAiYtK>?;VYo21ik4G zvb>%!v6N(PP38j<(*JW0&EvXKIRCc8$9rf063Ihz@9=R<5C7L~wAm3i?pq2CJG zVhVSQ2Qa0*_XfQ1^$X)QB_*4in{jy$Yg`sWNGRp+&HtjD8&He?Y)(+K5{Yf~`~U{0 zZmVz+NP4Xm_10cOMY2s)c$*~TcZ9c(s`oEP9ZBKQ*&zLF1e^?5**{X`<^XAE^2NgC zxSRNDg*e#39cGNim#IK>cS7rNb0?ylS)lgYNd&Cr2b{Qkw9!pTIjxf{YDry<`mh*c zhO3+yc|ke%rF^phmf`htX2wU%c&{2$T~!`u6#CKIN*pKJQq8?Mz&4qXU8xL@P!EoK zI>64D&l%w2ltCbw=2k6z;|C-tGL-a8)6=7hY*KM<$DkzI=%e{-kQvuiucc8alnhd+K)4X=$hCt8qZ^Z?1UO>Qg7s88$`s95=w? zaZ?&u#tIxQ&nVXIA(dY9W+y);QW83=6tDe^CGzR+AIkCfm^(WTrx=ER@)MfVW1A*y zEvQ8y=l0JW0;2lNf1V~Zxs=D?8#RwMsDK&;KN;q>LS7^VWj`RTvFj)gsufwx@3KTb zpxXW&MFH{$<*_@j|{&g3N?tTQ|Z0avz%_g&{+2ijsF? zX3!DZZ(|}_TLrK){#i4?_MMo9GsiZ(IpOp)hMyIt?^{>rE;J|}tPRT$7TTcHjog`= zVG}k%fEylYpH``G6x(_RFxRb{N!Ngg9evz7`yyM_dPPy0{S`N%?x^zcK<_Y)f+jcFJPFJlvMay$z8H+Hy#AO z6pR#~{<~)bwsGK4+172aaY7%EUeZW2_p}!?z7tvRTQ$)(cs;+u7x9f3K{$%0F|u=S zoUCiuJw{BO57jkKb>4DK$lkJ~U%loG(ct&JsSBNk53~1DYW+>p?Eb(p7sb<^Q-Re# zk68t6*SUzS#iZnAH>;A^l574-|r-3<&Y_yr!WsK zrc3}T52#nfBGRIU7}Z-|5?&10|MXAhf~QOIik)@ug$cqnc%f9H@c4=y||ySHx=1)!%#a8uI?nSH49mC){mtd$O7dy2B52iXM&>c7z08WM%= pi&=X#DYkgc{J(Ci=~Cpr9m}rA6?N?fzy@1BGh^#p6*oQp`5$vE!h`?- literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_2/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_2/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..3516b6f023bef923a96ed0ed47367af75f0ed24f GIT binary patch literal 7060 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 CEI;c2 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_3/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_pkh_1to1_0_3/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..066a141c36cf945611b85bd89d55612e677a6a54 GIT binary patch literal 11581 zcmeI2cU+R~`}fVvmgXKg8=BsUD;GH{Q!`U@pyD2(rs7CJA<=ATT54I&9A&w1pqP?4 zuqdruIS`eIjB=6dMjW_)SNHuq|2}^`^YwiHg4gwei;Lqt&*S(U@6VBX)y_)rkjx<- z9v(sKOBWq^c=kNv;o*ILfET!8Xx~=N!=uh;eet|=T;V*OPAR=itMfyr+wqup3TyER z?D_ZQy!kERV|)kpTzDkxDa%1(^fttVvpog^0y2tC4}4(29K=7AfHN=*0*^0ehf#5u zhbKV9jpzNbdY=2|efJ38>Eu1epS16s0Po>j(tMIU+6O>9{=)zHz<=WK|KfgF-<;(= z*G#NCZ0cQhd zP9<;ZWciX7H=E(4s+#o^i9f)rnBCzIx1^yt%GOy*pU&B(Pj2q~x^cW&>mb}sy1I_F zoj_tN;;5`A*I`hXETw0CQ;}d}GqtTFyoX;F+EvUWt8u?`O8r?ehU!Kh@oKz>g+>tV z^zeacHVb=UnvH54ze;&$&L^4diKEUVJs^~7saFBZl*6}!`6SUrb`{L!_2x8tFKWeb zYLB_VvHCCbF@~5|9nq#GpFk_e>%UAoT`zkCoiX=)F&l4c_Qa)*ReoKDFNsAQcshx0 z@82=(kVv|>Tgl>nB4#gc7EgO=!Ou z*Yy0#n%@i8%rIQ2j#r0YzbFpF3`xTmR(MV@?AK0BiMLrui39@K+nx%<3LA5r*8Zo3fU zWiY@7^{hzz_&qJ$2-2Cp<74Uj7GLg)1N9gd*;zQm6;ln2AG3&4eQ$|%z>>#ea+MAy z?R&6X?+bPDqCV>jT%|%_AwSb02)ogPhPlO8d@hH6`BR zMBExadygD@yx!L&f8SKmd5iQLP4sY~6!V~Ah`5E54(pTihuCBFS`~z(DmwAi1uPb; zWWBnHnRat^5VxJ%F*S}ePT))8u!mqj%x;Z5(H z`yEl%MGT1tbHas^_WijEB|GBe3k}Fs+m{Z4gxyHtRaQk!9i1UQJfd!SX&Em`3!j!J zXt@Xn@v|9EU{DAoWU7vp>^GLtTxGBm9J62EDv@4dmRP*Ooku>SmPC6;P&T(s1EA|N zo}&I8$i1VNpgC{??L*HUT(|P^snFQqt1sWi6&rl%o{I#3IV{c=cFV)byG^s9O&(Q` zw{9N`wvTS{oFjT~DG#mh^Az171{JF+%p{d{RgW*OZEklAx`oq_1?BVm(cbRP@%w@Q z&}WzQ*reV$8nVe>l3?-Sm9pLTp$-8c7J;OPtVyx6?$h6Uil=S+E{C`st52Z6>O4fg z+8+Id-KLr*lPDjYgT@nb-$^GtAKa$e3WC_};PT1iG^tMoLEn1Q7S9Q?sQD31N2fM- zmY(`aBlUGQIv5EW6?LpC6Ka)TlFTTs5l)LL)Xtn0G!yZoA;m2m#H*rwV-z?azK+zn zIpci)*;i}Z+DQnoTo?`MMP;`o)xE$_9|}4#9vNO=0>!Io9P|S=!r$1dh;`#4yHDTwj295rUrT8JvaN9jkBH?P_1F^?NmO&41s5HB2+JXwEfuZy^arvQ*9E;tGE`AH`< z3;0P7HOa&IBn>Y*ti0_#M2g^1O?*rSIe(%F#JQZVHfU)g_P1C*5->RVC8HAFOGw8sk7V8hf=x zlkPQy(K48EkH;J{_mo{PDE~`B?V*)@?3I`PHti}Lbi195nx$ZOO>&${h1T8y(H~G~ zj)cWySia1wxA8UI&2T*|-qLRJ=pRKBO#Z)G;+(2v5$jm?xx8v0CYSk1vTpx`f7p!5 zYQkcZX6-A60~^P~^ecvE;rH%}%PA}_t7HT)*37&f5olD%wv_S$aKqVjYGdbo+U`qlH7B2hL&56N$)D8Z?s#u{UY^OSj{0 zIkB!0IKfx8aqd@J;~EJe)1rV}@S=uXZpxN{i==1cB@OjEx))#j%`y|bnHf98#m#xr z6zUslrLwPjSKQ+9hC1e2^?;GkO8*C-a1fH(!}LGRmaTXAE<9>Jh^tM#|})u z;%*?gw?9P{;z35FGfj8hjdCRh*uAiH29})C-8rF`^Jb)L%f&3lx-#=O7Q3=IcOtEH zY;moK{^m#u`6Fz8ZL|NcCrW4KjtodPbWcXk)Y!S_AdD3quyJIoyy+#=8(}pgizD?i@Y4Cs zTV(!(3w?^H0rn4YKik;WiKDXs&gd|nt@it~4q_G#1?ATZ^b;O!Vx>=UEWBc`8c05+ z&5wFlp3a8TxZzbDWLWdBs*TFCKT+YMA7%Cr{HACd9jZi^Xe57Yu45JWxJl8fyJ6G)N*8XzmajT;$WAQPgGcZ65~+K=5|7hXN^V%^R8dsG>Rd$nQ_VM zW{4srZDZI(*sbVAm3>=BKEd`-P5*1haDs2aPS;A4}_%|k; z)4Bznf%`|v$_0bNP!aE?v2|Xvk>oPI^H+0Vt=Ka3bwDT4!wotPzEnN5-4^O&6wa7F zg>Y@yZmF{Z(XgdKrjcs4UZ;;RLRo5*5z3%gtp3VMA3Wq>HFjv1MsOOD@SherL(Wq! zD2Z*Z!TcO^t1USUV);aOZYS6e>k5#OYlA82&kImBEA-xl)(E=l(C@{5{n>+ArK)&P zt2eHjxje~kcXG8Vd2QhkrvHpQsr6FqD_OLFAjL)Iz-j$vPKTFzMJXhs{WsS?HZ-`K zjR;luv5g1VrK(t#p>-B}qh@a~iIIuAOA)9^N|o+fvgKq?>2mciHqC%XIb^Gj36(lqyQvzwtL}y)(H~htq z7YfOTKXbGZUW>@q?F5Db!s_0~A2z*gm6<@wg`F*jgePkWL=ZfnIS%4_G8NAD1QnY%6A6>t zrFDEsyX$(k&4tFsnWc@uRZR@ogMFX}U(;AriaiZYDpNev08&dUwJ0d*b|QpQNI>wt zJSbiwoC=h(Zfp)ZK4h|#kSEceq&#;L-t?HLKoWIBcqwLDaTb#*+G|p+GS8MMSsMna zEgTPNoEpmC7t!O>9rd>{BTPRemFUa9JT?X`@)>aePaW+_=>iS5JyBh`yjqm-E9;A~ zc+8C^2@5|{lu=+m_qlVXFd+zBrGDjZ$F%#D1Ems3EA((9l{|;V8MPNJjfUp7bU#3? z*qF4zG#a9L*~wG5^lc+DjxPr|MfbYG387}@)HrU~&wI(^c0k)gskP)>+}Vf^f8Eyh zmYsQ}AUZgrEU9}f(1~!MZ%>a*qT{ZC+Jt9_y3Af|yMD8fQ%5c?oRLC+s0| zDe^_^OI8aEdS3W_lw5a|xCOUGf17II(tTw=6#+R+3_%;X{@f7#=E2nEJ1=bEAj~)A zI&sp(_$zjAiq*|R56Z%59ADFNt*e}@&vybZ3)!09@+Gu_vOTzdJn(eB^M!Vu`US7d zE31N+ge-dmYygfRV&!s|!lHpqXpKn4R40m=o4T^oKl50%zPg_GQ~47yT{(3kcM`7M%3s!&ZXpv~QQOgb7}Y zFo$RD^4z&HAsAGDXXVO4${X={Bc;=`+|s4|S}ec&jAto#_~XWRDIa!OzCG_m^EUCO zE*e~6uqGO}lYjzhirRRyNn|MEd|=~9=UDxOjckb5xg5#s`;1d%M*T-1FV5;eK?g^Dr$_Ug zIu1~wx5~%=hZLyVh1&Eq_Q=80SWnX5qjI2k@m_s-D(NF*tC&PR#?ZIf7{jUtjdxm} z8;_=OYFM;H^S6g{Xp5<9?p!*o*YQQjTXfEWk~oJr`5g#UH4BDz&1YtSv7p{uMYV>a{ zO&dCH^(*@^UF^)K;kg~E%f`56?*VP@)M$cDWfku6yS459RtIjFgDbp+Gyw#g-B%ldSOd8ge zC#|Gp<5wTAEtyd2Sj{>;#^(HnzhjD($V_m>b#7Xx40yX(peDtrfnDMMtxi$Q%_-JO zG1`<#;>ahc)-SBxEGVB^XJs&7?dtZ&v-6fPX12q45ZgGSjURC>Q?~Kwh4z!~nDCD8 z-+)R^=zV?Y_OSsrZQdoP37vkE9{t7N|7^>p!U%_CW;)*V0JzA^ctUjNrLCh1$mzMQ|8_@Cr!&gOUaA6tKwa-{=B9tCi#C_QLncb$Vd*XRx^H?tL znuyV0+wPb~?S?B`Jg=Rl$Uizl9~_;r;@%+~Smbk=<}>t}u*&mS2nsk2CGRgYOp;Zc zLt6>+6|qMscP*8BjLVG@UvG}u`7AVr!qcE9-Rdh^SwzhKNu4B4q{^HiEPQgjHQ|b{ z?S#Bwdh>_LRFX7Zrl8m317^NyYMLua;lWhqdnxyk^kr=4h@-J@xrQg^beeH$=WaHq zWn5rqydmy8dn2{yblQ)2)6DUQ%=GcpIiRNX^n3H#%%kB$3&BQmN6@!>ehpPF?PM_K zMzxYrJ8Ml@*a{?NkM2~*4Pid4Y>b2Wv%W62F=K5%S|<-SW0cYN%LPI)J<4^@@S?(} z%g+)za&}aFTt@p_u~=v8v{JA_CNxKn`?z2KhKl}zR+~RH^a;|6%t2F9&KH!Eww82~ zDA)MkcdF}95tOF^=!JWJm4=ScT|-D!z(|xFMXW-^d&)Srl}_G>Ek64MZI?ei*C_=s z9r|(w?gtVqH!^xD>snQit>wad6r!5o{bp3p^sTRu4T7c?sxCWb1t4^KEmW%PWR6 zco5JWKy)&f-(1S548l@K6fx5Lb#E!RDMO8H-YL7^p7MI@jMTk<1Tr5bZ(s3bXG8w1`?HYOj#8MSKPthVr|}tOGBP;cMxsVF4QM)? zC9dFXyr=*kibCgY-^wWs&s#vY_N#0Cp0o?|j5TnXjx$C!U(@VhNj1>J0gM#bh@wX% zOPh@iw+}YgqF40L#|;bxH#!t89Hf)kXxV2KcUeTh#)y&wS}Rm*Hq7IQj1?1%rv%vMAM~7VPfc5Yb zkQ4%XQ<{hGv3lT+KbH7^(^7Si+brImugQF)n%<)B0Dc(!bwfK*hbHu zw6<~Ht~Y#EU8;Jz2hYxVf>;2V`qUPFR3|h>$*rZ6^?(I- zmaUIg>5BSF5X+@=><`^OmwPQFowK>6-8#ShT$@lyd4dUfJ~0iXZ6+wdwNnAILU&_&_hZ4;xn}m>TP9b zPfI23yKiu^LZLsT=#z!-p4;lukfLaBk1!FpTbFPTu&a)vVjg^w$9iv;V%y*Ay_W<& zzPwWzqPgAJU||M2mpo9Oy*loHmCQRDuIx~TsmEFf9(HSLD$8Ddd|Sk=6J4uc`*ckz zvy;~)d}rxpfln+o=6A`EaWKmV`)w%V*g` z_Wv56qZeX0mr98{UqZ6O-9eovu=s*^(`aW~LqYyA{ zrne%0=-P7L!=M_DJd8Dp0ESVrjF5M95Lb6B)_X$_pHcwSS&4?o!kR?e(-pYn*Wk7( z7QjT6t^EP!Ph-`zjWq*>pe`=KsZWHItX~rZgCg6#an$OxT0|Oi><`Ohf_Gw|_1-Mp zngf}8uz30xYG>Bbm*VVBUtH5OsB<9mn)R^};)2xQ;CVxUX4eNtCDv7A@t_`r z*8m$(x`D+|pyezNlIDB+FsF#c2{~#Y$x+FHp^B-f%p1!H>#U1DX#np8K+?SLkQxhY z#}I^4q+S1|c{A`*Q)e}pq+ZXNriBpo6&0>IV=d@w<%dl@(Ga*FS5b{*Glt?qbAF+` zr(G4kDfhD5*dRy3zHWwc*jIGu8&8b^Tu*&R%h`Vt9}buGeS6{doJ$U@wndN?37%>ExVEip+k*#~ zg@Cz9UjnIQv}2ghH@qrGPX9G0T*z|sqR1~`SF9=Yz+(#m!&H%)X=yCX+QqZY)<&b|BV zWO{1fMxK1Zglo{0Ag;@zyR#`X|HwS5fLc)`wldg=kgJHkJx{so8Xhl&E;5u~z@UIL;~pAQ^x&|x+3woYiijvSfyUwu&9d~JjmBe6sZMS9BIybT zKy=ez#PDh3KJ?q$NqRTExB^m++tRwGziA-!vz2UHsv_-y&fe-q!G+1RT|BDdQ~mOT zICH<`Trf>W^AEz35}7&}aK?dG$GRl^kdoecE_4aO?R(+ur7cH76zmL1{_St}b=5?-i#VpHm>6&Y* z9nMWk{=|QWTDT|e`6n?j*+yIL-^&s-F|tBn&dh7P_k@rQpJl=N?LHJ zV`2a5-n#Ydt+tl^b}!x0yFtTG`jmC)Xk}d}U7`ojrJGf_ZgLy`Y=(~KX$3pa?5>#u zu`j2IE3fgR@wt(0)*?FbNX*t(*%l2{v6aJ!DjWjA%DxRJJd2T7U2f{a8?vB2k6dzQ zI)|oLU$Nm}5mUYQ^oNLp9n%J+dhTC*VH zAIKpxF8x)pTC5ZDl^=E_rq7op^ic1dym#r+o{kRmCU z0i4YpqQw|$uwqfcoq6Ny@0nJ{;=ptxk>6QIaacH+v&kN)IE=qb$r$}I(>1%9Aa3C& zU7&Y=Qsu%3e5YTJZpnX)v!6Z`bhg#}dod-T?w~I~H_H>FO zz*rHhl6(&p6JieWp;!D4>9@^9Hov;Z&GyTQI&1)VuMD1+lr();#vJz8MU#`AT_aU1t_N}(B}tu{qe{8&e)C=5 zQah&IwFbc-0DXUkaSCj&>;L#KTJn|XC|72csa^2h6S}-FpEC#fZ_`L>Cx}^`^4A7R_whR;&w|wtttf5EIm@sqiyOzaX0rDb-Sgtm|3fLF&p^x6YVO^ zqhb(1vm96@j=6g{{{_gA;v>1!PeO~%mH`rDE%<$3-j+M+f*zm|s96%00bhjvm(Im> z0a`6fY2%MpYar#oHad1^{dqbAJVkl`4+~e*mso76s;SqZD=t($qlG&=2}B+igbG+^ z^MH>C80k@k|jDALFz2qs8244T0lYi|Gko>3d&G^421zJED9N{%t8Jit!z&>Uc+qFtBa^Pve&owf?q{xg007U6JcBi&L3(!;CeWr3pU{JfF7c8Pq z$GyyGxfJ;|DBq~+R9OiyZ88lfc=X_b$qg)){SNRdiFMOn-s!t_#LC}=_&V0=?rL9T z+>fqZ>^))~t@zWc2bY@)n&Cn|(9FWHp`oA%!ek#q}JOst-qG zbnF(uGuJTDhpR_5qGjmbtj(Q~#Z}u`a0aSqh^iFdN}q_9Eq2@06CeYEu4*jL{3OYf zYCHTo`Y%7}9N4&OVt~JePr>z$MS`ne?~v4Z_+F!aU`S!S{~K@cv3j)N{v1>DUO{kV zyKi%HjKbPU(oKVc&WRNP9}%~X#b*-xw>ifSa4&z$-#0JqC?j}#Z}yRBbxRG*G)WdS==Wo+0m=7h$hQJObrEQ_ARGA;&2Uzk?$pb<(5b4>a6vka z93|IuukZ8Y;u~9k{z{RN-GB>(^|!GB^))*sq*wBs3U9TmkMA#39r?qS6N7WRI1>P1 zPW|iQFP*v3Y*)7x`-x{u0K0UWp>ajrBK<9wIy23bKGSOwH;Co_92e%ur*qyD7;SCkGiu+ohwi&?q|ESytrP4D9y`5H~+Eph0 zU5$&e`-}V$dh%+@{OFn=5JBqI^TGlvv4BT5wNgY2>b>Cen$88{R?Gy?ojR8TOP|-j zez^0ZZ{JU_ow!9{Yn3Sy7!3;Wmp8x=#Jdw+i}t!uZHY;vg%$$3r>iP>(@L)r=86}E z0ie4P-wdk8VgVir&iGv3Rb`qmt2q(Aw~>SK!M*#v@iM7X#zJuzaJiZGUa2v5TfMW~ zrB?2Y&p`STdGgDKz_5<8NKgJ6I1=f_lh{bC&^#c_WFu%y2;rKi6-T;Yg>Q8}xvzm0cbl`R!YFiuL=w*59pbQQN69hw&ga z0rI33a`V&z>&D=ic;Eo2v2Jj|?MrcHv0Gy4opWpCGp)%ilQRjk55fp#T)*^j-kFPk zjt8ibREoMRAh7hEShr9@r~09LV;7m|Ftxz_u4RoCn@jJ>NtAItPr;+3W2R5+sI+Vn4 zAVh9&Y|Sa#nyMGSCqCT7Pg+Wpx9i0-G1|nmA?ucj|OyYzGt`){2^LRUW zfcF{9N=Ya`ZC`n*AdCL-FJJwT|9um}%e#B3&n$)SgSD*yW6?a;7IqiwF8JR5FSl&Z A4gdfE literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_0/00000.png index 46daae63d5984a6c8f82a0979e9ce9569a9a296a..9c787171418c01c3841788905a02d133e49e41e2 100644 GIT binary patch literal 11036 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 U<9G+?dSw9{S=^|;=KSn`0Z?_bBme*a literal 10255 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 WMf+JCmw-k;7E>e3TeUabp8Y>hhU?b= diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_1/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_sh_wpkh_1to2_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..bfdf581d3bdcf8c32558f4edc685387f5e638195 GIT binary patch literal 16326 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 A4gdfE literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_0_0/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_0_0/00000.png index 46daae63d5984a6c8f82a0979e9ce9569a9a296a..9c787171418c01c3841788905a02d133e49e41e2 100644 GIT binary patch literal 11036 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 U<9G+?dSw9{S=^|;=KSn`0Z?_bBme*a literal 10255 zcmeHt=|7b3-@cF((jrOL2+5j#PlaSl8cX&VOR{BOh9rbgWSg;kQpk{f$=FRb2{SP< zm>9B5V}`*nmNERUKEL}fxF6j2{op$fu9?^MI_Emi>pb7f@ji}s>Rn3{o)dy6SXfwi zOmE-1$HH>t6$=aNKb)+<9c`=5Y8DphanoCd_alo|rt!J(JNRVxaRXb{P|i?J0oLTF z;%Bam`sP<_``{(L% zLt|mn;T_WfZBZqJLfaBzE_io+y#c?nTFN(bEFsC^WD1fTfy)PDH}{`&K@-$%1KV{H zVl_xJDEh^5cK&4HlPQ%yBQjAEg-Ocn{2aPhKeGS(%Lz5VUebI5xfZK0ZF(koP7nNz z7Q6K)62#7bFd8;p99FHF`A$Z=*s>C9s(<{Mn^C0j$z!z_`wiXZ6iZ7>BfdT#kZQkz zqIF_Pq3uq!I6r6wtr8nH?bXy?DH*8;Jf*4m9=4~!cr_%iXRz^&fnP4 z$xWhu&A`lx148I=sl$;$0VX`pdTF}5cDH%1a^KAHt3ay}ZU(UR56=4X?36O&dVC^n z0@LR0S4-P+j6~Gt9lT#S<39d*Iu!=&r%oxx%;dA#rTW>Z5?olZRwAtG@D(qETbUa< zxOfkgt98=}BKi;nqKB@bIprc}HkNaVQ7Oo`wPcyJuOe1_$!{US^<-_rHm;bE3pRD@ zn~$1mrrdHp;AfjX14GYQxo2ih|_rLgw)z??FC43|xB*n*C{T=e~ zE8%Mnb`E*+%Ln?*waCuntmNtG!&4&-z1J2T?3kZSvpo--h8S|dvTGtD;!kKMs7(;= zl!PtDe%gG*n{f2+a0g^I?qn@&b~NriJ3laN`-5X~Mnms%Da#pq`?Sn=)KxUGW!s9} zD982eA2__#AN<>0pu%@5tF`?6fluf$VH3i%!Qp-g<`0e><{Xa>>jL$3ciRqeDJI(7 zsKEvHLaX3#zyee9k11yTy+i#WW|f#)=2Mn67SQ(Yyv(?GeZ7l8eJ1K%v*SR{ezqiu zH$=M_Q5&;k_I~}O=H=Lk?O)cqBWz|Rc1^%x;Xh*SR~ZMpv8#k1w2wxAH)UpenXh1y z%?w(-cYbH+sx1F-Fi9p-nSH#&k$J5a7O^0Z$m^O}=HqL756POawaS0g7Fw}^?vqJt zlnd!D_Q^vuwdK!Vi2G-RIW5m4$LP{*C7HAuNcyctsa$noQ>%&a?iurXAcVr+tnk&I z7~(?(A9fejlJn?JmB~jR*;CQmOfk--Ulkec3X`B5rOF>-*74A~>zRpL zAFWd}lgK_E&_;t8a3f{Xq!7uO#VXo)-Qr;*$fh;8=H=)4k^@6cH%MzynnLQZVH66r ze3E>1=4PL8-5OvP@h-`TP`N1o{C(%V@?SwJ(#e3om)V)es6a7mQjrhXbTKqId@7(V z-T1ZL*dPJFV!NkWkfQM|euWvR8O2Qn}f^kEUw{E$5#mc)Ol@!`;Z} zrfxG*HoG=Hxb*d35kIJuNi%A9lU;gZ@uLYLY`#74;L#Tg-G4nBwaqNAYj|CBtuj)o zUSvm-g9P9EP-UnyRlk-GoU&1_gqHFfYjZPfTu=PBbm)rLwcd9;T$zK5*LH%El*1AJ z>acVE?jEs(KX%}OD(9{anOH^0NiE8zSV!Rmiqr`Y(?$}1+vw2li3lq3HPPDXYHMFWAkzNJbj^) zqW^wUkaLsZ1XhYt$T_3+@;*{1qFpXn$Wfo}N5De{^*j>9FSMt(>v5tR-hv}CxM3Z*drG0H#XE+DY4!xnY1x6rCH1@Dc!3gkqL>eUoYsk`MRAZ3wQ^?d zt$!GC0?ENbytXLwWg~08$MoWlaf`9dBdxRG^RAumZq@6~sv!%b59JqBv7ejWHluzrA#j6fa z+|xV{7plZo8FXl7!YUeg1-#v@DzOvd%3Wd(d0K;N>RfnxrK5&Qt+QrkJ}>>dWzr~7 z!>-jD5d{t9Axk?Sa(Df@tlgaJa1Esrr<32FYCy z2l_R3@#k9#tGVJaU98J-WwI88`Pn3j(%ShExc6#Ru7v5NG0;&Y;w?4>D;LzLc#cCeuSJ ze9T-?I%~$<+CDk|@>4YU;7Q$CdrP}W;&p_>h*D1i zTK^ICER#^yARPMm(9xNj*4{)bJPsB9sgMfcP!2Mz(O1UyJf?p!-QlW=Ko~7Hsj2v4*rn5gDdPVng{Q`$J7WpT^ zCj7mxtlm_oK^K1EF88zR+Cmxf2W4lbko!Xxd@4kNsQ*J>uMzVT7X0C4Kd;mY~i>yuJeU7}FaAvkx zW0Q6YqO1C&PPBzvVbhJX_RP$q9;naX5?vjb(&%~5M9^=E?@P)DYj=$~le`K;%=F(sj9qXTkEO^#&#>;F~x|bP;XPAY;HX?TMu85x@$XL*nw??? zT%0}Q$^_!fRFAU9@E8aroCOphJFn;zt&lgacXu60g_KK*XYA>EwRCD_J*@Dnh@m5B z%&TdVy6u6hH$R`Ciy58?q0uu@{K%II7GGTID!dN-Dh`oj)mi~Amz{3GtzpAUG+Ic| z({o#y4QHTZesR1)4CXKi|j9z04(IO)bVH&vQBH;=`A-YyXd$2nId=Li&1=sjM10sK3-ArbIWa_UY z8i(Vu-rrJZ3eL7APdjjXZyu~K6`g;X8}t&g9}{2uYAUHcN-~xSF$m9=1Tvh_Yj9zE zoqv5~b(V6>Sdx1IxNr!4@aqED`FKyVx@#VI)GILlQ|RANh&J^TLXEC2sitasoVK@8 zr!5g1gzx{-O}x0jrBdX5!?FfJs!aN2!`%_Cw8O#?bLbL*GwN~hrug!B*c5!?5M=M0 z5N6#L^1u#jFr|lTuD&e*T$LOf{n3)Dgv~$7LEM2SY+drVPabG#^=GWy+PIa_SFB^2 zP2SRmtfNUknh^uDB@Z`Y6Zt2DZ1TY9#4@RpWX;9UI8g>I_qR@)q zZbaqt#@#*q?d$-#6I6%ljenB*w7%P^RMJ=vuB82zpISbU(r~}sL7JU@5eRyzyzQ!( z-)4FT!zd-4l-eHuM%ef~LYkvqd8@a&KOBL1;H-hN+o%A@v3GVlm)Y0){~OfUvpdc> z-zc8avNGV@)}V^I#Y_>XRv;?pSV9KG&xJ>4DM<6%MFFg8i)+Cq*A-d#$p<2@UlN9% z-#=74l}I_}l9f9D>G1Pj-AuZAk%r;EY+4%ps9McoK|XUJB&^iAC_7r{ecZAx07ihlFOw0?o2;m3tY)h7RfS+%I(yEX;Ju(5`^LdS_!TEJSA3$K5zip) zp!3)-ec2&c-#Zz>&WB@R#hrCdwc$zb0!Aa7`1K0YoQ!?>x|sIeC$DPB-y2oytdAp= zGUpqTv*B>hBjq2K&eGh4P#T2(djM1hdA-h&-0co8lr*I?y7s4AKXwIJTzDoHk@6E%X~w=l53Pc?+i3kT=cA4W$w9`cO3cG+FOXw7HQsTn;q@pG^4usNd( zt&%z4S8cuI^O`Fvv91{!sj%S8f1-1C%jCN8sf;)Tc6plAt&=}nKo z+g%|co${8)^8t#3M#Bc2YXyO}c6WW_8i*5*)je$d@N^ojiQroGH)4Chc{3a3+VCr( zR$o@ab?k3u}kP$MNeK9bfS zO4wd;9@qbgA<}MLD58lGWr}-z=tm}99})FPS6RtV+Ew|bS^JeJm525xVuvSQ(2WM- zd{+WjZhCB0^jxqv(?G!_>JLIfTs3w_3CQPNrNdR87SuOSSad|8(I(lFiCEP!_R4Iq zsCc5ml!ux3ROMcax;u_jWCE+ljch2UmGmOoPYsFxLqt6O;Fk#*F&8hk>Y2JnPTq7G-(gsB+kj>eSXc0&WxGb9dY+!hLD!eq}wupI;wzQy-tE5}om__p%YS+YAT@lvr$LSI~aC zxLc6WK*}(Jv9XUkgukD-3cHl z=ntwMQvO1O5X^->Hc_N1#0i43w&P10@WUqFKUxyE1^M8vS1{>76h;33L=VD+0ls!= z^vHK7PS&|Vs_wMlFuYPSB&>U!nvh+9x~M;q6`mm_t7z@*Y^6%cJM zQO_T=+O(2m7WaGUvGmyLYwE|obx-A9Sx4(~$ zeE?H^FkniUwcBWeuuM$X>}fzv`<4-C+P*bNsYwnn1?oK@Ao5aWB+r{`z=mf93&KMr zw29N`-<0i`CQZu}dzJB<>Uy?il^t`<{$^SFmFF9=zA~Bfa)YC)VGr`X&?EYi{YpcP zH8N>(gA@!yueF$K-!!`jU_VK!5MF4N#LH=Q&&=inq2ep3;G&AEs5co*u{X!)p>4yR zhE%^9V@h4G++en3gT}){<7Z*8123!XbFlg1)AsSCh=&w|LQjOp_UOec6`0VkB}ySp zHunzIkvdtg8lG?%26eggDAogxT9=U8y9aGMU1>KvVeHgEI$neN{bo(kA+Oj{nxWAY zpP2p&MCiHg9q`Fj)r6FyHsO>Db^xk{{J-nmjTPa3EooYdBO~j?zv~TH4z_hpEa}w# zHtU%zllfYLR0EFi%{k3ar_;*>@Gr8aH|^&{J7Pp$YUO`eMC(UQ5hsM*)0cc)d5W~u zqE^dQKmT$~)*6}ylEuNsNfScbY0(anvgls{%JTS;|0q)b5#IjK3XorWFbch9R|Xr& z2w38mU<%`a_YKh>KtIHGVie%fli)sy)Am{SabfsYjbi|%n>jBkll89FkFcF6wzKOH zU)q-hhu?|QT1K2iu9+Gk=Yi3Gb%KRZXFFWjDR%T6pV3Ix`Qd8vUZgIE;VbYY2E&BC zl)s-Xc@KH%qYHP!)@{qKD!D;KtscfKd%^T_v`sg)(sz$?Z+4xt#uZR?TK%QbI7F?= zu*fT$yV z3@kCll`A=r-g55XOsHRE1&~*Uk%p(9y8|UPmGPwaC68jp!)x`#s4(X&p2s`gff}^~ zpDZ2mb3w0UOLklTCL;U1#o_XLll;crZpBGY(XVF2OKh;?(Is}E+zT5^H!=!KDEAug zj;;kNzKQ)504=!AL-w6&Rg-rLSJ{v2$rtsnTr`tC>I;SLy%1XQ$J39sn&u8STW$M! zqUNn{U;_{ehcC)}_JmB9h0%YqZKFzH(cjD3zg-Ek=0mer!?Tn7VO(l|mOS&blb*n< zqkwtAiaH`mg5y|r!yxTqAOk1}-Vx!U6VuAR>BnT-@KUYF1KOkKZlZH3nBhXGQvgiB z`Cjh@Jqw#E>TPswL3)nihAWodJjEt`m1``^OiPr4sD;C0($e%<$%PBL57(;u06r<> z8qrk+|C6!skDzX0_8rvb8);)qBPCROz|M?#Et1*SoNx8Ud&)yvr{V5~xOWmS>dG8# zEKGij&m*Y5fz~L-x$xf0nV6cI4&IpCd@Vcp%#|g_q_~y8fGpeY^eeix0caPO1qER^y5w8sa9cKt>V?F z1?B*hS~3{OZ!}^P&>U^WK90TpK&$wv)XOo$h4XP+EBe>^`W`)t)hw2f@~n(`Jgt@Q z+MnuW<8>}6o<|j7;Bcr}>Ql86asJwQl5K>|oA(!Ao++IE`;rDiCjsUIjU5ZwHLb81 zPOUt++>@GgZOmJjA6QLAz{7ZZ(AX_EEy5jMxxg7cZI3V^5?MxAYz5;z!|AJFqx}vx zv+!h}pp{?F6((I+v#FS4#i5fw1#w-$;9KPf??rp)wYtr|S@X@71o(k4XXv9EB}9ySsf`2eYXma7HY z>^WRiBlnZ6cWK>j?#s2TtGbUm_7)4{q!7X4Nf|&x|R$G zdJu!bMxci5a={QovL&y*tg2+`xlsAMjvAy{(EJGcbsMs)n^q>1_Dl?jws@*?XJeU6_Zp%WS3NmSq(ub@U^jEX zh0I-2=n3SH8OMI5P^pK4J)^4rP^nChn4LZ?mpVJ|dNED_A{L1wl|t$EHcvG(&({h2 z+;r>uBsaJaNr%KgE}-oefeVXdp}fPB4@-p=!rgdI0tE~u%2^@50h*tqX@PxtPRs%u zcLWfbue)_=<^askkSI`OPOOJ^xxgxva~hj4?VW(Mvm4ur92_{EV{3Q{D9_rR%-=`H z!3h zhA4-jo7H%%2p~13p1mn$ic~5RIir|rynWt#?}fsdSxh?u-NAGOoo*rqe*eJerRE;d@PGq!qtX zByOQR)!OAv`sZ}Q*6$(lu4Z@(e#QKeZW_ew$B^|0(>`P1g>CY$3_hV8z<>l;>1NG0 zFfaw=rsj>m;9)HbDDSMEu^WmNjl4UP|efAFwec{_ZJ0_5h;Rve?jG6Y01m7 WMf+JCmw-k;7E>e3TeUabp8Y>hhU?b= diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_0_1/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..7491845317a2c765f8785ebe447bd567ddb92087 GIT binary patch literal 14492 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 A4gdfE literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_0_0/00000.png index 46daae63d5984a6c8f82a0979e9ce9569a9a296a..9c787171418c01c3841788905a02d133e49e41e2 100644 GIT binary patch literal 11036 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 U<9G+?dSw9{S=^|;=KSn`0Z?_bBme*a literal 10255 zcmeHt=|7b3-@cF((jrOL2+5j#PlaSl8cX&VOR{BOh9rbgWSg;kQpk{f$=FRb2{SP< zm>9B5V}`*nmNERUKEL}fxF6j2{op$fu9?^MI_Emi>pb7f@ji}s>Rn3{o)dy6SXfwi zOmE-1$HH>t6$=aNKb)+<9c`=5Y8DphanoCd_alo|rt!J(JNRVxaRXb{P|i?J0oLTF z;%Bam`sP<_``{(L% zLt|mn;T_WfZBZqJLfaBzE_io+y#c?nTFN(bEFsC^WD1fTfy)PDH}{`&K@-$%1KV{H zVl_xJDEh^5cK&4HlPQ%yBQjAEg-Ocn{2aPhKeGS(%Lz5VUebI5xfZK0ZF(koP7nNz z7Q6K)62#7bFd8;p99FHF`A$Z=*s>C9s(<{Mn^C0j$z!z_`wiXZ6iZ7>BfdT#kZQkz zqIF_Pq3uq!I6r6wtr8nH?bXy?DH*8;Jf*4m9=4~!cr_%iXRz^&fnP4 z$xWhu&A`lx148I=sl$;$0VX`pdTF}5cDH%1a^KAHt3ay}ZU(UR56=4X?36O&dVC^n z0@LR0S4-P+j6~Gt9lT#S<39d*Iu!=&r%oxx%;dA#rTW>Z5?olZRwAtG@D(qETbUa< zxOfkgt98=}BKi;nqKB@bIprc}HkNaVQ7Oo`wPcyJuOe1_$!{US^<-_rHm;bE3pRD@ zn~$1mrrdHp;AfjX14GYQxo2ih|_rLgw)z??FC43|xB*n*C{T=e~ zE8%Mnb`E*+%Ln?*waCuntmNtG!&4&-z1J2T?3kZSvpo--h8S|dvTGtD;!kKMs7(;= zl!PtDe%gG*n{f2+a0g^I?qn@&b~NriJ3laN`-5X~Mnms%Da#pq`?Sn=)KxUGW!s9} zD982eA2__#AN<>0pu%@5tF`?6fluf$VH3i%!Qp-g<`0e><{Xa>>jL$3ciRqeDJI(7 zsKEvHLaX3#zyee9k11yTy+i#WW|f#)=2Mn67SQ(Yyv(?GeZ7l8eJ1K%v*SR{ezqiu zH$=M_Q5&;k_I~}O=H=Lk?O)cqBWz|Rc1^%x;Xh*SR~ZMpv8#k1w2wxAH)UpenXh1y z%?w(-cYbH+sx1F-Fi9p-nSH#&k$J5a7O^0Z$m^O}=HqL756POawaS0g7Fw}^?vqJt zlnd!D_Q^vuwdK!Vi2G-RIW5m4$LP{*C7HAuNcyctsa$noQ>%&a?iurXAcVr+tnk&I z7~(?(A9fejlJn?JmB~jR*;CQmOfk--Ulkec3X`B5rOF>-*74A~>zRpL zAFWd}lgK_E&_;t8a3f{Xq!7uO#VXo)-Qr;*$fh;8=H=)4k^@6cH%MzynnLQZVH66r ze3E>1=4PL8-5OvP@h-`TP`N1o{C(%V@?SwJ(#e3om)V)es6a7mQjrhXbTKqId@7(V z-T1ZL*dPJFV!NkWkfQM|euWvR8O2Qn}f^kEUw{E$5#mc)Ol@!`;Z} zrfxG*HoG=Hxb*d35kIJuNi%A9lU;gZ@uLYLY`#74;L#Tg-G4nBwaqNAYj|CBtuj)o zUSvm-g9P9EP-UnyRlk-GoU&1_gqHFfYjZPfTu=PBbm)rLwcd9;T$zK5*LH%El*1AJ z>acVE?jEs(KX%}OD(9{anOH^0NiE8zSV!Rmiqr`Y(?$}1+vw2li3lq3HPPDXYHMFWAkzNJbj^) zqW^wUkaLsZ1XhYt$T_3+@;*{1qFpXn$Wfo}N5De{^*j>9FSMt(>v5tR-hv}CxM3Z*drG0H#XE+DY4!xnY1x6rCH1@Dc!3gkqL>eUoYsk`MRAZ3wQ^?d zt$!GC0?ENbytXLwWg~08$MoWlaf`9dBdxRG^RAumZq@6~sv!%b59JqBv7ejWHluzrA#j6fa z+|xV{7plZo8FXl7!YUeg1-#v@DzOvd%3Wd(d0K;N>RfnxrK5&Qt+QrkJ}>>dWzr~7 z!>-jD5d{t9Axk?Sa(Df@tlgaJa1Esrr<32FYCy z2l_R3@#k9#tGVJaU98J-WwI88`Pn3j(%ShExc6#Ru7v5NG0;&Y;w?4>D;LzLc#cCeuSJ ze9T-?I%~$<+CDk|@>4YU;7Q$CdrP}W;&p_>h*D1i zTK^ICER#^yARPMm(9xNj*4{)bJPsB9sgMfcP!2Mz(O1UyJf?p!-QlW=Ko~7Hsj2v4*rn5gDdPVng{Q`$J7WpT^ zCj7mxtlm_oK^K1EF88zR+Cmxf2W4lbko!Xxd@4kNsQ*J>uMzVT7X0C4Kd;mY~i>yuJeU7}FaAvkx zW0Q6YqO1C&PPBzvVbhJX_RP$q9;naX5?vjb(&%~5M9^=E?@P)DYj=$~le`K;%=F(sj9qXTkEO^#&#>;F~x|bP;XPAY;HX?TMu85x@$XL*nw??? zT%0}Q$^_!fRFAU9@E8aroCOphJFn;zt&lgacXu60g_KK*XYA>EwRCD_J*@Dnh@m5B z%&TdVy6u6hH$R`Ciy58?q0uu@{K%II7GGTID!dN-Dh`oj)mi~Amz{3GtzpAUG+Ic| z({o#y4QHTZesR1)4CXKi|j9z04(IO)bVH&vQBH;=`A-YyXd$2nId=Li&1=sjM10sK3-ArbIWa_UY z8i(Vu-rrJZ3eL7APdjjXZyu~K6`g;X8}t&g9}{2uYAUHcN-~xSF$m9=1Tvh_Yj9zE zoqv5~b(V6>Sdx1IxNr!4@aqED`FKyVx@#VI)GILlQ|RANh&J^TLXEC2sitasoVK@8 zr!5g1gzx{-O}x0jrBdX5!?FfJs!aN2!`%_Cw8O#?bLbL*GwN~hrug!B*c5!?5M=M0 z5N6#L^1u#jFr|lTuD&e*T$LOf{n3)Dgv~$7LEM2SY+drVPabG#^=GWy+PIa_SFB^2 zP2SRmtfNUknh^uDB@Z`Y6Zt2DZ1TY9#4@RpWX;9UI8g>I_qR@)q zZbaqt#@#*q?d$-#6I6%ljenB*w7%P^RMJ=vuB82zpISbU(r~}sL7JU@5eRyzyzQ!( z-)4FT!zd-4l-eHuM%ef~LYkvqd8@a&KOBL1;H-hN+o%A@v3GVlm)Y0){~OfUvpdc> z-zc8avNGV@)}V^I#Y_>XRv;?pSV9KG&xJ>4DM<6%MFFg8i)+Cq*A-d#$p<2@UlN9% z-#=74l}I_}l9f9D>G1Pj-AuZAk%r;EY+4%ps9McoK|XUJB&^iAC_7r{ecZAx07ihlFOw0?o2;m3tY)h7RfS+%I(yEX;Ju(5`^LdS_!TEJSA3$K5zip) zp!3)-ec2&c-#Zz>&WB@R#hrCdwc$zb0!Aa7`1K0YoQ!?>x|sIeC$DPB-y2oytdAp= zGUpqTv*B>hBjq2K&eGh4P#T2(djM1hdA-h&-0co8lr*I?y7s4AKXwIJTzDoHk@6E%X~w=l53Pc?+i3kT=cA4W$w9`cO3cG+FOXw7HQsTn;q@pG^4usNd( zt&%z4S8cuI^O`Fvv91{!sj%S8f1-1C%jCN8sf;)Tc6plAt&=}nKo z+g%|co${8)^8t#3M#Bc2YXyO}c6WW_8i*5*)je$d@N^ojiQroGH)4Chc{3a3+VCr( zR$o@ab?k3u}kP$MNeK9bfS zO4wd;9@qbgA<}MLD58lGWr}-z=tm}99})FPS6RtV+Ew|bS^JeJm525xVuvSQ(2WM- zd{+WjZhCB0^jxqv(?G!_>JLIfTs3w_3CQPNrNdR87SuOSSad|8(I(lFiCEP!_R4Iq zsCc5ml!ux3ROMcax;u_jWCE+ljch2UmGmOoPYsFxLqt6O;Fk#*F&8hk>Y2JnPTq7G-(gsB+kj>eSXc0&WxGb9dY+!hLD!eq}wupI;wzQy-tE5}om__p%YS+YAT@lvr$LSI~aC zxLc6WK*}(Jv9XUkgukD-3cHl z=ntwMQvO1O5X^->Hc_N1#0i43w&P10@WUqFKUxyE1^M8vS1{>76h;33L=VD+0ls!= z^vHK7PS&|Vs_wMlFuYPSB&>U!nvh+9x~M;q6`mm_t7z@*Y^6%cJM zQO_T=+O(2m7WaGUvGmyLYwE|obx-A9Sx4(~$ zeE?H^FkniUwcBWeuuM$X>}fzv`<4-C+P*bNsYwnn1?oK@Ao5aWB+r{`z=mf93&KMr zw29N`-<0i`CQZu}dzJB<>Uy?il^t`<{$^SFmFF9=zA~Bfa)YC)VGr`X&?EYi{YpcP zH8N>(gA@!yueF$K-!!`jU_VK!5MF4N#LH=Q&&=inq2ep3;G&AEs5co*u{X!)p>4yR zhE%^9V@h4G++en3gT}){<7Z*8123!XbFlg1)AsSCh=&w|LQjOp_UOec6`0VkB}ySp zHunzIkvdtg8lG?%26eggDAogxT9=U8y9aGMU1>KvVeHgEI$neN{bo(kA+Oj{nxWAY zpP2p&MCiHg9q`Fj)r6FyHsO>Db^xk{{J-nmjTPa3EooYdBO~j?zv~TH4z_hpEa}w# zHtU%zllfYLR0EFi%{k3ar_;*>@Gr8aH|^&{J7Pp$YUO`eMC(UQ5hsM*)0cc)d5W~u zqE^dQKmT$~)*6}ylEuNsNfScbY0(anvgls{%JTS;|0q)b5#IjK3XorWFbch9R|Xr& z2w38mU<%`a_YKh>KtIHGVie%fli)sy)Am{SabfsYjbi|%n>jBkll89FkFcF6wzKOH zU)q-hhu?|QT1K2iu9+Gk=Yi3Gb%KRZXFFWjDR%T6pV3Ix`Qd8vUZgIE;VbYY2E&BC zl)s-Xc@KH%qYHP!)@{qKD!D;KtscfKd%^T_v`sg)(sz$?Z+4xt#uZR?TK%QbI7F?= zu*fT$yV z3@kCll`A=r-g55XOsHRE1&~*Uk%p(9y8|UPmGPwaC68jp!)x`#s4(X&p2s`gff}^~ zpDZ2mb3w0UOLklTCL;U1#o_XLll;crZpBGY(XVF2OKh;?(Is}E+zT5^H!=!KDEAug zj;;kNzKQ)504=!AL-w6&Rg-rLSJ{v2$rtsnTr`tC>I;SLy%1XQ$J39sn&u8STW$M! zqUNn{U;_{ehcC)}_JmB9h0%YqZKFzH(cjD3zg-Ek=0mer!?Tn7VO(l|mOS&blb*n< zqkwtAiaH`mg5y|r!yxTqAOk1}-Vx!U6VuAR>BnT-@KUYF1KOkKZlZH3nBhXGQvgiB z`Cjh@Jqw#E>TPswL3)nihAWodJjEt`m1``^OiPr4sD;C0($e%<$%PBL57(;u06r<> z8qrk+|C6!skDzX0_8rvb8);)qBPCROz|M?#Et1*SoNx8Ud&)yvr{V5~xOWmS>dG8# zEKGij&m*Y5fz~L-x$xf0nV6cI4&IpCd@Vcp%#|g_q_~y8fGpeY^eeix0caPO1qER^y5w8sa9cKt>V?F z1?B*hS~3{OZ!}^P&>U^WK90TpK&$wv)XOo$h4XP+EBe>^`W`)t)hw2f@~n(`Jgt@Q z+MnuW<8>}6o<|j7;Bcr}>Ql86asJwQl5K>|oA(!Ao++IE`;rDiCjsUIjU5ZwHLb81 zPOUt++>@GgZOmJjA6QLAz{7ZZ(AX_EEy5jMxxg7cZI3V^5?MxAYz5;z!|AJFqx}vx zv+!h}pp{?F6((I+v#FS4#i5fw1#w-$;9KPf??rp)wYtr|S@X@71o(k4XXv9EB}9ySsf`2eYXma7HY z>^WRiBlnZ6cWK>j?#s2TtGbUm_7)4{q!7X4Nf|&x|R$G zdJu!bMxci5a={QovL&y*tg2+`xlsAMjvAy{(EJGcbsMs)n^q>1_Dl?jws@*?XJeU6_Zp%WS3NmSq(ub@U^jEX zh0I-2=n3SH8OMI5P^pK4J)^4rP^nChn4LZ?mpVJ|dNED_A{L1wl|t$EHcvG(&({h2 z+;r>uBsaJaNr%KgE}-oefeVXdp}fPB4@-p=!rgdI0tE~u%2^@50h*tqX@PxtPRs%u zcLWfbue)_=<^askkSI`OPOOJ^xxgxva~hj4?VW(Mvm4ur92_{EV{3Q{D9_rR%-=`H z!3h zhA4-jo7H%%2p~13p1mn$ic~5RIir|rynWt#?}fsdSxh?u-NAGOoo*rqe*eJerRE;d@PGq!qtX zByOQR)!OAv`sZ}Q*6$(lu4Z@(e#QKeZW_ew$B^|0(>`P1g>CY$3_hV8z<>l;>1NG0 zFfaw=rsj>m;9)HbDDSMEu^WmNjl4UP|efAFwec{_ZJ0_5h;Rve?jG6Y01m7 WMf+JCmw-k;7E>e3TeUabp8Y>hhU?b= diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_0_1/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_1to2_2_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..7491845317a2c765f8785ebe447bd567ddb92087 GIT binary patch literal 14492 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 A4gdfE literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_0/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_0/00000.png index 46daae63d5984a6c8f82a0979e9ce9569a9a296a..9c787171418c01c3841788905a02d133e49e41e2 100644 GIT binary patch literal 11036 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 U<9G+?dSw9{S=^|;=KSn`0Z?_bBme*a literal 10255 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 WMf+JCmw-k;7E>e3TeUabp8Y>hhU?b= diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_1/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_1/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..1ee945030dd2b42a33771fce1c3f99caa0b028fb GIT binary patch literal 20010 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_3/00000.png b/tests/snapshots/stax/test_sign_psbt_singlesig_wpkh_2to2_0_3/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..066a141c36cf945611b85bd89d55612e677a6a54 GIT binary patch literal 11581 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 A4gdfE literal 0 HcmV?d00001 From b5ffad8a67b339d01408c687e6e23ce9e7c186ae Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Tue, 30 Apr 2024 15:18:25 +0200 Subject: [PATCH 81/85] Makefile: remove unused COIN_COINID_HEADER field --- Makefile | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/Makefile b/Makefile index 5e3b4a21..dca95310 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,6 @@ COIN_P2PKH_VERSION=111 COIN_P2SH_VERSION=196 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" -COIN_COINID_HEADER=\"BITCOIN\" COIN_COINID_NAME="Bitcoin Test" COIN_COINID_SHORT=\"TEST\" COIN_NATIVE_SEGWIT_PREFIX=\"tb\" @@ -64,7 +63,6 @@ COIN_P2PKH_VERSION=0 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" -COIN_COINID_HEADER=\"BITCOIN\" COIN_COINID_NAME="Bitcoin" COIN_COINID_SHORT=\"BTC\" COIN_NATIVE_SEGWIT_PREFIX=\"bc\" @@ -81,7 +79,6 @@ COIN_P2PKH_VERSION=0 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\" -COIN_COINID_HEADER=\"BITCOINCASH\" COIN_COINID_NAME="Bitcoin Cash" COIN_COINID_SHORT=\"BCH\" COIN_KIND=COIN_KIND_BITCOIN_CASH @@ -97,7 +94,6 @@ COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=23 COIN_FAMILY=1 COIN_COINID=\"Bitcoin\\x20Gold\" -COIN_COINID_HEADER=\"BITCOINGOLD\" COIN_COINID_NAME="Bitcoin Gold" COIN_COINID_SHORT=\"BTG\" COIN_KIND=COIN_KIND_BITCOIN_GOLD @@ -113,7 +109,6 @@ COIN_P2PKH_VERSION=48 COIN_P2SH_VERSION=50 COIN_FAMILY=1 COIN_COINID=\"Litecoin\" -COIN_COINID_HEADER=\"LITECOIN\" COIN_COINID_NAME="Litecoin" COIN_COINID_SHORT=\"LTC\" COIN_NATIVE_SEGWIT_PREFIX=\"ltc\" @@ -129,7 +124,6 @@ COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=22 COIN_FAMILY=1 COIN_COINID=\"Dogecoin\" -COIN_COINID_HEADER=\"DOGECOIN\" COIN_COINID_NAME="Doge" COIN_COINID_SHORT=\"DOGE\" COIN_KIND=COIN_KIND_DOGE @@ -143,7 +137,6 @@ COIN_P2PKH_VERSION=76 COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"DarkCoin\" -COIN_COINID_HEADER=\"DASH\" COIN_COINID_NAME="Dash" COIN_COINID_SHORT=\"DASH\" COIN_KIND=COIN_KIND_DASH @@ -158,7 +151,6 @@ COIN_P2PKH_VERSION=7352 COIN_P2SH_VERSION=7357 COIN_FAMILY=1 COIN_COINID=\"Zcash\" -COIN_COINID_HEADER=\"ZCASH\" COIN_COINID_NAME="Zcash" COIN_COINID_SHORT=\"ZEC\" COIN_KIND=COIN_KIND_ZCASH @@ -174,7 +166,6 @@ COIN_P2PKH_VERSION=8329 COIN_P2SH_VERSION=8342 COIN_FAMILY=4 COIN_COINID=\"Horizen\" -COIN_COINID_HEADER=\"HORIZEN\" COIN_COINID_NAME="Horizen" COIN_COINID_SHORT=\"ZEN\" COIN_KIND=COIN_KIND_HORIZEN @@ -188,7 +179,6 @@ COIN_P2PKH_VERSION=60 COIN_P2SH_VERSION=85 COIN_FAMILY=1 COIN_COINID=\"Komodo\" -COIN_COINID_HEADER=\"KOMODO\" COIN_COINID_NAME="Komodo" COIN_COINID_SHORT=\"KMD\" COIN_KIND=COIN_KIND_KOMODO @@ -202,7 +192,6 @@ COIN_P2PKH_VERSION=75 COIN_P2SH_VERSION=140 COIN_FAMILY=2 COIN_COINID=\"Stratis\" -COIN_COINID_HEADER=\"STRATIS\" COIN_COINID_NAME="Stratis" COIN_COINID_SHORT=\"STRAX\" COIN_KIND=COIN_KIND_STRATIS @@ -217,7 +206,6 @@ COIN_P2PKH_VERSION=61 COIN_P2SH_VERSION=123 COIN_FAMILY=1 COIN_COINID=\"xrhodium\" -COIN_COINID_HEADER=\"XRHODIUM\" COIN_COINID_NAME="xRhodium" COIN_COINID_SHORT=\"XRC\" COIN_KIND=COIN_KIND_XRHODIUM @@ -231,7 +219,6 @@ COIN_P2PKH_VERSION=55 COIN_P2SH_VERSION=117 COIN_FAMILY=2 COIN_COINID=\"PPCoin\" -COIN_COINID_HEADER=\"PEERCOIN\" COIN_COINID_NAME="Peercoin" COIN_COINID_SHORT=\"PPC\" COIN_KIND=COIN_KIND_PEERCOIN @@ -247,7 +234,6 @@ COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=13 COIN_FAMILY=1 COIN_COINID=\"DarkNet\" -COIN_COINID_HEADER=\"PIVX\" COIN_COINID_NAME="PivX" COIN_COINID_SHORT=\"PIVX\" COIN_KIND=COIN_KIND_PIVX @@ -261,7 +247,6 @@ COIN_P2PKH_VERSION=62 COIN_P2SH_VERSION=85 COIN_FAMILY=4 COIN_COINID=\"Stealth\" -COIN_COINID_HEADER=\"STEALTH\" COIN_COINID_NAME="Stealth" COIN_COINID_SHORT=\"XST\" COIN_KIND=COIN_KIND_STEALTH @@ -276,7 +261,6 @@ COIN_P2PKH_VERSION=71 COIN_P2SH_VERSION=33 COIN_FAMILY=1 COIN_COINID=\"Viacoin\" -COIN_COINID_HEADER=\"VIACOIN\" COIN_COINID_NAME="Viacoin" COIN_COINID_SHORT=\"VIA\" COIN_KIND=COIN_KIND_VIACOIN @@ -292,7 +276,6 @@ COIN_P2PKH_VERSION=71 COIN_P2SH_VERSION=5 COIN_FAMILY=1 COIN_COINID=\"Vertcoin\" -COIN_COINID_HEADER=\"VERTCOIN\" COIN_COINID_NAME="Vertcoin" COIN_COINID_SHORT=\"VTC\" COIN_NATIVE_SEGWIT_PREFIX=\"vtc\" @@ -307,7 +290,6 @@ COIN_P2PKH_VERSION=30 COIN_P2SH_VERSION=63 COIN_FAMILY=1 COIN_COINID=\"DigiByte\" -COIN_COINID_HEADER=\"DIGIBYTE\" COIN_COINID_NAME="Digibyte" COIN_COINID_SHORT=\"DGB\" COIN_NATIVE_SEGWIT_PREFIX=\"dgb\" @@ -324,7 +306,6 @@ COIN_P2PKH_VERSION=82 COIN_P2SH_VERSION=7 COIN_FAMILY=1 COIN_COINID=\"Zcoin\" -COIN_COINID_HEADER=\"FIRO\" COIN_COINID_NAME="Firo" COIN_COINID_SHORT=\"FIRO\" COIN_KIND=COIN_KIND_FIRO @@ -340,7 +321,6 @@ COIN_P2PKH_VERSION=4901 COIN_P2SH_VERSION=5039 COIN_FAMILY=1 COIN_COINID=\"BPrivate\" -COIN_COINID_HEADER=\"BITCOINPRIVATE\" COIN_COINID_NAME="Bitcoin Private" COIN_COINID_SHORT=\"BTCP\" COIN_KIND=COIN_KIND_BITCOIN_PRIVATE @@ -355,7 +335,6 @@ COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=62 COIN_FAMILY=1 COIN_COINID=\"GameCredits\" -COIN_COINID_HEADER=\"GAMECREDITS\" COIN_COINID_NAME="GameCredits" COIN_COINID_SHORT=\"GAME\" COIN_KIND=COIN_KIND_GAMECREDITS @@ -370,7 +349,6 @@ COIN_P2PKH_VERSION=7352 COIN_P2SH_VERSION=7357 COIN_FAMILY=1 COIN_COINID=\"ZClassic\" -COIN_COINID_HEADER=\"ZCLASSIC\" COIN_COINID_NAME="ZClassic" COIN_COINID_SHORT=\"ZCL\" COIN_KIND=COIN_KIND_ZCLASSIC @@ -384,7 +362,6 @@ COIN_P2PKH_VERSION=76 COIN_P2SH_VERSION=16 COIN_FAMILY=1 COIN_COINID=\"XSN\" -COIN_COINID_HEADER=\"XSN\" COIN_COINID_NAME="XSN" COIN_COINID_SHORT=\"XSN\" COIN_NATIVE_SEGWIT_PREFIX=\"xc\" @@ -400,7 +377,6 @@ COIN_P2PKH_VERSION=38 COIN_P2SH_VERSION=53 COIN_FAMILY=1 COIN_COINID=\"NIX\" -COIN_COINID_HEADER=\"NIX\" COIN_COINID_NAME="NIX" COIN_COINID_SHORT=\"NIX\" COIN_NATIVE_SEGWIT_PREFIX=\"nix\" @@ -416,7 +392,6 @@ COIN_P2PKH_VERSION=85 COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"LBRY\" -COIN_COINID_HEADER=\"LBRY\" COIN_COINID_NAME="LBRY" COIN_COINID_SHORT=\"LBC\" COIN_KIND=COIN_KIND_LBRY @@ -430,7 +405,6 @@ COIN_P2PKH_VERSION=7063 COIN_P2SH_VERSION=7068 COIN_FAMILY=1 COIN_COINID=\"Res\" -COIN_COINID_HEADER=\"RES\" COIN_COINID_NAME="Resistance" COIN_COINID_SHORT=\"RES\" COIN_KIND=COIN_KIND_RESISTANCE @@ -444,7 +418,6 @@ COIN_P2PKH_VERSION=60 COIN_P2SH_VERSION=122 COIN_FAMILY=1 COIN_COINID=\"Ravencoin\" -COIN_COINID_HEADER=\"RAVENCOIN\" COIN_COINID_NAME="Ravencoin" COIN_COINID_SHORT=\"RVN\" COIN_KIND=COIN_KIND_RAVENCOIN @@ -458,7 +431,6 @@ COIN_P2PKH_VERSION=66 COIN_P2SH_VERSION=128 COIN_FAMILY=3 COIN_COINID=\"Hydra\" -COIN_COINID_HEADER=\"HYDRA\" COIN_COINID_NAME="Hydra Test" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" @@ -475,7 +447,6 @@ COIN_P2PKH_VERSION=40 COIN_P2SH_VERSION=63 COIN_FAMILY=3 COIN_COINID=\"Hydra\" -COIN_COINID_HEADER=\"HYDRA\" COIN_COINID_NAME="Hydra" COIN_COINID_SHORT=\"HYDRA\" COIN_NATIVE_SEGWIT_PREFIX=\"hc\" From 5dfab583c15304bfd4b0f80d7e1faa28310588eb Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 2 May 2024 11:48:07 +0200 Subject: [PATCH 82/85] lib-app-bitcoin: replace with submodule --- .gitmodules | 3 + lib-app-bitcoin | 1 + lib-app-bitcoin/Makefile | 147 --- lib-app-bitcoin/apdu/apdu_constants.h | 63 -- lib-app-bitcoin/apdu/dispatcher.c | 117 --- lib-app-bitcoin/apdu/dispatcher.h | 14 - lib-app-bitcoin/app_main.c | 66 -- lib-app-bitcoin/context.c | 36 - lib-app-bitcoin/context.h | 253 ----- lib-app-bitcoin/customizable_helpers.c | 235 ----- lib-app-bitcoin/customizable_helpers.h | 28 - lib-app-bitcoin/customizable_ui.c | 136 --- lib-app-bitcoin/customizable_ui.h | 24 - lib-app-bitcoin/display_utils.c | 138 --- lib-app-bitcoin/display_utils.h | 26 - lib-app-bitcoin/display_variables.c | 3 - lib-app-bitcoin/filesystem.h | 40 - lib-app-bitcoin/filesystem_tx.h | 43 - lib-app-bitcoin/handler/get_coin_version.c | 57 -- .../handler/get_firmware_version.c | 58 -- lib-app-bitcoin/handler/get_trusted_input.c | 105 --- .../handler/get_wallet_public_key.c | 206 ---- .../handler/hash_input_finalize_full.c | 619 ------------ lib-app-bitcoin/handler/hash_input_start.c | 143 --- lib-app-bitcoin/handler/hash_sign.c | 208 ---- lib-app-bitcoin/handler/sign_message.c | 284 ------ lib-app-bitcoin/helpers.c | 234 ----- lib-app-bitcoin/helpers.h | 61 -- lib-app-bitcoin/swap/handle_check_address.c | 139 --- lib-app-bitcoin/swap/handle_check_address.h | 9 - .../swap/handle_get_printable_amount.c | 23 - .../swap/handle_get_printable_amount.h | 10 - .../swap/handle_swap_sign_transaction.c | 77 -- .../swap/handle_swap_sign_transaction.h | 12 - lib-app-bitcoin/transaction.c | 890 ------------------ lib-app-bitcoin/transaction.h | 31 - lib-app-bitcoin/ui/display_variables.h | 41 - lib-app-bitcoin/ui/extensions.h | 54 -- lib-app-bitcoin/ui/main_ui.c | 301 ------ lib-app-bitcoin/ui/ui.h | 18 - lib-app-bitcoin/ui/ui_bagl.c | 437 --------- lib-app-bitcoin/ui/ui_menu_nbgl.c | 43 - lib-app-bitcoin/ui/ui_nbgl.c | 330 ------- lib-app-bitcoin/utils/be_operations.c | 38 - lib-app-bitcoin/utils/be_operations.h | 26 - lib-app-bitcoin/utils/cashaddr.c | 152 --- lib-app-bitcoin/utils/cashaddr.h | 49 - lib-app-bitcoin/utils/segwit_addr.c | 204 ---- lib-app-bitcoin/utils/segwit_addr.h | 84 -- 49 files changed, 4 insertions(+), 6312 deletions(-) create mode 100644 .gitmodules create mode 160000 lib-app-bitcoin delete mode 100644 lib-app-bitcoin/Makefile delete mode 100644 lib-app-bitcoin/apdu/apdu_constants.h delete mode 100644 lib-app-bitcoin/apdu/dispatcher.c delete mode 100644 lib-app-bitcoin/apdu/dispatcher.h delete mode 100644 lib-app-bitcoin/app_main.c delete mode 100644 lib-app-bitcoin/context.c delete mode 100644 lib-app-bitcoin/context.h delete mode 100644 lib-app-bitcoin/customizable_helpers.c delete mode 100644 lib-app-bitcoin/customizable_helpers.h delete mode 100644 lib-app-bitcoin/customizable_ui.c delete mode 100644 lib-app-bitcoin/customizable_ui.h delete mode 100644 lib-app-bitcoin/display_utils.c delete mode 100644 lib-app-bitcoin/display_utils.h delete mode 100644 lib-app-bitcoin/display_variables.c delete mode 100644 lib-app-bitcoin/filesystem.h delete mode 100644 lib-app-bitcoin/filesystem_tx.h delete mode 100644 lib-app-bitcoin/handler/get_coin_version.c delete mode 100644 lib-app-bitcoin/handler/get_firmware_version.c delete mode 100644 lib-app-bitcoin/handler/get_trusted_input.c delete mode 100644 lib-app-bitcoin/handler/get_wallet_public_key.c delete mode 100644 lib-app-bitcoin/handler/hash_input_finalize_full.c delete mode 100644 lib-app-bitcoin/handler/hash_input_start.c delete mode 100644 lib-app-bitcoin/handler/hash_sign.c delete mode 100644 lib-app-bitcoin/handler/sign_message.c delete mode 100644 lib-app-bitcoin/helpers.c delete mode 100644 lib-app-bitcoin/helpers.h delete mode 100644 lib-app-bitcoin/swap/handle_check_address.c delete mode 100644 lib-app-bitcoin/swap/handle_check_address.h delete mode 100644 lib-app-bitcoin/swap/handle_get_printable_amount.c delete mode 100644 lib-app-bitcoin/swap/handle_get_printable_amount.h delete mode 100644 lib-app-bitcoin/swap/handle_swap_sign_transaction.c delete mode 100644 lib-app-bitcoin/swap/handle_swap_sign_transaction.h delete mode 100644 lib-app-bitcoin/transaction.c delete mode 100644 lib-app-bitcoin/transaction.h delete mode 100644 lib-app-bitcoin/ui/display_variables.h delete mode 100644 lib-app-bitcoin/ui/extensions.h delete mode 100644 lib-app-bitcoin/ui/main_ui.c delete mode 100644 lib-app-bitcoin/ui/ui.h delete mode 100644 lib-app-bitcoin/ui/ui_bagl.c delete mode 100644 lib-app-bitcoin/ui/ui_menu_nbgl.c delete mode 100644 lib-app-bitcoin/ui/ui_nbgl.c delete mode 100644 lib-app-bitcoin/utils/be_operations.c delete mode 100644 lib-app-bitcoin/utils/be_operations.h delete mode 100644 lib-app-bitcoin/utils/cashaddr.c delete mode 100644 lib-app-bitcoin/utils/cashaddr.h delete mode 100644 lib-app-bitcoin/utils/segwit_addr.c delete mode 100644 lib-app-bitcoin/utils/segwit_addr.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..d09ce724 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib-app-bitcoin"] + path = lib-app-bitcoin + url = git@github.com:LedgerHQ/lib-app-bitcoin.git diff --git a/lib-app-bitcoin b/lib-app-bitcoin new file mode 160000 index 00000000..824df017 --- /dev/null +++ b/lib-app-bitcoin @@ -0,0 +1 @@ +Subproject commit 824df01726df459b1fd527f96a8ddd4558017fea diff --git a/lib-app-bitcoin/Makefile b/lib-app-bitcoin/Makefile deleted file mode 100644 index b409ac96..00000000 --- a/lib-app-bitcoin/Makefile +++ /dev/null @@ -1,147 +0,0 @@ -# **************************************************************************** -# Ledger App Bitcoin -# (c) 2023 Ledger SAS. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# **************************************************************************** - -ifeq ($(BOLOS_SDK),) -$(error Environment variable BOLOS_SDK is not set) -endif -include $(BOLOS_SDK)/Makefile.defines - -######################################## -# Mandatory configuration # -######################################## -# Name is defined later - -ifeq ($(APPVERSION_M),) -$(error APPVERSION_M must be defined) -endif -ifeq ($(APPVERSION_N),) -$(error APPVERSION_N must be defined) -endif -ifeq ($(APPVERSION_P),) -$(error APPVERSION_P must be defined) -endif - -APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" - -APP_SOURCE_PATH += lib-app-bitcoin/ - -ICON_NANOS = icons/nanos_app_$(COIN).gif -ICON_NANOX = icons/nanox_app_$(COIN).gif -ICON_NANOSP = icons/nanox_app_$(COIN).gif -ICON_STAX = icons/stax_app_$(COIN).gif -# Temporary reuse of stax icons while waiting for flex icons -ICON_FLEX = icons/stax_app_$(COIN).gif - -ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_STAX TARGET_FLEX)) -DEFINES += COIN_ICON=C_$(COIN)_64px -DEFINES += COIN_ICON_BITMAP=C_$(COIN)_64px_bitmap -endif - -# Application allowed derivation curves. -CURVE_APP_LOAD_PARAMS ?= secp256k1 - -# Application allowed derivation paths. -# Currently there is no path restriction -PATH_APP_LOAD_PARAMS ?= "" - -HAVE_APPLICATION_FLAG_DERIVE_MASTER = 1 -HAVE_APPLICATION_FLAG_LIBRARY = 1 - -VARIANT_PARAM = COIN - -ENABLE_BLUETOOTH = 1 -ENABLE_NBGL_QRCODE = 1 -ENABLE_SWAP = 1 - -ifndef BIP44_COIN_TYPE -$(error BIP44_COIN_TYPE must be defined) -endif - -ifndef BIP44_COIN_TYPE_2 -$(error BIP44_COIN_TYPE_2 must be defined) -endif - -ifndef COIN_P2PKH_VERSION -$(error COIN_P2PKH_VERSION must be defined) -endif - -ifndef COIN_P2SH_VERSION -$(error COIN_P2SH_VERSION must be defined) -endif - -ifndef COIN_FAMILY -$(error COIN_FAMILY must be defined) -endif - -ifndef COIN_COINID -$(error COIN_COINID must be defined) -endif - -ifndef COIN_COINID_HEADER -$(error COIN_COINID_HEADER must be defined) -endif - -ifndef COIN_COINID_NAME -$(error COIN_COINID_NAME must be defined) -endif - -ifndef COIN_COINID_SHORT -$(error COIN_COINID_SHORT must be defined) -endif - -ifndef COIN_NATIVE_SEGWIT_PREFIX -$(info COIN_NATIVE_SEGWIT_PREFIX automatically set to 0) -COIN_NATIVE_SEGWIT_PREFIX=0 -endif - -ifndef COIN_KIND -$(error COIN_KIND must be defined) -endif - -ifndef COIN_FLAGS -$(info COIN_FLAGS automatically set to 0) -COIN_FLAGS=0 -endif - -ifndef COIN_FORKID -$(info COIN_FORKID automatically set to 0) -COIN_FORKID=0 -endif - -ifeq ($(APPNAME),) -$(error APPNAME must be defined) -endif - -DEFINES +=BIP44_COIN_TYPE=$(BIP44_COIN_TYPE) -DEFINES +=BIP44_COIN_TYPE_2=$(BIP44_COIN_TYPE_2) -DEFINES +=COIN_P2PKH_VERSION=$(COIN_P2PKH_VERSION) -DEFINES +=COIN_P2SH_VERSION=$(COIN_P2SH_VERSION) -DEFINES +=COIN_FAMILY=$(COIN_FAMILY) -DEFINES +=COIN_COINID=$(COIN_COINID) -DEFINES +=COIN_COINID_HEADER=$(COIN_COINID_HEADER) -DEFINES +=COIN_COINID_SHORT=$(COIN_COINID_SHORT) -DEFINES +=COIN_NATIVE_SEGWIT_PREFIX=$(COIN_NATIVE_SEGWIT_PREFIX) -DEFINES +=COIN_KIND=$(COIN_KIND) -DEFINES +=COIN_FLAGS=$(COIN_FLAGS) -DEFINES +=COIN_FORKID=$(COIN_FORKID) - -# Following defines exposed to the app as a CFLAG because it might contain spaces -CFLAGS += -DCOIN_COINID_NAME=\"$(COIN_COINID_NAME)\" -CFLAGS += -DAPPDEVELOPPER=\"$(APPDEVELOPPER)\" -CFLAGS += -DAPPCOPYRIGHT=\"$(APPCOPYRIGHT)\" - -include $(BOLOS_SDK)/Makefile.standard_app diff --git a/lib-app-bitcoin/apdu/apdu_constants.h b/lib-app-bitcoin/apdu/apdu_constants.h deleted file mode 100644 index ce412089..00000000 --- a/lib-app-bitcoin/apdu/apdu_constants.h +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ -#pragma once - -#include "buffer.h" -#include "macros.h" -#include "os.h" - -#define CLA 0xE0 - -#define INS_GET_WALLET_PUBLIC_KEY 0x40 -#define INS_GET_TRUSTED_INPUT 0x42 -#define INS_HASH_INPUT_START 0x44 -#define INS_HASH_SIGN 0x48 -#define INS_HASH_INPUT_FINALIZE_FULL 0x4A -#define INS_SIGN_MESSAGE 0x4E -#define INS_GET_FIRMWARE_VERSION 0xC4 -#define INS_GET_COIN_VER 0x16 - -#define SW_INCORRECT_LENGTH 0x6700 -#define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 -#define SW_CONDITIONS_OF_USE_NOT_SATISFIED 0x6985 -#define SW_INCORRECT_DATA 0x6A80 -#define SW_SWAP_WITHOUT_TRUSTED_INPUTS 0x6A8A -#define SW_INCORRECT_P1_P2 0x6B00 -#define SW_INS_NOT_SUPPORTED 0x6D00 -#define SW_CLA_NOT_SUPPORTED 0x6E00 -#define SW_TECHNICAL_PROBLEM 0x6F00 -#define SW_TECHNICAL_PROBLEM_2 0x6F0F -#define SW_OK 0x9000 - -#define BITID_DERIVE 0xB11D -#define BITID_DERIVE_MULTIPLE 0xB11E - -#define ZCASH_USING_OVERWINTER 0x01 -#define ZCASH_USING_OVERWINTER_SAPLING 0x02 - -unsigned short handler_sign_message(buffer_t *buffer, uint8_t p1, uint8_t p2); -unsigned short handler_hash_sign(buffer_t *buffer, uint8_t p1, uint8_t p2); -unsigned short handler_hash_input_start(buffer_t *buffer, uint8_t p1, - uint8_t p2); -unsigned short handler_hash_input_finalize_full(buffer_t *buffer, uint8_t p1, - uint8_t p2); -unsigned short handler_get_wallet_public_key(buffer_t *buffer, uint8_t p1, - uint8_t p2); -unsigned short handler_get_trusted_input(buffer_t *buffer, uint8_t p1, - uint8_t p2); -unsigned short handler_get_firmware_version(void); -unsigned short handler_get_coin_version(void); diff --git a/lib-app-bitcoin/apdu/dispatcher.c b/lib-app-bitcoin/apdu/dispatcher.c deleted file mode 100644 index 1c44fae9..00000000 --- a/lib-app-bitcoin/apdu/dispatcher.c +++ /dev/null @@ -1,117 +0,0 @@ -/***************************************************************************** - * Ledger App Boilerplate. - * (c) 2020 Ledger SAS. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *****************************************************************************/ - -#include -#include - -#include "buffer.h" -#include "io.h" -#include "ledger_assert.h" - -#include "apdu_constants.h" -#include "dispatcher.h" - -int apdu_dispatcher(const command_t *cmd) { - LEDGER_ASSERT(cmd != NULL, "NULL cmd"); - - if (cmd->cla != CLA) { - return io_send_sw(SW_CLA_NOT_SUPPORTED); - } - - buffer_t buf = {0}; - - switch (cmd->ins) { - case INS_GET_WALLET_PUBLIC_KEY: - PRINTF("Get wallet public key\n"); - if (!cmd->data) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - buf.ptr = cmd->data; - buf.size = cmd->lc; - buf.offset = 0; - return handler_get_wallet_public_key(&buf, cmd->p1, cmd->p2); - - case INS_GET_TRUSTED_INPUT: - PRINTF("Get trusted input\n"); - if (!cmd->data) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - - buf.ptr = cmd->data; - buf.size = cmd->lc; - buf.offset = 0; - return handler_get_trusted_input(&buf, cmd->p1, cmd->p2); - - case INS_HASH_INPUT_START: - PRINTF("Hash input start\n"); - if (!cmd->data) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - - buf.ptr = cmd->data; - buf.size = cmd->lc; - buf.offset = 0; - return handler_hash_input_start(&buf, cmd->p1, cmd->p2); - - case INS_HASH_SIGN: - PRINTF("Hash sign\n"); - if (!cmd->data) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - - buf.ptr = cmd->data; - buf.size = cmd->lc; - buf.offset = 0; - return handler_hash_sign(&buf, cmd->p1, cmd->p2); - - case INS_HASH_INPUT_FINALIZE_FULL: - PRINTF("Hash input finalize full\n"); - if (!cmd->data) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - - buf.ptr = cmd->data; - buf.size = cmd->lc; - buf.offset = 0; - return handler_hash_input_finalize_full(&buf, cmd->p1, cmd->p2); - - case INS_SIGN_MESSAGE: - PRINTF("Sign message\n"); - if (!cmd->data) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - - buf.ptr = cmd->data; - buf.size = cmd->lc; - buf.offset = 0; - return handler_sign_message(&buf, cmd->p1, cmd->p2); - - case INS_GET_FIRMWARE_VERSION: - PRINTF("Get firmware version\n"); - - return handler_get_firmware_version(); - - case INS_GET_COIN_VER: - PRINTF("Get coin version\n"); - - return handler_get_coin_version(); - - default: - PRINTF("Instruction not supported\n"); - return io_send_sw(SW_INS_NOT_SUPPORTED); - } -} diff --git a/lib-app-bitcoin/apdu/dispatcher.h b/lib-app-bitcoin/apdu/dispatcher.h deleted file mode 100644 index 36e1f60c..00000000 --- a/lib-app-bitcoin/apdu/dispatcher.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "parser.h" - -/** - * Dispatch APDU command received to the right handler. - * - * @param[in] cmd - * Structured APDU command (CLA, INS, P1, P2, Lc, Command data). - * - * @return zero or positive integer if success, negative integer otherwise. - * - */ -int apdu_dispatcher(const command_t *cmd); diff --git a/lib-app-bitcoin/app_main.c b/lib-app-bitcoin/app_main.c deleted file mode 100644 index 9c32e633..00000000 --- a/lib-app-bitcoin/app_main.c +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ -#include "io.h" -#include "swap.h" - -#include "apdu_constants.h" -#include "context.h" -#include "dispatcher.h" -#include "ui.h" - -void app_main(void) { - // Structured APDU command - command_t cmd; - - io_init(); - - if (!G_called_from_swap) { - ui_idle_flow(); - } - - context_init(); - - for (;;) { - // Length of APDU command received in G_io_apdu_buffer - int input_len = 0; - - // Receive command bytes in G_io_apdu_buffer - if ((input_len = io_recv_command()) < 0) { - PRINTF("=> io_recv_command failure\n"); - return; - } - - // Parse APDU command from G_io_apdu_buffer - if (!apdu_parser(&cmd, G_io_apdu_buffer, input_len)) { - PRINTF("=> /!\\ BAD LENGTH: %.*H\n", input_len, G_io_apdu_buffer); - io_send_sw(SW_INCORRECT_LENGTH); - continue; - } - - PRINTF( - "=> CLA=%02X | INS=%02X | P1=%02X | P2=%02X | Lc=%02X | CData=%.*H\n", - cmd.cla, cmd.ins, cmd.p1, cmd.p2, cmd.lc, cmd.lc, cmd.data); - - context.outLength = 0; - - // Dispatch structured APDU command to handler - if (apdu_dispatcher(&cmd) < 0) { - PRINTF("=> apdu_dispatcher failure\n"); - return; - } - } -} diff --git a/lib-app-bitcoin/context.c b/lib-app-bitcoin/context.c deleted file mode 100644 index 1f19b25b..00000000 --- a/lib-app-bitcoin/context.c +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#include "context.h" -#include "filesystem.h" - -context_t context; -storage_t const N_real; - -/** - * Initialize the application context on boot - */ -void context_init() { - PRINTF("Context init\n"); - PRINTF("Backup size %d\n", sizeof(g_nvram_data.bkp)); - memset(&context, 0, sizeof(context)); - context.currentOutputOffset = 0; - context.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; - memset(context.totalOutputAmount, 0, sizeof(context.totalOutputAmount)); - context.changeOutputFound = 0; - context.segwitWarningSeen = 0; -} diff --git a/lib-app-bitcoin/context.h b/lib-app-bitcoin/context.h deleted file mode 100644 index 08978a7a..00000000 --- a/lib-app-bitcoin/context.h +++ /dev/null @@ -1,253 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#pragma once - -#include "cx.h" -#include "filesystem_tx.h" -#include "os.h" -#ifdef HAVE_NBGL -#include "nbgl_types.h" -#endif // HAVE_NBGL - -#define MAX_OUTPUT_TO_CHECK 100 -#define MAX_COIN_ID 13 -#define MAX_SHORT_COIN_ID 5 - -#define MAGIC_TRUSTED_INPUT 0x32 - -/** - * Current state of an untrusted transaction hashing - */ -enum transaction_state_e { - /** No transaction in progress */ - TRANSACTION_NONE = 0x00, - /** Transaction defined, waiting for an input to be hashed */ - TRANSACTION_DEFINED_WAIT_INPUT = 0x01, - /** Transaction defined, input hashing in progress, pending input script - data */ - TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT = 0x02, - /** Transaction defined, input hashing done, pending output hashing for this - input */ - TRANSACTION_INPUT_HASHING_DONE = 0x03, - /** Transaction defined, waiting for an output to be hashed */ - TRANSACTION_DEFINED_WAIT_OUTPUT = 0x04, - /** Transaction defined, output hashing in progress for a complex script, - pending output script data */ - TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT = 0x05, - /** Transaction defined, output hashing done, pending finalization */ - TRANSACTION_OUTPUT_HASHING_DONE = 0x06, - /** Extra data present */ - TRANSACTION_PROCESS_EXTRA = 0x07, - /** Transaction parsed */ - TRANSACTION_PARSED = 0x08, - /** Transaction parsed, ready to prepare for signature after validating the - user outputs */ - TRANSACTION_PRESIGN_READY = 0x09, - /** Transaction fully parsed, ready to be signed */ - TRANSACTION_SIGN_READY = 0x0a, -}; -typedef enum transaction_state_e transaction_state_t; - -enum output_parsing_state_e { - OUTPUT_PARSING_NONE = 0x00, - OUTPUT_PARSING_NUMBER_OUTPUTS = 0x01, - OUTPUT_PARSING_OUTPUT = 0x02, - OUTPUT_FINALIZE_TX = 0x03, - BIP44_CHANGE_PATH_VALIDATION = 0x04 -}; -typedef enum output_parsing_state_e output_parsing_state_t; - -typedef union multi_hash { - cx_sha256_t sha256; - cx_blake2b_t blake2b; -} multi_hash; - -struct segwit_hash_s { - union multi_hash hashPrevouts; -}; -struct segwit_cache_s { - unsigned char hashedPrevouts[32]; - unsigned char hashedSequence[32]; - unsigned char hashedOutputs[32]; -}; - -/** - * Structure defining an operation on a transaction - */ -struct transaction_context_s { - /** Transient over signing components */ - - /** Remaining number of inputs/outputs to process for this transaction */ - unsigned long int transactionRemainingInputsOutputs; - /** Index of the currently processed input/output for this transaction */ - unsigned long int transactionCurrentInputOutput; - /** Remaining script bytes to process for the current input or output */ - unsigned long int scriptRemaining; - - /** Persistent over signing components */ - - /** State of the transaction, type transaction_state_t */ - unsigned char transactionState; - /** Computed sum of transaction inputs or value of the output to convert to - * a trusted input */ - unsigned char transactionAmount[8]; - /** Flag indicating if this transaction has been processed before */ - unsigned char firstSigned; - /** If the transaction is relaxed */ - unsigned char relaxed; - /** If the transaction consumes a P2SH input */ - unsigned char consumeP2SH; -}; -typedef struct transaction_context_s transaction_context_t; - -struct tmp_output_s { - /** Change address if initialized */ - unsigned char changeAddress[20]; - /** Flag set if the change address was initialized */ - unsigned char changeInitialized; - /** Flag set if the change address was checked */ - unsigned char changeChecked; - /** Flag set if the change address can be submitted */ - unsigned char changeAccepted; - /** Flag set if the outputs have been fragmented */ - unsigned char multipleOutput; -}; -typedef struct tmp_output_s tmp_output_t; - -struct context_s { - /** Index of the output to convert into a trusted input in a transaction */ - unsigned long int trustedInputIndex; - /** (Integrity protected) transaction context */ - transaction_context_t transactionContext; - - /** Full transaction hash context */ - union multi_hash transactionHashFull; - /** Authorization transaction hash context */ - cx_sha256_t transactionHashAuthorization; - /** Current hash to perform (TRANSACTION_HASH_) */ - unsigned char transactionHashOption; - - /* Segregated Witness changes */ - - union { - struct segwit_hash_s hash; - struct segwit_cache_s cache; - } segwit; - unsigned char transactionVersion[4]; - unsigned char inputValue[8]; - unsigned char usingSegwit; - unsigned char usingCashAddr; - unsigned char segwitParsedOnce; - /** Prevents display of segwit input warning at each InputHashStart APDU */ - unsigned char segwitWarningSeen; - - /* /Segregated Witness changes */ - - /** Size currently available to the transaction parser */ - unsigned char transactionDataRemaining; - /** Current pointer to the transaction buffer for the transaction parser */ - unsigned char *transactionBufferPointer; - /** Trusted Input index processed */ - unsigned char trustedInputProcessed; - /** Transaction input to catch for a Trusted Input lookup */ - unsigned long int transactionTargetInput; - - /** Length of the incoming command */ - unsigned short inLength; - /** Length of the outgoing command */ - unsigned short outLength; - - /** Status Word of the response */ - unsigned short sw; - - /** Current scratch buffer */ - unsigned char *tmp; - - // was previously in NVRAM - transaction_summary_t transactionSummary; - - unsigned short hashedMessageLength; - - union { - tmp_output_t output; - } tmpCtx; - - unsigned char currentOutput[MAX_OUTPUT_TO_CHECK]; - unsigned short currentOutputOffset; - unsigned int remainingOutputs; - unsigned int totalOutputs; - unsigned int discardSize; - unsigned char outputParsingState; - unsigned char totalOutputAmount[8]; - unsigned char changeOutputFound; - - /* Overwinter */ - unsigned char usingOverwinter; - unsigned char overwinterSignReady; - unsigned char nVersionGroupId[4]; - unsigned char nExpiryHeight[4]; - unsigned char nLockTime[4]; - unsigned char sigHashType[4]; -}; -typedef struct context_s context_t; - -/** - * Structure to configure the bitcoin application for a given altcoin - * - */ -typedef enum coin_flags_e { - FLAG_PEERCOIN_UNITS = 1, - FLAG_PEERCOIN_SUPPORT = 2, - FLAG_SEGWIT_CHANGE_SUPPORT = 4 -} coin_flags_t; - -typedef enum coin_kind_e { - COIN_KIND_BITCOIN_TESTNET, - COIN_KIND_BITCOIN, - COIN_KIND_BITCOIN_CASH, - COIN_KIND_BITCOIN_GOLD, - COIN_KIND_LITECOIN, - COIN_KIND_DOGE, - COIN_KIND_DASH, - COIN_KIND_ZCASH, - COIN_KIND_KOMODO, - COIN_KIND_RFU, - COIN_KIND_STRATIS, - COIN_KIND_PEERCOIN, - COIN_KIND_PIVX, - COIN_KIND_STEALTH, - COIN_KIND_VIACOIN, - COIN_KIND_VERTCOIN, - COIN_KIND_DIGIBYTE, - COIN_KIND_BITCOIN_PRIVATE, - COIN_KIND_XRHODIUM, - COIN_KIND_HORIZEN, - COIN_KIND_GAMECREDITS, - COIN_KIND_FIRO, - COIN_KIND_ZCLASSIC, - COIN_KIND_XSN, - COIN_KIND_NIX, - COIN_KIND_LBRY, - COIN_KIND_RESISTANCE, - COIN_KIND_RAVENCOIN, - COIN_KIND_HYDRA -} coin_kind_t; - -void context_init(void); - -extern context_t context; diff --git a/lib-app-bitcoin/customizable_helpers.c b/lib-app-bitcoin/customizable_helpers.c deleted file mode 100644 index d1f0e387..00000000 --- a/lib-app-bitcoin/customizable_helpers.c +++ /dev/null @@ -1,235 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ -#include "macros.h" - -#include "context.h" -#include "customizable_helpers.h" - -const unsigned char TRANSACTION_OUTPUT_SCRIPT_PRE[] = { - 0x19, 0x76, 0xA9, - 0x14}; // script length, OP_DUP, OP_HASH160, address length -const unsigned char TRANSACTION_OUTPUT_SCRIPT_POST[] = { - 0x88, 0xAC}; // OP_EQUALVERIFY, OP_CHECKSIG - -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { - 0x17, 0xA9, 0x14}; // script length, OP_HASH160, address length -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL - -const unsigned char ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = { - 0x3D, 0xA9, 0x14}; // script length, OP_HASH160, address length - -const unsigned char ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = { - 0x87, // OP_EQUAL - 0x20, 0x9E, 0xC9, 0x84, 0x5A, 0xCB, 0x02, 0xFA, 0XB2, 0X4E, 0x1C, 0x03, - 0x68, 0xB3, 0xB5, 0x17, 0xC1, 0xA4, 0x48, 0x8F, 0xBA, 0x97, 0xF0, 0xE3, - 0x45, 0x9A, 0xC0, 0x53, 0xEA, 0x01, 0x00, 0x00, 0x00, // ParamHash - 0x03, // Push 3 bytes to stack to make ParamHeight line up properly - 0xC0, 0x1F, 0x02, // ParamHeight (139200) -> hex -> endianness swapped - 0xB4}; // OP_CHECKBLOCKATHEIGHT - -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE[] = {0x16, 0x00, 0x14}; -const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE[] = {0x22, 0x00, 0x20}; - -const unsigned char ZEN_OUTPUT_SCRIPT_PRE[] = { - 0x3F, 0x76, 0xA9, - 0x14}; // script length, OP_DUP, OP_HASH160, address length -const unsigned char ZEN_OUTPUT_SCRIPT_POST[] = { - 0x88, 0xAC, // OP_EQUALVERIFY, OP_CHECKSIG - 0x20, 0x9e, 0xc9, 0x84, 0x5a, 0xcb, 0x02, 0xfa, 0xb2, 0x4e, 0x1c, 0x03, - 0x68, 0xb3, 0xb5, 0x17, 0xc1, 0xa4, 0x48, 0x8f, 0xba, 0x97, 0xf0, 0xe3, - 0x45, 0x9a, 0xc0, 0x53, 0xea, 0x01, 0x00, 0x00, 0x00, // ParamHash - 0x03, // Push 3 bytes to stack to make ParamHeight line up properly - 0xc0, 0x1f, 0x02, // ParamHeight (139200) -> hex -> endianness swapped - 0xb4 // OP_CHECKBLOCKATHEIGHT -}; // BIP0115 Replay Protection - -/* - * Function: output_script_is_regular - * ----------------------------------- - * Checks if the given output script is a regular script. - * - * Parameters: - * - buffer: Pointer to the output script buffer. - * - * Returns: - * - 1 if the output script is regular - * - 0 otherwise. - */ -WEAK unsigned char output_script_is_regular(unsigned char *buffer) { - if (COIN_NATIVE_SEGWIT_PREFIX) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || - (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { - return 1; - } - } - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) && - (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20, - TRANSACTION_OUTPUT_SCRIPT_POST, - sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) { - return 1; - } - if (COIN_KIND == COIN_KIND_HORIZEN) { - if ((memcmp(buffer, ZEN_OUTPUT_SCRIPT_PRE, sizeof(ZEN_OUTPUT_SCRIPT_PRE)) == - 0) && - (memcmp(buffer + sizeof(ZEN_OUTPUT_SCRIPT_PRE) + 20, - ZEN_OUTPUT_SCRIPT_POST, sizeof(ZEN_OUTPUT_SCRIPT_POST)) == 0)) { - return 1; - } - } - - return 0; -} - -/* - * Function: output_script_is_p2sh - * -------------------------------- - * Checks if the given output script is a pay-to-script-hash (P2SH) script. - * - * Parameters: - * - buffer: Pointer to the output script buffer. - * - * Returns: - * - 1 if the output script is a P2SH script. - * - 0 otherwise. - */ -WEAK unsigned char output_script_is_p2sh(unsigned char *buffer) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && - (memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, - TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { - return 1; - } - if (COIN_KIND == COIN_KIND_HORIZEN) { - if ((memcmp(buffer, ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE, - sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) && - (memcmp(buffer + sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20, - ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST, - sizeof(ZEN_TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) { - return 1; - } - } - return 0; -} - -/* - * Function: output_script_is_native_witness - * ------------------------------------------ - * Checks if the given output script is a native witness script (P2WPKH or - * P2WSH). - * - * Parameters: - * - buffer: Pointer to the output script buffer. - * - * Returns: - * - 1 if the output script is a native witness script. - * - 0 otherwise. - */ -WEAK unsigned char output_script_is_native_witness(unsigned char *buffer) { - if (COIN_NATIVE_SEGWIT_PREFIX) { - if ((memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) || - (memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE, - sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) { - return 1; - } - } - return 0; -} - -/* - * Function: output_script_is_op_return - * ------------------------------------- - * Checks if the given output script is an OP_RETURN script. - * - * Parameters: - * - buffer: Pointer to the output script buffer. - * - * Returns: - * - 1 if the output script is an OP_RETURN script. - * - 0 otherwise. - * - */ -WEAK unsigned char output_script_is_op_return(unsigned char *buffer) { - if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { - return ((buffer[1] == 0x6A) || - ((buffer[1] == 0x00) && (buffer[2] == 0x6A))); - } else { - return (buffer[1] == 0x6A); - } -} - -/* - * Function: output_script_is_op_create_or_call - * --------------------------------------------- - * Checks if the given output script is an OP_CREATE or OP_CALL script. - * - * Parameters: - * - buffer: Pointer to the output script buffer. - * - size: Size of the output script. - * - value: Value to match against the last byte of the script. - * - * Returns: - * - 1 if the output script is an OP_CREATE or OP_CALL script. - * - 0 otherwise. - */ -WEAK unsigned char output_script_is_op_create_or_call(unsigned char *buffer, - size_t size, - unsigned char value) { - return (!output_script_is_regular(buffer) && !output_script_is_p2sh(buffer) && - !output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) && - (buffer[0] < size) && (buffer[buffer[0]] == value)); -} - -/* - * Function: output_script_is_op_create - * ------------------------------------- - * Checks if the given output script is an OP_CREATE script. - * - * Parameters: - * - buffer: Pointer to the output script buffer. - * - size: Size of the output script. - * - * Returns: - * - 1 if the output script is an OP_CREATE script. - * - 0 otherwise. - */ -WEAK unsigned char output_script_is_op_create(unsigned char *buffer, - size_t size) { - return output_script_is_op_create_or_call(buffer, size, 0xC1); -} - -/* - * Function: output_script_is_op_call - * ----------------------------------- - * Checks if the given output script is an OP_CALL script. - * - * Parameters: - * - buffer: Pointer to the output script buffer. - * - size: Size of the output script. - * - * Returns: - * - 1 if the output script is an OP_CALL script. - * - 0 otherwise. - */ -WEAK unsigned char output_script_is_op_call(unsigned char *buffer, - size_t size) { - return output_script_is_op_create_or_call(buffer, size, 0xC2); -} diff --git a/lib-app-bitcoin/customizable_helpers.h b/lib-app-bitcoin/customizable_helpers.h deleted file mode 100644 index 4f6e911c..00000000 --- a/lib-app-bitcoin/customizable_helpers.h +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#pragma once - -#include "cx.h" -#include "os.h" - -unsigned char output_script_is_regular(unsigned char *buffer); -unsigned char output_script_is_p2sh(unsigned char *buffer); -unsigned char output_script_is_op_return(unsigned char *buffer); -unsigned char output_script_is_native_witness(unsigned char *buffer); -unsigned char output_script_is_op_create(unsigned char *buffer, size_t size); -unsigned char output_script_is_op_call(unsigned char *buffer, size_t size); diff --git a/lib-app-bitcoin/customizable_ui.c b/lib-app-bitcoin/customizable_ui.c deleted file mode 100644 index 894d3f96..00000000 --- a/lib-app-bitcoin/customizable_ui.c +++ /dev/null @@ -1,136 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ -#include "customizable_ui.h" -#include "be_operations.h" -#include "cashaddr.h" -#include "context.h" -#include "customizable_helpers.h" -#include "display_utils.h" -#include "display_variables.h" -#include "helpers.h" -#include "read.h" -#include "segwit_addr.h" - -/* - * Function: get_address_from_output_script - * ----------------------------------------- - * Retrieves the address from a given output script and stores it in the - * provided buffer. - * - * Parameters: - * - script: Pointer to the output script data. - * - script_size: Size of the output script. - * - out: Pointer to the buffer where the address will be stored. - * - out_size: Size of the output buffer. - * - */ -WEAK void get_address_from_output_script(unsigned char *script, int script_size, - char *out, int out_size) { - if (output_script_is_op_return(script)) { - strncpy(out, "OP_RETURN", out_size); - return; - } - if ((COIN_KIND == COIN_KIND_HYDRA) && - output_script_is_op_create(script, script_size)) { - strncpy(out, "OP_CREATE", out_size); - return; - } - if ((COIN_KIND == COIN_KIND_HYDRA) && - output_script_is_op_call(script, script_size)) { - strncpy(out, "OP_CALL", out_size); - return; - } - if (output_script_is_native_witness(script)) { - if (COIN_NATIVE_SEGWIT_PREFIX) { - segwit_addr_encode( - out, (char *)PIC(COIN_NATIVE_SEGWIT_PREFIX), 0, - script + OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET, - script[OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET - 1]); - } - return; - } - unsigned char versionSize; - unsigned char address[22]; - unsigned short textSize; - int addressOffset = 3; - unsigned short version = COIN_P2SH_VERSION; - - if (output_script_is_regular(script)) { - addressOffset = 4; - version = COIN_P2PKH_VERSION; - } - - if (version > 255) { - versionSize = 2; - address[0] = (version >> 8); - address[1] = version; - } else { - versionSize = 1; - address[0] = version; - } - memmove(address + versionSize, script + addressOffset, 20); - - // Prepare address - if (context.usingCashAddr) { - cashaddr_encode( - address + versionSize, 20, (uint8_t *)out, out_size, - (version == COIN_P2SH_VERSION ? CASHADDR_P2SH : CASHADDR_P2PKH)); - } else { - textSize = public_key_to_encoded_base58( - address, 20 + versionSize, (unsigned char *)out, out_size, version, 1); - out[textSize] = '\0'; - } -} - -/* - * Function: prepare_fees - * ----------------------- - * Prepares the fee amount for display - * - * Returns: - * - 1 if the fee amount is successfully prepared. - * - 0 if an error occurs. - */ -WEAK uint8_t prepare_fees(void) { - if (context.transactionContext.relaxed) { - memmove(vars.tmp.feesAmount, "UNKNOWN", 7); - vars.tmp.feesAmount[7] = '\0'; - } else { - unsigned char fees[8]; - unsigned char borrow; - - borrow = transaction_amount_sub_be( - fees, context.transactionContext.transactionAmount, - context.totalOutputAmount); - if (borrow && COIN_KIND == COIN_KIND_KOMODO) { - memmove(vars.tmp.feesAmount, "REWARD", 6); - vars.tmp.feesAmount[6] = '\0'; - } else { - if (borrow) { - PRINTF("Error : Fees not consistent"); - goto error; - } - format_sats_amount( - COIN_COINID_SHORT, - (uint64_t)read_u64_be(fees, 0), // Cast prevents weird compilo bug - vars.tmp.feesAmount); - } - } - return 1; -error: - return 0; -} diff --git a/lib-app-bitcoin/customizable_ui.h b/lib-app-bitcoin/customizable_ui.h deleted file mode 100644 index 767b2211..00000000 --- a/lib-app-bitcoin/customizable_ui.h +++ /dev/null @@ -1,24 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ -#pragma once -#include "macros.h" -#include "os.h" - -void get_address_from_output_script(unsigned char *script, int script_size, - char *out, int out_size); - -uint8_t prepare_fees(void); diff --git a/lib-app-bitcoin/display_utils.c b/lib-app-bitcoin/display_utils.c deleted file mode 100644 index a871b8f2..00000000 --- a/lib-app-bitcoin/display_utils.c +++ /dev/null @@ -1,138 +0,0 @@ -#include "filesystem_tx.h" -#include "ledger_assert.h" -#include "read.h" -#include -#include -#include - -#include "./display_utils.h" - -// Division and modulus operators over uint64_t causes the inclusion of the -// __udivmoddi4 and other library functions that occupy more than 400 bytes. -// Since performance is not critical and division by 10 is sufficient, we avoid -// it with a binary search instead. -static uint64_t div10(uint64_t n) { - if (n < 10) - return 0; // special case needed to make sure that n - 10 is safe - - // Since low, mid and high are always <= UINT64_MAX / 10, there is no risk of - // overflow - uint64_t low = 0; - uint64_t high = UINT64_MAX / 10; - - while (true) { - uint64_t mid = (low + high) / 2; - - // the result equals mid if and only if mid * 10 <= n < mid * 10 + 10 - // care is taken to make sure overflows and underflows are impossible - if (mid * 10 > n - 10 && n >= mid * 10) { - return mid; - } else if (n < mid * 10) { - high = mid - 1; - } else /* n >= 10 * mid + 10 */ { - low = mid + 1; - } - } -} - -static uint64_t div100000000(uint64_t n) { - uint64_t res = n; - for (int i = 0; i < 8; i++) - res = div10(res); - return res; -} - -static size_t n_digits(uint64_t number) { - size_t count = 0; - do { - count++; - - // HACK: avoid __udivmoddi4 - // number /= 10; - - number = div10(number); - } while (number != 0); - return count; -} - -void format_sats_amount(const char *coin_name, uint64_t amount, - char out[static MAX_AMOUNT_LENGTH + 1]) { - size_t coin_name_len = strlen(coin_name); - strncpy(out, coin_name, MAX_AMOUNT_LENGTH + 1); - out[coin_name_len] = ' '; - - char *amount_str = out + coin_name_len + 1; - - // HACK: avoid __udivmoddi4 - // uint64_t integral_part = amount / 100000000; - // uint32_t fractional_part = (uint32_t) (amount % 100000000); - uint64_t integral_part = div100000000(amount); - uint32_t fractional_part = (uint32_t)(amount - integral_part * 100000000); - - // format the integral part, starting from the least significant digit - size_t integral_part_digit_count = n_digits(integral_part); - for (unsigned int i = 0; i < integral_part_digit_count; i++) { - // HACK: avoid __udivmoddi4 - // amount_str[integral_part_digit_count - 1 - i] = '0' + (integral_part % - // 10); integral_part /= 10; - - uint64_t tmp_quotient = div10(integral_part); - char tmp_remainder = (char)(integral_part - 10 * tmp_quotient); - amount_str[integral_part_digit_count - 1 - i] = '0' + tmp_remainder; - integral_part = tmp_quotient; - } - - if (fractional_part == 0) { - amount_str[integral_part_digit_count] = '\0'; - } else { - // format the fractional part (exactly 8 digits, possibly with trailing - // zeros) - amount_str[integral_part_digit_count] = '.'; - char *fract_part_str = amount_str + integral_part_digit_count + 1; - snprintf(fract_part_str, 8 + 1, "%08u", fractional_part); - - // drop trailing zeros - for (int i = 7; i > 0 && fract_part_str[i] == '0'; i--) { - fract_part_str[i] = '\0'; - } - } -} - -unsigned char format_path(const unsigned char *bip32Path, char *out, - unsigned char max_out_len) { - - unsigned char bip32PathLength; - unsigned char i, offset; - unsigned int current_level; - bool hardened; - - bip32PathLength = bip32Path[0]; - - LEDGER_ASSERT(bip32PathLength <= MAX_BIP32_PATH, "Wrong path len: %d", - bip32PathLength); - - bip32Path++; - out[0] = ' '; - offset = 1; - for (i = 0; i < bip32PathLength; i++) { - current_level = read_u32_be(bip32Path, 0); - hardened = (bool)(current_level & 0x80000000); - if (hardened) { - // remove hardening flag - current_level ^= 0x80000000; - } - bip32Path += 4; - snprintf(out + offset, max_out_len - offset, "%u", current_level); - offset = strnlen(out, max_out_len); - LEDGER_ASSERT(offset < max_out_len - 2, "OVERFLOW"); - if (hardened) - out[offset++] = '\''; - - out[offset++] = '/'; - out[offset] = '\0'; - } - // remove last '/' - out[offset - 1] = '\0'; - - return offset - 1; -} diff --git a/lib-app-bitcoin/display_utils.h b/lib-app-bitcoin/display_utils.h deleted file mode 100644 index 09cb9405..00000000 --- a/lib-app-bitcoin/display_utils.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -// up to 5 chars for ticker, 1 space, up to 20 digits (20 = digits of 2^64), + 1 -// decimal separator -#define MAX_AMOUNT_LENGTH (5 + 1 + 20 + 1) - -/** - * Converts a 64-bits unsigned integer into a decimal rapresentation, where the - * `amount` is a multiple of 1/100_000_000th. Trailing decimal zeros are not - * appended (and no decimal point is present if the `amount` is a multiple of - * 100_000_000). The resulting string is prefixed with a ticker name (up to 5 - * characters long), followed by a space. - * - * @param coin_name a zero-terminated ticker name, at most 5 characterso long - * (not including the terminating 0) - * @param amount the amount to format - * @param out the output array which must be at least MAX_AMOUNT_LENGTH + 1 - * bytes long - */ -void format_sats_amount(const char *coin_name, uint64_t amount, - char out[static MAX_AMOUNT_LENGTH + 1]); - -unsigned char format_path(const unsigned char *bip32Path, char *out, - unsigned char max_out_len); diff --git a/lib-app-bitcoin/display_variables.c b/lib-app-bitcoin/display_variables.c deleted file mode 100644 index 7d2e6d57..00000000 --- a/lib-app-bitcoin/display_variables.c +++ /dev/null @@ -1,3 +0,0 @@ -#include "display_variables.h" - -union display_variables vars; diff --git a/lib-app-bitcoin/filesystem.h b/lib-app-bitcoin/filesystem.h deleted file mode 100644 index 208f644f..00000000 --- a/lib-app-bitcoin/filesystem.h +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#pragma once - -#include "context.h" -#include "filesystem_tx.h" -#include "os.h" - -enum family_e { - FAMILY_BITCOIN = 0x01, - FAMILY_PEERCOIN = 0x02, - FAMILY_STEALTH = 0x04 -}; - -typedef struct backup_area_s { - uint8_t trustedinput_key[32]; -} backup_area_t; - -typedef struct storage_s { - backup_area_t bkp; -} storage_t; - -// the global nvram memory variable -extern storage_t const N_real; -#define g_nvram_data (*(volatile storage_t *)PIC(&N_real)) diff --git a/lib-app-bitcoin/filesystem_tx.h b/lib-app-bitcoin/filesystem_tx.h deleted file mode 100644 index f045e380..00000000 --- a/lib-app-bitcoin/filesystem_tx.h +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#pragma once -#include "os.h" - -#define MAX_BIP32_PATH 10 -#define MAX_BIP32_PATH_LENGTH (4 * MAX_BIP32_PATH) + 1 -#define BIP44_PATH_LEN 5 -#define BIP44_PURPOSE_OFFSET 0 -#define BIP44_COIN_TYPE_OFFSET 1 -#define BIP44_ACCOUNT_OFFSET 2 -#define BIP44_CHANGE_OFFSET 3 -#define BIP44_ADDRESS_INDEX_OFFSET 4 -#define MAX_BIP44_ACCOUNT_RECOMMENDED 100 -#define MAX_BIP44_ADDRESS_INDEX_RECOMMENDED 50000 - -struct transaction_summary_s { - unsigned char active; - unsigned char payToAddressVersion; - unsigned char payToScriptHashVersion; - unsigned char authorizationHash[32]; - unsigned char keyPath[MAX_BIP32_PATH_LENGTH]; - unsigned char - transactionNonce[8]; // used to bind to the current set of inputs - unsigned short messageLength; - unsigned char sighashType; -}; -typedef struct transaction_summary_s transaction_summary_t; diff --git a/lib-app-bitcoin/handler/get_coin_version.c b/lib-app-bitcoin/handler/get_coin_version.c deleted file mode 100644 index cf589124..00000000 --- a/lib-app-bitcoin/handler/get_coin_version.c +++ /dev/null @@ -1,57 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#include "io.h" -#include "write.h" - -#include "apdu_constants.h" -#include "context.h" - -/* - * Function: handler_get_coin_version - * ----------------------------------- - * Handles the retrieval of coin version information. - * - * Returns: - * - SW_OK if the operation is successful. - */ -WEAK unsigned short handler_get_coin_version(void) { - uint8_t offset = 0; - size_t string_size; - - write_u16_be(G_io_apdu_buffer, offset, COIN_P2PKH_VERSION); - offset += 2; - - write_u16_be(G_io_apdu_buffer, offset, COIN_P2SH_VERSION); - offset += 2; - - G_io_apdu_buffer[offset++] = COIN_FAMILY; - - string_size = strlen(COIN_COINID); - G_io_apdu_buffer[offset++] = string_size; - memmove(G_io_apdu_buffer + offset, COIN_COINID, string_size); - offset += string_size; - - string_size = strlen(COIN_COINID_SHORT); - G_io_apdu_buffer[offset++] = string_size; - memmove(G_io_apdu_buffer + offset, COIN_COINID_SHORT, string_size); - offset += string_size; - - context.outLength = offset; - - return io_send_response_pointer(G_io_apdu_buffer, offset, SW_OK); -} diff --git a/lib-app-bitcoin/handler/get_firmware_version.c b/lib-app-bitcoin/handler/get_firmware_version.c deleted file mode 100644 index 6ed5c123..00000000 --- a/lib-app-bitcoin/handler/get_firmware_version.c +++ /dev/null @@ -1,58 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ -#include "io.h" - -#include "apdu_constants.h" -#include "context.h" - -#define FEATURES_SELF_SCREEN_BUTTONS 0x02 -#define FEATURES_NFC 0x08 -#define FEATURES_BLE 0x10 - -#define MODE_SETUP 0x01 -#define MODE_OPERATION 0x02 - -#define FEATURES (FEATURES_NFC | FEATURES_BLE | FEATURES_SELF_SCREEN_BUTTONS) -#define MODE (MODE_SETUP | MODE_OPERATION) - -#define ARCH_ID 0x30 - -#define TCS_LOADER_PATCH_VERSION 0 - -/* - * Function: handler_get_firmware_version - * --------------------------------------- - * Retrieves the firmware version information. - * - * Returns: - * - -1 if the operation is unsuccessful. - */ -WEAK unsigned short handler_get_firmware_version() { - - G_io_apdu_buffer[0] = FEATURES; - G_io_apdu_buffer[1] = ARCH_ID; - G_io_apdu_buffer[2] = MAJOR_VERSION; - G_io_apdu_buffer[3] = MINOR_VERSION; - G_io_apdu_buffer[4] = PATCH_VERSION; - G_io_apdu_buffer[5] = 1; - G_io_apdu_buffer[6] = TCS_LOADER_PATCH_VERSION; - G_io_apdu_buffer[7] = MODE; - - context.outLength = 0x08; - - return io_send_response_pointer(G_io_apdu_buffer, 0x08, SW_OK); -} diff --git a/lib-app-bitcoin/handler/get_trusted_input.c b/lib-app-bitcoin/handler/get_trusted_input.c deleted file mode 100644 index 90aefa9d..00000000 --- a/lib-app-bitcoin/handler/get_trusted_input.c +++ /dev/null @@ -1,105 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ -#include "io.h" -#include "lib_standard_app/read.h" -#include "lib_standard_app/write.h" - -#include "apdu_constants.h" -#include "context.h" -#include "filesystem.h" -#include "transaction.h" - -#define GET_TRUSTED_INPUT_P1_FIRST 0x00 -#define GET_TRUSTED_INPUT_P1_NEXT 0x80 - -/* - * Function: handler_get_trusted_input - * ------------------------------------ - * Handles the retrieval of a trusted input for transaction signing. - * This function is defined as WEAK and can be overridden in the application own - * sources. - * - * The function manages the retrieval of a trusted input for transaction - * signing. It initializes transaction parameters, including the target input - * and hash option. It then parses the transaction data, processes the trusted - * input, and prepares the response. - * - * Parameters: - * - buffer: Pointer to the buffer containing transaction data. - * - p1: Instruction parameter 1. - * - p2: Instruction parameter 2. - * - */ -WEAK unsigned short handler_get_trusted_input(buffer_t *buffer, uint8_t p1, - uint8_t p2) { - unsigned char dataOffset = 0; - - if (p1 == GET_TRUSTED_INPUT_P1_FIRST) { - // Initialize - context.transactionTargetInput = read_u32_be(buffer->ptr, 0); - context.transactionContext.transactionState = TRANSACTION_NONE; - context.trustedInputProcessed = 0; - context.transactionContext.consumeP2SH = 0; - dataOffset = 4; - context.transactionHashOption = TRANSACTION_HASH_FULL; - context.usingSegwit = 0; - context.usingOverwinter = 0; - } else if (p1 != GET_TRUSTED_INPUT_P1_NEXT) { - return io_send_sw(SW_INCORRECT_P1_P2); - } - - if (p2 != 0x00) { - return io_send_sw(SW_INCORRECT_P1_P2); - } - - context.transactionBufferPointer = (uint8_t *)buffer->ptr + dataOffset; - context.transactionDataRemaining = buffer->size - dataOffset; - - transaction_parse(PARSE_MODE_TRUSTED_INPUT); - - if (context.transactionContext.transactionState == TRANSACTION_PARSED) { - - context.transactionContext.transactionState = TRANSACTION_NONE; - if (!context.trustedInputProcessed) { - // Output was not found - return io_send_sw(SW_INCORRECT_DATA); - } - - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, CX_LAST, - NULL, 0, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32)) { - return io_send_sw(SW_TECHNICAL_PROBLEM); - } - - // Otherwise prepare - cx_rng(G_io_apdu_buffer, 8); - G_io_apdu_buffer[0] = MAGIC_TRUSTED_INPUT; - G_io_apdu_buffer[1] = 0x00; - cx_hash_sha256(G_io_apdu_buffer + TRUSTED_INPUT_SIZE, 32, - G_io_apdu_buffer + 4, 32); - - write_u32_le(G_io_apdu_buffer, 4 + 32, context.transactionTargetInput); - memmove(G_io_apdu_buffer + 4 + 32 + 4, - context.transactionContext.transactionAmount, 8); - - cx_hmac_sha256((uint8_t *)g_nvram_data.bkp.trustedinput_key, - sizeof(g_nvram_data.bkp.trustedinput_key), G_io_apdu_buffer, - TRUSTED_INPUT_SIZE, G_io_apdu_buffer + TRUSTED_INPUT_SIZE, - 32); - context.outLength = TRUSTED_INPUT_TOTAL_SIZE; - } - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); -} diff --git a/lib-app-bitcoin/handler/get_wallet_public_key.c b/lib-app-bitcoin/handler/get_wallet_public_key.c deleted file mode 100644 index ca04f956..00000000 --- a/lib-app-bitcoin/handler/get_wallet_public_key.c +++ /dev/null @@ -1,206 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#include "apdu_constants.h" -#include "context.h" -#include "helpers.h" - -#include "extensions.h" - -#include "cashaddr.h" -#include "io.h" -#include "lib_standard_app/read.h" -#include "segwit_addr.h" -#include "swap.h" - -#define P1_NO_DISPLAY 0x00 -#define P1_DISPLAY 0x01 -#define P1_REQUEST_TOKEN 0x02 - -#define P2_LEGACY 0x00 -#define P2_SEGWIT 0x01 -#define P2_NATIVE_SEGWIT 0x02 -#define P2_CASHADDR 0x03 - -static int get_public_key_chain_code(const unsigned char *keyPath, - size_t keyPath_len, - unsigned char *publicKey, - unsigned char *chainCode) { - uint8_t public_key[65]; - int keyLength = 0; - - if (get_public_key(keyPath, keyPath_len, public_key, chainCode)) { - return keyLength; - } - // Then encode it - compress_public_key_value(public_key); - keyLength = 33; - - memmove(publicKey, public_key, sizeof(public_key)); - return keyLength; -} - -/* - * Function: handler_get_wallet_public_key - * --------------------------------------- - * Handles the retrieval of the wallet's public key. - * This function is defined as WEAK and can be overridden in the application own - * sources. - * - * The function retrieves the wallet's public key and optionally displays it. - * It validates input parameters, computes the public key and chain code, - * encodes them, and prepares the response. If the public key is to be - * displayed, it ensures the key length is appropriate and sends it for display. - * Parameters: - * - buffer: Pointer to the buffer containing the instruction data. - * - p1: Instruction parameter 1. - * - p2: Instruction parameter 2. - * - */ -WEAK unsigned short handler_get_wallet_public_key(buffer_t *buffer, uint8_t p1, - uint8_t p2) { - unsigned char keyLength; - unsigned char chainCode[32]; - uint8_t is_derivation_path_unusual = 0; - - bool display = (p1 == P1_DISPLAY); - bool segwit = (p2 == P2_SEGWIT); - bool nativeSegwit = (p2 == P2_NATIVE_SEGWIT); - bool cashAddr = (p2 == P2_CASHADDR); - - if (display && G_called_from_swap) { - PRINTF("Refused INS when in SWAP mode\n"); - return io_send_sw(SW_INS_NOT_SUPPORTED); - } - - if (p1 != P1_NO_DISPLAY && p1 != P1_DISPLAY) { - PRINTF("Wrong P1 value\n"); - return io_send_sw(SW_INCORRECT_P1_P2); - } - - if (p2 == P2_NATIVE_SEGWIT && !COIN_NATIVE_SEGWIT_PREFIX) { - PRINTF("Wrong P2 value\n"); - return io_send_sw(SW_INCORRECT_P1_P2); - } - - if (p2 == P2_CASHADDR && COIN_KIND != COIN_KIND_BITCOIN_CASH) { - PRINTF("Wrong P2 value\n"); - return io_send_sw(SW_INCORRECT_P1_P2); - } - - if (p2 != P2_NATIVE_SEGWIT && p2 != P2_LEGACY && p2 != P2_SEGWIT && - p2 != P2_CASHADDR) { - PRINTF("Wrong P2 value\n"); - return io_send_sw(SW_INCORRECT_P1_P2); - } - - if (buffer->size < 0x01) { - PRINTF("Wrong size\n"); - return io_send_sw(SW_INCORRECT_LENGTH); - } - - if (display) { - is_derivation_path_unusual = set_key_path_to_display(buffer->ptr); - } - - unsigned char bip44_enforced = enforce_bip44_coin_type(buffer->ptr, true); - - G_io_apdu_buffer[0] = 65; - keyLength = get_public_key_chain_code(buffer->ptr, MAX_BIP32_PATH_LENGTH, - G_io_apdu_buffer + 1, chainCode); - - if (keyLength == 0) { - return io_send_sw(SW_TECHNICAL_PROBLEM); - } - - if (cashAddr) { - uint8_t tmp[20]; - public_key_hash160(G_io_apdu_buffer + 1, // IN - keyLength, // INLEN - tmp); - keyLength = - cashaddr_encode(tmp, 20, G_io_apdu_buffer + 67, 50, CASHADDR_P2PKH); - } else if (!(segwit || nativeSegwit)) { - keyLength = public_key_to_encoded_base58(G_io_apdu_buffer + 1, // IN - keyLength, // INLEN - G_io_apdu_buffer + 67, // OUT - 150, // MAXOUTLEN - COIN_P2PKH_VERSION, 0); - } else { - uint8_t tmp[22]; - tmp[0] = 0x00; - tmp[1] = 0x14; - public_key_hash160(G_io_apdu_buffer + 1, // IN - keyLength, // INLEN - tmp + 2 // OUT - ); - if (!nativeSegwit) { - keyLength = public_key_to_encoded_base58(tmp, // IN - 22, // INLEN - G_io_apdu_buffer + 67, // OUT - 150, // MAXOUTLEN - COIN_P2SH_VERSION, 0); - } else { - if (COIN_NATIVE_SEGWIT_PREFIX) { - keyLength = segwit_addr_encode((char *)(G_io_apdu_buffer + 67), - (char *)PIC(COIN_NATIVE_SEGWIT_PREFIX), - 0, tmp + 2, 20); - if (keyLength == 1) { - keyLength = strlen((char *)(G_io_apdu_buffer + 67)); - } - } - } - } - G_io_apdu_buffer[66] = keyLength; - PRINTF("Length %d\n", keyLength); - // Restore for the full key component - G_io_apdu_buffer[1] = 0x04; - - // output chain code - memmove(G_io_apdu_buffer + 1 + 65 + 1 + keyLength, chainCode, - sizeof(chainCode)); - context.outLength = 1 + 65 + 1 + keyLength + sizeof(chainCode); - - // privacy : force display the address if the path isn't standard - // and could reveal another fork holdings according to BIP 44 rules - if (!display && !bip44_enforced) { - display = true; - } - - if (display) { - if (keyLength > 50) { - return io_send_sw(SW_INCORRECT_DATA); - } - // Hax, avoid wasting space - memmove(G_io_apdu_buffer + 200, G_io_apdu_buffer + 67, keyLength); - G_io_apdu_buffer[200 + keyLength] = '\0'; - display_public_key(is_derivation_path_unusual); - return 0; - } - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); -} - -int user_action_display(unsigned char confirming) { - // confirm and finish the apdu exchange //spaghetti - if (confirming) { - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); - - } else { - context.outLength = 0; - return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); - } -} diff --git a/lib-app-bitcoin/handler/hash_input_finalize_full.c b/lib-app-bitcoin/handler/hash_input_finalize_full.c deleted file mode 100644 index 4c34b104..00000000 --- a/lib-app-bitcoin/handler/hash_input_finalize_full.c +++ /dev/null @@ -1,619 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -// TODO Trustlet, BAGL : process each output separately. -// review nvm_write policy - -#include "crypto_helpers.h" -#include "io.h" -#include "read.h" -#include "swap.h" - -#include "apdu_constants.h" -#include "be_operations.h" -#include "context.h" -#include "customizable_helpers.h" -#include "extensions.h" -#include "helpers.h" -#include "ui.h" - -#define FINALIZE_P1_MORE 0x00 -#define FINALIZE_P1_LAST 0x80 -#define FINALIZE_P1_CHANGEINFO 0xFF - -#define FINALIZE_P2_DEFAULT 0x00 - -#define FLAG_SIGNATURE 0x01 -#define FLAG_CHANGE_VALIDATED 0x80 - -void hash_input_finalize_full_reset(void) { - context.currentOutputOffset = 0; - context.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; - memset(context.totalOutputAmount, 0, sizeof(context.totalOutputAmount)); - context.changeOutputFound = 0; -} - -static int check_output_displayable(bool *displayable) { - *displayable = true; - unsigned char amount[8], isOpReturn, isP2sh, isNativeSegwit, j, - nullAmount = 1; - - for (j = 0; j < 8; j++) { - if (context.currentOutput[j] != 0) { - nullAmount = 0; - break; - } - } - if (!nullAmount) { - swap_bytes(amount, context.currentOutput, 8); - transaction_amount_add_be(context.totalOutputAmount, - context.totalOutputAmount, amount); - } - isOpReturn = output_script_is_op_return(context.currentOutput + 8); - isP2sh = output_script_is_p2sh(context.currentOutput + 8); - isNativeSegwit = output_script_is_native_witness(context.currentOutput + 8); -#ifndef __clang_analyzer__ - unsigned char isOpCreate = output_script_is_op_create( - context.currentOutput + 8, sizeof(context.currentOutput) - 8); - unsigned char isOpCall = output_script_is_op_call( - context.currentOutput + 8, sizeof(context.currentOutput) - 8); - if (((COIN_KIND == COIN_KIND_HYDRA) && - !output_script_is_regular(context.currentOutput + 8) && !isP2sh && - !(nullAmount && isOpReturn) && !isOpCreate && !isOpCall) || - (!(COIN_KIND == COIN_KIND_HYDRA) && - !output_script_is_regular(context.currentOutput + 8) && !isP2sh && - !(nullAmount && isOpReturn))) { - PRINTF("Error : Unrecognized output script"); - return -1; - } -#endif - if (context.tmpCtx.output.changeInitialized && !isOpReturn) { - bool changeFound = false; - unsigned char addressOffset = - (isNativeSegwit ? OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET - : isP2sh ? OUTPUT_SCRIPT_P2SH_PRE_LENGTH - : OUTPUT_SCRIPT_REGULAR_PRE_LENGTH); - if (!isP2sh && memcmp(context.currentOutput + 8 + addressOffset, - context.tmpCtx.output.changeAddress, 20) == 0) { - changeFound = true; - } else if (isP2sh && context.usingSegwit) { - unsigned char changeSegwit[22]; - changeSegwit[0] = 0x00; - changeSegwit[1] = 0x14; - memmove(changeSegwit + 2, context.tmpCtx.output.changeAddress, 20); - public_key_hash160(changeSegwit, 22, changeSegwit); - if (memcmp(context.currentOutput + 8 + addressOffset, changeSegwit, 20) == - 0) { - if (COIN_FLAGS & FLAG_SEGWIT_CHANGE_SUPPORT) { - changeFound = true; - } else { - // Attempt to avoid fatal failures on Bitcoin Cash - PRINTF("Error : Non spendable Segwit change"); - return -1; - } - } - } - if (changeFound) { - if (context.changeOutputFound) { - PRINTF("Error : Multiple change output found"); - return -1; - } - context.changeOutputFound = true; - *displayable = false; - } - } - return 0; -} - -int handle_output_state(unsigned int *processed) { - uint32_t discardSize = 0; - context.discardSize = 0; - *processed = 0; - switch (context.outputParsingState) { - case OUTPUT_PARSING_NUMBER_OUTPUTS: { - context.totalOutputs = 0; - if (context.currentOutputOffset < 1) { - break; - } - if (context.currentOutput[0] < 0xFD) { - context.totalOutputs = context.remainingOutputs = - context.currentOutput[0]; - discardSize = 1; - context.outputParsingState = OUTPUT_PARSING_OUTPUT; - *processed = 1; - break; - } - if (context.currentOutput[0] == 0xFD) { - if (context.currentOutputOffset < 3) { - break; - } - context.totalOutputs = context.remainingOutputs = - (context.currentOutput[2] << 8) | context.currentOutput[1]; - discardSize = 3; - context.outputParsingState = OUTPUT_PARSING_OUTPUT; - *processed = 1; - break; - } else if (context.currentOutput[0] == 0xFE) { - if (context.currentOutputOffset < 5) { - break; - } - context.totalOutputs = context.remainingOutputs = - read_u32_le(context.currentOutput, 1); - discardSize = 5; - context.outputParsingState = OUTPUT_PARSING_OUTPUT; - *processed = 1; - break; - } else { - return -1; - } - } break; - - case OUTPUT_PARSING_OUTPUT: { - unsigned int scriptSize = 0; - if (context.currentOutputOffset < 9) { - break; - } - if (context.currentOutput[8] < 0xFD) { - scriptSize = context.currentOutput[8]; - discardSize = 1; - } else if (context.currentOutput[8] == 0xFD) { - if (context.currentOutputOffset < 9 + 2) { - break; - } - scriptSize = read_u32_le(context.currentOutput, 9); - discardSize = 3; - } else { - // Unrealistically large script - return -1; - } - if (context.currentOutputOffset < 8 + discardSize + scriptSize) { - discardSize = 0; - break; - } - - *processed = 1; - - discardSize += 8 + scriptSize; - - bool displayable; - if (check_output_displayable(&displayable)) { - return -1; - } - - if (displayable) { - // The output can be processed by the UI - - context.discardSize = discardSize; - discardSize = 0; - *processed = 2; - } else { - context.remainingOutputs--; - } - } break; - - default: - return -1; - } - - if (discardSize != 0) { - memmove(context.currentOutput, context.currentOutput + discardSize, - context.currentOutputOffset - discardSize); - context.currentOutputOffset -= discardSize; - } - - return 0; -} - -// out should be 32 bytes, even only 20 bytes is significant for output -int get_pubkey_hash160(unsigned char *keyPath, size_t keyPath_len, - unsigned char *out) { - cx_ecfp_public_key_t public_key; - if (get_public_key(keyPath, keyPath_len, public_key.W, NULL)) { - return -1; - } - compress_public_key_value(public_key.W); - - public_key_hash160(public_key.W, // IN - 33, // INLEN - out // OUT - ); - return 0; -} - -static unsigned short -hash_input_finalize_full_internal(transaction_summary_t *transactionSummary, - buffer_t *buffer, uint8_t p1, uint8_t p2, - bool *async) { - unsigned char authorizationHash[32]; - unsigned short sw = SW_OK; - unsigned char *target = G_io_apdu_buffer; - unsigned char hashOffset = 0; - - (void)p2; - - if ((p1 != FINALIZE_P1_MORE) && (p1 != FINALIZE_P1_LAST) && - (p1 != FINALIZE_P1_CHANGEINFO)) { - return SW_INCORRECT_P1_P2; - } - - // See if there is a hashing offset - if (context.usingSegwit && (context.tmpCtx.output.multipleOutput == 0)) { - unsigned char firstByte = buffer->ptr[0]; - if (firstByte < 0xfd) { - hashOffset = 1; - } else if (firstByte == 0xfd) { - hashOffset = 3; - } else if (firstByte == 0xfe) { - hashOffset = 5; - } - } - - // Check state - if (context.transactionContext.transactionState != - TRANSACTION_PRESIGN_READY) { - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - - if (p1 == FINALIZE_P1_CHANGEINFO) { - if (!context.transactionContext.firstSigned) { - // Already validated, should be prevented on the client side - return SW_OK; - } - if (!context.tmpCtx.output.changeAccepted) { - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - memset(transactionSummary, 0, sizeof(transaction_summary_t)); - if (buffer->ptr[0] == 0x00) { - // Called with no change path, abort, should be prevented on - // the client side - return SW_OK; - } - memmove(transactionSummary->keyPath, buffer->ptr, MAX_BIP32_PATH_LENGTH); - - if (get_pubkey_hash160(transactionSummary->keyPath, - sizeof(transactionSummary->keyPath), - context.tmpCtx.output.changeAddress)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - PRINTF("Change address = %.*H\n", 20, context.tmpCtx.output.changeAddress); - - context.tmpCtx.output.changeInitialized = 1; - context.tmpCtx.output.changeAccepted = 0; - - // if the bip44 change path provided is not canonical or its index are - // unsual, ask for user approval - if (bip44_derivation_guard(transactionSummary->keyPath, true)) { - if (G_called_from_swap) { - PRINTF("In swap mode only standart path is allowed\n"); - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - *async = true; - context.outputParsingState = BIP44_CHANGE_PATH_VALIDATION; - request_change_path_approval(transactionSummary->keyPath); - } - - return SW_OK; - } - - // Always update the transaction & authorization hashes with the - // given data - // For SegWit, this has been reset to hold hashOutputs - if (!context.segwitParsedOnce) { - if ((int)(buffer->size - hashOffset) < 0) { - sw = SW_INCORRECT_DATA; - goto discardTransaction; - } - if (context.usingOverwinter) { - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, - buffer->ptr + hashOffset, buffer->size - hashOffset, - NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - } else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", buffer->size - hashOffset, - buffer->ptr + hashOffset); - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - buffer->ptr + hashOffset, buffer->size - hashOffset, - NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - } - } - - if (context.transactionContext.firstSigned) { - if ((context.currentOutputOffset + buffer->size) > - sizeof(context.currentOutput)) { - PRINTF("Output is too long to be checked\n"); - sw = SW_INCORRECT_DATA; - goto discardTransaction; - } - memmove(context.currentOutput + context.currentOutputOffset, buffer->ptr, - buffer->size); - context.currentOutputOffset += buffer->size; - - unsigned int processed = 1; - while (processed == 1) { - if (handle_output_state(&processed)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - } - - if (processed == 2) { - *async = true; - } - // Finalize the TX if necessary - - if ((context.remainingOutputs == 0) && (!*async)) { - *async = true; - context.outputParsingState = OUTPUT_FINALIZE_TX; - } - } - - if (p1 == FINALIZE_P1_MORE) { - if (!context.usingSegwit) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", buffer->size, buffer->ptr); - if (cx_hash_no_throw(&context.transactionHashAuthorization.header, 0, - buffer->ptr, buffer->size, NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - } - G_io_apdu_buffer[0] = 0x00; - context.outLength = 1; - context.tmpCtx.output.multipleOutput = 1; - return SW_OK; - } - - if (!context.usingSegwit) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", buffer->size, buffer->ptr); - if (cx_hash_no_throw(&context.transactionHashAuthorization.header, CX_LAST, - buffer->ptr, buffer->size, authorizationHash, 32)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - } - - if (context.usingSegwit) { - if (!context.segwitParsedOnce) { - if (context.usingOverwinter) { - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, - CX_LAST, context.segwit.cache.hashedOutputs, 0, - context.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - } else { - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, - CX_LAST, context.segwit.cache.hashedOutputs, 0, - context.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, - CX_LAST, context.segwit.cache.hashedOutputs, - sizeof(context.segwit.cache.hashedOutputs), - context.segwit.cache.hashedOutputs, 32)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - } - PRINTF("hashOutputs\n%.*H\n", 32, context.segwit.cache.hashedOutputs); - if (cx_hash_no_throw(&context.transactionHashAuthorization.header, - CX_LAST, G_io_apdu_buffer, 0, authorizationHash, - 32)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); - } else { - if (cx_hash_no_throw(&context.transactionHashAuthorization.header, - CX_LAST, (unsigned char *)&context.segwit.cache, - sizeof(context.segwit.cache), authorizationHash, - 32)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discardTransaction; - } - PRINTF("Auth Hash:\n%.*H\n", 32, authorizationHash); - } - } - - if (context.transactionContext.firstSigned) { - if (!context.tmpCtx.output.changeInitialized) { - memset(transactionSummary, 0, sizeof(transaction_summary_t)); - } - - transactionSummary->payToAddressVersion = COIN_P2PKH_VERSION; - transactionSummary->payToScriptHashVersion = COIN_P2SH_VERSION; - - // Generate new nonce - - cx_rng(transactionSummary->transactionNonce, 8); - } - - G_io_apdu_buffer[0] = 0x00; - target++; - - *target = 0x00; - target++; - - context.outLength = (target - G_io_apdu_buffer); - - // Check that the input being signed is part of the same - // transaction, otherwise abort - // (this is done to keep the transaction counter limit per session - // synchronized) - if (context.transactionContext.firstSigned) { - memmove(transactionSummary->authorizationHash, authorizationHash, - sizeof(transactionSummary->authorizationHash)); - return SW_OK; - } else { - if (os_secure_memcmp(authorizationHash, - transactionSummary->authorizationHash, - sizeof(transactionSummary->authorizationHash))) { - PRINTF("Authorization hash not matching, aborting\n"); - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - goto discardTransaction; - } - - if (context.usingSegwit && !context.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context.transactionContext.transactionState = TRANSACTION_NONE; - } else { - context.transactionContext.transactionState = TRANSACTION_SIGN_READY; - } - hash_input_finalize_full_reset(); - return SW_OK; - } - -discardTransaction: - hash_input_finalize_full_reset(); - ui_transaction_error(); - context.transactionContext.transactionState = TRANSACTION_NONE; - context.outLength = 0; - - memmove(G_io_apdu_buffer, context.currentOutput, context.currentOutputOffset); - context.outLength = context.currentOutputOffset; - return sw; -} - -unsigned short handler_hash_input_finalize_full(buffer_t *buffer, uint8_t p1, - uint8_t p2) { - bool is_async = false; - PRINTF("state=%d\n", context.outputParsingState); - unsigned short sw = hash_input_finalize_full_internal( - &context.transactionSummary, buffer, p1, p2, &is_async); - - if (is_async) { - // if the UI reject the processing of the request, then reply - // immediately - int status; - if (context.outputParsingState == BIP44_CHANGE_PATH_VALIDATION) { - context.outputParsingState = OUTPUT_PARSING_NUMBER_OUTPUTS; - return 0; - } else if (context.outputParsingState == OUTPUT_FINALIZE_TX) { - status = finalize_tx(); - } else { - status = confirm_single_output(); - } - if (status == 0) { - ui_transaction_error(); - context.transactionContext.transactionState = TRANSACTION_NONE; - context.outLength = 0; - sw = SW_INCORRECT_DATA; - return io_send_sw(sw); - } else if (status == 2) { - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, - SW_OK); - } - return 0; - } - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); -} - -unsigned char user_action(unsigned char confirming) { - unsigned short sw = SW_OK; - - // confirm and finish the apdu exchange //spaghetti - - if (confirming) { - // Check if all inputs have been confirmed - - if (context.outputParsingState == OUTPUT_PARSING_OUTPUT) { - context.remainingOutputs--; - } - - while (context.remainingOutputs != 0) { - memmove(context.currentOutput, - context.currentOutput + context.discardSize, - context.currentOutputOffset - context.discardSize); - context.currentOutputOffset -= context.discardSize; - unsigned int processed = 1; - while (processed == 1) { - if (handle_output_state(&processed)) { - context.transactionContext.transactionState = TRANSACTION_NONE; - sw = SW_INCORRECT_DATA; - break; - } - } - - if (processed == 2) { - if (!confirm_single_output()) { - context.transactionContext.transactionState = TRANSACTION_NONE; - sw = SW_INCORRECT_DATA; - break; - } else { - // Let the UI play - return 1; - } - } else { - // Out of data to process, wait for the next call - break; - } - } - - if ((context.outputParsingState == OUTPUT_PARSING_OUTPUT) && - (context.remainingOutputs == 0)) { - context.outputParsingState = OUTPUT_FINALIZE_TX; - if (!finalize_tx()) { - context.outputParsingState = OUTPUT_PARSING_NONE; - context.transactionContext.transactionState = TRANSACTION_NONE; - sw = SW_INCORRECT_DATA; - } else { - // Let the UI play - return 1; - } - } - - if (context.outputParsingState == OUTPUT_FINALIZE_TX) { - context.transactionContext.firstSigned = 0; - - if (context.usingSegwit && !context.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context.transactionContext.transactionState = TRANSACTION_NONE; - } else { - context.transactionContext.transactionState = TRANSACTION_SIGN_READY; - } - } - } else { - // Discard transaction - context.transactionContext.transactionState = TRANSACTION_NONE; - sw = SW_CONDITIONS_OF_USE_NOT_SATISFIED; - context.outLength = 0; - } - - if ((context.outputParsingState == OUTPUT_FINALIZE_TX) || (sw != SW_OK)) { - - // we've finished the processing of the input - hash_input_finalize_full_reset(); - } - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); -} diff --git a/lib-app-bitcoin/handler/hash_input_start.c b/lib-app-bitcoin/handler/hash_input_start.c deleted file mode 100644 index ad662966..00000000 --- a/lib-app-bitcoin/handler/hash_input_start.c +++ /dev/null @@ -1,143 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#include "io.h" - -#include "apdu_constants.h" -#include "context.h" -#include "extensions.h" -#include "swap.h" -#include "transaction.h" - -#define P1_FIRST 0x00 -#define P1_NEXT 0x80 -#define P2_NEW 0x00 -#define P2_NEW_SEGWIT 0x02 -#define P2_NEW_SEGWIT_CASHADDR 0x03 -#define P2_NEW_SEGWIT_OVERWINTER 0x04 -#define P2_NEW_SEGWIT_SAPLING 0x05 -#define P2_CONTINUE 0x80 - -#define IS_INPUT() \ - (buffer->size - 1 > 8 && buffer->size - 1 <= TRUSTED_INPUT_TOTAL_SIZE + 2 && \ - buffer->ptr[0] <= 0x02) - -#define IS_INPUT_TRUSTED() \ - (buffer->ptr[0] == 0x01 && buffer->ptr[1] == TRUSTED_INPUT_TOTAL_SIZE && \ - buffer->ptr[2] == MAGIC_TRUSTED_INPUT && buffer->ptr[3] == 0x00) - -/* - * Function: handler_hash_input_start - * ----------------------------------- - * Handles the start of input hashing for a transaction. - * This function is defined as WEAK and can be overridden in the application own - * sources. - * - * The function manages the initialization and parsing of input data for hashing - * a transaction. It sets transaction parameters based on the instruction - * parameters, including flags for SegWit, CashAddr, Overwinter, and Sapling. It - * handles warnings for SegWit inputs, requests approval if needed, and starts - * parsing the transaction data for signature. Finally, it sends the response - * after parsing is complete. - * - * Parameters: - * - buffer: Pointer to the buffer containing transaction data. - * - p1: Instruction parameter 1. - * - p2: Instruction parameter 2. - * - */ -WEAK unsigned short handler_hash_input_start(buffer_t *buffer, uint8_t p1, - uint8_t p2) { - if (p1 == P1_FIRST) { - // Initialize - context.transactionContext.transactionState = TRANSACTION_NONE; - context.transactionHashOption = TRANSACTION_HASH_BOTH; - } else if (p1 != P1_NEXT) { - return io_send_sw(SW_INCORRECT_P1_P2); - } - - if ((p2 == P2_NEW) || (p2 == P2_NEW_SEGWIT) || - (p2 == P2_NEW_SEGWIT_CASHADDR) || (p2 == P2_NEW_SEGWIT_OVERWINTER) || - (p2 == P2_NEW_SEGWIT_SAPLING)) { - if (p1 == P1_FIRST) { - unsigned char usingSegwit = - (p2 == P2_NEW_SEGWIT) || (p2 == P2_NEW_SEGWIT_CASHADDR) || - (p2 == P2_NEW_SEGWIT_OVERWINTER) || (p2 == P2_NEW_SEGWIT_SAPLING); - // Master transaction reset - context.transactionContext.firstSigned = 1; - context.transactionContext.consumeP2SH = 0; - context.transactionContext.relaxed = 0; - context.usingSegwit = usingSegwit; - - if (COIN_KIND == COIN_KIND_BITCOIN_CASH) { - unsigned char usingCashAddr = (p2 == P2_NEW_SEGWIT_CASHADDR); - context.usingCashAddr = usingCashAddr; - } else { - context.usingCashAddr = 0; - } - - context.usingOverwinter = 0; - if ((COIN_KIND == COIN_KIND_ZCASH) || (COIN_KIND == COIN_KIND_KOMODO) || - (COIN_KIND == COIN_KIND_ZCLASSIC) || - (COIN_KIND == COIN_KIND_RESISTANCE)) { - if (p2 == P2_NEW_SEGWIT_OVERWINTER) { - context.usingOverwinter = ZCASH_USING_OVERWINTER; - } else if (p2 == P2_NEW_SEGWIT_SAPLING) { - context.usingOverwinter = ZCASH_USING_OVERWINTER_SAPLING; - } - } - context.overwinterSignReady = 0; - context.segwitParsedOnce = 0; - // Initialize for screen pairing - memset(&context.tmpCtx.output, 0, sizeof(context.tmpCtx.output)); - context.tmpCtx.output.changeAccepted = 1; - // Reset segwitWarningSeen flag to prevent displaying the warning for each - // segwit input when coontinuing from a previous session (P2=0x80) - context.segwitWarningSeen = 0; - } - } else if (p2 != P2_CONTINUE) { - return io_send_sw(SW_INCORRECT_P1_P2); - } - - // In segwit mode, warn user one time only to update its client wallet... - if (context.usingSegwit && !context.segwitWarningSeen && (p1 == P1_NEXT) && - (p2 != P2_CONTINUE) - // ...if input is not passed as a TrustedInput - && IS_INPUT() && !IS_INPUT_TRUSTED()) { - if (G_called_from_swap) { - /* There is no point in displaying a warning when the app is signing - in silent mode, as its UI is hidden behind the exchange app*/ - return io_send_sw(SW_SWAP_WITHOUT_TRUSTED_INPUTS); - } - context.segwitWarningSeen = 1; - request_segwit_input_approval(); - // Start parsing of the 1st chunk - context.transactionBufferPointer = (uint8_t *)buffer->ptr; - context.transactionDataRemaining = buffer->size; - - transaction_parse(PARSE_MODE_SIGNATURE); - return 0; - } - - // Start parsing of the 1st chunk - context.transactionBufferPointer = (uint8_t *)buffer->ptr; - context.transactionDataRemaining = buffer->size; - - transaction_parse(PARSE_MODE_SIGNATURE); - - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); -} diff --git a/lib-app-bitcoin/handler/hash_sign.c b/lib-app-bitcoin/handler/hash_sign.c deleted file mode 100644 index 33598ef9..00000000 --- a/lib-app-bitcoin/handler/hash_sign.c +++ /dev/null @@ -1,208 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#include "io.h" -#include "ledger_assert.h" -#include "macros.h" -#include "read.h" -#include "swap.h" -#include "write.h" - -#include "apdu_constants.h" -#include "context.h" -#include "display_variables.h" -#include "extensions.h" -#include "helpers.h" -#include "ui.h" - -#define SIGHASH_ALL 0x01 - -#ifndef COIN_FORKID -#define COIN_FORKID 0 -#endif - -/* - * Function: handler_hash_sign - * ---------------------------- - * Handles the signing process for hashing a transaction. - * This function is defined as WEAK and can be overridden in the application own - * sources. - * - * The function verifies parameters handles Zcash-specific scenarios, reads - * transaction parameters, finalizes the hash, checks for path enforcement, and - * initiates signing. It also handles specific cases for Bitcoin Cash and sets - * the appropriate sighash type. After hashing and signing, it sends the - * response. Parameters: - * - buffer: Pointer to the buffer containing transaction data. - * - p1: Instruction parameter 1. - * - p2: Instruction parameter 2. - * - */ -WEAK unsigned short handler_hash_sign(buffer_t *buffer, uint8_t p1, - uint8_t p2) { - unsigned long int lockTime; - uint32_t sighashType; - unsigned char dataBuffer[8]; - unsigned char authorizationLength; - unsigned char *parameters = (uint8_t *)buffer->ptr; - - if ((p1 != 0) || (p2 != 0)) { - return io_send_sw(SW_INCORRECT_P1_P2); - } - -#define HASH_LENGTH 1 + 1 + 4 + 1 - if (buffer->size < HASH_LENGTH) { - return io_send_sw(SW_INCORRECT_LENGTH); - } - - // Zcash special - store parameters for later - - if ((context.usingOverwinter) && (!context.overwinterSignReady) && - (context.segwitParsedOnce) && - (context.transactionContext.transactionState == TRANSACTION_NONE)) { - unsigned long int expiryHeight; - parameters += (4 * buffer->ptr[0]) + 1; - authorizationLength = *(parameters++); - parameters += authorizationLength; - lockTime = read_u32_be(parameters, 0); - parameters += 4; - sighashType = *(parameters++); - expiryHeight = read_u32_be(parameters, 0); - write_u32_le(context.nLockTime, 0, lockTime); - write_u32_le(context.sigHashType, 0, sighashType); - write_u32_le(context.nExpiryHeight, 0, expiryHeight); - context.overwinterSignReady = 1; - return io_send_sw(SW_OK); - } - - if (context.transactionContext.transactionState != TRANSACTION_SIGN_READY) { - PRINTF("Invalid transaction state %d\n", - context.transactionContext.transactionState); - context.transactionContext.transactionState = TRANSACTION_NONE; - return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); - } - - if (context.usingOverwinter && !context.overwinterSignReady) { - PRINTF("Overwinter not ready to sign\n"); - context.transactionContext.transactionState = TRANSACTION_NONE; - return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); - } - - // Read parameters - if (buffer->ptr[0] > MAX_BIP32_PATH) { - context.transactionContext.transactionState = TRANSACTION_NONE; - return io_send_sw(SW_INCORRECT_DATA); - } - memmove(context.transactionSummary.keyPath, buffer->ptr, - MAX_BIP32_PATH_LENGTH); - parameters += (4 * buffer->ptr[0]) + 1; - authorizationLength = *(parameters++); - parameters += authorizationLength; - lockTime = read_u32_be(parameters, 0); - parameters += 4; - sighashType = *(parameters++); - context.transactionSummary.sighashType = sighashType; - - // if bitcoin cash OR forkid is set, then use the fork id - if ((COIN_KIND == COIN_KIND_BITCOIN_CASH) || (COIN_FORKID)) { -#define SIGHASH_FORKID 0x40 - if (sighashType != (SIGHASH_ALL | SIGHASH_FORKID)) { - context.transactionContext.transactionState = TRANSACTION_NONE; - return io_send_sw(SW_INCORRECT_DATA); - } - sighashType |= (COIN_FORKID << 8); - - } else { - if (sighashType != SIGHASH_ALL) { - context.transactionContext.transactionState = TRANSACTION_NONE; - return io_send_sw(SW_INCORRECT_DATA); - } - } - - // Finalize the hash - if (!context.usingOverwinter) { - write_u32_le(dataBuffer, 0, lockTime); - write_u32_le(dataBuffer, 4, sighashType); - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(dataBuffer), dataBuffer); - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - dataBuffer, sizeof(dataBuffer), NULL, 0)) { - context.transactionContext.transactionState = TRANSACTION_NONE; - return io_send_sw(SW_INCORRECT_DATA); - } - } - - // Check if the path needs to be enforced - if (!enforce_bip44_coin_type(context.transactionSummary.keyPath, false)) { - request_sign_path_approval(context.transactionSummary.keyPath); - } else { - // Sign immediately - user_action_signtx(1, 0); - } - if (G_called_from_swap) { - // if we signed all outputs we should exit, - // but only after sending response, so lets raise the - // vars.swap_data.should_exit flag and check it on timer later - vars.swap_data.alreadySignedInputs++; - if (vars.swap_data.alreadySignedInputs >= - vars.swap_data.totalNumberOfInputs) { - vars.swap_data.should_exit = 1; - } - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); - } - return 0; -} - -int user_action_signtx(unsigned char confirming, unsigned char direct) { - // confirm and finish the apdu exchange //spaghetti - if (confirming) { - unsigned char hash[32]; - if (context.usingOverwinter) { - LEDGER_ASSERT( - cx_hash_no_throw(&context.transactionHashFull.blake2b.header, CX_LAST, - hash, 0, hash, 32) == CX_OK, - "Hash Failed"); - } else { - LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashFull.sha256.header, - CX_LAST, hash, 0, hash, 32) == CX_OK, - "Hash Failed"); - PRINTF("Hash1\n%.*H\n", sizeof(hash), hash); - - // Rehash - cx_hash_sha256(hash, sizeof(hash), hash, 32); - } - PRINTF("Hash2\n%.*H\n", sizeof(hash), hash); - // Sign - size_t out_len = sizeof(G_io_apdu_buffer); - sign_finalhash(context.transactionSummary.keyPath, - sizeof(context.transactionSummary.keyPath), hash, - sizeof(hash), G_io_apdu_buffer, &out_len); - - context.outLength = G_io_apdu_buffer[1] + 2; - G_io_apdu_buffer[context.outLength++] = - context.transactionSummary.sighashType; - ui_transaction_finish(); - - } else { - context.outLength = 0; - return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); - } - - if (!direct) { - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, SW_OK); - } - return 0; -} diff --git a/lib-app-bitcoin/handler/sign_message.c b/lib-app-bitcoin/handler/sign_message.c deleted file mode 100644 index 23e0595f..00000000 --- a/lib-app-bitcoin/handler/sign_message.c +++ /dev/null @@ -1,284 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#include "apdu_constants.h" -#include "context.h" -#include "extensions.h" -#include "helpers.h" -#include "io.h" -#include "lib_standard_app/read.h" -#include "swap.h" - -#define P1_PREPARE 0x00 -#define P1_SIGN 0x80 -#define P2_LEGACY 0x00 -#define P2_FIRST 0x01 -#define P2_OTHER 0x80 - -#define BITID_NONE 0 -#define BITID_POWERCYCLE 1 -#define BITID_MULTIPLE 2 - -unsigned char const SIGNMAGIC[] = {' ', 'S', 'i', 'g', 'n', 'e', 'd', ' ', 'M', - 'e', 's', 's', 'a', 'g', 'e', ':', '\n'}; - -// TODO : support longer messages -unsigned char message_check_bit_id(unsigned char *bip32Path) { - unsigned char i; - unsigned char bip32PathLength = bip32Path[0]; - bip32Path++; - for (i = 0; i < bip32PathLength; i++) { - unsigned short account = read_u32_be(bip32Path, 0); - bip32Path += 4; - - if (account == BITID_DERIVE) { - return BITID_POWERCYCLE; - } - if (account == BITID_DERIVE_MULTIPLE) { - return BITID_MULTIPLE; - } - } - return BITID_NONE; -} - -unsigned short message_compute_hash(void) { - unsigned char hash[32]; - unsigned short sw = SW_OK; - - context.outLength = 0; - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, CX_LAST, - hash, 0, hash, 32)) { - goto discard; - } - - if (cx_hash_sha256(hash, sizeof(hash), hash, 32) == 0) { - goto discard; - } - - size_t out_len = 100; - sign_finalhash(context.transactionSummary.keyPath, - sizeof(context.transactionSummary.keyPath), hash, - sizeof(hash), // IN - G_io_apdu_buffer, &out_len); // OUT - context.outLength = G_io_apdu_buffer[1] + 2; - memset(&context.transactionSummary, 0, sizeof(transaction_summary_t)); - return sw; - -discard: - sw = SW_TECHNICAL_PROBLEM_2; - return sw; -} - -static unsigned short sign_message_internal(buffer_t *buffer, uint8_t p1, - uint8_t p2) { - unsigned short sw = SW_OK; - unsigned char apduLength = buffer->size; - unsigned short offset = 0; - - if ((p1 != P1_PREPARE) && (p1 != P1_SIGN)) { - return io_send_sw(SW_INCORRECT_P1_P2); - } - if (p1 == P1_PREPARE) { - if ((p2 != P2_FIRST) && (p2 != P2_OTHER) && (p2 != P2_LEGACY)) { - return io_send_sw(SW_INCORRECT_P1_P2); - } - } - - if (p1 == P1_PREPARE) { - if ((p2 == P2_FIRST) || (p2 == P2_LEGACY)) { - unsigned char chunkLength; - unsigned char messageLength[3]; - unsigned char messageLengthSize; - memset(&context.transactionSummary, 0, sizeof(transaction_summary_t)); - if (buffer->ptr[0] > MAX_BIP32_PATH) { - PRINTF("Invalid path\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - context.transactionSummary.payToAddressVersion = COIN_P2PKH_VERSION; - context.transactionSummary.payToScriptHashVersion = COIN_P2SH_VERSION; - memmove(context.transactionSummary.keyPath, buffer->ptr, - MAX_BIP32_PATH_LENGTH); - offset += (4 * buffer->ptr[0]) + 1; - if (p2 == P2_LEGACY) { - context.transactionSummary.messageLength = buffer->ptr[offset]; - offset++; - } else { - context.transactionSummary.messageLength = - (buffer->ptr[offset] << 8) | (buffer->ptr[offset + 1]); - offset += 2; - } - if (context.transactionSummary.messageLength == 0) { - PRINTF("Null message length\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - context.hashedMessageLength = 0; - - // Horizen signed message magic header is "Zcash" - // See - // https://github.com/HorizenOfficial/zen/blob/v5.0.0/src/main.cpp#L122 - const char *magicHeader = - (COIN_KIND != COIN_KIND_HORIZEN) ? COIN_COINID : "Zcash"; - - cx_sha256_init_no_throw(&context.transactionHashFull.sha256); - cx_sha256_init_no_throw(&context.transactionHashAuthorization); - - chunkLength = strlen(magicHeader) + sizeof(SIGNMAGIC); - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - &chunkLength, 1, NULL, 0)) { - goto discard; - } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - (uint8_t *)magicHeader, strlen(magicHeader), NULL, - 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - (unsigned char *)SIGNMAGIC, sizeof(SIGNMAGIC), NULL, - 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - if (context.transactionSummary.messageLength < 0xfd) { - messageLength[0] = context.transactionSummary.messageLength; - messageLengthSize = 1; - } else { - messageLength[0] = 0xfd; - messageLength[1] = (context.transactionSummary.messageLength & 0xff); - messageLength[2] = - ((context.transactionSummary.messageLength >> 8) & 0xff); - messageLengthSize = 3; - } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - messageLength, messageLengthSize, NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - chunkLength = apduLength - offset; - if ((context.hashedMessageLength + chunkLength) > - context.transactionSummary.messageLength) { - PRINTF("Invalid data length\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - buffer->ptr + offset, chunkLength, NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - if (cx_hash_no_throw(&context.transactionHashAuthorization.header, 0, - buffer->ptr + offset, chunkLength, NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - context.hashedMessageLength += chunkLength; - G_io_apdu_buffer[0] = 0x00; - if (context.hashedMessageLength == - context.transactionSummary.messageLength) { - G_io_apdu_buffer[1] = 0x00; - context.outLength = 2; - } else { - context.outLength = 1; - } - } else { - if ((context.hashedMessageLength + apduLength) > - context.transactionSummary.messageLength) { - PRINTF("Invalid data length\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - buffer->ptr + offset, apduLength, NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - if (cx_hash_no_throw(&context.transactionHashAuthorization.header, 0, - buffer->ptr + offset, apduLength, NULL, 0)) { - sw = SW_TECHNICAL_PROBLEM_2; - goto discard; - } - context.hashedMessageLength += apduLength; - G_io_apdu_buffer[0] = 0x00; - if (context.hashedMessageLength == - context.transactionSummary.messageLength) { - G_io_apdu_buffer[1] = 0x00; - context.outLength = 2; - } else { - context.outLength = 1; - } - } - } else { - if ((context.transactionSummary.messageLength == 0) || - (context.hashedMessageLength != - context.transactionSummary.messageLength)) { - PRINTF("Invalid length to sign\n"); - sw = SW_INCORRECT_DATA; - goto discard; - } - if (message_check_bit_id(context.transactionSummary.keyPath) != - BITID_NONE) { - sw = message_compute_hash(); - } else { - confirm_message_signature(); - return 0; - } - } - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); - -discard: - memset(&context.transactionSummary, 0, sizeof(transaction_summary_t)); - return io_send_sw(sw); -} - -/* - * Function: handler_sign_message - * ------------------------------ - * Handles the signing of a message. - * This function is defined as WEAK and can be overridden in the application own - * sources. - * - * The function checks if called from the swap application, in which case it - * sends an error status code indicating security status not satisfied. All the - * logic for message signing is done in the sign_message_internal function. - * - * Parameters: - * - buffer: Pointer to the buffer containing the message data. - * - p1: Instruction parameter 1. - * - p2: Instruction parameter 2. - * - */ -WEAK unsigned short handler_sign_message(buffer_t *buffer, uint8_t p1, - uint8_t p2) { - if (G_called_from_swap) { - return io_send_sw(SW_SECURITY_STATUS_NOT_SATISFIED); - } - - return sign_message_internal(buffer, p1, p2); -} - -int user_action_message_signing(unsigned char confirming) { - unsigned short sw; - if (confirming) { - sw = message_compute_hash(); - return io_send_response_pointer(G_io_apdu_buffer, context.outLength, sw); - } else { - context.outLength = 0; - return io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); - } -} diff --git a/lib-app-bitcoin/helpers.c b/lib-app-bitcoin/helpers.c deleted file mode 100644 index 2fe38b9f..00000000 --- a/lib-app-bitcoin/helpers.c +++ /dev/null @@ -1,234 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#include "base58.h" -#include "io.h" -#include "ledger_assert.h" -#include "lib_standard_app/bip32.h" -#include "lib_standard_app/crypto_helpers.h" -#include "read.h" - -#include "context.h" -#include "helpers.h" - -void public_key_hash160(unsigned char *in, unsigned short inlen, - unsigned char out[static CX_RIPEMD160_SIZE]) { - unsigned char buffer[CX_SHA256_SIZE]; - cx_hash_sha256(in, inlen, buffer, sizeof(buffer)); - cx_ripemd160_hash(buffer, sizeof(buffer), out); -} - -static void compute_checksum(unsigned char *in, unsigned short inlen, - unsigned char output[static 4]) { - unsigned char checksumBuffer[32]; - cx_hash_sha256(in, inlen, checksumBuffer, 32); - cx_hash_sha256(checksumBuffer, 32, checksumBuffer, 32); - - PRINTF("Checksum\n%.*H\n", 4, checksumBuffer); - memmove(output, checksumBuffer, 4); -} - -unsigned short public_key_to_encoded_base58(unsigned char *in, - unsigned short inlen, - unsigned char *out, - unsigned short outlen, - unsigned short version, - unsigned char alreadyHashed) { - unsigned char tmpBuffer[34]; - - unsigned char versionSize = (version > 255 ? 2 : 1); - short outputLen; - - if (!alreadyHashed) { - PRINTF("To hash\n%.*H\n", inlen, in); - public_key_hash160(in, inlen, tmpBuffer + versionSize); - PRINTF("Hash160\n%.*H\n", 20, (tmpBuffer + versionSize)); - if (version > 255) { - tmpBuffer[0] = (version >> 8); - tmpBuffer[1] = version; - } else { - tmpBuffer[0] = version; - } - } else { - memmove(tmpBuffer, in, 20 + versionSize); - } - - compute_checksum(tmpBuffer, 20 + versionSize, tmpBuffer + 20 + versionSize); - - outputLen = base58_encode(tmpBuffer, 24 + versionSize, (char *)out, outlen); - LEDGER_ASSERT(outputLen >= 0, "Error encoding public key"); - - return outputLen; -} - -void swap_bytes(unsigned char *target, unsigned char *source, - unsigned char size) { - unsigned char i; - for (i = 0; i < size; i++) { - target[i] = source[size - 1 - i]; - } -} - -/* -Checks if the values of a derivation path are within "normal" (arbitrary) -ranges: Account < 100, change == 1 or 0, address index < 50000 -Returns 1 if the path is unusual, or not compliant with BIP44*/ -unsigned char bip44_derivation_guard(const unsigned char *bip32Path, - bool is_change_path) { - unsigned char path_len; - bip32_path_t bip32PathInt; - - path_len = bip32Path[0]; - if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { - return 1; - } - - // If the path length is not compliant with BIP44 or if the purpose don't - // match regular usage, return a warning - if (path_len != BIP44_PATH_LEN || - ((bip32PathInt.path[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 44 && - (bip32PathInt.path[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 49 && - (bip32PathInt.path[BIP44_PURPOSE_OFFSET] ^ 0x80000000) != 84)) { - return 1; - } - - // If the coin type doesn't match, return a warning - if ((BIP44_COIN_TYPE != 0) && (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET] ^ - 0x80000000) != BIP44_COIN_TYPE) && - ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET] ^ - 0x80000000) != BIP44_COIN_TYPE_2))) { - return 1; - } - - // If the account or address index is very high or if the change isn't 1, - // return a warning - if ((bip32PathInt.path[BIP44_ACCOUNT_OFFSET] ^ 0x80000000) > - MAX_BIP44_ACCOUNT_RECOMMENDED || - bip32PathInt.path[BIP44_CHANGE_OFFSET] != is_change_path - ? 1 - : 0 || bip32PathInt.path[BIP44_ADDRESS_INDEX_OFFSET] > - MAX_BIP44_ADDRESS_INDEX_RECOMMENDED) { - return 1; - } - - return 0; -} - -/* -Only enforce the structure or coin type for consumed UTXOs or a public address -Returns 0 if the path is non compliant, or 1 if compliant -*/ -unsigned char enforce_bip44_coin_type(const unsigned char *bip32Path, - bool for_pubkey) { - bip32_path_t bip32PathInt; - // No enforcement required - if (BIP44_COIN_TYPE == 0) { - return 1; - } - // Path is too short - always require a user validation if signing - if (bip32Path[0] < 2) { - return for_pubkey; - } - - if (!parse_serialized_path(&bip32PathInt, bip32Path, MAX_BIP32_PATH_LENGTH)) { - return 1; - } - - // Path is not compliant with BIP 44 or derivatives - valid if not signing - if (!(((bip32PathInt.path[BIP44_PURPOSE_OFFSET] ^ 0x80000000) == 44 || - (bip32PathInt.path[BIP44_PURPOSE_OFFSET] ^ 0x80000000) == 49 || - (bip32PathInt.path[BIP44_PURPOSE_OFFSET] ^ 0x80000000) == 84))) { - return for_pubkey; - } - - if (((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET] ^ 0x80000000) == - BIP44_COIN_TYPE) || - ((bip32PathInt.path[BIP44_COIN_TYPE_OFFSET] ^ 0x80000000) == - BIP44_COIN_TYPE_2)) { - // Valid BIP 44 path - return 1; - } - // Everything else needs a user validation - return 0; -} - -int sign_finalhash(unsigned char *path, size_t path_len, unsigned char *in, - unsigned short inlen, unsigned char *out, size_t *outlen) { - - unsigned int info = 0; - - io_seproxyhal_io_heartbeat(); - - bip32_path_t bip32Path; - bip32Path.length = path[0]; - - if (!parse_serialized_path(&bip32Path, path, path_len)) { - return -1; - } - - if (bip32_derive_ecdsa_sign_hash_256(CX_CURVE_SECP256K1, bip32Path.path, - bip32Path.length, - CX_LAST | CX_RND_RFC6979, CX_SHA256, in, - inlen, out, outlen, &info) != CX_OK) { - return -1; - } - - // Store information about the parity of the 'y' coordinate - if (info & CX_ECCINFO_PARITY_ODD) { - out[0] |= 0x01; - } - - io_seproxyhal_io_heartbeat(); - return 0; -} - -int get_public_key(const unsigned char *keyPath, size_t keyPath_len, - uint8_t raw_pubkey[static 65], unsigned char *chainCode) { - - bip32_path_t bip32Path; - - if (!parse_serialized_path(&bip32Path, keyPath, keyPath_len)) { - return -1; - } - - if (bip32_derive_get_pubkey_256(CX_CURVE_SECP256K1, bip32Path.path, - bip32Path.length, raw_pubkey, chainCode, - CX_SHA512) != CX_OK) { - return -1; - } - - return 0; -} - -void compress_public_key_value(unsigned char *value) { - bool odd = (value[64] & 1); - value[0] = odd ? 0x03 : 0x02; -} - -bool parse_serialized_path(bip32_path_t *path, - const unsigned char *serialized_path, - unsigned char serialized_path_length) { - if (serialized_path_length < 1 || serialized_path[0] > MAX_BIP32_PATH || - serialized_path[0] * 4 + 1 > serialized_path_length) - return false; - path->length = serialized_path[0]; - serialized_path++; - for (int i = 0; i < path->length; i += 1, serialized_path += 4) { - path->path[i] = read_u32_be(serialized_path, 0); - } - return true; -} diff --git a/lib-app-bitcoin/helpers.h b/lib-app-bitcoin/helpers.h deleted file mode 100644 index 9c100a83..00000000 --- a/lib-app-bitcoin/helpers.h +++ /dev/null @@ -1,61 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#pragma once - -#include "cx.h" -#include "filesystem_tx.h" -#include "os.h" -#include "stdbool.h" - -#define OUTPUT_SCRIPT_REGULAR_PRE_LENGTH 4 -#define OUTPUT_SCRIPT_REGULAR_POST_LENGTH 2 -#define OUTPUT_SCRIPT_P2SH_PRE_LENGTH 3 -#define OUTPUT_SCRIPT_P2SH_POST_LENGTH 1 - -#define OUTPUT_SCRIPT_NATIVE_WITNESS_PROGRAM_OFFSET 3 - -typedef struct bip32_path { - unsigned char length; - unsigned int path[MAX_BIP32_PATH]; -} bip32_path_t; - -void public_key_hash160(unsigned char *in, unsigned short inlen, - unsigned char out[static CX_RIPEMD160_SIZE]); -unsigned short public_key_to_encoded_base58( - unsigned char *in, unsigned short inlen, unsigned char *out, - unsigned short outlen, unsigned short version, unsigned char alreadyHashed); - -unsigned char bip44_derivation_guard(const unsigned char *bip32Path, - bool is_change_path); -unsigned char enforce_bip44_coin_type(const unsigned char *bip32Path, - bool for_pubkey); - -void swap_bytes(unsigned char *target, unsigned char *source, - unsigned char size); - -int sign_finalhash(unsigned char *path, size_t path_len, unsigned char *in, - unsigned short inlen, unsigned char *out, size_t *outlen); - -int get_public_key(const unsigned char *keyPath, size_t keyPath_len, - uint8_t raw_pubkey[static 65], unsigned char *chainCode); - -void compress_public_key_value(unsigned char *value); - -bool parse_serialized_path(bip32_path_t *path, - const unsigned char *serialized_path, - unsigned char serialized_path_length); diff --git a/lib-app-bitcoin/swap/handle_check_address.c b/lib-app-bitcoin/swap/handle_check_address.c deleted file mode 100644 index 7b8e7f0b..00000000 --- a/lib-app-bitcoin/swap/handle_check_address.c +++ /dev/null @@ -1,139 +0,0 @@ -#include "handle_check_address.h" -#include "cashaddr.h" -#include "context.h" -#include "helpers.h" -#include "segwit_addr.h" - -#define P1_NO_DISPLAY 0x00 -#define P1_DISPLAY 0x01 -#define P1_REQUEST_TOKEN 0x02 - -#define P2_LEGACY 0x00 -#define P2_SEGWIT 0x01 -#define P2_NATIVE_SEGWIT 0x02 -#define P2_CASHADDR 0x03 - -static bool derive_compressed_public_key(unsigned char *serialized_path, - unsigned char serialized_path_length, - unsigned char *public_key, - unsigned char public_key_length) { - UNUSED(public_key_length); - uint8_t pubKey[65]; - - if (get_public_key(serialized_path, serialized_path_length, pubKey, NULL)) { - return false; - } - - compress_public_key_value(pubKey); - memcpy(public_key, pubKey, 33); - return true; -} - -static bool get_address_from_compressed_public_key( - unsigned char format, unsigned char *compressed_pub_key, - unsigned short payToAddressVersion, unsigned short payToScriptHashVersion, - const char *native_segwit_prefix, char *address, - unsigned char max_address_length) { - bool segwit = (format == P2_SEGWIT); - bool nativeSegwit = (format == P2_NATIVE_SEGWIT); - bool cashAddr = (format == P2_CASHADDR); - int address_length; - if (cashAddr) { - uint8_t tmp[20]; - public_key_hash160(compressed_pub_key, // IN - 33, // INLEN - tmp); - if (!cashaddr_encode(tmp, 20, (uint8_t *)address, max_address_length, - CASHADDR_P2PKH)) - return false; - } else if (!(segwit || nativeSegwit)) { - // public_key_to_encoded_base58 doesn't add terminating 0, - // so we will do this ourself - address_length = - public_key_to_encoded_base58(compressed_pub_key, // IN - 33, // INLEN - (uint8_t *)address, // OUT - max_address_length - 1, // MAXOUTLEN - payToAddressVersion, 0); - address[address_length] = 0; - } else { - uint8_t tmp[22]; - tmp[0] = 0x00; - tmp[1] = 0x14; - public_key_hash160(compressed_pub_key, // IN - 33, // INLEN - tmp + 2 // OUT - ); - if (!nativeSegwit) { - address_length = public_key_to_encoded_base58(tmp, // IN - 22, // INLEN - (uint8_t *)address, // OUT - 150, // MAXOUTLEN - payToScriptHashVersion, 0); - address[address_length] = 0; - } else { - if (!native_segwit_prefix) - return false; - if (!segwit_addr_encode(address, native_segwit_prefix, 0, tmp + 2, 20)) { - return false; - } - } - } - return true; -} - -void swap_handle_check_address(check_address_parameters_t *params) { - PRINTF("Inside swap_handle_check_address\n"); - params->result = 0; - - if (params->address_parameters == NULL) { - PRINTF("derivation path expected\n"); - return; - } - - if (params->address_to_check == NULL) { - PRINTF("Address to check expected\n"); - return; - } - PRINTF("Address to check %s\n", params->address_to_check); - - if (params->extra_id_to_check == NULL) { - PRINTF("extra_id_to_check expected\n"); - return; - } else if (params->extra_id_to_check[0] != '\0') { - PRINTF("extra_id_to_check expected empty, not '%s'\n", - params->extra_id_to_check); - return; - } - - if (params->address_to_check == 0) { - PRINTF("Address to check == 0\n"); - return; - } - - unsigned char compressed_public_key[33]; - if (!derive_compressed_public_key( - params->address_parameters + 1, params->address_parameters_length - 1, - compressed_public_key, sizeof(compressed_public_key))) { - PRINTF("Failed to derive public key\n"); - return; - } - - char address[51]; - if (!get_address_from_compressed_public_key( - params->address_parameters[0], compressed_public_key, - COIN_P2PKH_VERSION, COIN_P2SH_VERSION, COIN_NATIVE_SEGWIT_PREFIX, - address, sizeof(address))) { - PRINTF("Can't create address from given public key\n"); - return; - } - if (strcmp(params->address_to_check, address) != 0) { - PRINTF("Address %s != %s\n", params->address_to_check, address); - return; - } - - PRINTF("Addresses match\n"); - - params->result = 1; - return; -} \ No newline at end of file diff --git a/lib-app-bitcoin/swap/handle_check_address.h b/lib-app-bitcoin/swap/handle_check_address.h deleted file mode 100644 index 95361a26..00000000 --- a/lib-app-bitcoin/swap/handle_check_address.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _HANDLE_CHECK_ADDRESS_H_ -#define _HANDLE_CHECK_ADDRESS_H_ - -#include "swap_lib_calls.h" - -void swap_handle_check_address( - check_address_parameters_t *check_address_params); - -#endif // _HANDLE_CHECK_ADDRESS_H_ \ No newline at end of file diff --git a/lib-app-bitcoin/swap/handle_get_printable_amount.c b/lib-app-bitcoin/swap/handle_get_printable_amount.c deleted file mode 100644 index c6834598..00000000 --- a/lib-app-bitcoin/swap/handle_get_printable_amount.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "read.h" - -#include "display_utils.h" -#include "handle_get_printable_amount.h" - -void swap_handle_get_printable_amount( - get_printable_amount_parameters_t *params) { - params->printable_amount[0] = 0; - if (params->amount_length > 8) { - PRINTF("Amount is too big"); - return; - } - unsigned char amount[8]; - memset(amount, 0, 8); - memcpy(amount + (8 - params->amount_length), params->amount, - params->amount_length); - - format_sats_amount( - COIN_COINID_SHORT, - (uint64_t)(read_u64_be(amount, 0)), // Cast prevents weird compilo bug - params->printable_amount); - return; -} \ No newline at end of file diff --git a/lib-app-bitcoin/swap/handle_get_printable_amount.h b/lib-app-bitcoin/swap/handle_get_printable_amount.h deleted file mode 100644 index 2718126c..00000000 --- a/lib-app-bitcoin/swap/handle_get_printable_amount.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _HANDLE_GET_PRINTABLE_AMOUNT_H_ -#define _HANDLE_GET_PRINTABLE_AMOUNT_H_ - -#include "context.h" -#include "swap_lib_calls.h" - -void swap_handle_get_printable_amount( - get_printable_amount_parameters_t *get_printable_amount_params); - -#endif // _HANDLE_GET_PRINTABLE_AMOUNT_H_ \ No newline at end of file diff --git a/lib-app-bitcoin/swap/handle_swap_sign_transaction.c b/lib-app-bitcoin/swap/handle_swap_sign_transaction.c deleted file mode 100644 index e30abb58..00000000 --- a/lib-app-bitcoin/swap/handle_swap_sign_transaction.c +++ /dev/null @@ -1,77 +0,0 @@ -#include "handle_swap_sign_transaction.h" -#include "context.h" -#include "display_variables.h" -#include "os_io_seproxyhal.h" -#include "usbd_core.h" -#include "ux.h" - -#ifdef HAVE_NBGL -#include "nbgl_use_case.h" -#endif - -#include "swap.h" - -// Save the BSS address where we will write the return value when finished -static uint8_t *G_swap_sign_return_value_address; - -bool swap_copy_transaction_parameters(create_transaction_parameters_t *params) { - PRINTF("Inside swap_copy_transaction_parameters\n"); - - // Ensure no extraid - if (params->destination_address_extra_id == NULL) { - PRINTF("destination_address_extra_id expected\n"); - return false; - } else if (params->destination_address_extra_id[0] != '\0') { - PRINTF("destination_address_extra_id expected empty, not '%s'\n", - params->destination_address_extra_id); - return false; - } - - // We need this "trick" as the input data position can overlap with app - // globals and also because we want to memset the whole bss segment as it is - // not done when an app is called as a lib. This is necessary as many part of - // the code expect bss variables to initialized at 0. - swap_data_t swap_validated; - memset(&swap_validated, 0, sizeof(swap_validated)); - - // Save recipient - strlcpy(swap_validated.destination_address, params->destination_address, - sizeof(swap_validated.destination_address)); - if (swap_validated - .destination_address[sizeof(swap_validated.destination_address) - - 1] != '\0') { - return false; - } - - // store amount as big endian in 8 bytes, so the passed data should be - // alligned to right input {0xEE, 0x00, 0xFF} should be stored like {0x00, - // 0x00, 0x00, 0x00, 0x00, 0xEE, 0x00, 0xFF} - memcpy(swap_validated.amount + 8 - params->amount_length, params->amount, - params->amount_length); - memcpy(swap_validated.fees + 8 - params->fee_amount_length, - params->fee_amount, params->fee_amount_length); - - // Save amount and fees - // swap_str_to_u64(params->amount, params->amount_length, - // &swap_validated.amount); swap_str_to_u64(params->fee_amount, - // params->fee_amount_length, &swap_validated.fees); - // - swap_validated.initialized = true; - - // Full reset the global variables - os_explicit_zero_BSS_segment(); - - // Keep the address at which we'll reply the signing status - G_swap_sign_return_value_address = ¶ms->result; - - // Copy from stack back to global data segment - memcpy(&vars.swap_data, &swap_validated, sizeof(swap_validated)); - swap_validated.initialized = true; - return true; -} - -void __attribute__((noreturn)) -swap_finalize_exchange_sign_transaction(bool is_success) { - *G_swap_sign_return_value_address = is_success; - os_lib_end(); -} diff --git a/lib-app-bitcoin/swap/handle_swap_sign_transaction.h b/lib-app-bitcoin/swap/handle_swap_sign_transaction.h deleted file mode 100644 index 7b3d12e3..00000000 --- a/lib-app-bitcoin/swap/handle_swap_sign_transaction.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _HANDLE_SWAP_SIGN_TRANSACTION_H_ -#define _HANDLE_SWAP_SIGN_TRANSACTION_H_ - -#include "swap_lib_calls.h" - -bool swap_copy_transaction_parameters( - create_transaction_parameters_t *sign_transaction_params); - -void __attribute__((noreturn)) -swap_finalize_exchange_sign_transaction(bool is_success); - -#endif // _HANDLE_SWAP_SIGN_TRANSACTION_H_ diff --git a/lib-app-bitcoin/transaction.c b/lib-app-bitcoin/transaction.c deleted file mode 100644 index 2d6b0e1e..00000000 --- a/lib-app-bitcoin/transaction.c +++ /dev/null @@ -1,890 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#include "ledger_assert.h" -#include "lib_standard_app/read.h" -#include "lib_standard_app/write.h" -#include "swap.h" - -#include "apdu_constants.h" -#include "be_operations.h" -#include "context.h" -#include "display_variables.h" -#include "filesystem.h" -#include "helpers.h" -#include "transaction.h" - -#ifndef COIN_CONSENSUS_BRANCH_ID -#define COIN_CONSENSUS_BRANCH_ID 0 -#endif - -#define CONSENSUS_BRANCH_ID_OVERWINTER 0x5ba81b19 -#define CONSENSUS_BRANCH_ID_SAPLING 0x76b809bb -#define CONSENSUS_BRANCH_ID_ZCLASSIC 0x930b540d - -unsigned char const OVERWINTER_PARAM_PREVOUTS[16] = { - 'Z', 'c', 'a', 's', 'h', 'P', 'r', 'e', - 'v', 'o', 'u', 't', 'H', 'a', 's', 'h'}; -unsigned char const OVERWINTER_PARAM_SEQUENCE[16] = { - 'Z', 'c', 'a', 's', 'h', 'S', 'e', 'q', - 'u', 'e', 'n', 'c', 'H', 'a', 's', 'h'}; -unsigned char const OVERWINTER_PARAM_OUTPUTS[16] = { - 'Z', 'c', 'a', 's', 'h', 'O', 'u', 't', - 'p', 'u', 't', 's', 'H', 'a', 's', 'h'}; -unsigned char const OVERWINTER_PARAM_SIGHASH[16] = { - 'Z', 'c', 'a', 's', 'h', 'S', 'i', 'g', 'H', 'a', 's', 'h', 0, 0, 0, 0}; -unsigned char const OVERWINTER_NO_JOINSPLITS[32] = { - 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}; - -// Check if fOverwintered flag is set and if nVersion is >= 0x03 -#define TRUSTED_INPUT_OVERWINTER \ - ((COIN_KIND == COIN_KIND_ZCASH || COIN_KIND == COIN_KIND_ZCLASSIC || \ - COIN_KIND == COIN_KIND_KOMODO) && \ - (read_u32_le(context.transactionVersion, 0) & (1 << 31)) && \ - (read_u32_le(context.transactionVersion, 0) ^ (1 << 31)) >= 0x03) - -static void check_transaction_available(unsigned char x) { - LEDGER_ASSERT(context.transactionDataRemaining >= x, - "Check transaction available failed %d < %d\n", - context.transactionDataRemaining, x); -} - -#define OP_HASH160 0xA9 -#define OP_EQUAL 0x87 -#define OP_CHECKMULTISIG 0xAE - -static void transaction_offset(unsigned char value) { - if ((context.transactionHashOption & TRANSACTION_HASH_FULL) != 0) { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", value, - context.transactionBufferPointer); - if (context.usingOverwinter) { - LEDGER_ASSERT( - cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, - context.transactionBufferPointer, value, NULL, - 0) == CX_OK, - "Hash Failed"); - } else { - LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashFull.sha256.header, - 0, context.transactionBufferPointer, value, - NULL, 0) == CX_OK, - "Hash Failed"); - } - } - if ((context.transactionHashOption & TRANSACTION_HASH_AUTHORIZATION) != 0) { - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", value, - context.transactionBufferPointer); - LEDGER_ASSERT(cx_hash_no_throw(&context.transactionHashAuthorization.header, - 0, context.transactionBufferPointer, value, - NULL, 0) == CX_OK, - "Hash Failed"); - } -} - -static void transaction_offset_increase(unsigned char value) { - transaction_offset(value); - context.transactionBufferPointer += value; - context.transactionDataRemaining -= value; -} - -static unsigned long int transaction_get_varint(void) { - unsigned char firstByte; - check_transaction_available(1); - firstByte = *context.transactionBufferPointer; - if (firstByte < 0xFD) { - transaction_offset_increase(1); - return firstByte; - } else if (firstByte == 0xFD) { - unsigned long int result; - transaction_offset_increase(1); - check_transaction_available(2); - result = - (unsigned long int)(*context.transactionBufferPointer) | - ((unsigned long int)(*(context.transactionBufferPointer + 1)) << 8); - transaction_offset_increase(2); - return result; - } else if (firstByte == 0xFE) { - unsigned long int result; - transaction_offset_increase(1); - check_transaction_available(4); - result = read_u32_le(context.transactionBufferPointer, 0); - transaction_offset_increase(4); - return result; - } else { - LEDGER_ASSERT(false, "Varint parsing failed"); - __builtin_unreachable(); - } -} - -void transaction_parse(unsigned char parseMode) { - for (;;) { - switch (context.transactionContext.transactionState) { - case TRANSACTION_NONE: { - PRINTF("Init transaction parser\n"); - // Reset transaction state - context.transactionContext.transactionRemainingInputsOutputs = 0; - context.transactionContext.transactionCurrentInputOutput = 0; - context.transactionContext.scriptRemaining = 0; - memset(context.transactionContext.transactionAmount, 0, - sizeof(context.transactionContext.transactionAmount)); - // TODO : transactionControlFid - // Reset hashes - if (context.usingOverwinter) { - if (context.segwitParsedOnce) { - uint8_t parameters[16]; - memmove(parameters, OVERWINTER_PARAM_SIGHASH, 16); - if (COIN_KIND == COIN_KIND_ZCLASSIC) { - write_u32_le(parameters, 12, CONSENSUS_BRANCH_ID_ZCLASSIC); - } else { - write_u32_le(parameters, 12, - context.usingOverwinter == - ZCASH_USING_OVERWINTER_SAPLING - ? (COIN_CONSENSUS_BRANCH_ID != 0 - ? COIN_CONSENSUS_BRANCH_ID - : CONSENSUS_BRANCH_ID_SAPLING) - : CONSENSUS_BRANCH_ID_OVERWINTER); - } - if (cx_blake2b_init2_no_throw(&context.transactionHashFull.blake2b, - 256, NULL, 0, parameters, 16)) { - goto fail; - } - } - } else { - if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { - goto fail; - } - } - if (cx_sha256_init_no_throw(&context.transactionHashAuthorization)) { - goto fail; - } - if (context.usingSegwit) { - context.transactionHashOption = 0; - if (!context.segwitParsedOnce) { - if (context.usingOverwinter) { - if (cx_blake2b_init2_no_throw( - &context.segwit.hash.hashPrevouts.blake2b, 256, NULL, 0, - (uint8_t *)OVERWINTER_PARAM_PREVOUTS, 16)) { - goto fail; - } - if (cx_blake2b_init2_no_throw( - &context.transactionHashFull.blake2b, 256, NULL, 0, - (uint8_t *)OVERWINTER_PARAM_SEQUENCE, 16)) { - goto fail; - } - } else { - if (cx_sha256_init_no_throw( - &context.segwit.hash.hashPrevouts.sha256)) { - goto fail; - } - } - } else { - PRINTF("Resume SegWit hash\n"); - PRINTF("SEGWIT Version\n%.*H\n", sizeof(context.transactionVersion), - context.transactionVersion); - PRINTF("SEGWIT HashedPrevouts\n%.*H\n", - sizeof(context.segwit.cache.hashedPrevouts), - context.segwit.cache.hashedPrevouts); - PRINTF("SEGWIT HashedSequence\n%.*H\n", - sizeof(context.segwit.cache.hashedSequence), - context.segwit.cache.hashedSequence); - if (context.usingOverwinter) { - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, - context.transactionVersion, - sizeof(context.transactionVersion), NULL, 0)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, - context.nVersionGroupId, - sizeof(context.nVersionGroupId), NULL, 0)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, - context.segwit.cache.hashedPrevouts, - sizeof(context.segwit.cache.hashedPrevouts), - NULL, 0)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, - context.segwit.cache.hashedSequence, - sizeof(context.segwit.cache.hashedSequence), - NULL, 0)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, - context.segwit.cache.hashedOutputs, - sizeof(context.segwit.cache.hashedOutputs), - NULL, 0)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, - OVERWINTER_NO_JOINSPLITS, 32, NULL, 0)) { - goto fail; - } - if (context.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, - 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, - 0)) { // sapling hashShieldedSpend) - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, - 0, OVERWINTER_NO_JOINSPLITS, 32, NULL, - 0)) { // sapling hashShieldedOutputs - goto fail; - } - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, - context.nLockTime, sizeof(context.nLockTime), - NULL, 0)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, - context.nExpiryHeight, - sizeof(context.nExpiryHeight), NULL, 0)) { - goto fail; - } - if (context.usingOverwinter == ZCASH_USING_OVERWINTER_SAPLING) { - unsigned char valueBalance[8]; - memset(valueBalance, 0, sizeof(valueBalance)); - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, - 0, valueBalance, sizeof(valueBalance), NULL, - 0)) { // sapling valueBalance - goto fail; - } - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, - context.sigHashType, - sizeof(context.sigHashType), NULL, 0)) { - goto fail; - } - } else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", - sizeof(context.transactionVersion), - context.transactionVersion); - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - context.transactionVersion, - sizeof(context.transactionVersion), NULL, 0)) { - goto fail; - } - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", - sizeof(context.segwit.cache.hashedPrevouts), - context.segwit.cache.hashedPrevouts); - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - context.segwit.cache.hashedPrevouts, - sizeof(context.segwit.cache.hashedPrevouts), - NULL, 0)) { - goto fail; - } - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", - sizeof(context.segwit.cache.hashedSequence), - context.segwit.cache.hashedSequence); - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - context.segwit.cache.hashedSequence, - sizeof(context.segwit.cache.hashedSequence), - NULL, 0)) { - goto fail; - } - PRINTF("--- ADD TO HASH AUTH:\n%.*H\n", - sizeof(context.segwit.cache), - (unsigned char *)&context.segwit.cache); - if (cx_hash_no_throw(&context.transactionHashAuthorization.header, - 0, (unsigned char *)&context.segwit.cache, - sizeof(context.segwit.cache), NULL, 0)) { - goto fail; - } - } - } - } - // Parse the beginning of the transaction - // Version - check_transaction_available(4); - memmove(context.transactionVersion, context.transactionBufferPointer, 4); - transaction_offset_increase(4); - - if (context.usingOverwinter || TRUSTED_INPUT_OVERWINTER) { - // nVersionGroupId - check_transaction_available(4); - memmove(context.nVersionGroupId, context.transactionBufferPointer, 4); - transaction_offset_increase(4); - } - - if (COIN_FLAGS & FLAG_PEERCOIN_SUPPORT) { - if (((COIN_FAMILY == FAMILY_PEERCOIN && - (context.transactionVersion[0] < 3))) || - ((COIN_FAMILY == FAMILY_STEALTH) && - (context.transactionVersion[0] < 2))) { - // Timestamp - check_transaction_available(4); - transaction_offset_increase(4); - } - } - - // Number of inputs - context.transactionContext.transactionRemainingInputsOutputs = - transaction_get_varint(); - PRINTF("Number of inputs : %d\n", - context.transactionContext.transactionRemainingInputsOutputs); - if (G_called_from_swap && parseMode == PARSE_MODE_SIGNATURE) { - // remember number of inputs to know when to exit from library - // we will count number of already signed inputs and compare with this - // value As there are a lot of different states in which we can have - // different number of input (when for ex. we sign segregated witness) - if (vars.swap_data.totalNumberOfInputs == 0) { - vars.swap_data.totalNumberOfInputs = - context.transactionContext.transactionRemainingInputsOutputs; - } - // Reseting the flag, because we should check address ones for each - // input - vars.swap_data.was_address_checked = 0; - } - // Ready to proceed - context.transactionContext.transactionState = - TRANSACTION_DEFINED_WAIT_INPUT; - - __attribute__((fallthrough)); - } - - case TRANSACTION_DEFINED_WAIT_INPUT: { - unsigned char trustedInputFlag = 1; - PRINTF("Process input\n"); - if (context.transactionContext.transactionRemainingInputsOutputs == 0) { - // No more inputs to hash, move forward - context.transactionContext.transactionState = - TRANSACTION_INPUT_HASHING_DONE; - continue; - } - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Proceed with the next input - if (parseMode == PARSE_MODE_TRUSTED_INPUT) { - check_transaction_available(36); // prevout : 32 hash + 4 index - transaction_offset_increase(36); - } - if (parseMode == PARSE_MODE_SIGNATURE) { - unsigned char trustedInputLength; - unsigned char trustedInput[TRUSTED_INPUT_TOTAL_SIZE]; - unsigned char amount[8]; - unsigned char *savePointer; - - // Expect the trusted input flag and trusted input length - check_transaction_available(2); - switch (*context.transactionBufferPointer) { - case 0: - if (context.usingSegwit) { - PRINTF("Non trusted input used in segwit mode\n"); - goto fail; - } - trustedInputFlag = 0; - break; - case 1: - if (context.usingSegwit) { - // Segwit inputs can be passed as TrustedInput also - PRINTF("Trusted input used in segwit mode\n"); - } - trustedInputFlag = 1; - break; - case 2: - if (!context.usingSegwit) { - PRINTF("Segwit input not used in segwit mode\n"); - goto fail; - } - trustedInputFlag = 0; - break; - default: - PRINTF("Invalid trusted input flag\n"); - goto fail; - } - // Check TrustedInput (TI) integrity, be it a non-segwit TI or a segwit - // TI - if (trustedInputFlag) { - trustedInputLength = *(context.transactionBufferPointer + 1); - if ((trustedInputLength > sizeof(trustedInput)) || - (trustedInputLength < 8)) { - PRINTF("Invalid trusted input size\n"); - goto fail; - } - - check_transaction_available(2 + trustedInputLength); - // Check TrustedInput Hmac - cx_hmac_sha256((uint8_t *)g_nvram_data.bkp.trustedinput_key, - sizeof(g_nvram_data.bkp.trustedinput_key), - context.transactionBufferPointer + 2, - trustedInputLength - 8, trustedInput, - trustedInputLength); - PRINTF("====> Input HMAC: %.*H\n", 8, - context.transactionBufferPointer + 2 + trustedInputLength - 8); - PRINTF("====> Computed HMAC: %.*H\n", 8, trustedInput); - - if (os_secure_memcmp(trustedInput, // Contains computed Hmac for now - context.transactionBufferPointer + 2 + - trustedInputLength - 8, - 8) != 0) { - PRINTF("Invalid signature\n"); - goto fail; - } - // Hmac is valid. If TrustedInput contains a segwit input, update data - // pointer & length to fake the parser into believing a normal segwit - // input was received. Do not use transaction_offset_increase() here - // as it could update the hash being computed. - if (context.usingSegwit) { - // Overwrite the no longer needed HMAC's 1st byte w/ the input - // script length byte. - *(context.transactionBufferPointer + 1 + TRUSTED_INPUT_SIZE + 1) = - *(context.transactionBufferPointer + 1 + - TRUSTED_INPUT_TOTAL_SIZE + 1); - // Set tx data pointer on TI header's (i.e. 0x38||0x32||0x00||Nonce - // (2B)) last byte before prevout tx hash. Also remove HMAC size - // from remaining data length. - context.transactionBufferPointer += 5; - context.transactionDataRemaining -= (5 + 8); - } - } - // Handle pure segwit inputs, whether trusted or not (i.e. - // InputHashStart 1st APDU's P2==02 & data[0]=={0x01, 0x02}) - if (context.usingSegwit) { - transaction_offset_increase(1); // Set tx pointer on 1st byte of hash - check_transaction_available(36); // prevout : 32 hash + 4 index - if (!context.segwitParsedOnce) { - if (context.usingOverwinter) { - if (cx_hash_no_throw( - &context.segwit.hash.hashPrevouts.blake2b.header, 0, - context.transactionBufferPointer, 36, NULL, 0)) { - goto fail; - } - } else { - if (cx_hash_no_throw( - &context.segwit.hash.hashPrevouts.sha256.header, 0, - context.transactionBufferPointer, 36, NULL, 0)) { - goto fail; - } - } - transaction_offset_increase(36); - check_transaction_available(8); // update amount - swap_bytes(amount, context.transactionBufferPointer, 8); - if (transaction_amount_add_be( - context.transactionContext.transactionAmount, - context.transactionContext.transactionAmount, amount)) { - PRINTF("Overflow\n"); - goto fail; - } - PRINTF("Adding amount\n%.*H\n", 8, - context.transactionBufferPointer); - PRINTF("New amount\n%.*H\n", 8, - context.transactionContext.transactionAmount); - transaction_offset_increase(8); - } else { - context.transactionHashOption = TRANSACTION_HASH_FULL; - transaction_offset_increase(36); - context.transactionHashOption = 0; - check_transaction_available(8); // save amount - memmove(context.inputValue, context.transactionBufferPointer, 8); - transaction_offset_increase(8); - context.transactionHashOption = TRANSACTION_HASH_FULL; - } - } - // Handle non-segwit inputs (i.e. InputHashStart 1st APDU's P2==00 && - // data[0]==0x00) - else if (!trustedInputFlag) { - PRINTF("Untrusted input not authorized\n"); - goto fail; - } - // Handle non-segwit TrustedInput (i.e. InputHashStart 1st APDU's P2==00 - // & data[0]==0x01) - else if (trustedInputFlag && !context.usingSegwit) { - memmove(trustedInput, context.transactionBufferPointer + 2, - trustedInputLength - 8); - if (trustedInput[0] != MAGIC_TRUSTED_INPUT) { - PRINTF("Failed to verify trusted input signature\n"); - goto fail; - } - // Update the hash with prevout data - savePointer = context.transactionBufferPointer; - context.transactionBufferPointer = trustedInput + 4; - PRINTF("Trusted input hash\n%.*H\n", 36, - context.transactionBufferPointer); - transaction_offset(36); - - context.transactionBufferPointer = - savePointer + (2 + trustedInputLength); - context.transactionDataRemaining -= (2 + trustedInputLength); - - // Update the amount - - swap_bytes(amount, trustedInput + 40, 8); - if (transaction_amount_add_be( - context.transactionContext.transactionAmount, - context.transactionContext.transactionAmount, amount)) { - PRINTF("Overflow\n"); - goto fail; - } - - PRINTF("Adding amount\n%.*H\n", 8, (trustedInput + 40)); - PRINTF("New amount\n%.*H\n", 8, - context.transactionContext.transactionAmount); - } - - if (!context.usingSegwit) { - // Do not include the input script length + value in - // the authentication hash - context.transactionHashOption = TRANSACTION_HASH_FULL; - } - } - // Read the script length - context.transactionContext.scriptRemaining = transaction_get_varint(); - PRINTF("Script to read %d\n", context.transactionContext.scriptRemaining); - - if ((parseMode == PARSE_MODE_SIGNATURE) && !trustedInputFlag && - !context.usingSegwit) { - // Only proceeds if this is not to be signed - so length - // should be null - if (context.transactionContext.scriptRemaining != 0) { - PRINTF("Request to sign relaxed input\n"); - goto fail; - } - } - // Move on - context.transactionContext.transactionState = - TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT; - - __attribute__((fallthrough)); - } - case TRANSACTION_INPUT_HASHING_IN_PROGRESS_INPUT_SCRIPT: { - unsigned char dataAvailable; - PRINTF("Process input script, remaining %d\n", - context.transactionContext.scriptRemaining); - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Scan for P2SH consumption - huge shortcut, but fine - // enough - // Also usable in SegWit mode - if (context.transactionContext.scriptRemaining == 1) { - if (*context.transactionBufferPointer == OP_CHECKMULTISIG) { - PRINTF("Marking P2SH consumption\n"); - context.transactionContext.consumeP2SH = 1; - } else { - // When using the P2SH shortcut, all inputs must use - // P2SH - PRINTF("Disabling P2SH consumption\n"); - context.transactionContext.consumeP2SH = 0; - } - transaction_offset_increase(1); - context.transactionContext.scriptRemaining--; - } - - if (context.transactionContext.scriptRemaining == 0) { - if (parseMode == PARSE_MODE_SIGNATURE) { - if (!context.usingSegwit) { - // Restore dual hash for signature + - // authentication - context.transactionHashOption = TRANSACTION_HASH_BOTH; - } else { - if (context.segwitParsedOnce) { - // Append the saved value - PRINTF("SEGWIT Add value\n%.*H\n", 8, context.inputValue); - if (context.usingOverwinter) { - if (cx_hash_no_throw( - &context.transactionHashFull.blake2b.header, 0, - context.inputValue, 8, NULL, 0)) { - goto fail; - } - } else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", - sizeof(context.inputValue), context.inputValue); - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, - 0, context.inputValue, 8, NULL, 0)) { - goto fail; - } - } - } - } - } - // Sequence - check_transaction_available(4); - if (context.usingSegwit && !context.segwitParsedOnce) { - if (context.usingOverwinter) { - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, 0, - context.transactionBufferPointer, 4, NULL, - 0)) { - goto fail; - } - } else { - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", 4, - context.transactionBufferPointer); - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - context.transactionBufferPointer, 4, NULL, - 0)) { - goto fail; - } - } - } - transaction_offset_increase(4); - // Move to next input - context.transactionContext.transactionRemainingInputsOutputs--; - context.transactionContext.transactionCurrentInputOutput++; - context.transactionContext.transactionState = - TRANSACTION_DEFINED_WAIT_INPUT; - continue; - } - // Save the last script byte for the P2SH check - dataAvailable = (context.transactionDataRemaining > - context.transactionContext.scriptRemaining - 1 - ? context.transactionContext.scriptRemaining - 1 - : context.transactionDataRemaining); - if (dataAvailable == 0) { - goto ok; - } - transaction_offset_increase(dataAvailable); - context.transactionContext.scriptRemaining -= dataAvailable; - break; - } - case TRANSACTION_INPUT_HASHING_DONE: { - PRINTF("Input hashing done\n"); - if (parseMode == PARSE_MODE_SIGNATURE) { - // inputs have been prepared, stop the parsing here - if (context.usingSegwit && !context.segwitParsedOnce) { - unsigned char hashedPrevouts[32]; - unsigned char hashedSequence[32]; - // Flush the cache - if (context.usingOverwinter) { - if (cx_hash_no_throw( - &context.segwit.hash.hashPrevouts.blake2b.header, CX_LAST, - hashedPrevouts, 0, hashedPrevouts, 32)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.blake2b.header, - CX_LAST, hashedSequence, 0, hashedSequence, - 32)) { - goto fail; - } - } else { - if (cx_hash_no_throw( - &context.segwit.hash.hashPrevouts.sha256.header, CX_LAST, - hashedPrevouts, 0, hashedPrevouts, 32)) { - goto fail; - } - if (cx_sha256_init_no_throw( - &context.segwit.hash.hashPrevouts.sha256)) { - goto fail; - } - if (cx_hash_no_throw( - &context.segwit.hash.hashPrevouts.sha256.header, CX_LAST, - hashedPrevouts, sizeof(hashedPrevouts), hashedPrevouts, - 32)) { - goto fail; - } - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, - CX_LAST, hashedSequence, 0, hashedSequence, - 32)) { - goto fail; - } - if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { - goto fail; - } - PRINTF("--- ADD TO HASH FULL:\n%.*H\n", sizeof(hashedSequence), - hashedSequence); - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, - CX_LAST, hashedSequence, - sizeof(hashedSequence), hashedSequence, 32)) { - goto fail; - } - } - memmove(context.segwit.cache.hashedPrevouts, hashedPrevouts, - sizeof(hashedPrevouts)); - memmove(context.segwit.cache.hashedSequence, hashedSequence, - sizeof(hashedSequence)); - PRINTF("hashPrevout\n%.*H\n", 32, - context.segwit.cache.hashedPrevouts); - PRINTF("hashSequence\n%.*H\n", 32, - context.segwit.cache.hashedSequence); - } - if (context.usingSegwit && context.segwitParsedOnce) { - if (!context.usingOverwinter) { - PRINTF("SEGWIT hashedOutputs\n%.*H\n", - sizeof(context.segwit.cache.hashedOutputs), - context.segwit.cache.hashedOutputs); - if (cx_hash_no_throw(&context.transactionHashFull.sha256.header, 0, - context.segwit.cache.hashedOutputs, - sizeof(context.segwit.cache.hashedOutputs), - NULL, 0)) { - goto fail; - } - } - context.transactionContext.transactionState = TRANSACTION_SIGN_READY; - } else { - context.transactionContext.transactionState = - TRANSACTION_PRESIGN_READY; - if (context.usingOverwinter) { - if (cx_blake2b_init2_no_throw( - &context.transactionHashFull.blake2b, 256, NULL, 0, - (uint8_t *)OVERWINTER_PARAM_OUTPUTS, 16)) { - goto fail; - } - } else if (context.usingSegwit) { - if (cx_sha256_init_no_throw(&context.transactionHashFull.sha256)) { - goto fail; - } - } - } - continue; - } - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Number of outputs - context.transactionContext.transactionRemainingInputsOutputs = - transaction_get_varint(); - context.transactionContext.transactionCurrentInputOutput = 0; - PRINTF("Number of outputs : %d\n", - context.transactionContext.transactionRemainingInputsOutputs); - // Ready to proceed - context.transactionContext.transactionState = - TRANSACTION_DEFINED_WAIT_OUTPUT; - - __attribute__((fallthrough)); - } - case TRANSACTION_DEFINED_WAIT_OUTPUT: { - if (context.transactionContext.transactionRemainingInputsOutputs == 0) { - // No more outputs to hash, move forward - context.transactionContext.transactionState = - TRANSACTION_OUTPUT_HASHING_DONE; - continue; - } - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Amount - check_transaction_available(8); - if ((parseMode == PARSE_MODE_TRUSTED_INPUT) && - (context.transactionContext.transactionCurrentInputOutput == - context.transactionTargetInput)) { - // Save the amount - memmove(context.transactionContext.transactionAmount, - context.transactionBufferPointer, 8); - context.trustedInputProcessed = 1; - } - transaction_offset_increase(8); - // Read the script length - context.transactionContext.scriptRemaining = transaction_get_varint(); - - PRINTF("Script to read %d\n", context.transactionContext.scriptRemaining); - // Move on - context.transactionContext.transactionState = - TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT; - - __attribute__((fallthrough)); - } - case TRANSACTION_OUTPUT_HASHING_IN_PROGRESS_OUTPUT_SCRIPT: { - unsigned char dataAvailable; - PRINTF("Process output script, remaining %d\n", - context.transactionContext.scriptRemaining); - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - if (context.transactionContext.scriptRemaining == 0) { - // Move to next output - context.transactionContext.transactionRemainingInputsOutputs--; - context.transactionContext.transactionCurrentInputOutput++; - context.transactionContext.transactionState = - TRANSACTION_DEFINED_WAIT_OUTPUT; - continue; - } - dataAvailable = (context.transactionDataRemaining > - context.transactionContext.scriptRemaining - ? context.transactionContext.scriptRemaining - : context.transactionDataRemaining); - if (dataAvailable == 0) { - goto ok; - } - transaction_offset_increase(dataAvailable); - context.transactionContext.scriptRemaining -= dataAvailable; - break; - } - case TRANSACTION_OUTPUT_HASHING_DONE: { - PRINTF("Output hashing done\n"); - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - // Locktime - check_transaction_available(4); - transaction_offset_increase(4); - - if (context.transactionDataRemaining == 0) { - context.transactionContext.transactionState = TRANSACTION_PARSED; - continue; - } else { - context.transactionHashOption = 0; - context.transactionContext.scriptRemaining = transaction_get_varint(); - context.transactionHashOption = TRANSACTION_HASH_FULL; - context.transactionContext.transactionState = TRANSACTION_PROCESS_EXTRA; - continue; - } - } - - case TRANSACTION_PROCESS_EXTRA: { - unsigned char dataAvailable; - - if (context.transactionContext.scriptRemaining == 0) { - context.transactionContext.transactionState = TRANSACTION_PARSED; - continue; - } - - if (context.transactionDataRemaining < 1) { - // No more data to read, ok - goto ok; - } - - dataAvailable = (context.transactionDataRemaining > - context.transactionContext.scriptRemaining - ? context.transactionContext.scriptRemaining - : context.transactionDataRemaining); - if (dataAvailable == 0) { - goto ok; - } - transaction_offset_increase(dataAvailable); - context.transactionContext.scriptRemaining -= dataAvailable; - break; - } - - case TRANSACTION_PARSED: { - PRINTF("Transaction parsed\n"); - goto ok; - } - - case TRANSACTION_PRESIGN_READY: { - PRINTF("Presign ready\n"); - goto ok; - } - - case TRANSACTION_SIGN_READY: { - PRINTF("Sign ready\n"); - goto ok; - } - } - } - -fail: - LEDGER_ASSERT(false, "Transaction parse - fail\n"); -ok: - return; -} diff --git a/lib-app-bitcoin/transaction.h b/lib-app-bitcoin/transaction.h deleted file mode 100644 index 249a5527..00000000 --- a/lib-app-bitcoin/transaction.h +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#pragma once - -#define TRANSACTION_HASH_NONE 0x00 -#define TRANSACTION_HASH_FULL 0x01 -#define TRANSACTION_HASH_AUTHORIZATION 0x02 -#define TRANSACTION_HASH_BOTH 0x03 - -#define PARSE_MODE_TRUSTED_INPUT 0x01 -#define PARSE_MODE_SIGNATURE 0x02 - -#define TRUSTED_INPUT_SIZE 48 -#define TRUSTED_INPUT_TOTAL_SIZE (TRUSTED_INPUT_SIZE + 8) - -void transaction_parse(unsigned char parseMode); diff --git a/lib-app-bitcoin/ui/display_variables.h b/lib-app-bitcoin/ui/display_variables.h deleted file mode 100644 index ad292b2a..00000000 --- a/lib-app-bitcoin/ui/display_variables.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "os.h" - -// A path contains 10 elements max, which max length in ascii is 1 whitespace + -// 10 char + optional quote "'" + "/" + \0" -#define MAX_DERIV_PATH_ASCII_LENGTH 1 + 10 * (10 + 2) + 1 -#define MAX_CHAR_PER_LINE 25 - -typedef struct swap_data_s { - int was_address_checked; - // total number of inputs to be signed - int totalNumberOfInputs; - // number of already signed input in the transaction, to compare with - // totalNumberOfInputs and exit properly - int alreadySignedInputs; - int initialized; - unsigned char amount[8]; - unsigned char fees[8]; - char destination_address[65]; - unsigned char should_exit; -} swap_data_t; - -union display_variables { - struct { - // char addressSummary[40]; // beginning of the output address ... end - // of - - char fullAddress[65]; // the address - char fullAmount[28]; // full amount - char feesAmount[28]; // fees - } tmp; - - struct { - char derivation_path[MAX_DERIV_PATH_ASCII_LENGTH]; - } tmp_warning; - - swap_data_t swap_data; -}; - -extern union display_variables vars; diff --git a/lib-app-bitcoin/ui/extensions.h b/lib-app-bitcoin/ui/extensions.h deleted file mode 100644 index c28d928a..00000000 --- a/lib-app-bitcoin/ui/extensions.h +++ /dev/null @@ -1,54 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#pragma once - -// btchip asking the per-output UI -unsigned int confirm_single_output(void); - -// btchip display token -void display_token(void); - -// btchip finalizing the transaction -unsigned int finalize_tx(void); - -// UI response to btchip to finish the exchange -unsigned char user_action(unsigned char confirming); - -// request the UI to redisplay the idle screen -void idle(void); - -// btchip asking message signing confirmation -void confirm_message_signature(void); - -// UI response to message signature -int user_action_message_signing(unsigned char confirming); - -// Public key display -uint8_t set_key_path_to_display(const unsigned char *keyPath); -void display_public_key(uint8_t is_derivation_path_unusual); -int user_action_display(unsigned char confirming); - -void request_pubkey_approval(void); -void request_change_path_approval(unsigned char *change_path); - -// UI to confirm processing of tx with segwit inputs -void request_segwit_input_approval(void); - -// UI to confirm signing path -void request_sign_path_approval(unsigned char *change_path); -int user_action_signtx(unsigned char confirming, unsigned char direct); diff --git a/lib-app-bitcoin/ui/main_ui.c b/lib-app-bitcoin/ui/main_ui.c deleted file mode 100644 index 2fd4e0fd..00000000 --- a/lib-app-bitcoin/ui/main_ui.c +++ /dev/null @@ -1,301 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ -#include "bip32.h" -#include "cx.h" -#include "format.h" -#include "os.h" -#include "read.h" -#include "string.h" -#include "swap.h" -#include "write.h" - -#include "be_operations.h" -#include "context.h" -#include "customizable_helpers.h" -#include "customizable_ui.h" -#include "display_utils.h" -#include "display_variables.h" -#include "extensions.h" -#include "handle_check_address.h" -#include "handle_get_printable_amount.h" -#include "handle_swap_sign_transaction.h" -#include "helpers.h" -#include "swap_lib_calls.h" -#include "ui.h" -#include "ux.h" - -#define OMNI_ASSETID 1 -#define MAIDSAFE_ASSETID 3 -#define USDT_ASSETID 31 - -static uint8_t check_fee_swap() { - unsigned char fees[8]; - unsigned char borrow; - - borrow = transaction_amount_sub_be( - fees, context.transactionContext.transactionAmount, - context.totalOutputAmount); - if ((borrow != 0) || (memcmp(fees, vars.swap_data.fees, 8) != 0)) - return 0; - context.transactionContext.firstSigned = 0; - - if (context.usingSegwit && !context.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context.transactionContext.transactionState = TRANSACTION_NONE; - } else { - context.transactionContext.transactionState = TRANSACTION_SIGN_READY; - } - context.sw = 0x9000; - context.outLength = 0; - G_io_apdu_buffer[context.outLength++] = 0x90; - G_io_apdu_buffer[context.outLength++] = 0x00; - - return 1; -} - -#define OMNI_ASSETID 1 -#define MAIDSAFE_ASSETID 3 -#define USDT_ASSETID 31 - -static void prepare_single_output(void) { - // TODO : special display for OP_RETURN - unsigned char amount[8]; - unsigned int offset = 0; - char tmp[80] = {0}; - - swap_bytes(amount, context.currentOutput + offset, 8); - offset += 8; - - get_address_from_output_script(context.currentOutput + offset, - sizeof(context.currentOutput) - offset, tmp, - sizeof(tmp)); - strncpy(vars.tmp.fullAddress, tmp, sizeof(vars.tmp.fullAddress) - 1); - - // Prepare amount - - // Handle Omni simple send - if ((context.currentOutput[offset + 2] == 0x14) && - (memcmp(context.currentOutput + offset + 3, "omni", 4) == 0) && - (memcmp(context.currentOutput + offset + 3 + 4, "\0\0\0\0", 4) == 0)) { - uint32_t omniAssetId = - read_u32_be(context.currentOutput, offset + 3 + 4 + 4); - switch (omniAssetId) { - case OMNI_ASSETID: - strcpy(vars.tmp.fullAmount, "OMNI "); - break; - case USDT_ASSETID: - strcpy(vars.tmp.fullAmount, "USDT "); - break; - case MAIDSAFE_ASSETID: - strcpy(vars.tmp.fullAmount, "MAID "); - break; - default: - snprintf(vars.tmp.fullAmount, sizeof(vars.tmp.fullAmount), - "OMNI asset %d ", omniAssetId); - break; - } - format_sats_amount( - vars.tmp.fullAmount, - (uint64_t)read_u64_be(context.currentOutput, - offset + 3 + 4 + 4 + - 4), // Cast prevents weird compilo bug - vars.tmp.fullAmount); - } else { - format_sats_amount( - COIN_COINID_SHORT, - (uint64_t)read_u64_be(amount, 0), // Cast prevents weird compilo bug - vars.tmp.fullAmount); - } -} - -static uint8_t prepare_message_signature(void) { - uint8_t buffer[32]; - - if (cx_hash_no_throw(&context.transactionHashAuthorization.header, CX_LAST, - (uint8_t *)vars.tmp.fullAmount, 0, buffer, 32)) { - return 0; - } - - format_hex((const uint8_t *)buffer, sizeof(buffer), vars.tmp.fullAddress, - sizeof(vars.tmp.fullAddress)); - - return 1; -} - -extern int handle_output_state(unsigned int *processed); -extern void hash_input_finalize_full_reset(void); - -// Analog of confirm_single_output to work -// in silent mode, when called from SWAP app -unsigned int silent_confirm_single_output() { - char tmp[80] = {0}; - unsigned char amount[8]; - while (true) { - // in swap operation we can only have 1 "external" output - if (vars.swap_data.was_address_checked) { - PRINTF("Address was already checked\n"); - return 0; - } - vars.swap_data.was_address_checked = 1; - // check amount - swap_bytes(amount, context.currentOutput, 8); - if (memcmp(amount, vars.swap_data.amount, 8) != 0) { - PRINTF("Amount not matched\n"); - return 0; - } - get_address_from_output_script(context.currentOutput + 8, - sizeof(context.currentOutput) - 8, tmp, - sizeof(tmp)); - if (strcmp(tmp, vars.swap_data.destination_address) != 0) { - PRINTF("Address not matched\n"); - return 0; - } - - // Check if all inputs have been confirmed - - if (context.outputParsingState == OUTPUT_PARSING_OUTPUT) { - context.remainingOutputs--; - if (context.remainingOutputs == 0) - break; - } - - memmove(context.currentOutput, context.currentOutput + context.discardSize, - context.currentOutputOffset - context.discardSize); - context.currentOutputOffset -= context.discardSize; - unsigned int processed = true; - while (processed == 1) { - if (handle_output_state(&processed)) { - PRINTF("Error in handle output state \n"); - return 0; - } - } - - if (processed != 2) { - // Out of data to process, wait for the next call - break; - } - } - - if ((context.outputParsingState == OUTPUT_PARSING_OUTPUT) && - (context.remainingOutputs == 0)) { - context.outputParsingState = OUTPUT_FINALIZE_TX; - // check fees - unsigned char fees[8]; - - if ((transaction_amount_sub_be(fees, - context.transactionContext.transactionAmount, - context.totalOutputAmount) != 0) || - (memcmp(fees, vars.swap_data.fees, 8) != 0)) { - PRINTF("Fees is not matched\n"); - return 0; - } - } - - if (context.outputParsingState == OUTPUT_FINALIZE_TX) { - context.transactionContext.firstSigned = 0; - - if (context.usingSegwit && !context.segwitParsedOnce) { - // This input cannot be signed when using segwit - just restart. - context.segwitParsedOnce = 1; - PRINTF("Segwit parsed once\n"); - context.transactionContext.transactionState = TRANSACTION_NONE; - } else { - context.transactionContext.transactionState = TRANSACTION_SIGN_READY; - } - } - if (context.outputParsingState == OUTPUT_FINALIZE_TX) { - // we've finished the processing of the input - hash_input_finalize_full_reset(); - } - - return 1; -} - -unsigned int confirm_single_output(void) { - if (G_called_from_swap) { - if (silent_confirm_single_output()) { - return 2; - } - return 0; - } - prepare_single_output(); - - ui_confirm_single_flow(); - return 1; -} - -unsigned int finalize_tx(void) { - if (G_called_from_swap) { - if (check_fee_swap()) { - return 2; - } - } - - if (!prepare_fees()) { - return 0; - } - - ui_finalize_flow(); - return 1; -} - -void confirm_message_signature(void) { - if (!prepare_message_signature()) { - return; - } - - ui_sign_message_flow(); -} - -uint8_t set_key_path_to_display(const unsigned char *keyPath) { - format_path(keyPath, vars.tmp_warning.derivation_path, - sizeof(vars.tmp_warning.derivation_path)); - return bip44_derivation_guard(keyPath, false); -} - -void display_public_key(uint8_t is_derivation_path_unusual) { - // append a white space at the end of the address to avoid glitch on nano S - strlcat((char *)G_io_apdu_buffer + 200, " ", sizeof(G_io_apdu_buffer) - 200); - - if (is_derivation_path_unusual) { - ui_display_public_with_warning_flow(); - } else { - ui_display_public_flow(); - } -} - -void display_token(void) { ui_display_token_flow(); } - -void request_pubkey_approval(void) { ui_request_pubkey_approval_flow(); } - -void request_change_path_approval(unsigned char *change_path) { - format_path(change_path, vars.tmp_warning.derivation_path, - sizeof(vars.tmp_warning.derivation_path)); - ui_request_change_path_approval_flow(); -} - -void request_sign_path_approval(unsigned char *change_path) { - format_path(change_path, vars.tmp_warning.derivation_path, - sizeof(vars.tmp_warning.derivation_path)); - ui_request_sign_path_approval_flow(); -} - -void request_segwit_input_approval(void) { - ui_request_segwit_input_approval_flow(); -} diff --git a/lib-app-bitcoin/ui/ui.h b/lib-app-bitcoin/ui/ui.h deleted file mode 100644 index ee63bab7..00000000 --- a/lib-app-bitcoin/ui/ui.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "ux.h" - -void ui_idle_flow(void); -void ui_sign_message_flow(void); -void ui_confirm_full_flow(void); -void ui_confirm_single_flow(void); -void ui_finalize_flow(void); -void ui_display_public_with_warning_flow(void); -void ui_display_public_flow(void); -void ui_display_token_flow(void); -void ui_request_pubkey_approval_flow(void); -void ui_request_change_path_approval_flow(void); -void ui_request_sign_path_approval_flow(void); -void ui_request_segwit_input_approval_flow(void); -void ui_transaction_finish(void); -void ui_transaction_error(void); diff --git a/lib-app-bitcoin/ui/ui_bagl.c b/lib-app-bitcoin/ui/ui_bagl.c deleted file mode 100644 index e4eaaf69..00000000 --- a/lib-app-bitcoin/ui/ui_bagl.c +++ /dev/null @@ -1,437 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2022 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#ifdef HAVE_BAGL -////////////////////////////////////////////////////////////////////// -#include "context.h" -#include "display_variables.h" -#include "transaction.h" -#include "ui.h" - -#include "extensions.h" - -bagl_element_t tmp_element; - -static unsigned int io_seproxyhal_touch_verify_cancel(const bagl_element_t *e) { - UNUSED(e); - // user denied the transaction, tell the USB side - if (!user_action(0)) { - // redraw ui - ui_idle_flow(); - } - return 0; // DO NOT REDRAW THE BUTTON -} - -static unsigned int io_seproxyhal_touch_verify_ok(const bagl_element_t *e) { - UNUSED(e); - // user accepted the transaction, tell the USB side - if (!user_action(1)) { - // redraw ui - ui_idle_flow(); - } - return 0; // DO NOT REDRAW THE BUTTON -} - -static unsigned int -io_seproxyhal_touch_message_signature_verify_cancel(const bagl_element_t *e) { - UNUSED(e); - // user denied the transaction, tell the USB side - user_action_message_signing(0); - // redraw ui - ui_idle_flow(); - return 0; // DO NOT REDRAW THE BUTTON -} - -static unsigned int -io_seproxyhal_touch_message_signature_verify_ok(const bagl_element_t *e) { - UNUSED(e); - // user accepted the transaction, tell the USB side - user_action_message_signing(1); - // redraw ui - ui_idle_flow(); - return 0; // DO NOT REDRAW THE BUTTON -} - -static unsigned int -io_seproxyhal_touch_display_cancel(const bagl_element_t *e) { - UNUSED(e); - // user denied the transaction, tell the USB side - user_action_display(0); - // redraw ui - ui_idle_flow(); - return 0; // DO NOT REDRAW THE BUTTON -} - -static unsigned int io_seproxyhal_touch_display_ok(const bagl_element_t *e) { - UNUSED(e); - // user accepted the transaction, tell the USB side - // redraw ui - ui_idle_flow(); - return user_action_display(1); -} - -static unsigned int io_seproxyhal_touch_sign_cancel(const bagl_element_t *e) { - UNUSED(e); - // user denied the transaction, tell the USB side - user_action_signtx(0, 0); - // redraw ui - ui_idle_flow(); - return 0; // DO NOT REDRAW THE BUTTON -} - -static unsigned int io_seproxyhal_touch_sign_ok(const bagl_element_t *e) { - UNUSED(e); - // user accepted the transaction, tell the USB side - user_action_signtx(1, 0); - // redraw ui - ui_idle_flow(); - return 0; // DO NOT REDRAW THE BUTTON -} - -void io_seproxyhal_display(const bagl_element_t *element) { - if ((element->component.type & (~BAGL_TYPE_FLAGS_MASK)) != BAGL_NONE) { - io_seproxyhal_display_default((bagl_element_t *)element); - } -} -////////////////////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_idle_flow_1_step, nn, - { - "Application", - "is ready", - }); -UX_STEP_NOCB(ux_idle_flow_2_step, bn, - { - "Version", - APPVERSION, - }); -UX_STEP_CB(ux_idle_flow_3_step, pb, os_sched_exit(-1), - { - &C_icon_dashboard_x, - "Quit", - }); -UX_FLOW(ux_idle_flow, &ux_idle_flow_1_step, &ux_idle_flow_2_step, - &ux_idle_flow_3_step, FLOW_LOOP); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_sign_flow_1_step, pnn, - { - &C_icon_certificate, - "Sign", - "message", - }); -UX_STEP_NOCB(ux_sign_flow_2_step, bnnn_paging, - { - .title = "Message hash", - .text = vars.tmp.fullAddress, - }); -UX_STEP_CB(ux_sign_flow_3_step, pbb, - io_seproxyhal_touch_message_signature_verify_ok(NULL), - { - &C_icon_validate_14, - "Sign", - "message", - }); -UX_STEP_CB(ux_sign_flow_4_step, pbb, - io_seproxyhal_touch_message_signature_verify_cancel(NULL), - { - &C_icon_crossmark, - "Cancel", - "signature", - }); - -UX_FLOW(ux_sign_flow, &ux_sign_flow_1_step, &ux_sign_flow_2_step, - &ux_sign_flow_3_step, &ux_sign_flow_4_step); - -////////////////////////////////////////////////////////////////////// - -UX_STEP_NOCB(ux_confirm_single_flow_1_step, pnn, - { - &C_icon_eye, "Review", - vars.tmp.feesAmount, // output # - }); -UX_STEP_NOCB(ux_confirm_single_flow_2_step, bnnn_paging, - { - .title = "Amount", - .text = vars.tmp.fullAmount, - }); -UX_STEP_NOCB(ux_confirm_single_flow_3_step, bnnn_paging, - { - .title = "Address", - .text = vars.tmp.fullAddress, - }); -UX_STEP_CB(ux_confirm_single_flow_5_step, pb, - io_seproxyhal_touch_verify_ok(NULL), - { - &C_icon_validate_14, - "Accept", - }); -UX_STEP_CB(ux_confirm_single_flow_6_step, pb, - io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); -// confirm_single: confirm output #x(feesAmount) / Amount: fullAmount / Address: -// fullAddress -UX_FLOW(ux_confirm_single_flow, &ux_confirm_single_flow_1_step, - &ux_confirm_single_flow_2_step, &ux_confirm_single_flow_3_step, - &ux_confirm_single_flow_5_step, &ux_confirm_single_flow_6_step); - -////////////////////////////////////////////////////////////////////// - -UX_STEP_NOCB(ux_finalize_flow_1_step, pnn, - {&C_icon_eye, "Confirm", "transaction"}); -UX_STEP_NOCB(ux_finalize_flow_4_step, bnnn_paging, - { - .title = "Fees", - .text = vars.tmp.feesAmount, - }); -UX_STEP_CB(ux_finalize_flow_5_step, pbb, io_seproxyhal_touch_verify_ok(NULL), - {&C_icon_validate_14, "Accept", "and send"}); -UX_STEP_CB(ux_finalize_flow_6_step, pb, io_seproxyhal_touch_verify_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); -// finalize: confirm transaction / Fees: feesAmount -UX_FLOW(ux_finalize_flow, &ux_finalize_flow_1_step, &ux_finalize_flow_4_step, - &ux_finalize_flow_5_step, &ux_finalize_flow_6_step); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_display_public_flow_1_step, pnn, - { - &C_icon_warning, - "The derivation", - "path is unusual!", - }); -UX_STEP_NOCB(ux_display_public_flow_2_step, bnnn_paging, - { - .title = "Derivation path", - .text = vars.tmp_warning.derivation_path, - }); -UX_STEP_CB(ux_display_public_flow_3_step, pnn, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject if you're", - "not sure", - }); -UX_STEP_NOCB(ux_display_public_flow_4_step, pnn, - { - &C_icon_validate_14, - "Approve derivation", - "path", - }); -UX_STEP_NOCB(ux_display_public_flow_5_step, bnnn_paging, - { - .title = "Address", - .text = (char *)G_io_apdu_buffer + 200, - }); -UX_STEP_CB(ux_display_public_flow_6_step, pb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Approve", - }); -UX_STEP_CB(ux_display_public_flow_7_step, pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); - -UX_FLOW(ux_display_public_with_warning_flow, &ux_display_public_flow_1_step, - &ux_display_public_flow_2_step, &ux_display_public_flow_3_step, - &ux_display_public_flow_4_step, FLOW_BARRIER, - &ux_display_public_flow_5_step, &ux_display_public_flow_6_step, - &ux_display_public_flow_7_step); - -UX_FLOW(ux_display_public_flow, &ux_display_public_flow_5_step, - &ux_display_public_flow_6_step, &ux_display_public_flow_7_step); - -////////////////////////////////////////////////////////////////////// -UX_STEP_CB(ux_display_token_flow_1_step, pbb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Confirm token", - (char *)G_io_apdu_buffer + 200, - }); -UX_STEP_CB(ux_display_token_flow_2_step, pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); - -UX_FLOW(ux_display_token_flow, &ux_display_token_flow_1_step, - &ux_display_token_flow_2_step); - -////////////////////////////////////////////////////////////////////// -UX_STEP_CB(ux_request_pubkey_approval_flow_1_step, pbb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Export", - "public key?", - }); -UX_STEP_CB(ux_request_pubkey_approval_flow_2_step, pb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject", - }); - -UX_FLOW(ux_request_pubkey_approval_flow, - &ux_request_pubkey_approval_flow_1_step, - &ux_request_pubkey_approval_flow_2_step); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_request_change_path_approval_flow_1_step, pbb, - { - &C_icon_eye, - "The change path", - "is unusual", - }); -UX_STEP_NOCB(ux_request_change_path_approval_flow_2_step, bnnn_paging, - { - .title = "Change path", - .text = vars.tmp_warning.derivation_path, - }); -UX_STEP_CB(ux_request_change_path_approval_flow_3_step, pbb, - io_seproxyhal_touch_display_cancel(NULL), - { - &C_icon_crossmark, - "Reject if you're", - "not sure", - }); -UX_STEP_CB(ux_request_change_path_approval_flow_4_step, pb, - io_seproxyhal_touch_display_ok(NULL), - { - &C_icon_validate_14, - "Approve", - }); - -UX_FLOW(ux_request_change_path_approval_flow, - &ux_request_change_path_approval_flow_1_step, - &ux_request_change_path_approval_flow_2_step, - &ux_request_change_path_approval_flow_3_step, - &ux_request_change_path_approval_flow_4_step); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_request_sign_path_approval_flow_1_step, pbb, - { - &C_icon_eye, - "The sign path", - "is unusual", - }); -UX_STEP_NOCB(ux_request_sign_path_approval_flow_2_step, bnnn_paging, - { - .title = "Sign path", - .text = vars.tmp_warning.derivation_path, - }); -UX_STEP_CB(ux_request_sign_path_approval_flow_3_step, pbb, - io_seproxyhal_touch_sign_cancel(NULL), - { - &C_icon_crossmark, - "Reject if you're", - "not sure", - }); -UX_STEP_CB(ux_request_sign_path_approval_flow_4_step, pb, - io_seproxyhal_touch_sign_ok(NULL), - { - &C_icon_validate_14, - "Approve", - }); - -UX_FLOW(ux_request_sign_path_approval_flow, - &ux_request_sign_path_approval_flow_1_step, - &ux_request_sign_path_approval_flow_2_step, - &ux_request_sign_path_approval_flow_3_step, - &ux_request_sign_path_approval_flow_4_step); - -////////////////////////////////////////////////////////////////////// -UX_STEP_NOCB(ux_request_segwit_input_approval_flow_1_step, pb, - {.icon = &C_icon_warning, .line1 = "Unverified inputs"}); -UX_STEP_NOCB(ux_request_segwit_input_approval_flow_2_step, nn, - {.line1 = "Update", .line2 = " Ledger Live"}); -UX_STEP_NOCB(ux_request_segwit_input_approval_flow_3_step, nn, - {.line1 = "or third party", .line2 = "wallet software"}); -UX_STEP_CB(ux_request_segwit_input_approval_flow_4_step, pb, - io_seproxyhal_touch_display_cancel(NULL), - {.icon = &C_icon_crossmark, .line1 = "Cancel"}); -UX_STEP_CB(ux_request_segwit_input_approval_flow_5_step, pb, - io_seproxyhal_touch_display_ok(NULL), - {&C_icon_validate_14, "Continue"}); - -UX_FLOW(ux_request_segwit_input_approval_flow, - &ux_request_segwit_input_approval_flow_1_step, - &ux_request_segwit_input_approval_flow_2_step, - &ux_request_segwit_input_approval_flow_3_step, - &ux_request_segwit_input_approval_flow_4_step, - &ux_request_segwit_input_approval_flow_5_step); - -void ui_sign_message_flow(void) { ux_flow_init(0, ux_sign_flow, NULL); } - -void ui_confirm_single_flow(void) { - snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "output #%d", - context.totalOutputs - context.remainingOutputs + 1); - ux_flow_init(0, ux_confirm_single_flow, NULL); -} - -void ui_finalize_flow(void) { ux_flow_init(0, ux_finalize_flow, NULL); } - -void ui_display_public_with_warning_flow(void) { - ux_flow_init(0, ux_display_public_with_warning_flow, NULL); -} - -void ui_display_public_flow(void) { - ux_flow_init(0, ux_display_public_flow, NULL); -} - -void ui_display_token_flow(void) { - ux_flow_init(0, ux_display_token_flow, NULL); -} - -void ui_request_pubkey_approval_flow(void) { - ux_flow_init(0, ux_request_pubkey_approval_flow, NULL); -} - -void ui_request_change_path_approval_flow(void) { - ux_flow_init(0, ux_request_change_path_approval_flow, NULL); -} - -void ui_request_sign_path_approval_flow(void) { - ux_flow_init(0, ux_request_sign_path_approval_flow, NULL); -} - -void ui_request_segwit_input_approval_flow(void) { - ux_flow_init(0, ux_request_segwit_input_approval_flow, NULL); -} - -void ui_idle_flow(void) { - if (G_ux.stack_count == 0) { - ux_stack_push(); - } - ux_flow_init(0, ux_idle_flow, NULL); -} - -void ui_transaction_error(void) {} - -void ui_transaction_finish(void) {} - -#endif // HAVE_BAGL diff --git a/lib-app-bitcoin/ui/ui_menu_nbgl.c b/lib-app-bitcoin/ui/ui_menu_nbgl.c deleted file mode 100644 index 0b37fee3..00000000 --- a/lib-app-bitcoin/ui/ui_menu_nbgl.c +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2022 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#ifdef HAVE_NBGL -#include "display_variables.h" -#include "ui.h" - -#include "extensions.h" -#include "nbgl_use_case.h" - -#define SETTING_INFO_NB 3 -static const char *const INFO_TYPES[SETTING_INFO_NB] = {"Version", "Developer", - "Copyright"}; -static const char *const INFO_CONTENTS[SETTING_INFO_NB] = { - APPVERSION, APPDEVELOPPER, APPCOPYRIGHT}; - -static const nbgl_contentInfoList_t infoList = { - .nbInfos = SETTING_INFO_NB, - .infoTypes = INFO_TYPES, - .infoContents = INFO_CONTENTS, -}; - -static void exit(void) { os_sched_exit(-1); } - -void ui_idle_flow(void) { - nbgl_useCaseHomeAndSettings(COIN_COINID_NAME, &COIN_ICON, NULL, - INIT_HOME_PAGE, NULL, &infoList, NULL, exit); -} -#endif // HAVE_NBGL diff --git a/lib-app-bitcoin/ui/ui_nbgl.c b/lib-app-bitcoin/ui/ui_nbgl.c deleted file mode 100644 index 4bd409a8..00000000 --- a/lib-app-bitcoin/ui/ui_nbgl.c +++ /dev/null @@ -1,330 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2022 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#ifdef HAVE_NBGL -#include "context.h" -#include "display_variables.h" -#include "nbgl_use_case.h" -#include "ui.h" - -#include "extensions.h" - -static nbgl_layoutTagValue_t pairs[3]; -static nbgl_layoutTagValueList_t pairList; - -bool transaction_prompt_done; - -static void (*start_transaction_callback)(bool); -static char text[40]; - -// User action callbacks -static void approved_user_action_callback(void) { user_action(1); } - -static void approved_user_action_processing_callback(void) { - if (!user_action(1)) { - nbgl_useCaseSpinner("Processing"); - } -} - -static void abandon_user_action_callback(void) { user_action(0); } - -static void approved_user_action_message_signing_callback(void) { - user_action_message_signing(1); -} - -static void abandon_user_action_message_signing_callback(void) { - user_action_message_signing(0); -} - -static void approved_user_action_display_callback(void) { - user_action_display(1); -} - -static void abandon_user_action_display_callback(void) { - user_action_display(0); -} - -static void approved_user_action_signtx_callback(void) { - user_action_signtx(1, 0); -} - -static void abandon_user_action_signtx_callback(void) { - transaction_prompt_done = false; - user_action_signtx(0, 0); - nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_idle_flow); -} - -// Flow entry point -static void sign_transaction_callback(bool confirmed) { - if (confirmed) { - approved_user_action_processing_callback(); - } else { - transaction_prompt_done = false; - abandon_user_action_callback(); - nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_idle_flow); - } -} - -static void sign_transaction_processing_callback(bool confirmed) { - if (confirmed) { - approved_user_action_processing_callback(); - } else { - transaction_prompt_done = false; - abandon_user_action_callback(); - nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_idle_flow); - } -} - -static void continue_single_flow(bool confirmed) { - if (confirmed) { - snprintf(vars.tmp.feesAmount, sizeof(vars.tmp.feesAmount), "#%d", - context.totalOutputs - context.remainingOutputs + 1); - - pairs[0].item = "Output"; - pairs[0].value = vars.tmp.feesAmount; - - pairs[1].item = "Amount"; - pairs[1].value = vars.tmp.fullAmount; - - pairs[2].item = "Address"; - pairs[2].value = vars.tmp.fullAddress; - - // Setup list - pairList.nbMaxLinesForValue = 0; - pairList.nbPairs = 3; - pairList.pairs = pairs; - - nbgl_useCaseReviewStreamingContinue(&pairList, sign_transaction_callback); - } else { - sign_transaction_callback(false); - } -} - -static void start_transaction_flow(void) { - snprintf(text, sizeof(text), "Review transaction\nto send %s?", - COIN_COINID_NAME); - transaction_prompt_done = true; - nbgl_useCaseReviewStreamingStart(TYPE_TRANSACTION, &COIN_ICON, text, NULL, - start_transaction_callback); -} - -void ui_confirm_single_flow(void) { - if (!transaction_prompt_done) { - start_transaction_callback = continue_single_flow; - start_transaction_flow(); - } - - else { - continue_single_flow(true); - } -} - -static void finish_transaction_flow(bool choice) { - if (choice) { - nbgl_useCaseReviewStreamingFinish("Sign transaction\nto send Bitcoin?", - sign_transaction_processing_callback); - } else { - sign_transaction_processing_callback(false); - } -} - -static void continue_finalize_flow(bool confirmed) { - if (confirmed) { - pairs[0].item = "Fees"; - pairs[0].value = vars.tmp.feesAmount; - - // Setup list - pairList.nbMaxLinesForValue = 0; - pairList.pairs = pairs; - pairList.nbPairs = 1; - - nbgl_useCaseReviewStreamingContinue(&pairList, finish_transaction_flow); - } else { - finish_transaction_flow(false); - } -} - -void ui_finalize_flow(void) { - if (!transaction_prompt_done) { - start_transaction_callback = continue_finalize_flow; - start_transaction_flow(); - } else { - continue_finalize_flow(true); - } -} - -static void request_approval_callback(bool confirmed) { - if (confirmed) { - approved_user_action_processing_callback(); - } else { - transaction_prompt_done = false; - abandon_user_action_display_callback(); - nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_idle_flow); - } -} - -static void continue_change_path_approval_flow(bool confirmed) { - if (confirmed) { - nbgl_useCaseChoice(&C_Important_Circle_64px, "Unusual\nchange path", - vars.tmp_warning.derivation_path, "Continue", - "Reject if not sure", request_approval_callback); - } else { - request_approval_callback(false); - } -} - -void ui_request_change_path_approval_flow(void) { - if (!transaction_prompt_done) { - start_transaction_callback = continue_change_path_approval_flow; - start_transaction_flow(); - } else { - continue_change_path_approval_flow(false); - } -} - -static void continue_segwit_input_approval_flow(bool confirmed) { - if (confirmed) { - nbgl_useCaseChoice(&C_Important_Circle_64px, "Unverified inputs", - "Update Ledger Live\nor third party software", - "Continue", "Reject if not sure", - request_approval_callback); - } else { - request_approval_callback(false); - } -} - -void ui_request_segwit_input_approval_flow(void) { - if (!transaction_prompt_done) { - start_transaction_callback = continue_segwit_input_approval_flow; - start_transaction_flow(); - } else { - continue_change_path_approval_flow(false); - } -} - -void ui_request_pubkey_approval_flow(void) { - nbgl_useCaseChoice(&COIN_ICON, "Export public key", NULL, "Approve", "Reject", - request_approval_callback); -} - -static void user_action_signtx_callback(bool confirmed) { - if (confirmed) { - nbgl_useCaseSpinner("Processing"); - approved_user_action_signtx_callback(); - } else { - abandon_user_action_signtx_callback(); - } -} - -void ui_request_sign_path_approval_flow(void) { - nbgl_useCaseChoice(&C_Important_Circle_64px, "Unusual\nsign path", - vars.tmp_warning.derivation_path, "Continue", - "Reject if not sure", user_action_signtx_callback); -} - -static void sign_message_callback(bool confirmed) { - if (confirmed) { - nbgl_useCaseSpinner("Processing"); - approved_user_action_message_signing_callback(); - nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_SIGNED, ui_idle_flow); - } else { - abandon_user_action_message_signing_callback(); - nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_REJECTED, ui_idle_flow); - } -} -void ui_sign_message_flow(void) { - // Setup data to display - pairs[0].item = "Message hash"; - pairs[0].value = vars.tmp.fullAddress; - - // Setup list - pairList.nbMaxLinesForValue = 0; - pairList.nbPairs = 1; - pairList.pairs = pairs; - - nbgl_useCaseReview(TYPE_MESSAGE, &pairList, &COIN_ICON, "Review\nmessage", - NULL, "Sign message", sign_message_callback); -} - -static void token_flow_callback(bool confirmed) { - if (confirmed) { - approved_user_action_display_callback(); - nbgl_useCaseStatus("Token\nconfirmed", true, ui_idle_flow); - } else { - abandon_user_action_display_callback(); - nbgl_useCaseStatus("Token\nrejected", false, ui_idle_flow); - } -} - -void ui_display_token_flow(void) { - nbgl_useCaseChoice(&COIN_ICON, "Confirm token", - (char *)G_io_apdu_buffer + 200, "Approve", "Reject", - token_flow_callback); -} - -static void public_flow_callback(bool confirmed) { - if (confirmed) { - approved_user_action_callback(); - nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_VERIFIED, ui_idle_flow); - } else { - abandon_user_action_callback(); - nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_REJECTED, ui_idle_flow); - } -} - -static void public_post_warning_flow(bool confirmed) { - if (confirmed) { - pairs[0].item = "Derivation path"; - pairs[0].value = vars.tmp_warning.derivation_path; - - // Setup list - pairList.nbMaxLinesForValue = 0; - pairList.nbPairs = 1; - pairList.pairs = pairs; - - snprintf(text, sizeof(text), "Verify %s\naddress", COIN_COINID_NAME); - nbgl_useCaseAddressReview((char *)G_io_apdu_buffer + 200, &pairList, - &COIN_ICON, text, NULL, public_flow_callback); - } else { - public_flow_callback(false); - } -} - -void ui_display_public_with_warning_flow(void) { - nbgl_useCaseChoice(&C_Important_Circle_64px, "Unusual\nderivation path", NULL, - "Continue", "Reject if not sure", - public_post_warning_flow); -} - -void ui_display_public_flow(void) { - snprintf(text, sizeof(text), "Verify %s\naddress", COIN_COINID_NAME); - nbgl_useCaseAddressReview((char *)G_io_apdu_buffer + 200, NULL, &COIN_ICON, - text, NULL, public_flow_callback); -} - -void ui_transaction_finish(void) { - if (transaction_prompt_done) { - transaction_prompt_done = false; - nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_SIGNED, ui_idle_flow); - } -} - -void ui_transaction_error(void) { - transaction_prompt_done = false; - nbgl_useCaseStatus("Transaction\nerror", false, ui_idle_flow); -} -#endif // HAVE_NBGL diff --git a/lib-app-bitcoin/utils/be_operations.c b/lib-app-bitcoin/utils/be_operations.c deleted file mode 100644 index c99d05be..00000000 --- a/lib-app-bitcoin/utils/be_operations.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "be_operations.h" - -unsigned char transaction_amount_add_be(unsigned char *target, unsigned char *a, - unsigned char *b) { - unsigned char carry = 0; - unsigned char i; - for (i = 0; i < 8; i++) { - unsigned short val = a[8 - 1 - i] + b[8 - 1 - i] + (carry ? 1 : 0); - carry = (val > 255); - target[8 - 1 - i] = (val & 255); - } - return carry; -} - -unsigned char transaction_amount_sub_be(unsigned char *target, unsigned char *a, - unsigned char *b) { - unsigned char borrow = 0; - unsigned char i; - for (i = 0; i < 8; i++) { - unsigned short tmpA = a[8 - 1 - i]; - unsigned short tmpB = b[8 - 1 - i]; - if (borrow) { - if (tmpA <= tmpB) { - tmpA += (255 + 1) - 1; - } else { - borrow = 0; - tmpA--; - } - } - if (tmpA < tmpB) { - borrow = 1; - tmpA += 255 + 1; - } - target[8 - 1 - i] = (unsigned char)(tmpA - tmpB); - } - - return borrow; -} diff --git a/lib-app-bitcoin/utils/be_operations.h b/lib-app-bitcoin/utils/be_operations.h deleted file mode 100644 index 81533086..00000000 --- a/lib-app-bitcoin/utils/be_operations.h +++ /dev/null @@ -1,26 +0,0 @@ -/******************************************************************************* - * Ledger App - Bitcoin Wallet - * (c) 2016-2019 Ledger - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - ********************************************************************************/ - -#pragma once - -// target = a + b -unsigned char transaction_amount_add_be(unsigned char *target, unsigned char *a, - unsigned char *b); - -// target = a - b -unsigned char transaction_amount_sub_be(unsigned char *target, unsigned char *a, - unsigned char *b); diff --git a/lib-app-bitcoin/utils/cashaddr.c b/lib-app-bitcoin/utils/cashaddr.c deleted file mode 100644 index 3214af13..00000000 --- a/lib-app-bitcoin/utils/cashaddr.c +++ /dev/null @@ -1,152 +0,0 @@ -/* Copyright (c) 2017 Pieter Wuille - * Modified work Copyright (c) 2018 Jonas Karlsson - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "cx.h" -#include "os.h" -#include -#include -#include -#include - -#include "cashaddr.h" - -static const char *charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; - -uint64_t cashaddr_polymod_step(uint64_t pre) { - uint8_t b = pre >> 35; - return ((pre & 0x07ffffffff) << 5) ^ (-((b >> 0) & 1) & 0x98f2bc8e61UL) ^ - (-((b >> 1) & 1) & 0x79b76d99e2UL) ^ - (-((b >> 2) & 1) & 0xf33e5fb3c4UL) ^ - (-((b >> 3) & 1) & 0xae2eabe2a8UL) ^ - (-((b >> 4) & 1) & 0x1e4f43e470UL); -} - -uint64_t PolyMod(uint8_t *prefix, uint8_t *payload, size_t payload_length) { - size_t i; - uint64_t c = 1; - while (*prefix != 0) { - c = cashaddr_polymod_step(c) ^ (*prefix++ & 0x1f); // Prefix - } - c = cashaddr_polymod_step(c); // The zero valued separator - for (i = 0; i < payload_length; ++i) { - c = cashaddr_polymod_step(c) ^ (*payload++); // Hash - } - for (i = 0; i < 8; ++i) { - c = cashaddr_polymod_step(c); // 8 zeros for empty checksum - } - return c ^ 1; -} - -static int convert_bits(uint8_t *out, size_t *outlen, int outbits, - const uint8_t *in, size_t inlen, int inbits, int pad) { - uint32_t val = 0; - int bits = 0; - uint32_t maxv = (((uint32_t)1) << outbits) - 1; - while (inlen--) { - val = (val << inbits) | *(in++); - bits += inbits; - while (bits >= outbits) { - bits -= outbits; - out[(*outlen)++] = (val >> bits) & maxv; - } - } - if (pad) { - if (bits) { - out[(*outlen)++] = (val << (outbits - bits)) & maxv; - } - } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { - return 0; - } - return 1; -} - -void create_checksum(uint8_t *payload, size_t payload_length, - uint8_t *checksum) { - uint8_t *prefix = (uint8_t *)"bitcoincash"; - uint64_t mod = PolyMod(prefix, payload, payload_length); - - for (size_t i = 0; i < 8; ++i) { - // Convert the 5-bit groups in mod to checksum values. - *checksum++ = (mod >> (5 * (7 - i))) & 0x1f; - } -} - -int cashaddr_encode(uint8_t *hash, const size_t hash_length, uint8_t *addr, - const size_t max_addr_len, const unsigned short version) { - uint8_t version_byte; - uint8_t checksum[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // 5-bit bytes. - uint8_t tmp[40]; // 8-bit bytes. Should be enough for 1 version byte + 160 bit - uint8_t payload[40]; // 5-bit bytes. Should be enough for 1 version byte + - // 160 bit hash - uint8_t *addr_start; - size_t payload_length = 0; - size_t addr_length = 0; - size_t i; - - addr_start = addr; - *addr_start = 0; - - if (hash_length != 20) // Only support 160 bit hash - return 0; - if (version == CASHADDR_P2PKH) { // Support P2PKH = 0, P2SH = 1 - version_byte = 0; - } else if (version == CASHADDR_P2SH) { - version_byte = 8; - } else { - return 0; - } - - tmp[0] = version_byte; - memmove(tmp + 1, hash, hash_length); - convert_bits(payload, &payload_length, 5, tmp, hash_length + 1, 8, 1); - - create_checksum(payload, payload_length, - checksum); // Assume prefix is 'bitcoincash' - - for (i = 0; i < payload_length; ++i) { - if (*payload >> 5) { - *addr_start = 0; - return 0; - } - addr_length++; - if (max_addr_len < addr_length) { - *addr_start = 0; - return 0; - } - *(addr++) = charset[payload[i]]; - } - for (i = 0; i < 8; ++i) { - if (*checksum >> 5) { - *addr_start = 0; - return 0; - } - addr_length++; - if (max_addr_len < addr_length) { - *addr_start = 0; - return 0; - } - *(addr++) = charset[checksum[i]]; - } - *addr = 0; - - return addr_length; -} diff --git a/lib-app-bitcoin/utils/cashaddr.h b/lib-app-bitcoin/utils/cashaddr.h deleted file mode 100644 index 9eeb4bd4..00000000 --- a/lib-app-bitcoin/utils/cashaddr.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (c) 2017 Pieter Wuille - * Modified work Copyright (c) 2018 Jonas Karlsson - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef _CASHADDR_H_ -#define _CASHADDR_H_ - -#include -#include - -#define CASHADDR_P2PKH 0 -#define CASHADDR_P2SH 1 - -/** Encode a Bitcoin Cash address - * - * In: hash: Pointer to the hash - * hash_length: Length of hash (bytes). Only 20 bytes (160 bits) - * supported. - * max_addr_len: Maximum length of encoded address - * version: P2PKH = 0, P2SH = 1 - * - * Out: addr: Pointer to a buffer with encoded address. The encoded - * address end with a '\0'. - * - * Returns the length of the address if successful, 0 if unsuccessful. - */ - -int cashaddr_encode(uint8_t *hash, const size_t hash_length, uint8_t *addr, - const size_t max_addr_len, const unsigned short version); - -#endif /* _CASHADDR_H_ */ diff --git a/lib-app-bitcoin/utils/segwit_addr.c b/lib-app-bitcoin/utils/segwit_addr.c deleted file mode 100644 index bec567ec..00000000 --- a/lib-app-bitcoin/utils/segwit_addr.c +++ /dev/null @@ -1,204 +0,0 @@ -/* Copyright (c) 2017 Pieter Wuille - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include -#include - -#include "segwit_addr.h" - -uint32_t bech32_polymod_step(uint32_t pre) { - uint8_t b = pre >> 25; - return ((pre & 0x1FFFFFF) << 5) ^ (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ - (-((b >> 1) & 1) & 0x26508e6dUL) ^ (-((b >> 2) & 1) & 0x1ea119faUL) ^ - (-((b >> 3) & 1) & 0x3d4233ddUL) ^ (-((b >> 4) & 1) & 0x2a1462b3UL); -} - -static const char *charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; - -static const int8_t charset_rev[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, -1, 10, 17, 21, 20, 26, 30, 7, - 5, -1, -1, -1, -1, -1, -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, - 31, 27, 19, -1, 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, - -1, -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, 1, 0, - 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1}; - -int bech32_encode(char *output, const char *hrp, const uint8_t *data, - size_t data_len) { - uint32_t chk = 1; - size_t i = 0; - while (hrp[i] != 0) { - if (hrp[i] >= 'A' && hrp[i] <= 'Z') - return 0; - if (!(hrp[i] >> 5)) - return 0; - chk = bech32_polymod_step(chk) ^ (hrp[i] >> 5); - ++i; - } - if (i + 7 + data_len > 90) - return 0; - chk = bech32_polymod_step(chk); - while (*hrp != 0) { - chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f); - *(output++) = *(hrp++); - } - *(output++) = '1'; - for (i = 0; i < data_len; ++i) { - if (*data >> 5) - return 0; - chk = bech32_polymod_step(chk) ^ (*data); - *(output++) = charset[*(data++)]; - } - for (i = 0; i < 6; ++i) { - chk = bech32_polymod_step(chk); - } - chk ^= 1; - for (i = 0; i < 6; ++i) { - *(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f]; - } - *output = 0; - return 1; -} - -int bech32_decode(char *hrp, uint8_t *data, size_t *data_len, - const char *input) { - uint32_t chk = 1; - size_t i; - size_t input_len = strlen(input); - size_t hrp_len; - int have_lower = 0, have_upper = 0; - if (input_len < 8 || input_len > 90) { - return 0; - } - *data_len = 0; - while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') { - ++(*data_len); - } - hrp_len = input_len - (1 + *data_len); - if (hrp_len < 1 || *data_len < 6) { - return 0; - } - *(data_len) -= 6; - for (i = 0; i < hrp_len; ++i) { - int ch = input[i]; - if (ch < 33 || ch > 126) { - return 0; - } - if (ch >= 'a' && ch <= 'z') { - have_lower = 1; - } else if (ch >= 'A' && ch <= 'Z') { - have_upper = 1; - ch = (ch - 'A') + 'a'; - } - hrp[i] = ch; - chk = bech32_polymod_step(chk) ^ (ch >> 5); - } - hrp[i] = 0; - chk = bech32_polymod_step(chk); - for (i = 0; i < hrp_len; ++i) { - chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f); - } - ++i; - while (i < input_len) { - int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; - if (input[i] >= 'a' && input[i] <= 'z') - have_lower = 1; - if (input[i] >= 'A' && input[i] <= 'Z') - have_upper = 1; - if (v == -1) { - return 0; - } - chk = bech32_polymod_step(chk) ^ v; - if (i + 6 < input_len) { - data[i - (1 + hrp_len)] = v; - } - ++i; - } - if (have_lower && have_upper) { - return 0; - } - return chk == 1; -} - -static int convert_bits(uint8_t *out, size_t *outlen, int outbits, - const uint8_t *in, size_t inlen, int inbits, int pad) { - uint32_t val = 0; - int bits = 0; - uint32_t maxv = (((uint32_t)1) << outbits) - 1; - while (inlen--) { - val = (val << inbits) | *(in++); - bits += inbits; - while (bits >= outbits) { - bits -= outbits; - out[(*outlen)++] = (val >> bits) & maxv; - } - } - if (pad) { - if (bits) { - out[(*outlen)++] = (val << (outbits - bits)) & maxv; - } - } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { - return 0; - } - return 1; -} - -int segwit_addr_encode(char *output, const char *hrp, int witver, - const uint8_t *witprog, size_t witprog_len) { - uint8_t data[65]; - size_t datalen = 0; - if (witver > 16) - return 0; - if (witver == 0 && witprog_len != 20 && witprog_len != 32) - return 0; - if (witprog_len < 2 || witprog_len > 40) - return 0; - data[0] = witver; - convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1); - ++datalen; - return bech32_encode(output, hrp, data, datalen); -} - -int segwit_addr_decode(int *witver, uint8_t *witdata, size_t *witdata_len, - const char *hrp, const char *addr) { - uint8_t data[84]; - char hrp_actual[84]; - size_t data_len; - if (!bech32_decode(hrp_actual, data, &data_len, addr)) - return 0; - if (data_len == 0 || data_len > 65) - return 0; - if (strncmp(hrp, hrp_actual, 84) != 0) - return 0; - if (data[0] > 16) - return 0; - *witdata_len = 0; - if (!convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) - return 0; - if (*witdata_len < 2 || *witdata_len > 40) - return 0; - if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) - return 0; - *witver = data[0]; - return 1; -} diff --git a/lib-app-bitcoin/utils/segwit_addr.h b/lib-app-bitcoin/utils/segwit_addr.h deleted file mode 100644 index d86e203c..00000000 --- a/lib-app-bitcoin/utils/segwit_addr.h +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright (c) 2017 Pieter Wuille - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef _SEGWIT_ADDR_H_ -#define _SEGWIT_ADDR_H_ - -#include - -/** Encode a SegWit address - * - * Out: output: Pointer to a buffer of size 73 + strlen(hrp) that will be - * updated to contain the null-terminated address. - * In: hrp: Pointer to the null-terminated human readable part to use - * (chain/network specific). - * ver: Version of the witness program (between 0 and 16 inclusive). - * prog: Data bytes for the witness program (between 2 and 40 bytes). - * prog_len: Number of data bytes in prog. - * Returns 1 if successful. - */ -int segwit_addr_encode(char *output, const char *hrp, int ver, - const uint8_t *prog, size_t prog_len); - -/** Decode a SegWit address - * - * Out: ver: Pointer to an int that will be updated to contain the witness - * program version (between 0 and 16 inclusive). - * prog: Pointer to a buffer of size 40 that will be updated to - * contain the witness program bytes. - * prog_len: Pointer to a size_t that will be updated to contain the - * length - * of bytes in prog. - * hrp: Pointer to the null-terminated human readable part that is - * expected (chain/network specific). - * addr: Pointer to the null-terminated address. - * Returns 1 if successful. - */ -int segwit_addr_decode(int *ver, uint8_t *prog, size_t *prog_len, - const char *hrp, const char *addr); - -/** Encode a Bech32 string - * - * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that - * will be updated to contain the null-terminated Bech32 string. - * In: hrp : Pointer to the null-terminated human readable part. - * data : Pointer to an array of 5-bit values. - * data_len: Length of the data array. - * Returns 1 if successful. - */ -int bech32_encode(char *output, const char *hrp, const uint8_t *data, - size_t data_len); - -/** Decode a Bech32 string - * - * Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be - * updated to contain the null-terminated human readable part. - * data: Pointer to a buffer of size strlen(input) - 8 that will - * hold the encoded 5-bit data values. - * data_len: Pointer to a size_t that will be updated to be the number - * of entries in data. - * In: input: Pointer to a null-terminated Bech32 string. - * Returns 1 if succesful. - */ -int bech32_decode(char *hrp, uint8_t *data, size_t *data_len, - const char *input); - -#endif /* _SEGWIT_ADDR_H_ */ From 1bc2738c1fe2201f56fd804022e02113db126260 Mon Sep 17 00:00:00 2001 From: Sarah GLINER Date: Thu, 2 May 2024 13:25:34 +0200 Subject: [PATCH 83/85] Tests: update snapshots --- .../00000.png | Bin 11447 -> 11666 bytes .../00000.png | Bin 11723 -> 11942 bytes .../00000.png | Bin 11447 -> 11666 bytes .../00000.png | Bin 11723 -> 11942 bytes .../00000.png | Bin 11447 -> 11666 bytes .../00000.png | Bin 11723 -> 11942 bytes .../00000.png | Bin 11447 -> 11666 bytes .../00000.png | Bin 11723 -> 11942 bytes .../00000.png | Bin 11447 -> 11666 bytes .../00000.png | Bin 11723 -> 11942 bytes .../00000.png | Bin 11036 -> 11179 bytes .../00000.png | Bin 11581 -> 11763 bytes .../00000.png | Bin 11036 -> 11179 bytes .../00000.png | Bin 11581 -> 11763 bytes .../00000.png | Bin 11036 -> 11179 bytes .../00000.png | Bin 11581 -> 11763 bytes .../00000.png | Bin 11036 -> 11179 bytes .../00000.png | Bin 11581 -> 11763 bytes .../00000.png | Bin 11036 -> 11179 bytes .../00000.png | Bin 11581 -> 11763 bytes 20 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_0/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_0/00000.png index e31f881c73a477c557522b43bf4f06a7d6bb1ba5..764dec9263f5865e4fc258310cc38364630d02f8 100644 GIT binary patch literal 11666 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 S0+4IXVP$^r2GYzc?Y{u%|HC{0 delta 9569 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 Ov$48*5p({Z)c*mW{I`<; diff --git a/tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_3/00000.png b/tests/snapshots/flex/test_sign_psbt_singlesig_pkh_1to1_0_3/00000.png index 78571a283096b9a72dfa7d06957c2c8c5229cf72..a19a87d4a2dac3687a81bb15ac2750bc32e4e67a 100644 GIT binary patch literal 11942 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 literal 11723 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