From f67cf1b5ce530bc5e6b511d6db8287a5f5a671e1 Mon Sep 17 00:00:00 2001 From: becominginsane Date: Mon, 4 Dec 2023 16:43:54 +0800 Subject: [PATCH 1/6] docs: fix APDUSPEC --- docs/APDUSPEC.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/APDUSPEC.md b/docs/APDUSPEC.md index c9b56763..34a3a07e 100644 --- a/docs/APDUSPEC.md +++ b/docs/APDUSPEC.md @@ -270,7 +270,7 @@ Returns a sapling full viewing key fvk = (ak, nk, ovk). Forced user confirmation --- -### INS_INIT_TX_SAPLING +### INS_INIT_TX Initiates a transaction for sapling. The init_message should have the following format: @@ -323,7 +323,7 @@ s_output: | Field | Type | Content | Expected | |-------|----------|------------------------|-----------| -| CLA | byte (1) | Application Identifier | 0xE0 | +| CLA | byte (1) | Application Identifier | 0x85 | | INS | byte (1) | Instruction ID | 0xa0 | | P1 | byte (1) | Payload desc | 0 = init | | | | | 1 = add | @@ -361,7 +361,7 @@ Data is defined as: --- -### INS_GET_SPENDINFO +### INS_EXTRACT_SPEND Returns a proof generating key (PGK) and randomness (rcv and alpha) for a sapling spend. @@ -389,7 +389,7 @@ Returns a proof generating key (PGK) and randomness (rcv and alpha) for a saplin --- -### INS_GET_OUTPUTINFO +### INS_EXTRACT_OUTPUT Returns randomness (rcv and rseed (after ZIP202) and optional Hash_Seed) for a sapling output. @@ -410,7 +410,8 @@ Returns randomness (rcv and rseed (after ZIP202) and optional Hash_Seed) for a s #### Response | Field | Type | Content | Note | -|-----------|-----------|---------------|-------------------------------------------| +|-----------|-----------|---------------|------------------------------------------ +-| | rcv_RAW | byte (32) | Raw rcv | | | rseed_RAW | byte (32) | Raw rseed | | | hash_seed | byte (32) | Raw hash_seed | Only returned if OVK=None for this output | @@ -418,13 +419,13 @@ Returns randomness (rcv and rseed (after ZIP202) and optional Hash_Seed) for a s --- -### INS_CHECKANDSIGN_TX_SAPLING +### INS_CHECKANDSIGN Checks the transaction data and signs if it is correct with the corresponding keys. -- This command requires you already called the INS_INIT_TX_SAPLING. -- This command requires you already called the correct number of INS_GET_SPENDINFO. -- This command requires you already called the correct number of INS_GET_OUTPUTINFO. +- This command requires you already called the INS_INIT_TX +- This command requires you already called the correct number of INS_EXTRACT_SPEND. +- This command requires you already called the correct number of INS_EXTRACT_OUTPUT. The transaction_blob should have the following format: @@ -481,7 +482,7 @@ shielded output data to check: | Field | Type | Content | Expected | |-------|----------|------------------------|-------------------------| -| CLA | byte (1) | Application Identifier | 0xE0 | +| CLA | byte (1) | Application Identifier | 0x85 | | INS | byte (1) | Instruction ID | 0xa3 | | P1 | byte (1) | Payload desc | 0 = init | | | | | 1 = add | @@ -520,11 +521,11 @@ Data is defined as: --- -### INS_GET_TRANSPARENT_SIGNATURE +### INS_GET_EXTRACT_TRANSSSIG Returns a SECP256K1 signature for a sapling transparent input. -- This command requires that you already called INS_CHECKANDSIGN_SAPLING. +- This command requires that you already called INS_CHECKANDSIGN. It gives the signatures in order of the transaction. Returns error if all signatures are retrieved. @@ -548,11 +549,11 @@ Returns error if all signatures are retrieved. --- -### INS_GET_SPEND_SIGNATURE +### INS_EXTRACT_SPENDSIG Returns a spend signature for a sapling shielded spend input. -- This command requires that you already called INS_CHECKANDSIGN_SAPLING. +- This command requires that you already called INS_CHECKANDSIGN. #### Command From 0404033f4697621f8e38919044efd73b6a733baa Mon Sep 17 00:00:00 2001 From: ftheirs Date: Thu, 7 Dec 2023 14:51:08 -0300 Subject: [PATCH 2/6] update deps --- deps/ledger-zxlib | 2 +- deps/nanos-secure-sdk | 2 +- deps/nanosplus-secure-sdk | 2 +- deps/nanox-secure-sdk | 2 +- deps/stax-secure-sdk | 2 +- js/package.json | 14 +++++++------- tests_zemu/package.json | 24 +++++++++++++----------- 7 files changed, 25 insertions(+), 23 deletions(-) diff --git a/deps/ledger-zxlib b/deps/ledger-zxlib index 3ffe6488..42e82e91 160000 --- a/deps/ledger-zxlib +++ b/deps/ledger-zxlib @@ -1 +1 @@ -Subproject commit 3ffe64882bece4e6a17895ce306c0129862681c6 +Subproject commit 42e82e9115de2727696e8508c47f65eae87acbfe diff --git a/deps/nanos-secure-sdk b/deps/nanos-secure-sdk index 40a60bc8..0532bf20 160000 --- a/deps/nanos-secure-sdk +++ b/deps/nanos-secure-sdk @@ -1 +1 @@ -Subproject commit 40a60bc83c6b1422e047c36beb4018891bc34b12 +Subproject commit 0532bf20fbbb11dd08dada62060f8337097b6078 diff --git a/deps/nanosplus-secure-sdk b/deps/nanosplus-secure-sdk index 71128b69..0e727929 160000 --- a/deps/nanosplus-secure-sdk +++ b/deps/nanosplus-secure-sdk @@ -1 +1 @@ -Subproject commit 71128b6987e2548da83dff7495e7f94bdd128033 +Subproject commit 0e727929ecf3ebd8ffc90e00c043314f5b276fe1 diff --git a/deps/nanox-secure-sdk b/deps/nanox-secure-sdk index f8c1a80b..0e727929 160000 --- a/deps/nanox-secure-sdk +++ b/deps/nanox-secure-sdk @@ -1 +1 @@ -Subproject commit f8c1a80bf74aa3fcf4fb3b079ee45116f61cb607 +Subproject commit 0e727929ecf3ebd8ffc90e00c043314f5b276fe1 diff --git a/deps/stax-secure-sdk b/deps/stax-secure-sdk index 6b2d5ecb..0e727929 160000 --- a/deps/stax-secure-sdk +++ b/deps/stax-secure-sdk @@ -1 +1 @@ -Subproject commit 6b2d5ecb2c24e792733b529868c811d4440d96f9 +Subproject commit 0e727929ecf3ebd8ffc90e00c043314f5b276fe1 diff --git a/js/package.json b/js/package.json index 9ade21a4..b2298fae 100644 --- a/js/package.json +++ b/js/package.json @@ -31,22 +31,22 @@ "@babel/plugin-transform-runtime": "^7.18.2", "@babel/preset-env": "^7.18.2", "babel-jest": "^29.1.2", - "bip32": "^3.0.1", + "bip32": "^4.0.0", "bip39": "^3.0.4", "core-js": "^3.22.8", - "crypto-js": "4.1.1", + "crypto-js": "4.2.0", "eslint": "^8.17.0", "eslint-config-airbnb-base": "^15.0.0", - "eslint-config-prettier": "^8.5.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-jest": "^27.1.1", - "eslint-plugin-prettier": "^4.0.0", + "eslint-plugin-prettier": "^5.0.1", "index.js": "^0.0.3", "jest": "^29.1.2", "jest-serial-runner": "^1.2.0", - "prettier": "^2.6.2", - "secp256k1": "^4.0.3", - "typescript": "^4.7.3" + "prettier": "^3.1.0", + "secp256k1": "^5.0.0", + "typescript": "^5.3.3" }, "scripts": { "build": "babel src --out-dir dist && yarn build:types", diff --git a/tests_zemu/package.json b/tests_zemu/package.json index 32389713..ab56ef0b 100644 --- a/tests_zemu/package.json +++ b/tests_zemu/package.json @@ -9,7 +9,9 @@ "type": "git", "url": "git+https://github.com/Zondax/ledger-zcash" }, - "keywords": ["zondax"], + "keywords": [ + "zondax" + ], "scripts": { "clean": "ts-node tests/pullImageKillOld.ts", "test": "yarn clean && jest --maxConcurrency 2", @@ -18,25 +20,25 @@ "dependencies": { "@zondax/ledger-zcash": "link:../js", "@zondax/zcashtools": "link:../zcashtools/neon", - "@zondax/zemu": "^0.44.0" + "@zondax/zemu": "^0.46.0" }, "devDependencies": { "@ledgerhq/hw-transport-node-hid": "^6.27.19", "@ledgerhq/logs": "^6.10.1", - "@types/jest": "^28.1.1", + "@types/jest": "^29.5.11", "@types/ledgerhq__hw-transport": "^4.21.4", - "@typescript-eslint/eslint-plugin": "^5.27.1", - "@typescript-eslint/parser": "^5.27.1", + "@typescript-eslint/eslint-plugin": "^6.13.2", + "@typescript-eslint/parser": "^6.13.2", "eslint": "^8.17.0", - "eslint-config-prettier": "^8.5.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.26.0", - "eslint-plugin-jest": "^26.5.3", - "eslint-plugin-prettier": "^4.0.0", + "eslint-plugin-jest": "^27.6.0", + "eslint-plugin-prettier": "^5.0.1", "jest": "^29.5.0", "jest-serial-runner": "^1.2.0", - "prettier": "^2.6.2", + "prettier": "^3.1.0", "ts-jest": "^29.0.5", - "ts-node": "^10.9.1", - "typescript": "^4.7.3" + "ts-node": "^10.9.2", + "typescript": "^5.3.3" } } From c40419e466d84dd24e90046044c45fc5cae35934 Mon Sep 17 00:00:00 2001 From: ftheirs Date: Thu, 7 Dec 2023 14:53:27 -0300 Subject: [PATCH 3/6] bump version & update snapshots --- app/Makefile.version | 2 +- tests_zemu/snapshots/s-mainmenu/00004.png | Bin 393 -> 388 bytes tests_zemu/snapshots/s-mainmenu/00010.png | Bin 393 -> 388 bytes tests_zemu/snapshots/sp-mainmenu/00004.png | Bin 346 -> 353 bytes tests_zemu/snapshots/sp-mainmenu/00010.png | Bin 346 -> 353 bytes tests_zemu/snapshots/st-mainmenu/00001.png | Bin 13508 -> 13385 bytes tests_zemu/snapshots/x-mainmenu/00004.png | Bin 346 -> 353 bytes tests_zemu/snapshots/x-mainmenu/00010.png | Bin 346 -> 353 bytes 8 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Makefile.version b/app/Makefile.version index fd7f9b50..8698c7d3 100644 --- a/app/Makefile.version +++ b/app/Makefile.version @@ -3,4 +3,4 @@ APPVERSION_M=3 # This is the minor version of this release APPVERSION_N=3 # This is the patch version of this release -APPVERSION_P=0 +APPVERSION_P=1 diff --git a/tests_zemu/snapshots/s-mainmenu/00004.png b/tests_zemu/snapshots/s-mainmenu/00004.png index d535fddfb700a3ea9a0367f051c6f94c073cbe28..a8025d2a61c385001e2f92b931dd78981de2c252 100644 GIT binary patch delta 361 zcmV-v0ha!W1B3&RB!5duL_t(|ob8xP4udcZM4>A8KQIfrh-8`A7(-IG4)b>W5^3xV zlS~r;0Dz}5M@+J<+RRJqfGs2Z4ey9axKaaY*M*P*5OOK-JM&Uss_)2eGnX^A0EJ3f zE+2oit@V%p1Qwu@Th-1GbWrc|72s;4Ntrw&aEXtssef7)`FVxTW?PE=;aIv8 zAr{2@mnfPRuctfwQhq)SXhFVxfDz=oXZ(k8YXwLr$)84kh4v4Cntd@%RTQAa47&!! zsa3xQl1k5gklPo4o_Y2-luS^DQ%Fw{qgesu&eKrV-cJEZ(Nn~eTPf(Y@trBi&X=C_ znSXoSP=HG>cw)xCs`3zraUnb5>UZ7c?>&n3MQy~Wi;s@v)Gj{l@%$FlumZX?vK^%! z5VT?sScrBq?N3(mVK0?8EG zsmlTY0N|;t5t|&lw)57yV9N@B!#iRVuGB=@bs;1GguDv;&AR1}>Nj%k$l;6)Kq6C? z%g2X~T_56a)Z{i4fdRA8KQIfrh-8`A7(-IG4)b>W5^3xV zlS~r;0Dz}5M@+J<+RRJqfGs2Z4ey9axKaaY*M*P*5OOK-JM&Uss_)2eGnX^A0EJ3f zE+2oit@V%p1Qwu@Th-1GbWrc|72s;4Ntrw&aEXtssef7)`FVxTW?PE=;aIv8 zAr{2@mnfPRuctfwQhq)SXhFVxfDz=oXZ(k8YXwLr$)84kh4v4Cntd@%RTQAa47&!! zsa3xQl1k5gklPo4o_Y2-luS^DQ%Fw{qgesu&eKrV-cJEZ(Nn~eTPf(Y@trBi&X=C_ znSXoSP=HG>cw)xCs`3zraUnb5>UZ7c?>&n3MQy~Wi;s@v)Gj{l@%$FlumZX?vK^%! z5VT?sScrBq?N3(mVK0?8EG zsmlTY0N|;t5t|&lw)57yV9N@B!#iRVuGB=@bs;1GguDv;&AR1}>Nj%k$l;6)Kq6C? z%g2X~T_56a)Z{i4fdR?8VMs@q}Y})mb~n)xKUfyXQ~Pc6gfKTBfoz#q99?AGKFc zt&DCsq;mV%b-$-`4zDaz$;rFiDR$t9Y}$3sl7;p6zRsy-YV_B;Dz(wmGROLq2zS7j zXs`O?s_Xt9+NN;XXMMPS^k)lQ-#xX{w#}~l?z@SV_fhPld9io%PAsXPsgQMPzl74&~Q{BX70 zVr%Ao#zlvi-q`o@ET6)?;6_uP>z8VWzjdF!`^IcxnD>8uWVo1hFv7nK54PPqEx%hN S`RMP@AW=_OKbLh*2~7ZrLzNi- delta 319 zcmaFJbc<<%O1+||i(^Q|oVPcl`I;33S`%-VsK2TAe6y5arG@A5g(KYTzw7gpa?eOg zif-p+K!BJ>roUO%%qg~?5oGnF-TmLgp!qk|6SjJGrk8W=WD5BklHnfYm3H~BZ~dAm z%Tn%u87a4a+={hKFAukVWVZdK3wOe!vd!E~vGps;_omNpcs$*Et6NS`+3h}~qf8=& z-ktn0k8bJba2uWdQulR}>GsQ)j@+)!+&F9zl!bNI-X9qUV zeBorw>$Hq*`m4uNqj~QN>pVO1+J<|t==#JROb`1`oXa_Co+vymr_BFZ+|GBa^Y?hy zvvqJaEoOb_W3lKy^Q-TZkK6C<5L?8VMs@q}Y})mb~n)xKUfyXQ~Pc6gfKTBfoz#q99?AGKFc zt&DCsq;mV%b-$-`4zDaz$;rFiDR$t9Y}$3sl7;p6zRsy-YV_B;Dz(wmGROLq2zS7j zXs`O?s_Xt9+NN;XXMMPS^k)lQ-#xX{w#}~l?z@SV_fhPld9io%PAsXPsgQMPzl74&~Q{BX70 zVr%Ao#zlvi-q`o@ET6)?;6_uP>z8VWzjdF!`^IcxnD>8uWVo1hFv7nK54PPqEx%hN S`RMP@AW=_OKbLh*2~7ZrLzNi- delta 319 zcmaFJbc<<%O1+||i(^Q|oVPcl`I;33S`%-VsK2TAe6y5arG@A5g(KYTzw7gpa?eOg zif-p+K!BJ>roUO%%qg~?5oGnF-TmLgp!qk|6SjJGrk8W=WD5BklHnfYm3H~BZ~dAm z%Tn%u87a4a+={hKFAukVWVZdK3wOe!vd!E~vGps;_omNpcs$*Et6NS`+3h}~qf8=& z-ktn0k8bJba2uWdQulR}>GsQ)j@+)!+&F9zl!bNI-X9qUV zeBorw>$Hq*`m4uNqj~QN>pVO1+J<|t==#JROb`1`oXa_Co+vymr_BFZ+|GBa^Y?hy zvvqJaEoOb_W3lKy^Q-TZkK6C<5L2EPNV6baa0@6(?p4D7^+q z=qMdgA_NElG*m-Jh!D!R*n7X%_nzx||DAK5{LES_Ypwg9bB-~`n0a=`>?Y4~k>el` zhzES@#$6DI=>-VH{MRvN;G3)Fjm034+6nLtgL@%wmMPy~idb^{l-yMS)udXB&k2TZ(?1+7$J~N z<6$_84di&4nJY?!RRE-ZOb+CE!Upv1Tm|U8fg{tMm{#V$*rVC5@%-v1Ob`+7*@_I6Q`OV;|yvND>N2Nj`VN(_RYV6{AdH$JOg1$GMh=j&XVrPh(1hb!e@ zf+%542fu&Ylv))J|6HAF$;ruyafTNX!B!QBGAmhOZTb?5ker-6I5;@$xwW&iv%X#l zD<_nRmcU6txEkQ=7WCm<=s|)xcWsp%VY+FIy>C5aNm0IU<9@;g@TuT|0k?o*wm{0u!;W7}-%@&JLx%swz1;BSK%jw7KL5UhkQke>A2|QW*k*j6t1t0P-b)3#7P!dW#Gr04$!zxIo<1Yr| zCw>K3)JQ$?bxhU8LBYrJCQ7LOjj+G`!AWaS=u~%pX#D*xB*@+!J(UWGq|;J|CM_eCTw7 zl@vR_{$t@(b0H!^H+f%Icu6U20%xAHdY%W zV3)Wujm&}Hx-oE}+xH-lS;OS4IO&M%+T-dfJndB8@YzrW=soRMfxBI8jK7|2q09=2 zso>>y4YbR*9(fl6W!&nOawqTQ29Mz&C|U?nM=mAN1_#Z9#d<|=w=ACi9`U6;OmSQG z#A8Oatf^(sS>ba&8Aj~gz#a<48d@x&v~7vJO*bv1#%jpRGhq%8NX)FJsibn<{n9GA zgk0dY>>Pz+CqiS2g#yvCk}tnPSL}1S`+O&3lv|0hepf2lHi%AGTz2TPuyR{DXEGe#;Dr4E`759DO} zPZy^D@>Gpb#~`RRWVjl^G=1@)A99DNW@ynpm^m;v?rCVDX6l>>WM>k!0jFnS!SCSU z(D@q3XdQ8h#vo9Onw=w?K?TKoc0NT3NChZK*f|>`7@FP3r(wq=qhgn)bnKB7cxIls zs8(-g!H==(6e4U$=6i_5zTI2GvJ_*H_1qebQ>RJyKo^;1&vsN$dOBh$OCwx4S+GW{CR;X~wEhm`8q!^&slq`9aRTYCK+z!%LP)glMu`ycAdX>)DkJMLr(hmFbD=gGcj2!9I@+wX0896~LU53liD40`j@eB&;ZoY-s zH^>yEZG~+)XcRRfd}FAlxX}U+J^iB(iMI9K_xJX07Sv$ltE+QTLR9OY6SJ^CMJ0wR zsx}Q{&ee}-6@__^=W;{G-s$%*cz0xx4&NxbfsM$P~t)xWHrSK?G3^6>BXNOS%uv9552-3D4IKy_z*+ z_kg<&%#xtO(2?t-!5dDe*`s`WV;K}+g$*>y%Yg+} zIaeji2VsvQG8%QX#=o>P!@B$B<%CtoSLu_qQ<{br6NJYF9y66&jQwl@fi)*L@j(5Y z!9n>yz?jHUrVt*!jFA`f4a#o5G7*!fLPm7f+Qm=W6cRlM6cOho5RqyOT4P>O=j#*N zTwjNylc>K#bYkJZr%!sfPI_rdFsnuZL7zN(<% zx5AK#9%P(;pS{xqoxn&3<|si8cP?4r!qJ8!CKe#LjM8rCoR1{-{S%<&`}@tn{k$eK zb0|Ks&!}3amcia(wpi2vzHIiB68F4(n_YBfPIQ{`Asr5VvzlA=L(7{yVrP0an6ZB# zE^U8IZhH2ii!D~FN2j#*@F(63A0+wC3`%LKcCk4)irhV`NolWjS&_-EK8h(|eu}_ex_{WA8C0516 z#a|Wj%puAFD9%zPZY1>+ur>|L-ClKe&i!uH4P7XvMjU|^tK50^6eb5?aBAf^G7=*d zbN#+4F%T*k3rBm9f;Ku#6FU3e0HxHqznknzLjm8J5>3V?KE|t?O0vO3D>Iz(PLv<) z8I;QcVpp!xX#9D!JwJ<^A}wZ)W+E;`%5!bd1rO1Qy^#HCS$D6{y|+h|ww zRjs7ugq3IC!NhN6ZXGKR^$4yjbVlTYiQMLW$5*bQrB|pUdmB@&{vDq-oLrqgO<0^y6EktOKFuGe$>#9|-i{9SWF~{V|_2J7X0mIpb9vS1q6Dr86dI=Y& zbP{tPR@m_C&O?R1p$LZK%-FdXuPAH&^fhsv(Wq-LZa1&Ix7o{8&yWH`_<+Phd zAN0Z=)gTd;gBtDy*8Q=!POy4ULdkEsN{h&^@mk6*RF4Yl2f{h-2~U{>G<1P-LN2)Lj|3&^mW?SxSg%Sps@4I23FavdJN#^p=ocNRdUFC!Py^8 zUAKFFaXFiyO)i5m9p9(RoVToTZ=E%-HaTs##C+nNG*fzih+@Q39xDU=+>TH7{LmIo z8~bd-CN+*7s|((Rf6vw@)kjO4g02LWQ*2c8`}IVPB#Fm%ql1V~4j0cb2JXc!vf;Hy zcuLM4tC^^LthxTBwaPT+z~hDMSZ%;$wzI#xefGRcad-AM={}QXub915=r^^2=_f61 zb%f_#KBncPw~W`^cP$VHY?c=M5J(V|zMRCCJ?j?@fxK!`?8@e};2%p*Ck?f^YTpRW zCU5o<{LzSX@xQU%r!HDM|H*@J2=2w=nS|V1lQ76D!4=%-rQKTm$e0Q7-fg`sGmURc zuWTLv5D!%Rz8HAF)M_I@tZQ4U##Yk#dfBjNEv!7h*l8?JJIf5GzwoK6)HQ7BLSr47 zkkEgJtI|V+uF+FQTS8N~0#3`i_34Z8dXtv}uTs9H(tP?3NL+G+Pq{KKT}Bpa;c@)G zOSL2Ht}pp&3dX(-&pP;FuUTXHazc1=|H=YPKOcP-8J50{u|2`sMg0nUxVNrT0uUfs zLLr_JdeN!`X-9TX#Z!F5v9o7Cw4LSBAyJ!QoqL3akKt+Bncq$uTA(9*WcN?|gr$2c z2whZ+R3hqvF_%;+h3L_?tSclFdK*2=ZfP}idJ(`ixKOXe4#KB|hSzVVQHnNlZfi>) zR+-dAQ_W2ATd;O1aAPLxI~kG2G~eC0rmm*Pq!l}Ujpl~49DTo1T*v$s*n0$pSPhh@ z3q6W`Vu!d`;-Zwp>z7i`0+oFBaj`zK7g*d4PV8;Sp3Zx-jx4p3-Dw11_hhi#m+OV< z4{74>8e8NxM`(!#CrlppeT*NdHE)*h%DVLDeRw+dj7>; za$;llgn0>{(xcX0`9;sgeKWK4FN#!eFy@Q!M~pn;%UO`o+BwL7SMQnI>-<_&v^!`- z|LC`uI?ovly~w8)xhsh6JN@>hRQiT=J_K^c5S}wZL@UX!!Q37yd{6ZuMT~4dp5-i9 zdC8H}u7?Pl`H+wcP%y9K9lkT1$*qXY>L;(HdTK{3iE42jKy&Js@bi}JpiqF8SmVt> zLQxSAb8}Ow4`v(SReYHRJG;AA#gol_E;E}eIddT%zwsaRgh2&}?U)FKaObs#FMs;$ zgE0r^MFS*#IAFt)>=g4tO9;e*|M@TB*-P0_5|6?%{<8uG=nw)DZw5j&T}=j{JNMI9 zMhX>wR==~ZlE~{Bt0OOG6g;DjZc9KtGH%NT)samn6xOb;P}+-V_ciX3g3ti%fL&Bh zaxPy!Cw;@>o5N0s4zKsuv-_NnrbBdK2>99Lo8_XJQeZM}=+DaJ82V2KQmuVN zwQKK%JPRrt_AGlmKw5|cZq76+1Of}bKJ!qIuPpR=USes~V<>vwxWY_PAVikVBNrOG zR+}RE>|*(>6T<+v<4Ar0yAmVpLjBNEP*){CLRh$9u~19dUH_I`;dhtAPI>2bjC^z3 zh*(q~lm*eKsx_3l_IWwQzwv?SB}=DnuBSL803YA782f37H?!w-)wNl!0n4L!^KL6|INGk@;xT4&?XO>P zL#{Q(7X$$P48Ti{PaHjKE%cLl*(#^>tDtu6)`K67kGJ-{4iLxEe6M@qF=klBxl0gjE(iI~?4`vT4uCAnC?GFyZ*CHWBzY>IvCsdN?~ySdnmxawfMKeS z^a46~e#660i$Ne*E0o!I{9Nbj6pg2Eyhs-^V&S7|rlcUt6^C@EiZ?)t%3la3_=(Zq z8F*=k+B#TeHV1j^f^|X@q-2&OD*|pb4gb)>335DFrfu!smyQ-hrL~Hzavul3DDYq> z>-l$ner4tMUimKnClo=w697diaIOqy;EbW4JeL<<-8A58)`idNb$f?<|Y8NAvyp@TJG`5eD42g z%~#80DFqzCUYOVeVGd^ZIKeuE+5|e^L6xDm?69#$YtF86?(M z-vL}H_6rWusVL%awXeVtr2fkI@r{!c@6JVQ*=W|yO-<_YG-ju>&FZ-*O&G~ZKfjq+Uve*)IU0#O&@pNmKA$#8&6krcO2t#{~qLxrCcR8 zwS0`OU3{JjxK8HPJ16q?8|C8xI zA#DFmfzd~Ov_3%uwAQ5G`TB^c@_>GeL;w8mmf!!TU_TO7Mk^``L&<}FABkBIh@pj$ z^P_X4UK%8*bVv97i_q&6uQG~tO; z0Q3fp;JjgKm2SzAzOX4UWFCJ0Dvvu_NR{T6+opg9{%nd0vnDB)|?lz;y2v5 z4&*V-TZ%`a)~7CoegiHv5)|Q=aUUe$^trWaS<>g@IKns7n9?dDhw~6o+%W2XZ$(s_ zDzkzN*A4?pnC3ik+-{dz#9TjS?`)ISmyfiwD`DWzwqn@tonT$LOD+PGFqj97PdWa4 zIc`!2OS&Mk_rUw6xfJ+ElF3-~wiI~cFl?gE>OKw$Kh6eC1=nUJLU;cQ1WWurhO!D$DLC|q%g9M+-9CC)wA;u zSKNahoUcX-P2Puq^fi6BiuDIu5s;oiKe2FQO2G?KXXR2qr(Hee&7yjNmm5+;H1rdS zy-6KF72>y*xVBO?=rhK#xD5U9z!)gQb^X@{ifS_gpyh-=yNWH|pGp)%K<%)?N zD-FFR8vvg*^2#Vlo0+1!yTX55x2A2~zgy*zQQ)zmGqsEYW5klXruvzwlh>!2=J){O zS502-M-Rfat)#236Ut=c+ueF=Iah44P_7govRq6+Nv;e4)!tquMZHFz+4B&{bNf}s zh)>aR$J`wjKp|M90jwB?2COGQfE{X&&%M=d7KXIc826b@?7#Uc`>(w>^9{e|X0qSf ziQ4MFzZ@k&=p*%wf-qO6U@W}{*4S-E4DQNEi=R*J{ZbObqb;=Y)iRoLi5Gwd0E)7n zt&A*lsD49R0Xr3#%sIC5NtVEpqMhTkQyd3DE7NFIb&vU8MlU__N0n<*DSvwZ*Qn*%k*Y>a*PL&(Xh81%ymF zBsq!u;+Q8lJ62oLVf3m=2@t9Tl4jC)(&Tg$o?Ip@wwv;G{UDrpq=)(DEr#ge)1`wq z8_NF?#`^ye#-cHFJZ;oq|7c?d|E{Y(Z$;p79T#EV)d2)IIbs#nJ_h`Y>cnKCdlofFigH!h>uWM`e+DRiB>N0xd%DJ+BO~V_ND++eH=sYR?y5J z{gS%PDTW*Nu8iuE9i+?N+?7EHga@l%->oNzUmZVflkW`|;w?MJ)|*>Kn`xouIPH2@ z$~ur$k0_;x6lESEK~$e@ql7pB;pujlRI7Y}yQ6RR$MdB;Ks6T?%f+5C5*XW{YBk#{ zObV6SH3Oazo%?Sh8AbyDZp;gC;97M1RGj-GTXL#y!5TVc^N@Bvf}i~Cv94&e5kNm1 z4llVx)S)j+SfM=l4JUhn7K!W0k)#$xN_l<({G-VlCNUwO9XT*7@`NtjvY*BD5y~uk zWvGo|>?v`mgExbkKXrJ*ae zUc2raVg$v>{eJWSGVYWBV5EIog85rlM@s{@#S|<$MpsqcsFt_X_#ig?GnN8+rXnv^ z`sCdPV{TYTN&GCB5_UW&ejFoN??2wJeyLHvM=3s6i955Pl4bjDT&_&x^KIIN{geYM zm*&~&k|!yK09FACgiwH94#iI`bah%_HlXMD*sXWoSuW zBq!rsd9q1z{jj4n0BQ5{h5es(v&=9Xk~_4dUh_9HgcqV`)|_BhDiW0$`^`sAc5>Id zHy&{v-)S@&Srb6*AWH2{E=k~7$M+ZWJGEsmrMhc3ZDBc;pS}(@=gI&Q9Z?Oi-yZ7q zU3+bx(`5DZ7e{{B>D3MR`7YFXVGxUZLi1>0MFG$1CE=r+!$v`QvjI0AlR{>May1Iko1z%iPDE#qM7n zC=|Qxm4=HVy#O#yv`l>Jqob;)iv=lY=wV;g(*2e0iqF&Oauypggbz1+m!_=ca+(|t z5#P@rtvOX|a+U5+*zhT;ft6bqpNTNq`C5{2UMAKWY7TT@c#||s;cMsd zHLn`?9m`Cl&pN1SwR!&VB+bEjyp4Z!?(-Ap;XU(P02AN-%UV|0X?3t;W6oC^d@A<) z^vAMGn-v#;EHdXR>1%O#(C|^uHANo%!z6fdX*7K$X0wpvqWfgv%_Ql7)V$b;mC$gS z3H<;E2vEoZf>e^-(=6E|^>HgQaXc((FtCpCMf=x&@)Z?g)1fe@+%H|#ig8@+#Ugre zh;NGBK`P*z{P}UZ>9M~+gRs;SKC?M-TNf6@i?l*bit*@_m41bS^@_BZ+{a9I>4pp7 z8S$s(uKVnBj>#40^e8 zC+>#5WJ09d9$6%Ex`1-tVOXh8b0&oGMRlJn5_OWkAC~^is4U^RTt;L;L^x$YH$lpP zU6DCSZnttw@o=if&TV2hW?#DQd58OD2GHTF>9NNjPQrwU%IRB)}8` za+NO$4Oa#Qe*M;7)v*kkd|4$R5EX3nzcUB}xY`>!=)YZUpgRC#bdI_MUHs$!m^twO z9Pr5&uz`{wkgbwZmM;tcYV-}t7ml21qY=6IA2eE@Q1zHsQWrHb2(;Ed$6ZoXgd>+8 z0oZyg#$L6P-%#0^4b+I659B1O@pRmY47tq)dZ6acg}^Iu)9{hK1xyQDZ(3D41EKDT zoR1uRKO}a=!9$R2#U2@Dw1N^3Yu-oK#)Dhzmq!50yHu`EK^36Ecin_ysfh8v**A#{ zIM6MBJJ9>5b`eGvGZ6xWS8Ap-{PqaoPwhJ~px=&wZoh4Wso&cm8iJjz6?mS8kfije znKJAeH11kq^X-;yh4&7WJhS6aBCwf?LCZ;|L?P#PrT(fCxxW2K#e@x=Iza(f(;dL< z`kR-J1!{@yT8s0=#VB7eC2sC4#iliSYr^Xk4CXZ6&HS7n#PK?6aCyMTtQ+a$Bmla% zVHVi@MsdTGx&q~bGFoJMrw}8TrwSOX5y%8EwE(4PI(0Q_Oc(iu;w*XxMn_hUb@QR_ zku~664C5O|#2BDEoWH=BdP>uP8x{9jr;ykKog(-00e4a`25jXdVdq?#4S})#QySx5 zr2Z=SSG9pU!QZ=fDdJ8LT-}L#x zEPrWw9cYW;LgRT0npNz;U;uKPI4GiJ!4FKd9EoKR$XMsSBibA)$l(q=xR1O-MN!cP zGcE9H58sex>f7_7eIFkXp8aB-o!1%6r@0qmCc|kUBRSXmFon1Kzcw`l}sp3~Vn(BvUz|QpO7N`q3Yh3TV$T6CI z4=s+hHfQ8!aR%w-Aj1pwA?=xurm>C=fC)VhZ+J|2)@gk|8py3KRpG7jh4|bmIgV9npsBH|M*IAAw6RrkXq1Hi z3D*5mQDErg18w|l8NO?T$z&bSaDS&Q>wYSo8c~|fJX1i}B8$vXu0|oS{;z;K#5|#k zaSBVH;a|JO_45>StJeSQ#M}h^5B`nR9Vsw&XHE7)cEsz=rXc8%WW*AUk=kkNSOI21 z;sN_iiJPhg7_GeOY*^1ujt^l=9jrvPCgO$2cV&ppshd})hJisgeW!~_)Xd|H9QOQ% z!9_|H*MgT$&4nreQhXc(Y51h5sJXd0qaY=&bR;Ot)%IvWsf0v(_5`rdii&b&fc7{D znlm^r6aTjm8(gYWagL6FgLj5xd?mJ;Pb7Q6!Cgq8>s7=dWszld6__ zXq^B%Y|_iQqK{Z(Smkru=}(joPi8erT(0j2qkpTH%O+c!qUCc*$|R+_3+Mhokm99^ZyFl>L!k+)Os1^G(A4wfgMsWaUp7(3P? z5pNC>J{q8}Yg9-b`=Mn<{1*Es`r0^D3UNDRix7mXlNO{7snvE2YgBtV_89gLxV3Ma;?%bm(`~T`A_q=FI2Zirxy=W^;fVJ0J|^(Y$T+=vsju_|wt|BkR&L zV+NjION$Nebo#@f##q79;rcC+WYy_c{rU?E&O;Xb4Kb!e$dr`d%?IC1LkXJ4#aY{G z)3GZj>JzVpcicUHG-pVOXEXScBQ9-M*>Nbz)|;R&w28Il1!K4cxE#OisZwSiIiiKM z2RC&Fn`B)(Uq`~8Y9#>zy9Gb&4dhVmFvKU-`T~1f>ZRWp`_OE9xnnQx0<63S2(hA~ zc|aVG*_kS!ZMnCd#aZdhKBFagFX z6LO#CK5)8kOS*7(LamMY4sx!w>W?7g)#1g!pXL_;1NrZHP+&Jy_@$A@8|pqoRk=GZ zy=?Ff(h)~bMUanRSzlPQ62`liXcBD}2nMoCFMzj_6TuMelD@)I+mZ zQ3N}(73?gEkVVHgws-4Jeo7>YHhC$PV!w%#maZ=+JEhMhX)3!rf=v?nWmKmJTCSvPs1)=E)~!Czl`*x{ zmW3W{RrO@OR*+5Z4_qZxOV~`B1P7Znra4LG+@GABkGv~tvL8QI*#hLx>X1{f%w(5W zw0dMq=B$}Xu%t7f#ZK~HzBE6Mlm!Uhf^cKnd$i))yzjqs1D*%-MLq0n6T+0I`b~A8 zy%HiTVT;v8u;zJW0F$o(0Z(1Qn;E5bDu(n-6sLgm#2Gv}0R#6i#jG)^X7lG~lkZ)N ztao6Ga>cJ&OHH{ru{TJrTlPmb9Wp5^XP3_KPYUq81^qp^@I2Yh=LA!f`;PN#)Uj)v z|BIaI|JQAGvyG2k~Q$LXU9T&Xt-BS!TQ!n?jjJg3}1O~Ckn2M4{;}_Mk zIjLF-eKl*;sxPhh?Qo_1qL$Frp*36Vv%w9y1THxr`hK%_wcu}|+r_$BLwxUR#)2O#t$I)~1`+_Le%B zm4tCV;|@RDg87v<7yAPp#(iQ+J7ea*$szUSc)DEEvxDqEzGFe8x9}wEv-eH>bM8gA zk?VxV8|&D;;sShC$-;QC!ZT8(586KFyJ1*i~owE{s_I}cxe||PgA~A zBY};jR+;d9F1g8y#ZSd*pJfU9_q^_Ye7NI>=B$X$-r~uB?!&Rv&k@8qyuX9Dd@>BY z(f4{eVh3tEg2gz zx3{x9EAc#S?4KjynpF?rOn0aX(OXXF=E%L9)KA+TL%#Od#j@ve_kpqZ*ZLK(jX@IM z!Gp$`NE?x)J{3xNiXj&;91p0YT!%aO#pGE0{$F(7S0p`!Y+%sa-5Oq`tq%O^_d|5? zFSn7*7d3ZNZRyt>o3#CJX9a&QxxzvdUtR{z%sHDa(c<^{Gf3>RAiHQ$+9v}M2)`)Z)5U>e8`}K`~i1~R1<=Hx>`?=EFqLZ9bp6B){{79cIzlO>#ZG|`XwqI4jMwz{|SFQ{WQ+wD4>sW0R7QzCt#iV zpPUL@oqN>~%w@c_`Y|!wVe6k*);(9+-+_PpGxFlfJ^24gzKXLU^wzr(FUJ#KSvUQg zqoe7`58xjVAyXgxioO3$aiTCk-_KK*ceCnglh*$xbFzu-X152=<;aWT6?DkbKWQ36 z>=oJs3ZZ13JNgf-25N0OULN&tNvVA&uIu+Lve9t=QuyAa!`#2mr96_OM2zrgIXyVe zFed+#tMeLvN>HQ&b(?nfe;t=A66vdaaklD(r(D-5RJSTi-yS`A)G~HRype*yTIIOg zjz`+ukH~ht!uZ}3EiK-ljjg6Ju=aJ~b{p;v{*)D@M^41aXz7(E1Qtgt|9W?@;lWPh z{hwFTTq7sh*syCxSJ4i2V_Xlp^M|v|7CG+SUtSbAU=kFx`7zFxaS5_N5S|u0SY`4M z>u&qN(YB?frg6qxlR|?!%>#w0J-Kg)rB8L1e*J6Lj`H()PM~@Qo)vVBW}D7h&szCk e?dK0TRP>&=YhP9o1O6fe0vnp$DErg#(f``q{E^%v(H&gD3dGG}^;%Y#V z_E!@wV5xcc^64SgB_5uMEHR?YF?fqpY}!uY2ys25_c&zPUWZ8B_cJRBqJ}s!>`~&2 z`Ak$yf&TN;9hA-%)*DPVR{4<5xnAGt=AT5OZph1=p*U2R{2x~NpQ&xbpFWad(jJSn zqm3u4p`m%in&EY3OM84n-FGESO*v_b+9vnM<TML7G-0eTRW6F3WYLUU4>f~m!43vEK5(!Rau3#B9TboI56Pw@NjFZ-T_H!Su1xw zK09!@GxGN(y-k#4oDGq>mw1oh5Ww<}_5I(Q9vbk?$ShDs>-a+A#)XFir*vF=s= zwSUcevy2vfeI{M)>bAO?T^tISS!p3M5O=*xdZAjx*a17|Z)aGv7Pf z8exybmzEYvc|I*5C~SdclIE#kp5a9 zU9dGm{zk_fC49~p7tl!P&xZZfU_Q}bG6R*w(>B2rP$x+LMe~?vpk{uos1#tFPo&66)?ULP94bWMV}7YRY|2-fKx) z6Efm|7}T4$0MAY1o;oSuQYdvLAqLse6@{ekfy0yps?cG!vE>Sz>Sv+*4X2{yK+{eJ zRAR{`Zq;WwUnCg+QvmSaFlN^!Q7?62Y>X~y?obYW%jDOJCmo9Nll#Pf5|;k^T{WRf zNorWCCH@3TeT;dm4CgH-~UVvI)Wm?I{qI5ZQ z<$-~(5U?S%z>y?6VMS{;3}5Y}R}qVgpgf0iUySHF*r&@dd4U#T!h@Z=7NuvP`cpXW zE&T1UCLS4U2eDoXhT1xF1lqU01eTPLX2wm|qE-A&fuh0av(PEts290dA}PR2S0$%Ww*?_W@Qx?R1YlLCFBz>JBnDbGA%>iZ$UX}b?X!QUW&bY=Ugk2Nt=r?TCPN+T$u3_DiMcUUN{|1 z*`XaqXvse7a`@u)YqLwX?yv_Y4ZO(4bE>i?yr`#cETHAHYATCKSqfj>o{bb(4IX$c<_X_ifTS`fr zh@1wgKP{Cp12qPzu8jmeKMn)aDrZGmH)AJyHo3(flSj3aee1P~+I%7sp=bs}{6*k8ibHmN4#6wNi z(afUOCpZiTTgULFiNCOm0byz?Ny9hlqSJ}N?@lOhGJ~ANmi9yVa||1Fc^S27gN^ulN0^5 z?murov7YMFNiXY#D0>=|vk)?U@tJ{NF*nLUb4`qg?$?F?QL==#<9z!{@+*cq7e1F< z_;Z~2#lZZgHKKzO@7%}mhJNc(CE;e?c83G97aVl7!JR0#iP{%szLueH!jplKV2%M}Ez8DYMYvGX zhJ>zER}b*_@NZkHcPA)2C1n~C-j#GQukj+sT3-sYNu#y;)FY8HE(Rt%Y2XI}s5A`^n?F;<(V4oHI59i(0rshN*c1d6VfmX?2ptef&d zg~Ad&s7JxZ%7mxCh_QKWiACa9;Qmkc6Qvp-^?wHE4IaFH8BR?XO{>~hOWq8jRi3B2 zVjyItm-_4EK;IubO!}{aIm0VtgL7L8=!;9(%Udde{Tb4}wi>L*&JjO6FOeCURsn0Z zpAQUPWT|zfAA}^?`gh5emkxy6hxjjbs*K+<0Z@5fIJ;M0D&gjMfMW*D@0dt|clqht z2700wBNPBW=PT5DD6?}~TTr@#Vr<*BHFt4EqvhBKTR0k83o#N4km=OF@_REgVY&(oY1!Z zU@R>#VQHN;Ipc;AJ>_ZqJ-Yu?^+b!f7^I3LD^JlKtR>4`N+`6nWT1=C&EWd~Kx&*p znBxOe#mV?^0P#@NHkL-E7d0T9qSD{RyR1y%ZgvU8TEL}C_E&hP|9M(782hsD=f^Du zH-L^I&otXzV-RHRmc`V3Y*2bJzabR}d^#4$k2&=PkQBDP!p}vS^Q={zpjZ-jiARe~ z1t3{)4b0z$3??P&!sZ&`=Z@#5;bQF!6fT!DobF3Vhg?3n4Yz{J-MjPd zh^!N?AAK&a+ELfV`-_JvJhjmZ8Zq9T6jAPAoM!s=5QIR+Vwbdb8{Cy zhio`}%!>t}F{P!V%+p)yy{l-m!8PMXlq~zqPLfEsXPx_u_hdUUcovmJCUC908gqa` zL*ktuItCag#$8V$dn&I23c_|NqSGgSxKEyTLK;vtONq8rQX~V0<6PMv(if$d5UZ>) z-^NiZtKpQL(AFAnjVm_LU<)I^L(WZckG)|5>&AHRz{{=7&7pVBC-(yM<;<-_7Etx1*R>4HUKs3=InT3l zua`4k%1|-b;_X-TGQYl}S{#sYl)%IJ37omZ^6J|r$%b&>u&mriQ|AQpy9}eZ2jGk! zO9x8wyoVE!nH+xr%%P1$u#2@dZtX~YS2byDI5IM?m#Ew;bw zCr`GG+gY-xPnH=i%{`M;SBPkLP_aN@{Ly^PZIHxCFXh%5qge@J<{(k|cdn$bX_mMA zVHY1xI4z;@=i}>5Br9^d_sXqez{u$HKwdduzXB(4K_R<>ktSSM8%VhwZHC55#To*azr zCUDd-QgBH&RGG|C#UW~2CCM=ew0;H4Ru0CJ!&SEpm}5}GgRA;X8DuUAy$9GbbUMuz z<5hJ`E9S|{k9+I5ypaRE@*NMfx%voHu+P)htFS~^#lBh&Ae;K%0D)x#c2U~G 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 k8KZ+*82+8Te!C(Th!|NFUtY{5dZ)H diff --git a/tests_zemu/snapshots/x-mainmenu/00004.png b/tests_zemu/snapshots/x-mainmenu/00004.png index b43e129ce457a124b5232000f714f0ada417fc19..ebcc9ca244c41667e70e0aa0cef9f679b0b9abdb 100644 GIT binary patch delta 326 zcmcb`^pI(SO1*}si(^Q|oVPav`I;33Tmx^HsK2TAe6v(urR7Y|g)3V9Rp;ji^j0oT zKAOwSfB?%Y&e$<(KYzm>?8VMs@q}Y})mb~n)xKUfyXQ~Pc6gfKTBfoz#q99?AGKFc zt&DCsq;mV%b-$-`4zDaz$;rFiDR$t9Y}$3sl7;p6zRsy-YV_B;Dz(wmGROLq2zS7j zXs`O?s_Xt9+NN;XXMMPS^k)lQ-#xX{w#}~l?z@SV_fhPld9io%PAsXPsgQMPzl74&~Q{BX70 zVr%Ao#zlvi-q`o@ET6)?;6_uP>z8VWzjdF!`^IcxnD>8uWVo1hFv7nK54PPqEx%hN S`RMP@AW=_OKbLh*2~7ZrLzNi- delta 319 zcmaFJbc<<%O1+||i(^Q|oVPcl`I;33S`%-VsK2TAe6y5arG@A5g(KYTzw7gpa?eOg zif-p+K!BJ>roUO%%qg~?5oGnF-TmLgp!qk|6SjJGrk8W=WD5BklHnfYm3H~BZ~dAm z%Tn%u87a4a+={hKFAukVWVZdK3wOe!vd!E~vGps;_omNpcs$*Et6NS`+3h}~qf8=& z-ktn0k8bJba2uWdQulR}>GsQ)j@+)!+&F9zl!bNI-X9qUV zeBorw>$Hq*`m4uNqj~QN>pVO1+J<|t==#JROb`1`oXa_Co+vymr_BFZ+|GBa^Y?hy zvvqJaEoOb_W3lKy^Q-TZkK6C<5L?8VMs@q}Y})mb~n)xKUfyXQ~Pc6gfKTBfoz#q99?AGKFc zt&DCsq;mV%b-$-`4zDaz$;rFiDR$t9Y}$3sl7;p6zRsy-YV_B;Dz(wmGROLq2zS7j zXs`O?s_Xt9+NN;XXMMPS^k)lQ-#xX{w#}~l?z@SV_fhPld9io%PAsXPsgQMPzl74&~Q{BX70 zVr%Ao#zlvi-q`o@ET6)?;6_uP>z8VWzjdF!`^IcxnD>8uWVo1hFv7nK54PPqEx%hN S`RMP@AW=_OKbLh*2~7ZrLzNi- delta 319 zcmaFJbc<<%O1+||i(^Q|oVPcl`I;33S`%-VsK2TAe6y5arG@A5g(KYTzw7gpa?eOg zif-p+K!BJ>roUO%%qg~?5oGnF-TmLgp!qk|6SjJGrk8W=WD5BklHnfYm3H~BZ~dAm z%Tn%u87a4a+={hKFAukVWVZdK3wOe!vd!E~vGps;_omNpcs$*Et6NS`+3h}~qf8=& z-ktn0k8bJba2uWdQulR}>GsQ)j@+)!+&F9zl!bNI-X9qUV zeBorw>$Hq*`m4uNqj~QN>pVO1+J<|t==#JROb`1`oXa_Co+vymr_BFZ+|GBa^Y?hy zvvqJaEoOb_W3lKy^Q-TZkK6C<5L Date: Thu, 7 Dec 2023 15:05:17 -0300 Subject: [PATCH 4/6] update Ledger guidelines enforcer --- .github/workflows/guidelines_enforcer.yml | 2 - app/script_s2.ld | 170 ---------------------- ledger_app.toml | 7 + 3 files changed, 7 insertions(+), 172 deletions(-) delete mode 100644 app/script_s2.ld create mode 100644 ledger_app.toml diff --git a/.github/workflows/guidelines_enforcer.yml b/.github/workflows/guidelines_enforcer.yml index e2dae281..fdaf9f27 100644 --- a/.github/workflows/guidelines_enforcer.yml +++ b/.github/workflows/guidelines_enforcer.yml @@ -21,5 +21,3 @@ jobs: guidelines_enforcer: name: Call Ledger guidelines_enforcer uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_guidelines_enforcer.yml@v1 - with: - relative_app_directory: app diff --git a/app/script_s2.ld b/app/script_s2.ld deleted file mode 100644 index db3150b3..00000000 --- a/app/script_s2.ld +++ /dev/null @@ -1,170 +0,0 @@ -/******************************************************************************* -* Ledger Blue - Secure firmware -* (c) 2016, 2017, 2018, 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. -********************************************************************************/ - -/** - * Global chip memory layout and constants - * - */ - -MEMORY -{ - DISCARD (rwx) : ORIGIN = 0xd0000000, LENGTH = 1M - - FLASH (rx) : ORIGIN = 0xc0de0000, LENGTH = 400K - DATA (r) : ORIGIN = 0xc0de0000, LENGTH = 400K - SRAM (rwx) : ORIGIN = 0xda7a0000, LENGTH = 30K -} - -PAGE_SIZE = 512; -STACK_SIZE = 8192; -END_STACK = ORIGIN(SRAM) + LENGTH(SRAM); - -ENTRY(main); - -SECTIONS -{ - /****************************************************************/ - /* This section locates the code in FLASH */ - /****************************************************************/ - - /** put text in Flash memory, VMA will be equal to LMA */ - .text : - { - /* provide start code symbol, shall be zero */ - _text = .; - _nvram_start = .; - - /* ensure main is always @ 0xC0D00000 */ - *(.boot*) - - /* place the other code and rodata defined BUT nvram variables that are displaced in a r/w area */ - *(.text*) - *(.rodata) - *(.rodata.[^N]*) /*.data.rel.ro* not here to detect invalid PIC usage */ - *(.rodata.N[^_]*) - - . = ALIGN(4); - - /* all code placed */ - _etext = .; - - . = ALIGN(PAGE_SIZE); - - _nvram_data = .; - - /* NVM data (ex-filesystem) */ - *(.bss.N_* .rodata.N_*) - - . = ALIGN(PAGE_SIZE); - _envram_data = .; - - _install_parameters = .; - _nvram_end = .; - } > FLASH = 0x00 - - .data (NOLOAD): - { - . = ALIGN(4); - - /** - * Place RAM initialized variables - */ - _data = .; - - *(vtable) - *(.data*) - - _edata = .; - - } > DISCARD /*> SRAM AT>FLASH = 0x00 */ - - .bss : - { - /** - * Place RAM uninitialized variables - */ - _bss = .; - *(.bss*) - _ebss = .; - - - /** - * Reserve stack size - */ - . = ALIGN(4); - app_stack_canary = .; - PROVIDE(app_stack_canary = .); - . += 4; - _stack_validation = .; - . = _stack_validation + STACK_SIZE; - _stack = ABSOLUTE(END_STACK) - STACK_SIZE; - PROVIDE( _stack = ABSOLUTE(END_STACK) - STACK_SIZE); - _estack = ABSOLUTE(END_STACK); - PROVIDE( _estack = ABSOLUTE(END_STACK) ); - - } > SRAM = 0x00 - - /****************************************************************/ - /* DEBUG */ - /****************************************************************/ - - /* remove the debugging information from the standard libraries */ - DEBUG (NOLOAD) : - { - libc.a ( * ) - libm.a ( * ) - libgcc.a ( * ) - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > DISCARD - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } -} - -PROVIDE(_nvram = ABSOLUTE(_nvram_start)); -PROVIDE(_envram = ABSOLUTE(_nvram_end)); \ No newline at end of file diff --git a/ledger_app.toml b/ledger_app.toml new file mode 100644 index 00000000..10d2a7bf --- /dev/null +++ b/ledger_app.toml @@ -0,0 +1,7 @@ +[app] +build_directory = "./app/" +sdk = "C" +devices = ["nanos", "nanox", "nanos+", "stax"] + +[tests] +unit_directory = "" From ae9ce3ade49eed38f5be1875c971708f1bf118b7 Mon Sep 17 00:00:00 2001 From: ftheirs Date: Fri, 8 Dec 2023 14:43:15 -0300 Subject: [PATCH 5/6] make static analyzer happy --- app/Makefile | 1 - app/src/apdu_handler.c | 10 +- app/src/c_api/rust.c | 136 +++++++---- app/src/coin.h | 3 +- app/src/crypto.c | 35 ++- app/src/crypto.h | 1 - app/src/jubjub.c | 208 ++++++++-------- app/src/jubjub.h | 6 +- app/src/sighash.c | 211 +++++++++------- app/src/sighash.h | 15 +- app/src/txid.c | 541 ++++++++++++++++++++--------------------- app/src/txid.h | 20 +- app/src/zcash_utils.h | 37 +++ 13 files changed, 656 insertions(+), 568 deletions(-) create mode 100644 app/src/zcash_utils.h diff --git a/app/Makefile b/app/Makefile index 0342b5fb..c62e042c 100755 --- a/app/Makefile +++ b/app/Makefile @@ -51,7 +51,6 @@ endif APP_LOAD_PARAMS = --curve secp256k1 --curve ed25519 $(COMMON_LOAD_PARAMS) --path $(APPPATH) -NANOS_STACK_SIZE := 3216 include $(CURDIR)/../deps/ledger-zxlib/makefiles/Makefile.devices $(info TARGET_NAME = [$(TARGET_NAME)]) diff --git a/app/src/apdu_handler.c b/app/src/apdu_handler.c index 0221a046..f34fd6d8 100644 --- a/app/src/apdu_handler.c +++ b/app/src/apdu_handler.c @@ -758,13 +758,17 @@ void handleTest(volatile uint32_t *tx) { jubjub_extendedpoint p; jubjub_fq scal; - jubjub_field_frombytes(scal, scalar); + if (jubjub_field_frombytes(scal, scalar) != zxerr_ok) { + *tx = 0; + MEMZERO(point, sizeof(point)); + THROW(APDU_CODE_OK); + } jubjub_extendedpoint_tobytes(point, JUBJUB_GEN); - zxerr_t err = jubjub_extendedpoint_frombytes(&p, point); + const zxerr_t err = jubjub_extendedpoint_frombytes(&p, point); if (err != zxerr_ok) { *tx = 0; - MEMZERO(point, 32); + MEMZERO(point, sizeof(point)); THROW(APDU_CODE_OK); } // MEMCPY(&p, &JUBJUB_GEN, 32); diff --git a/app/src/c_api/rust.c b/app/src/c_api/rust.c index 046ca3e5..c2b2590d 100644 --- a/app/src/c_api/rust.c +++ b/app/src/c_api/rust.c @@ -7,6 +7,7 @@ #include #include #include +#include "zcash_utils.h" #define CTX_REDJUBJUB "Zcash_RedJubjubH" #define CTX_REDJUBJUB_LEN 16 @@ -29,78 +30,103 @@ unsigned char *bolos_cx_rng(uint8_t *buffer, size_t len) { } #endif -void c_blake2b32_withpersonal(const uint8_t *person, const uint8_t *a, +zxerr_t c_blake2b32_withpersonal(const uint8_t *person, const uint8_t *a, uint32_t a_len, uint8_t *out) { - cx_blake2b_t ctx; - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)person, 16); - cx_hash_no_throw(&ctx.header, CX_LAST, a, a_len, out, 256); + if (person == NULL || a == NULL || out == NULL) { + return zxerr_no_data; + } + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)person, 16)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, a, a_len, out, 256)); + return zxerr_ok; }; -void c_blake2b64_withpersonal(const uint8_t *person, const uint8_t *a, +zxerr_t c_blake2b64_withpersonal(const uint8_t *person, const uint8_t *a, uint32_t a_len, uint8_t *out) { - cx_blake2b_t ctx; - cx_blake2b_init2_no_throw(&ctx, 512, NULL, 0, (uint8_t *)person, 16); - cx_hash_no_throw(&ctx.header, CX_LAST, a, a_len, out, 512); + if (person == NULL || a == NULL || out == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 512, NULL, 0, (uint8_t *)person, 16)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, a, a_len, out, 512)); + return zxerr_ok; }; -void c_zcash_blake2b_redjubjub(const uint8_t *a, uint32_t a_len, +zxerr_t c_zcash_blake2b_redjubjub(const uint8_t *a, uint32_t a_len, const uint8_t *b, uint32_t b_len, uint8_t *out) { - cx_blake2b_t ctx; - cx_blake2b_init2_no_throw(&ctx, 8 * CTX_REDJUBJUB_HASH_LEN, NULL, 0, - (uint8_t *)CTX_REDJUBJUB, CTX_REDJUBJUB_LEN); - cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0); - cx_hash_no_throw(&ctx.header, CX_LAST, b, b_len, out, CTX_REDJUBJUB_HASH_LEN); + if (a == NULL || b == NULL || out == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 8 * CTX_REDJUBJUB_HASH_LEN, NULL, 0,(uint8_t *)CTX_REDJUBJUB, CTX_REDJUBJUB_LEN)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, b, b_len, out, CTX_REDJUBJUB_HASH_LEN)); + return zxerr_ok; } -void c_zcash_blake2b_expand_seed(const uint8_t *a, uint32_t a_len, - const uint8_t *b, uint32_t b_len, - uint8_t *out) { - cx_blake2b_t ctx; - cx_blake2b_init2_no_throw(&ctx, 8 * CTX_EXPAND_SEED_HASH_LEN, NULL, 0, - (uint8_t *)CTX_EXPAND_SEED, CTX_EXPAND_SEED_LEN); - cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0); - cx_hash_no_throw(&ctx.header, CX_LAST, b, b_len, out, - CTX_EXPAND_SEED_HASH_LEN); +zxerr_t c_zcash_blake2b_expand_seed(const uint8_t *a, uint32_t a_len, + const uint8_t *b, uint32_t b_len, uint8_t *out) { + if (a == NULL || b == NULL || out == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 8 * CTX_EXPAND_SEED_HASH_LEN, NULL, 0,(uint8_t *)CTX_EXPAND_SEED, CTX_EXPAND_SEED_LEN)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, b, b_len, out,CTX_EXPAND_SEED_HASH_LEN)); + return zxerr_ok; } -void c_zcash_blake2b_expand_vec_two(const uint8_t *a, uint32_t a_len, +zxerr_t c_zcash_blake2b_expand_vec_two(const uint8_t *a, uint32_t a_len, const uint8_t *b, uint32_t b_len, const uint8_t *c, uint32_t c_len, uint8_t *out) { - cx_blake2b_t ctx; - cx_blake2b_init2_no_throw(&ctx, 8 * CTX_EXPAND_SEED_HASH_LEN, NULL, 0, - (uint8_t *)CTX_EXPAND_SEED, CTX_EXPAND_SEED_LEN); - cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, b, b_len, NULL, 0); - cx_hash_no_throw(&ctx.header, CX_LAST, c, c_len, out, - CTX_EXPAND_SEED_HASH_LEN); + if (a == NULL || b == NULL || c == NULL || out == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 8 * CTX_EXPAND_SEED_HASH_LEN, NULL, 0, (uint8_t *)CTX_EXPAND_SEED, CTX_EXPAND_SEED_LEN)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, b, b_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, c, c_len, out, CTX_EXPAND_SEED_HASH_LEN)); + return zxerr_ok; } -void c_zcash_blake2b_expand_vec_four(const uint8_t *a, uint32_t a_len, +zxerr_t c_zcash_blake2b_expand_vec_four(const uint8_t *a, uint32_t a_len, const uint8_t *b, uint32_t b_len, const uint8_t *c, uint32_t c_len, const uint8_t *d, uint32_t d_len, const uint8_t *e, uint32_t e_len, uint8_t *out) { - cx_blake2b_t ctx; - cx_blake2b_init2_no_throw(&ctx, 8 * CTX_EXPAND_SEED_HASH_LEN, NULL, 0, - (uint8_t *)CTX_EXPAND_SEED, CTX_EXPAND_SEED_LEN); - cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, b, b_len, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, c, c_len, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, d, d_len, NULL, 0); - cx_hash_no_throw(&ctx.header, CX_LAST, e, e_len, out, - CTX_EXPAND_SEED_HASH_LEN); + if (a == NULL || b == NULL || c == NULL || d == NULL || e == NULL || out == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 8 * CTX_EXPAND_SEED_HASH_LEN, NULL, 0, (uint8_t *)CTX_EXPAND_SEED, CTX_EXPAND_SEED_LEN)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, b, b_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, c, c_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, d, d_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, e, e_len, out, CTX_EXPAND_SEED_HASH_LEN)); + return zxerr_ok; } -void zcash_blake2b_hash_two(const uint8_t *perso, uint32_t perso_len, +zxerr_t zcash_blake2b_hash_two(const uint8_t *perso, uint32_t perso_len, const uint8_t *a, uint32_t a_len, const uint8_t *b, uint32_t b_len, uint8_t *out, uint32_t out_len) { - cx_blake2b_t zcashHashBlake2b; - cx_blake2b_init2_no_throw(&zcashHashBlake2b, 8 * out_len, NULL, 0, - (uint8_t *)perso, perso_len); - cx_hash_no_throw(&zcashHashBlake2b.header, 0, a, a_len, NULL, 0); - cx_hash_no_throw(&zcashHashBlake2b.header, CX_LAST, b, b_len, out, out_len); + if (perso == NULL || a == NULL || b == NULL || out == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t zcashHashBlake2b = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&zcashHashBlake2b, 8 * out_len, NULL, 0, (uint8_t *)perso, perso_len)); + CHECK_CX_OK(cx_hash_no_throw(&zcashHashBlake2b.header, 0, a, a_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&zcashHashBlake2b.header, CX_LAST, b, b_len, out, out_len)); + return zxerr_ok; } uint16_t fp_uint64_to_str(char *out, uint16_t outLen, const uint64_t value, @@ -128,13 +154,12 @@ void c_jubjub_scalarmult(uint8_t *point, const uint8_t *scalar) { MEMCPY(scal, scalar, JUBJUB_FIELD_BYTES); SWAP_ENDIAN_BYTES(scal); - zxerr_t err = jubjub_extendedpoint_frombytes(&p, point); - if (err != zxerr_ok) { + if (jubjub_extendedpoint_frombytes(&p, point) != zxerr_ok || + jubjub_extendedpoint_scalarmult(&p, scal) != zxerr_ok || + jubjub_extendedpoint_tobytes(point, &p) != zxerr_ok) { + MEMZERO(point, JUBJUB_FIELD_BYTES); - return; } - jubjub_extendedpoint_scalarmult(&p, scal); - jubjub_extendedpoint_tobytes(point, p); } void c_jubjub_spending_base_scalarmult(uint8_t *point, const uint8_t *scalar) { @@ -143,8 +168,11 @@ void c_jubjub_spending_base_scalarmult(uint8_t *point, const uint8_t *scalar) { MEMCPY(scal, scalar, JUBJUB_FIELD_BYTES); SWAP_ENDIAN_BYTES(scal); MEMCPY(&p, &JUBJUB_GEN, sizeof(jubjub_extendedpoint)); - jubjub_extendedpoint_scalarmult(&p, scal); - jubjub_extendedpoint_tobytes(point, p); + if (jubjub_extendedpoint_scalarmult(&p, scal) != zxerr_ok || + jubjub_extendedpoint_tobytes(point, &p) != zxerr_ok) { + + MEMZERO(point, JUBJUB_FIELD_BYTES); + } } // Replace functions affected by non-constant time opcodes diff --git a/app/src/coin.h b/app/src/coin.h index 0eee2f8d..6176a818 100644 --- a/app/src/coin.h +++ b/app/src/coin.h @@ -49,8 +49,7 @@ extern "C" { #define DATA_LENGTH_GET_IVK 4 // ZIP32-path #define DATA_LENGTH_GET_OVK 4 // ZIP32-path #define DATA_LENGTH_GET_FVK 4 // ZIP32-path -#define DATA_LENGTH_GET_NF \ - 44 // ZIP32-path + 8-byte note position + 32-byte note commitment +#define DATA_LENGTH_GET_NF 44 // ZIP32-path + 8-byte note position + 32-byte note commitment #define DATA_LENGTH_GET_ADDR_SAPLING 4 // ZIP32-path #define DATA_LENGTH_GET_DIV_LIST 15 // ZIP32-path + 11-byte index #define DATA_LENGTH_GET_ADDR_DIV 15 // ZIP32-path + 11-byte div diff --git a/app/src/crypto.c b/app/src/crypto.c index b1a40ca5..b6aed11b 100644 --- a/app/src/crypto.c +++ b/app/src/crypto.c @@ -69,10 +69,16 @@ typedef struct { uint8_t address[50]; } __attribute__((packed)) answer_t; -void ripemd160(uint8_t *in, uint16_t inLen, uint8_t *out) { +zxerr_t ripemd160(uint8_t *in, uint16_t inLen, uint8_t *out) { + if (in == NULL || out == NULL) { + return zxerr_no_data; + } + cx_ripemd160_t rip160; cx_ripemd160_init(&rip160); - cx_hash_no_throw(&rip160.header, CX_LAST, in, inLen, out, CX_RIPEMD160_SIZE); + const cx_err_t error = cx_hash_no_throw(&rip160.header, CX_LAST, in, inLen, out, CX_RIPEMD160_SIZE); + + return error == CX_OK ? zxerr_ok : zxerr_invalid_crypto_settings; } // According to 5.6 Encodings of Addresses and Keys @@ -172,8 +178,8 @@ zxerr_t crypto_fillAddress_secp256k1(uint8_t *buffer, uint16_t buffer_len, address_temp.version[1] = VERSION_P2PKH & 0xFF; cx_hash_sha256(answer->publicKey, PK_LEN_SECP256K1, address_temp.sha256_pk, CX_SHA256_SIZE); // SHA256 - ripemd160(address_temp.sha256_pk, CX_SHA256_SIZE, - address_temp.ripe_sha256_pk); // RIPEMD-160 + CHECK_ZXERR(ripemd160(address_temp.sha256_pk, CX_SHA256_SIZE, + address_temp.ripe_sha256_pk)); // RIPEMD-160 // checksum = sha256(sha256(extended-ripe)) cx_hash_sha256(address_temp.extended_ripe, CX_RIPEMD160_SIZE + VERSION_SIZE, @@ -206,7 +212,7 @@ zxerr_t crypto_fillSaplingSeed(uint8_t *sk) { zxerr_t error = zxerr_unknown; CATCH_CXERROR(os_derive_bip32_with_seed_no_throw(HDW_NORMAL, CX_CURVE_Ed25519, path, HDPATH_LEN_DEFAULT, sk, - NULL, NULL, 0)) + NULL, NULL, 0)); error = zxerr_ok; catch_cx_error: @@ -1088,7 +1094,11 @@ zxerr_t crypto_checkencryptions_sapling(uint8_t *buffer, uint16_t bufferLen, return zxerr_ok; // or some code for ok } -void address_to_script(uint8_t *address, uint8_t *output) { +static zxerr_t address_to_script(uint8_t *address, uint8_t *output) { + if (address == NULL || output == NULL) { + return zxerr_no_data; + } + uint8_t script[SCRIPT_SIZE] = {0}; script[0] = 0x19; script[1] = 0x76; @@ -1097,10 +1107,13 @@ void address_to_script(uint8_t *address, uint8_t *output) { uint8_t tmp[HASH_SIZE] = {0}; cx_hash_sha256(address, PK_LEN_SECP256K1, tmp, CX_SHA256_SIZE); - ripemd160(tmp, CX_SHA256_SIZE, script + SCRIPT_CONSTS_SIZE); + + CHECK_ZXERR(ripemd160(tmp, CX_SHA256_SIZE, script + SCRIPT_CONSTS_SIZE)); + script[24] = 0x88; script[25] = 0xac; MEMCPY(output, script, SCRIPT_SIZE); + return zxerr_ok; } typedef struct { @@ -1167,13 +1180,13 @@ zxerr_t crypto_sign_and_check_transparent(uint8_t *buffer, uint16_t bufferLen, const t_input_item_t *item = t_inlist_retrieve_item(i); CATCH_CXERROR(os_derive_bip32_no_throw( - CX_CURVE_256K1, item->path, HDPATH_LEN_DEFAULT, privateKeyData, NULL)) + CX_CURVE_256K1, item->path, HDPATH_LEN_DEFAULT, privateKeyData, NULL)); CATCH_CXERROR(cx_ecfp_init_private_key_no_throw( - CX_CURVE_256K1, privateKeyData, SK_SECP256K1_SIZE, &cx_privateKey)) + CX_CURVE_256K1, privateKeyData, SK_SECP256K1_SIZE, &cx_privateKey)); CATCH_CXERROR(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, NULL, 0, - &cx_publicKey)) + &cx_publicKey)); CATCH_CXERROR(cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1, &cx_publicKey, - &cx_privateKey, 1)) + &cx_privateKey, 1)); for (int j = 0; j < PUB_KEY_SIZE; j++) { pubKey[j] = cx_publicKey.W[SIG_S_SIZE + SIG_R_SIZE - j]; diff --git a/app/src/crypto.h b/app/src/crypto.h index e81bfe28..210e40c1 100644 --- a/app/src/crypto.h +++ b/app/src/crypto.h @@ -107,7 +107,6 @@ zxerr_t crypto_check_valuebalance(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint8_t tx_version); -void address_to_script(uint8_t *address, uint8_t *output); zxerr_t crypto_sign_and_check_transparent(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint16_t txdatalen, diff --git a/app/src/jubjub.c b/app/src/jubjub.c index 40ff1aa0..90a9ffdf 100644 --- a/app/src/jubjub.c +++ b/app/src/jubjub.c @@ -19,6 +19,9 @@ #include #include +#define CONVERT_CX_ZX(CALL) \ + return CALL == CX_OK ? zxerr_ok : zxerr_invalid_crypto_settings; + unsigned char const JUBJUB_FR_MODULUS_BYTES[JUBJUB_SCALAR_BYTES] = { 14, 125, 180, 234, 101, 51, 175, 169, 6, 103, 59, 1, 1, 52, 59, 0, 166, 104, 32, 147, 204, 200, @@ -101,18 +104,18 @@ void u8_cmov(uint8_t *r, uint8_t a, uint8_t bit) { *r = *r ^ x; } -void jubjub_field_frombytes(jubjub_fq r, const uint8_t *s) { +zxerr_t jubjub_field_frombytes(jubjub_fq r, const uint8_t *s) { MEMZERO(r, sizeof(jubjub_fq)); MEMCPY(r, s, sizeof(jubjub_fq)); - cx_math_modm_no_throw(r, JUBJUB_FIELD_BYTES, JUBJUB_FQ_MODULUS_BYTES, - JUBJUB_FIELD_BYTES); + CONVERT_CX_ZX(cx_math_modm_no_throw(r, JUBJUB_FIELD_BYTES, JUBJUB_FQ_MODULUS_BYTES, + JUBJUB_FIELD_BYTES)); } int jubjub_field_iszero(const jubjub_fq r) { return cx_math_is_zero(r, JUBJUB_FIELD_BYTES); } -uint8_t jubjub_field_is_equal(const jubjub_fq a, const jubjub_fq b) { +__Z_INLINE uint8_t jubjub_field_is_equal(const jubjub_fq a, const jubjub_fq b) { return (MEMCMP(a, b, sizeof(jubjub_fq)) == 0) & 0x01; } @@ -126,38 +129,38 @@ void jubjub_field_copy(jubjub_fq r, const jubjub_fq a) { MEMCPY(r, a, sizeof(jubjub_fq)); } -void jubjub_field_mult(jubjub_fq r, const jubjub_fq a, const jubjub_fq b) { - cx_math_multm_no_throw(r, a, b, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES); +static zxerr_t jubjub_field_mult(jubjub_fq r, const jubjub_fq a, const jubjub_fq b) { + CONVERT_CX_ZX(cx_math_multm_no_throw(r, a, b, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } -void jubjub_field_add(jubjub_fq r, const jubjub_fq a, const jubjub_fq b) { - cx_math_addm_no_throw(r, a, b, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES); +static zxerr_t jubjub_field_add(jubjub_fq r, const jubjub_fq a, const jubjub_fq b) { + CONVERT_CX_ZX(cx_math_addm_no_throw(r, a, b, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } -void jubjub_field_sub(jubjub_fq r, const jubjub_fq a, const jubjub_fq b) { - cx_math_subm_no_throw(r, a, b, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES); +static zxerr_t jubjub_field_sub(jubjub_fq r, const jubjub_fq a, const jubjub_fq b) { + CONVERT_CX_ZX(cx_math_subm_no_throw(r, a, b, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } -void jubjub_field_inverse(jubjub_fq r, jubjub_fq a) { - cx_math_invprimem_no_throw(r, a, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES); +static zxerr_t jubjub_field_inverse(jubjub_fq r, jubjub_fq a) { + CONVERT_CX_ZX(cx_math_invprimem_no_throw(r, a, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } -void jubjub_field_square(jubjub_fq r, jubjub_fq a) { - cx_math_multm_no_throw(r, a, a, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES); +static zxerr_t jubjub_field_square(jubjub_fq r, jubjub_fq a) { + CONVERT_CX_ZX(cx_math_multm_no_throw(r, a, a, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } -void jubjub_field_double(jubjub_fq r, jubjub_fq a) { - cx_math_addm_no_throw(r, a, a, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES); +static zxerr_t jubjub_field_double(jubjub_fq r, jubjub_fq a) { + CONVERT_CX_ZX(cx_math_addm_no_throw(r, a, a, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } -void jubjub_field_pow_t(jubjub_fq r, const jubjub_fq a) { - cx_math_powm_no_throw(r, a, JUBJUB_FQ_SQRT_T, JUBJUB_FIELD_BYTES, - JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES); +static zxerr_t jubjub_field_pow_t(jubjub_fq r, const jubjub_fq a) { + CONVERT_CX_ZX(cx_math_powm_no_throw(r, a, JUBJUB_FQ_SQRT_T, JUBJUB_FIELD_BYTES, + JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } -void jubjub_field_negate(jubjub_fq r, const jubjub_fq a) { - cx_math_subm_no_throw(r, JUBJUB_FQ_ZERO, a, JUBJUB_FQ_MODULUS_BYTES, - JUBJUB_FIELD_BYTES); +static zxerr_t jubjub_field_negate(jubjub_fq r, const jubjub_fq a) { + CONVERT_CX_ZX(cx_math_subm_no_throw(r, JUBJUB_FQ_ZERO, a, JUBJUB_FQ_MODULUS_BYTES, + JUBJUB_FIELD_BYTES)); } void jubjub_field_cmov(jubjub_fq r, const jubjub_fq a, uint8_t bit) { @@ -174,24 +177,24 @@ void jubjub_field_cmov(jubjub_fq r, const jubjub_fq a, uint8_t bit) { zxerr_t jubjub_field_sqrt(jubjub_fq r, const jubjub_fq a) { jubjub_fq w, x, b, z; - jubjub_field_pow_t(w, a); + CHECK_ZXERR(jubjub_field_pow_t(w, a)); uint8_t v = 32; - jubjub_field_mult(x, a, w); - jubjub_field_mult(b, x, w); + CHECK_ZXERR(jubjub_field_mult(x, a, w)); + CHECK_ZXERR(jubjub_field_mult(b, x, w)); jubjub_field_copy(z, JUBJUB_FQ_ROOT_OF_UNITY); jubjub_fq tmp; // uint8_t index = 0; for (uint8_t max_v = 32; max_v >= 1; max_v--) { uint8_t k = 1; - jubjub_field_square(tmp, b); + CHECK_ZXERR(jubjub_field_square(tmp, b)); uint8_t j_less_than_v = 1; for (uint8_t j = 2; j < max_v; j++) { uint8_t tmp_is_one = jubjub_field_is_equal(tmp, JUBJUB_FQ_ONE); jubjub_fq squared; jubjub_field_copy(squared, z); jubjub_field_cmov(squared, tmp, !tmp_is_one); - jubjub_field_square(squared, squared); + CHECK_ZXERR(jubjub_field_square(squared, squared)); jubjub_field_cmov(tmp, squared, !tmp_is_one); jubjub_fq new_z; jubjub_field_copy(new_z, squared); @@ -202,16 +205,16 @@ zxerr_t jubjub_field_sqrt(jubjub_fq r, const jubjub_fq a) { } jubjub_fq result; - jubjub_field_mult(result, x, z); + CHECK_ZXERR(jubjub_field_mult(result, x, z)); uint8_t b_is_one = jubjub_field_is_equal(b, JUBJUB_FQ_ONE); jubjub_field_cmov(x, result, !b_is_one); - jubjub_field_square(z, z); - jubjub_field_mult(b, b, z); + CHECK_ZXERR(jubjub_field_square(z, z)); + CHECK_ZXERR(jubjub_field_mult(b, b, z)); v = k; } - jubjub_field_square(w, x); + CHECK_ZXERR(jubjub_field_square(w, x)); uint8_t correct = jubjub_field_is_equal(w, a); if (!correct) { @@ -222,129 +225,129 @@ zxerr_t jubjub_field_sqrt(jubjub_fq r, const jubjub_fq a) { return zxerr_ok; } -void jubjub_extendedpoint_cmov(jubjub_extendedpoint *r, jubjub_extendedpoint p, +static void jubjub_extendedpoint_cmov(jubjub_extendedpoint *r, jubjub_extendedpoint *p, unsigned int bit) { - jubjub_field_cmov(r->U, p.U, bit); - jubjub_field_cmov(r->V, p.V, bit); - jubjub_field_cmov(r->Z, p.Z, bit); - jubjub_field_cmov(r->T1, p.T1, bit); - jubjub_field_cmov(r->T1, p.T2, bit); -} - -void jubjub_extendedpoint_normalize(jubjub_extendedpoint *r, - jubjub_extendedpoint p) { - jubjub_fq zinv; - jubjub_field_inverse(zinv, r->Z); - jubjub_field_one(r->Z); - jubjub_field_mult(r->U, p.U, zinv); - jubjub_field_mult(r->V, p.V, zinv); - jubjub_field_copy(r->T1, p.U); - jubjub_field_copy(r->T2, p.V); + jubjub_field_cmov(r->U, p->U, bit); + jubjub_field_cmov(r->V, p->V, bit); + jubjub_field_cmov(r->Z, p->Z, bit); + jubjub_field_cmov(r->T1, p->T1, bit); + jubjub_field_cmov(r->T1, p->T2, bit); } -void jubjub_extendedpoint_add(jubjub_extendedpoint *r, jubjub_extendedpoint p) { +static zxerr_t jubjub_extendedpoint_add(jubjub_extendedpoint *r, const jubjub_extendedpoint *p) { + if (r == NULL || p == NULL) { + return zxerr_no_data; + } // jubjub_extendedpoint np; // jubjub_extendedpoint_normalize(&np, p); // extendednielspoint jubjub_fq v_minus_u, v_plus_u, t2d; - jubjub_field_add(v_plus_u, p.V, p.U); - jubjub_field_sub(v_minus_u, p.V, p.U); - jubjub_field_mult(t2d, p.T1, p.T2); - jubjub_field_mult(t2d, t2d, JUBJUB_FQ_EDWARDS_2D); + CHECK_ZXERR(jubjub_field_add(v_plus_u, p->V, p->U)); + CHECK_ZXERR(jubjub_field_sub(v_minus_u, p->V, p->U)); + CHECK_ZXERR(jubjub_field_mult(t2d, p->T1, p->T2)); + CHECK_ZXERR(jubjub_field_mult(t2d, t2d, JUBJUB_FQ_EDWARDS_2D)); jubjub_fq a, b, c, d; - jubjub_field_sub(a, r->V, r->U); - jubjub_field_mult(a, a, v_minus_u); + CHECK_ZXERR(jubjub_field_sub(a, r->V, r->U)); + CHECK_ZXERR(jubjub_field_mult(a, a, v_minus_u)); - jubjub_field_add(b, r->V, r->U); - jubjub_field_mult(b, b, v_plus_u); + CHECK_ZXERR(jubjub_field_add(b, r->V, r->U)); + CHECK_ZXERR(jubjub_field_mult(b, b, v_plus_u)); - jubjub_field_mult(c, r->T1, r->T2); - jubjub_field_mult(c, c, t2d); + CHECK_ZXERR(jubjub_field_mult(c, r->T1, r->T2)); + CHECK_ZXERR(jubjub_field_mult(c, c, t2d)); - jubjub_field_mult(d, r->Z, p.Z); - jubjub_field_double(d, d); + CHECK_ZXERR(jubjub_field_mult(d, r->Z, p->Z)); + CHECK_ZXERR(jubjub_field_double(d, d)); // completed point jubjub_fq u, v, z, t; - jubjub_field_sub(u, b, a); - jubjub_field_add(v, b, a); - jubjub_field_add(z, d, c); - jubjub_field_sub(t, d, c); + CHECK_ZXERR(jubjub_field_sub(u, b, a)); + CHECK_ZXERR(jubjub_field_add(v, b, a)); + CHECK_ZXERR(jubjub_field_add(z, d, c)); + CHECK_ZXERR(jubjub_field_sub(t, d, c)); // completed point to extended - jubjub_field_mult(r->U, u, t); - jubjub_field_mult(r->V, v, z); - jubjub_field_mult(r->Z, t, z); + CHECK_ZXERR(jubjub_field_mult(r->U, u, t)); + CHECK_ZXERR(jubjub_field_mult(r->V, v, z)); + CHECK_ZXERR(jubjub_field_mult(r->Z, t, z)); jubjub_field_copy(r->T1, u); jubjub_field_copy(r->T2, v); + + return zxerr_ok; } -void jubjub_extendedpoint_double(jubjub_extendedpoint *r, - jubjub_extendedpoint p) { +static zxerr_t jubjub_extendedpoint_double(jubjub_extendedpoint *r, + jubjub_extendedpoint *p) { jubjub_fq uu, vv; jubjub_fq zz2, uv2; jubjub_fq vv_plus_uu, vv_minus_uu; - jubjub_field_square(uu, p.U); - jubjub_field_square(vv, p.V); + CHECK_ZXERR(jubjub_field_square(uu, p->U)); + CHECK_ZXERR(jubjub_field_square(vv, p->V)); - jubjub_field_square(zz2, p.Z); - jubjub_field_double(zz2, zz2); + CHECK_ZXERR(jubjub_field_square(zz2, p->Z)); + CHECK_ZXERR(jubjub_field_double(zz2, zz2)); - jubjub_field_add(uv2, p.U, p.V); - jubjub_field_square(uv2, uv2); + CHECK_ZXERR(jubjub_field_add(uv2, p->U, p->V)); + CHECK_ZXERR(jubjub_field_square(uv2, uv2)); - jubjub_field_add(vv_plus_uu, vv, uu); - jubjub_field_sub(vv_minus_uu, vv, uu); + CHECK_ZXERR(jubjub_field_add(vv_plus_uu, vv, uu)); + CHECK_ZXERR(jubjub_field_sub(vv_minus_uu, vv, uu)); // completed point jubjub_fq u, v, z, t; - jubjub_field_sub(u, uv2, vv_plus_uu); + CHECK_ZXERR(jubjub_field_sub(u, uv2, vv_plus_uu)); jubjub_field_copy(v, vv_plus_uu); jubjub_field_copy(z, vv_minus_uu); - jubjub_field_sub(t, zz2, vv_minus_uu); + CHECK_ZXERR(jubjub_field_sub(t, zz2, vv_minus_uu)); // completed point to extended - jubjub_field_mult(r->U, u, t); - jubjub_field_mult(r->V, v, z); - jubjub_field_mult(r->Z, t, z); + CHECK_ZXERR(jubjub_field_mult(r->U, u, t)); + CHECK_ZXERR(jubjub_field_mult(r->V, v, z)); + CHECK_ZXERR(jubjub_field_mult(r->Z, t, z)); jubjub_field_copy(r->T1, u); jubjub_field_copy(r->T2, v); + + return zxerr_ok; } -void jubjub_extendedpoint_scalarmult(jubjub_extendedpoint *r, +zxerr_t jubjub_extendedpoint_scalarmult(jubjub_extendedpoint *r, jubjub_fr scalar) { jubjub_extendedpoint p, dummy; MEMCPY(&p, &JUBJUB_ID, sizeof(jubjub_extendedpoint)); // skip the first 4 bits as they are always 0 for (int i = 4; i < 8 * JUBJUB_SCALAR_BYTES; i++) { uint8_t di = (scalar[i / 8] >> (7 - (i % 8))) & 0x01; - jubjub_extendedpoint_double(&p, p); + CHECK_ZXERR(jubjub_extendedpoint_double(&p, &p)); MEMCPY(&dummy, &p, sizeof(jubjub_extendedpoint)); - jubjub_extendedpoint_add(&dummy, *r); - jubjub_extendedpoint_cmov(&p, dummy, di); + CHECK_ZXERR(jubjub_extendedpoint_add(&dummy, r)); + jubjub_extendedpoint_cmov(&p, &dummy, di); } MEMCPY(r, &p, sizeof(jubjub_extendedpoint)); + + return zxerr_ok; } -void jubjub_extendedpoint_tobytes(uint8_t *s, jubjub_extendedpoint p) { +zxerr_t jubjub_extendedpoint_tobytes(uint8_t *s, jubjub_extendedpoint *p) { jubjub_fq x, y, zinv; - jubjub_field_inverse(zinv, p.Z); - jubjub_field_mult(x, p.U, zinv); - jubjub_field_mult(y, p.V, zinv); + CHECK_ZXERR(jubjub_field_inverse(zinv, p->Z)); + CHECK_ZXERR(jubjub_field_mult(x, p->U, zinv)); + CHECK_ZXERR(jubjub_field_mult(y, p->V, zinv)); MEMCPY(s, y, sizeof(jubjub_fq)); s[0] |= (x[31] << 7); SWAP_ENDIAN_BYTES(&s[0]); + + return zxerr_ok; } zxerr_t jubjub_extendedpoint_frombytes(jubjub_extendedpoint *p, uint8_t *s) { - uint8_t b[JUBJUB_FIELD_BYTES]; + uint8_t b[JUBJUB_FIELD_BYTES] = {0}; MEMCPY(b, s, JUBJUB_FIELD_BYTES); SWAP_ENDIAN_BYTES(&b[0]); @@ -353,26 +356,24 @@ zxerr_t jubjub_extendedpoint_frombytes(jubjub_extendedpoint *p, uint8_t *s) { jubjub_fq v, v2, v3, u; - jubjub_field_frombytes(v, b); - jubjub_field_square(v2, v); + CHECK_ZXERR(jubjub_field_frombytes(v, b)); + CHECK_ZXERR(jubjub_field_square(v2, v)); jubjub_field_copy(v3, v2); - jubjub_field_mult(v2, v2, JUBJUB_FQ_EDWARDS_D); - jubjub_field_add(v2, v2, JUBJUB_FQ_ONE); + CHECK_ZXERR(jubjub_field_mult(v2, v2, JUBJUB_FQ_EDWARDS_D)); + CHECK_ZXERR(jubjub_field_add(v2, v2, JUBJUB_FQ_ONE)); if (jubjub_field_iszero(v2)) { return zxerr_unknown; } - jubjub_field_inverse(v2, v2); - jubjub_field_sub(v3, v3, JUBJUB_FQ_ONE); - jubjub_field_mult(v3, v3, v2); - if (jubjub_field_sqrt(u, v3) != zxerr_ok) { - return zxerr_unknown; - } + CHECK_ZXERR(jubjub_field_inverse(v2, v2)); + CHECK_ZXERR(jubjub_field_sub(v3, v3, JUBJUB_FQ_ONE)); + CHECK_ZXERR(jubjub_field_mult(v3, v3, v2)); + CHECK_ZXERR(jubjub_field_sqrt(u, v3)); uint8_t flip_sign = (u[JUBJUB_FIELD_BYTES - 1] ^ sign) & 1; jubjub_fq u_neg; - jubjub_field_negate(u_neg, u); + CHECK_ZXERR(jubjub_field_negate(u_neg, u)); jubjub_field_cmov(u, u_neg, flip_sign); jubjub_field_copy(p->U, u); @@ -380,5 +381,6 @@ zxerr_t jubjub_extendedpoint_frombytes(jubjub_extendedpoint *p, uint8_t *s) { jubjub_field_copy(p->Z, JUBJUB_FQ_ONE); jubjub_field_copy(p->T1, u); jubjub_field_copy(p->T2, v); + return zxerr_ok; } diff --git a/app/src/jubjub.h b/app/src/jubjub.h index e3364db7..fb575e3b 100644 --- a/app/src/jubjub.h +++ b/app/src/jubjub.h @@ -54,10 +54,10 @@ extern const jubjub_extendedpoint JUBJUB_GEN; } \ } -void jubjub_extendedpoint_tobytes(uint8_t *s, jubjub_extendedpoint p); +zxerr_t jubjub_extendedpoint_tobytes(uint8_t *s, jubjub_extendedpoint *p); -void jubjub_extendedpoint_scalarmult(jubjub_extendedpoint *r, jubjub_fr scalar); +zxerr_t jubjub_extendedpoint_scalarmult(jubjub_extendedpoint *r, jubjub_fr scalar); -void jubjub_field_frombytes(jubjub_fq r, const uint8_t *s); +zxerr_t jubjub_field_frombytes(jubjub_fq r, const uint8_t *s); zxerr_t jubjub_extendedpoint_frombytes(jubjub_extendedpoint *p, uint8_t *s); diff --git a/app/src/sighash.c b/app/src/sighash.c index 02a6d9c2..b89a41fd 100644 --- a/app/src/sighash.c +++ b/app/src/sighash.c @@ -22,189 +22,212 @@ #include "txid.h" #include #include +#include "zcash_utils.h" -#define ZCASH_PREVOUTS_HASH_PERSONALIZATION "ZcashPrevoutHash" -#define ZCASH_SEQUENCE_HASH_PERSONALIZATION "ZcashSequencHash" -#define ZCASH_OUTPUTS_HASH_PERSONALIZATION "ZcashOutputsHash" -// #define ZCASH_JOINSPLITS_HASH_PERSONALIZATION "ZcashJSplitsHash" not -// supported -#define CTX_ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION "ZcashSSpendsHash" -#define CTX_ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION "ZcashSOutputHash" +const uint8_t PERSONALIZATION_SIZE = 16; +const uint8_t ZCASH_PREVOUTS_HASH_PERSONALIZATION[] = "ZcashPrevoutHash"; +const uint8_t ZCASH_SEQUENCE_HASH_PERSONALIZATION[] = "ZcashSequencHash"; +const uint8_t ZCASH_OUTPUTS_HASH_PERSONALIZATION[] = "ZcashOutputsHash"; +// #define ZCASH_JOINSPLITS_HASH_PERSONALIZATION "ZcashJSplitsHash" not supported +const uint8_t CTX_ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION[] = "ZcashSSpendsHash"; +const uint8_t CTX_ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION[] = "ZcashSOutputHash"; // const uint8_t CONSENSUS_BRANCH_ID_SAPLING[4] = {0x76, 0xb8, 0x09, 0xBB}; // // sapling const uint8_t CONSENSUS_BRANCH_ID_ORCHARD[4] = {0xC2, 0xD6, 0xD0, // 0xB4}; // orchard // -const uint8_t CONSENSUS_BRANCH_ID_SAPLING[4] = {0xBB, 0x09, 0xB8, - 0x76}; // sapling -const uint8_t CONSENSUS_BRANCH_ID_ORCHARD[4] = {0xB4, 0xD0, 0xD6, - 0xC2}; // orchard +const uint8_t CONSENSUS_BRANCH_ID_SAPLING[4] = {0xBB, 0x09, 0xB8, 0x76}; // sapling +const uint8_t CONSENSUS_BRANCH_ID_ORCHARD[4] = {0xB4, 0xD0, 0xD6, 0xC2}; // orchard -void sapling_transparent_prevouts_hash(const uint8_t *input, uint8_t *output) { +zxerr_t sapling_transparent_prevouts_hash(const uint8_t *input, uint8_t *output) { const uint8_t n = t_inlist_len(); - cx_blake2b_t ctx; - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, - (uint8_t *)ZCASH_PREVOUTS_HASH_PERSONALIZATION, 16); + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0,(uint8_t *)ZCASH_PREVOUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); if (n == 0) { - cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE); - return; + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; } const uint8_t *data = input + INDEX_TIN_PREVOUT; for (uint8_t i = 0; i < n - 1; i++, data += T_IN_TX_LEN) { - cx_hash_no_throw(&ctx.header, 0, data, 36, NULL, 0); + if (cx_hash_no_throw(&ctx.header, 0, data, 36, NULL, 0) != CX_OK) { + return zxerr_invalid_crypto_settings; + } } - cx_hash_no_throw(&ctx.header, CX_LAST, data, 36, output, HASH_SIZE); + const cx_err_t error = cx_hash_no_throw(&ctx.header, CX_LAST, data, 36, output, HASH_SIZE); + + return error == CX_OK ? zxerr_ok : zxerr_invalid_crypto_settings; } -void sapling_transparent_sequence_hash(const uint8_t *input, uint8_t *output) { +zxerr_t sapling_transparent_sequence_hash(const uint8_t *input, uint8_t *output) { const uint8_t n = t_inlist_len(); - cx_blake2b_t ctx; - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, - (uint8_t *)ZCASH_SEQUENCE_HASH_PERSONALIZATION, 16); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_SEQUENCE_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); if (n == 0) { - cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE); - return; + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; } const uint8_t *data = input + INDEX_TIN_SEQ; for (uint8_t i = 0; i < n - 1; i++, data += T_IN_TX_LEN) { - cx_hash_no_throw(&ctx.header, 0, data, 4, NULL, 0); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, 4, NULL, 0)); } - cx_hash_no_throw(&ctx.header, CX_LAST, data, 4, output, HASH_SIZE); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, 4, output, HASH_SIZE)); + + return zxerr_ok; } -void v4_transparent_outputs_hash(uint8_t *output) { +zxerr_t v4_transparent_outputs_hash(uint8_t *output) { const uint8_t n = t_outlist_len(); - cx_blake2b_t ctx; - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, - (uint8_t *)ZCASH_OUTPUTS_HASH_PERSONALIZATION, 16); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_OUTPUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); if (n == 0) { - cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE); - return; + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; } - uint8_t data[34]; + uint8_t data[34] = {0}; uint8_t i = 0; for (; i < n - 1; i++) { t_output_item_t *item = t_outlist_retrieve_item(i); MEMCPY(data, (uint8_t *)&(item->value), 8); MEMCPY(data + 8, item->address, SCRIPT_SIZE); - cx_hash_no_throw(&ctx.header, 0, data, sizeof(data), NULL, 0); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, sizeof(data), NULL, 0)); } t_output_item_t *item = t_outlist_retrieve_item(i); MEMCPY(data, (uint8_t *)&(item->value), 8); MEMCPY(data + 8, item->address, SCRIPT_SIZE); - cx_hash_no_throw(&ctx.header, CX_LAST, data, sizeof(data), output, HASH_SIZE); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, sizeof(data), output, HASH_SIZE)); + + return zxerr_ok; } -void shielded_output_hash(const uint8_t *input, uint16_t inputlen, +zxerr_t shielded_output_hash(const uint8_t *input, uint16_t inputlen, uint8_t *output) { if (inputlen == 0) { MEMZERO(output, HASH_SIZE); - return; + return zxerr_no_data; } - cx_blake2b_t ctx; - cx_blake2b_init2_no_throw( - &ctx, 256, NULL, 0, - (uint8_t *)CTX_ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION, 16); - cx_hash_no_throw(&ctx.header, CX_LAST, input, inputlen, output, HASH_SIZE); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0,(uint8_t *)CTX_ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, input, inputlen, output, HASH_SIZE)); + + return zxerr_ok; } -void shielded_spend_hash(const uint8_t *input, uint16_t inputlen, +zxerr_t shielded_spend_hash(const uint8_t *input, uint16_t inputlen, uint8_t *output) { if (inputlen == 0) { MEMZERO(output, HASH_SIZE); - return; + return zxerr_no_data; } - cx_blake2b_t ctx; - cx_blake2b_init2_no_throw( - &ctx, 256, NULL, 0, - (uint8_t *)CTX_ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION, 16); - cx_hash_no_throw(&ctx.header, CX_LAST, input, inputlen, output, HASH_SIZE); + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0,(uint8_t *)CTX_ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION, 16)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, input, inputlen, output, HASH_SIZE)); + + return zxerr_ok; } -static void signature_hash_v4(const uint8_t *input, uint16_t inputlen, - uint8_t *output) { +static zxerr_t signature_hash_v4(const uint8_t *input, uint16_t inputlen, uint8_t *output) { zemu_log_stack("signature_hash_v4"); - cx_blake2b_t ctx; + if (input == NULL || output == NULL) { + return zxerr_no_data; + } - uint8_t personalization[16] = {0}; - MEMCPY(personalization, "ZcashSigHash", 12); + cx_blake2b_t ctx = {0}; + + uint8_t personalization[16] = "ZcashSigHash"; MEMCPY(personalization + 12, CONSENSUS_BRANCH_ID_ORCHARD, 4); - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, 16); + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, PERSONALIZATION_SIZE)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, input, inputlen, output, HASH_SIZE)); - cx_hash_no_throw(&ctx.header, CX_LAST, input, inputlen, output, HASH_SIZE); + return zxerr_ok; } -static void signature_hash_v5(const uint8_t *input, uint8_t *start_signdata, +static zxerr_t signature_hash_v5(const uint8_t *input, uint8_t *start_signdata, uint8_t index, signable_input type, uint8_t *output) { zemu_log_stack("signature_hash_v5"); - cx_blake2b_t ctx; + if (input == NULL || start_signdata == NULL || output == NULL) { + return zxerr_no_data; + } - uint8_t personalization[16] = {0}; - MEMCPY(personalization, "ZcashTxHash_", 12); + cx_blake2b_t ctx = {0}; + + uint8_t personalization[16] = "ZcashTxHash_"; MEMCPY(personalization + 12, CONSENSUS_BRANCH_ID_ORCHARD, 4); - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, 16); + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, PERSONALIZATION_SIZE)); uint8_t header_digest[32] = {0}; uint8_t transparent_digest[32] = {0}; uint8_t sapling_digest[32] = {0}; uint8_t orchard_digest[32] = {0}; - hash_header_txid_data(start_signdata, header_digest); - transparent_sig_digest(input, start_signdata, index, type, - transparent_digest); - hash_sapling_txid_data(start_signdata, sapling_digest); - hash_empty_orchard_txid_data(orchard_digest); - - cx_hash_no_throw(&ctx.header, 0, header_digest, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, transparent_digest, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, sapling_digest, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, CX_LAST, orchard_digest, HASH_SIZE, output, - HASH_SIZE); + CHECK_ZXERR(hash_header_txid_data(start_signdata, header_digest)); + CHECK_ZXERR(transparent_sig_digest(input, start_signdata, index, type, transparent_digest)); + CHECK_ZXERR(hash_sapling_txid_data(start_signdata, sapling_digest)); + CHECK_ZXERR(hash_empty_orchard_txid_data(orchard_digest)); + + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, header_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, transparent_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, sapling_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, orchard_digest, HASH_SIZE, output, HASH_SIZE)); + + return zxerr_ok; } -void signature_hash(const uint8_t *txdata, uint8_t *start_signdata, - uint16_t inputlen, const uint8_t tx_version, - uint8_t *output) { +zxerr_t signature_hash(const uint8_t *txdata, uint8_t *start_signdata, + uint16_t inputlen, const uint8_t tx_version, uint8_t *output) { + if (txdata == NULL || start_signdata == NULL || output == NULL) { + return zxerr_no_data; + } + if (tx_version == TX_VERSION_SAPLING) { - signature_hash_v4(start_signdata, inputlen, output); + return signature_hash_v4(start_signdata, inputlen, output); } else if (tx_version == TX_VERSION_NU5) { - signature_hash_v5(txdata, start_signdata, 0, shielded, output); + return signature_hash_v5(txdata, start_signdata, 0, shielded, output); } + + return zxerr_unknown; } -static void signature_script_hash_v4(const uint8_t *input, uint16_t inputlen, - uint8_t *script, uint16_t scriptlen, - uint8_t *output) { - cx_blake2b_t ctx; +static zxerr_t signature_script_hash_v4(const uint8_t *input, uint16_t inputlen, + uint8_t *script, uint16_t scriptlen, uint8_t *output) { + if (input == NULL || script == NULL || output == NULL) { + return zxerr_no_data; + } - uint8_t personalization[16] = {0}; - MEMCPY(personalization, "ZcashSigHash", 12); + cx_blake2b_t ctx = {0}; + uint8_t personalization[16] = "ZcashSigHash"; MEMCPY(personalization + 12, CONSENSUS_BRANCH_ID_ORCHARD, 4); - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, 16); - cx_hash_no_throw(&ctx.header, 0, input, inputlen, NULL, 0); + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, PERSONALIZATION_SIZE)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, input, inputlen, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, script, scriptlen, output, HASH_SIZE)); - cx_hash_no_throw(&ctx.header, CX_LAST, script, scriptlen, output, HASH_SIZE); + return zxerr_ok; } -void signature_script_hash(const uint8_t *input, uint8_t *start_signdata, - uint16_t inputlen, uint8_t *script, - uint16_t scriptlen, uint8_t index, - const uint8_t tx_version, uint8_t *output) { +zxerr_t signature_script_hash(const uint8_t *input, uint8_t *start_signdata, uint16_t inputlen, + uint8_t *script, uint16_t scriptlen, uint8_t index, + const uint8_t tx_version, uint8_t *output) { + if (input == NULL || start_signdata == NULL || script == NULL || output == NULL) { + return zxerr_no_data; + } + if (tx_version == TX_VERSION_SAPLING) { - signature_script_hash_v4(start_signdata, inputlen, script, scriptlen, - output); + return signature_script_hash_v4(start_signdata, inputlen, script, scriptlen,output); } else if (tx_version == TX_VERSION_NU5) { - signature_hash_v5(input, start_signdata, index, transparent, output); + return signature_hash_v5(input, start_signdata, index, transparent, output); } + + return zxerr_unknown; } diff --git a/app/src/sighash.h b/app/src/sighash.h index e0a11c38..892ff262 100644 --- a/app/src/sighash.h +++ b/app/src/sighash.h @@ -17,29 +17,30 @@ #pragma once #include +#include "zxerror.h" typedef enum { transparent = 0, shielded = 1, } signable_input; -void sapling_transparent_prevouts_hash(const uint8_t *input, uint8_t *output); +zxerr_t sapling_transparent_prevouts_hash(const uint8_t *input, uint8_t *output); -void sapling_transparent_sequence_hash(const uint8_t *input, uint8_t *output); +zxerr_t sapling_transparent_sequence_hash(const uint8_t *input, uint8_t *output); -void v4_transparent_outputs_hash(uint8_t *output); +zxerr_t v4_transparent_outputs_hash(uint8_t *output); -void shielded_output_hash(const uint8_t *input, uint16_t inputlen, +zxerr_t shielded_output_hash(const uint8_t *input, uint16_t inputlen, uint8_t *output); -void shielded_spend_hash(const uint8_t *input, uint16_t inputlen, +zxerr_t shielded_spend_hash(const uint8_t *input, uint16_t inputlen, uint8_t *output); -void signature_hash(const uint8_t *txdata, uint8_t *start_signdata, +zxerr_t signature_hash(const uint8_t *txdata, uint8_t *start_signdata, uint16_t inputlen, const uint8_t tx_version, uint8_t *output); -void signature_script_hash(const uint8_t *input, uint8_t *start_signdata, +zxerr_t signature_script_hash(const uint8_t *input, uint8_t *start_signdata, uint16_t inputlen, uint8_t *script, uint16_t scriptlen, uint8_t index, const uint8_t tx_version, uint8_t *output); diff --git a/app/src/txid.c b/app/src/txid.c index ff28732d..b95db9a3 100644 --- a/app/src/txid.c +++ b/app/src/txid.c @@ -8,6 +8,9 @@ #include #include #include +#include "zcash_utils.h" + +#define PERSONALIZATION_SIZE 16 // TxId level 1 node personalization #define ZCASH_HEADERS_HASH_PERSONALIZATION "ZTxIdHeadersHash" @@ -36,78 +39,86 @@ #define SIGHASH_ALL 0x01 -void nu5_transparent_prevouts_hash(const uint8_t *input, uint8_t *output) { +zxerr_t nu5_transparent_prevouts_hash(const uint8_t *input, uint8_t *output) { zemu_log_stack("nu5_transparent_prevouts_hash\n"); + if (input == NULL || output == NULL) { + return zxerr_no_data; + } + const uint8_t n = t_inlist_len(); - cx_blake2b_t ctx; - uint8_t personalization[16] = {0}; - MEMCPY(personalization, PIC(ZCASH_PREVOUTS_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, 16); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_PREVOUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); if (n == 0) { - cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE); - return; + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; } const uint8_t *data = input + INDEX_TIN_PREVOUT; for (uint8_t i = 0; i < n - 1; i++, data += T_IN_TX_LEN) { - cx_hash_no_throw(&ctx.header, 0, data, PREVOUT_SIZE, NULL, 0); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, PREVOUT_SIZE, NULL, 0)); } - cx_hash_no_throw(&ctx.header, CX_LAST, data, PREVOUT_SIZE, output, HASH_SIZE); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, PREVOUT_SIZE, output, HASH_SIZE)); + return zxerr_ok; } -void nu5_transparent_sequence_hash(const uint8_t *input, uint8_t *output) { +zxerr_t nu5_transparent_sequence_hash(const uint8_t *input, uint8_t *output) { zemu_log_stack("nu5_transparent_sequence_hash"); - + if (input == NULL || output == NULL) { + return zxerr_no_data; + } const uint8_t n = t_inlist_len(); - cx_blake2b_t ctx; - uint8_t personalization[16] = {0}; - MEMCPY(personalization, PIC(ZCASH_SEQUENCE_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, 16); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_SEQUENCE_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); if (n == 0) { - cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE); - return; + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; } const uint8_t *data = input + INDEX_TIN_SEQ; for (uint8_t i = 0; i < n - 1; i++, data += T_IN_TX_LEN) { - cx_hash_no_throw(&ctx.header, 0, data, SEQUENCE_SIZE, NULL, 0); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, SEQUENCE_SIZE, NULL, 0)); } - cx_hash_no_throw(&ctx.header, CX_LAST, data, SEQUENCE_SIZE, output, - HASH_SIZE); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, SEQUENCE_SIZE, output, HASH_SIZE)); + return zxerr_ok; } /// Sequentially append the full serialized value of each transparent output /// to a hash personalized by ZCASH_OUTPUTS_HASH_PERSONALIZATION. /// In the case that no outputs are provided, this produces a default /// hash from just the personalization string. -void nu5_transparent_outputs_hash(uint8_t *output) { +zxerr_t nu5_transparent_outputs_hash(uint8_t *output) { + if (output == NULL) { + return zxerr_no_data; + } + const uint8_t n = t_outlist_len(); - cx_blake2b_t ctx; - uint8_t personalization[16] = {0}; - MEMCPY(personalization, PIC(ZCASH_OUTPUTS_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, 16); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_OUTPUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); if (n == 0) { - cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE); - return; + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; } - uint8_t data[T_OUTPUT_SIZE]; + uint8_t data[T_OUTPUT_SIZE] = {0}; uint8_t i = 0; for (; i < n - 1; i++) { t_output_item_t *item = t_outlist_retrieve_item(i); MEMCPY(data, (uint8_t *)&(item->value), 8); MEMCPY(data + 8, item->address, SCRIPT_SIZE); - cx_hash_no_throw(&ctx.header, 0, data, sizeof(data), NULL, 0); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, sizeof(data), NULL, 0)); } + t_output_item_t *item = t_outlist_retrieve_item(i); MEMCPY(data, (uint8_t *)&(item->value), 8); MEMCPY(data + 8, item->address, SCRIPT_SIZE); - cx_hash_no_throw(&ctx.header, CX_LAST, data, sizeof(data), output, HASH_SIZE); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, sizeof(data), output, HASH_SIZE)); + + return zxerr_ok; } /// Implements [ZIP 244 section @@ -121,63 +132,56 @@ void nu5_transparent_outputs_hash(uint8_t *output) { /// /// Then, hash these together personalized by /// ZCASH_SAPLING_SPENDS_HASH_PERSONALIZATION -void nu5_hash_sapling_spends(const uint8_t *input, uint8_t *output) { +zxerr_t nu5_hash_sapling_spends(const uint8_t *input, uint8_t *output) { zemu_log_stack("nu5_hash_sapling_spends"); + if (input == NULL || output == NULL) { + return zxerr_no_data; + } + const uint8_t n = spendlist_len(); - cx_blake2b_t ctx; - uint8_t personalization[16] = {0}; - MEMCPY(personalization, PIC(ZCASH_SAPLING_SPENDS_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, 16); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_SPENDS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); if (n == 0) { - cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE); - return; + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; } - cx_blake2b_t ch_ctx; - uint8_t ch_personalization[16] = {0}; - MEMCPY(ch_personalization, - PIC(ZCASH_SAPLING_SPENDS_COMPACT_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&ch_ctx, 256, NULL, 0, - (uint8_t *)ch_personalization, 16); - - cx_blake2b_t nh_ctx; - uint8_t nh_personalization[16] = {0}; - MEMCPY(nh_personalization, - PIC(ZCASH_SAPLING_SPENDS_NONCOMPACT_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&nh_ctx, 256, NULL, 0, - (uint8_t *)nh_personalization, 16); + cx_blake2b_t ch_ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ch_ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_SPENDS_COMPACT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + cx_blake2b_t nh_ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&nh_ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_SPENDS_NONCOMPACT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); const uint8_t *nullifier_data = input + INDEX_SPEND_NF; const uint8_t *cv_data = input + INDEX_SPEND_VALUECMT; const uint8_t *anchor_data = input + INDEX_SPEND_ANCHOR; const uint8_t *rk_data = input + INDEX_SPEND_RK; + for (uint8_t i = 0; i < n - 1; i++, nullifier_data += SPEND_TX_LEN, - cv_data += SPEND_TX_LEN, anchor_data += SPEND_TX_LEN, - rk_data += SPEND_TX_LEN) { + cv_data += SPEND_TX_LEN, + anchor_data += SPEND_TX_LEN, + rk_data += SPEND_TX_LEN) { // build the hash of nullifiers separately for compact blocks. - cx_hash_no_throw(&ch_ctx.header, 0, nullifier_data, NULLIFIER_SIZE, NULL, - 0); + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, nullifier_data, NULLIFIER_SIZE, NULL,0)); - cx_hash_no_throw(&nh_ctx.header, 0, cv_data, VALUE_COMMITMENT_SIZE, NULL, - 0); - cx_hash_no_throw(&nh_ctx.header, 0, anchor_data, ANCHOR_SIZE, NULL, 0); - cx_hash_no_throw(&nh_ctx.header, 0, rk_data, RK_SIZE, NULL, 0); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, cv_data, VALUE_COMMITMENT_SIZE, NULL,0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, anchor_data, ANCHOR_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, rk_data, RK_SIZE, NULL, 0)); } uint8_t ch_out[HASH_SIZE] = {0}; - cx_hash_no_throw(&ch_ctx.header, CX_LAST, nullifier_data, NULLIFIER_SIZE, - (uint8_t *)ch_out, HASH_SIZE); + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, CX_LAST, nullifier_data, NULLIFIER_SIZE,(uint8_t *)ch_out, HASH_SIZE)); uint8_t nh_out[HASH_SIZE] = {0}; - cx_hash_no_throw(&nh_ctx.header, 0, cv_data, VALUE_COMMITMENT_SIZE, NULL, 0); - cx_hash_no_throw(&nh_ctx.header, 0, anchor_data, ANCHOR_SIZE, NULL, 0); - cx_hash_no_throw(&nh_ctx.header, CX_LAST, rk_data, RK_SIZE, (uint8_t *)nh_out, - HASH_SIZE); - - cx_hash_no_throw(&ctx.header, 0, (uint8_t *)ch_out, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, CX_LAST, (uint8_t *)nh_out, HASH_SIZE, output, - HASH_SIZE); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, cv_data, VALUE_COMMITMENT_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, anchor_data, ANCHOR_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, CX_LAST, rk_data, RK_SIZE, (uint8_t *)nh_out,HASH_SIZE)); + + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, (uint8_t *)ch_out, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, (uint8_t *)nh_out, HASH_SIZE, output,HASH_SIZE)); + + return zxerr_ok; } /// Implements [ZIP 244 section @@ -193,40 +197,30 @@ void nu5_hash_sapling_spends(const uint8_t *input, uint8_t *output) { /// /// Then, hash these together personalized with /// ZCASH_SAPLING_OUTPUTS_HASH_PERSONALIZATION -void nu5_hash_sapling_outputs(const uint8_t *input, uint8_t *output) { +zxerr_t nu5_hash_sapling_outputs(const uint8_t *input, uint8_t *output) { zemu_log_stack("nu5_hash_sapling_outputs"); + if (input == NULL || output == NULL) { + return zxerr_no_data; + } + const uint8_t n = outputlist_len(); - cx_blake2b_t ctx; - uint8_t personalization[16] = {0}; - MEMCPY(personalization, PIC(ZCASH_SAPLING_OUTPUTS_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, 16); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_OUTPUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); if (n == 0) { - cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE); - return; + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; } - cx_blake2b_t ch_ctx; - uint8_t ch_personalization[16] = {0}; - MEMCPY(ch_personalization, - PIC(ZCASH_SAPLING_OUTPUTS_COMPACT_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&ch_ctx, 256, NULL, 0, - (uint8_t *)ch_personalization, 16); - - cx_blake2b_t mh_ctx; - uint8_t mh_personalization[16] = {0}; - MEMCPY(mh_personalization, - PIC(ZCASH_SAPLING_OUTPUTS_MEMOS_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&mh_ctx, 256, NULL, 0, - (uint8_t *)mh_personalization, 16); - - cx_blake2b_t nh_ctx; - uint8_t nh_personalization[16] = {0}; - MEMCPY(nh_personalization, - PIC(ZCASH_SAPLING_OUTPUTS_NONCOMPACT_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&nh_ctx, 256, NULL, 0, - (uint8_t *)nh_personalization, 16); + cx_blake2b_t ch_ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ch_ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_OUTPUTS_COMPACT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + cx_blake2b_t mh_ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&mh_ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_OUTPUTS_MEMOS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + cx_blake2b_t nh_ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&nh_ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_OUTPUTS_NONCOMPACT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); const uint8_t *cmu = input + INDEX_OUTPUT_NOTECMT; const uint8_t *ephemeral_key = input + INDEX_OUTPUT_EPK; @@ -238,224 +232,213 @@ void nu5_hash_sapling_outputs(const uint8_t *input, uint8_t *output) { const uint8_t *enc_ciphertext_aead_tag = input + INDEX_OUTPUT_ENC_AEAD_TAG; const uint8_t *out_ciphertext = input + INDEX_OUTPUT_OUT; - for (uint8_t i = 0; i < n - 1; i++, cmu += OUTPUT_TX_LEN, - ephemeral_key += OUTPUT_TX_LEN, enc_ciphertext += OUTPUT_TX_LEN, - enc_ciphertext_memo += OUTPUT_TX_LEN, cv += OUTPUT_TX_LEN, - enc_ciphertext_aead_tag += OUTPUT_TX_LEN, - out_ciphertext += OUTPUT_TX_LEN) { - cx_hash_no_throw(&ch_ctx.header, 0, cmu, NOTE_COMMITMENT_SIZE, NULL, 0); - cx_hash_no_throw(&ch_ctx.header, 0, ephemeral_key, EPK_SIZE, NULL, 0); - cx_hash_no_throw(&ch_ctx.header, 0, enc_ciphertext, 52, NULL, 0); - - cx_hash_no_throw(&mh_ctx.header, 0, enc_ciphertext_memo, - OUTPUT_ENC_MEMO_SIZE, NULL, 0); - - cx_hash_no_throw(&nh_ctx.header, 0, cv, VALUE_COMMITMENT_SIZE, NULL, 0); - cx_hash_no_throw(&nh_ctx.header, 0, enc_ciphertext_aead_tag, - OUTPUT_ENC_AEAD_TAG_SIZE, NULL, 0); - cx_hash_no_throw(&nh_ctx.header, 0, out_ciphertext, OUTPUT_OUT_SIZE, NULL, - 0); + for (uint8_t i = 0; i < n - 1; i++, cmu += OUTPUT_TX_LEN, ephemeral_key += OUTPUT_TX_LEN, + enc_ciphertext += OUTPUT_TX_LEN, enc_ciphertext_memo += OUTPUT_TX_LEN, + cv += OUTPUT_TX_LEN, enc_ciphertext_aead_tag += OUTPUT_TX_LEN, + out_ciphertext += OUTPUT_TX_LEN) { + + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, cmu, NOTE_COMMITMENT_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, ephemeral_key, EPK_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, enc_ciphertext, 52, NULL, 0)); + + CHECK_CX_OK(cx_hash_no_throw(&mh_ctx.header, 0, enc_ciphertext_memo,OUTPUT_ENC_MEMO_SIZE, NULL, 0)); + + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, cv, VALUE_COMMITMENT_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, enc_ciphertext_aead_tag,OUTPUT_ENC_AEAD_TAG_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, out_ciphertext, OUTPUT_OUT_SIZE, NULL,0)); } uint8_t ch_out[HASH_SIZE] = {0}; - cx_hash_no_throw(&ch_ctx.header, 0, cmu, NOTE_COMMITMENT_SIZE, NULL, 0); - cx_hash_no_throw(&ch_ctx.header, 0, ephemeral_key, EPK_SIZE, NULL, 0); - cx_hash_no_throw(&ch_ctx.header, CX_LAST, enc_ciphertext, 52, ch_out, - HASH_SIZE); + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, cmu, NOTE_COMMITMENT_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, ephemeral_key, EPK_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, CX_LAST, enc_ciphertext, 52, ch_out,HASH_SIZE)); uint8_t mh_out[HASH_SIZE] = {0}; - cx_hash_no_throw(&mh_ctx.header, CX_LAST, enc_ciphertext_memo, - OUTPUT_ENC_MEMO_SIZE, (uint8_t *)mh_out, HASH_SIZE); + CHECK_CX_OK(cx_hash_no_throw(&mh_ctx.header, CX_LAST, enc_ciphertext_memo,OUTPUT_ENC_MEMO_SIZE, (uint8_t *)mh_out, HASH_SIZE)); uint8_t nh_out[HASH_SIZE] = {0}; - cx_hash_no_throw(&nh_ctx.header, 0, cv, VALUE_COMMITMENT_SIZE, NULL, 0); - cx_hash_no_throw(&nh_ctx.header, 0, enc_ciphertext_aead_tag, - OUTPUT_ENC_AEAD_TAG_SIZE, NULL, 0); - cx_hash_no_throw(&nh_ctx.header, CX_LAST, out_ciphertext, OUTPUT_OUT_SIZE, - nh_out, HASH_SIZE); - - cx_hash_no_throw(&ctx.header, 0, ch_out, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, mh_out, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, CX_LAST, nh_out, HASH_SIZE, output, HASH_SIZE); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, cv, VALUE_COMMITMENT_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, enc_ciphertext_aead_tag,OUTPUT_ENC_AEAD_TAG_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, CX_LAST, out_ciphertext, OUTPUT_OUT_SIZE,nh_out, HASH_SIZE)); + + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, ch_out, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, mh_out, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, nh_out, HASH_SIZE, output, HASH_SIZE)); + + return zxerr_ok; } /// The txid commits to the hash of all transparent outputs. The /// prevout and sequence_hash components of txid -void hash_header_txid_data(const uint8_t *input, uint8_t *output) { +zxerr_t hash_header_txid_data(const uint8_t *input, uint8_t *output) { zemu_log_stack("hash_header_txid_data"); - cx_blake2b_t ctx; - uint8_t personalization[16] = {0}; - MEMCPY(personalization, PIC(ZCASH_HEADERS_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, 16); + if (input == NULL || output == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_HEADERS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); const uint8_t *version = input + NU5_INDEX_HASH_VERSION; const uint8_t *version_group_id = input + NU5_INDEX_HASH_VERSION_GROUP_ID; - const uint8_t *consensus_branch_id = - input + NU5_INDEX_HASH_CONSENSUS_BRANCH_ID; + const uint8_t *consensus_branch_id = input + NU5_INDEX_HASH_CONSENSUS_BRANCH_ID; const uint8_t *lock_time = input + NU5_INDEX_HASH_LOCK_TIME; const uint8_t *expiry_height = input + NU5_INDEX_EXPIRY_HEIGHT; - cx_hash_no_throw(&ctx.header, 0, version, 4, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, version_group_id, 4, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, consensus_branch_id, 4, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, lock_time, 4, NULL, 0); - cx_hash_no_throw(&ctx.header, CX_LAST, expiry_height, 4, output, HASH_SIZE); + if (cx_hash_no_throw(&ctx.header, 0, version, 4, NULL, 0) != CX_OK || + cx_hash_no_throw(&ctx.header, 0, version_group_id, 4, NULL, 0) != CX_OK || + cx_hash_no_throw(&ctx.header, 0, consensus_branch_id, 4, NULL, 0) != CX_OK || + cx_hash_no_throw(&ctx.header, 0, lock_time, 4, NULL, 0) != CX_OK || + cx_hash_no_throw(&ctx.header, CX_LAST, expiry_height, 4, output, HASH_SIZE) != CX_OK) { + + return zxerr_invalid_crypto_settings; + } + + return zxerr_ok; } -void hash_transparent_txid_data(const uint8_t *input, uint8_t *output) { +zxerr_t hash_transparent_txid_data(const uint8_t *input, uint8_t *output) { zemu_log_stack("hash_transparent_txid_data"); - cx_blake2b_t ctx; - uint8_t personalization[16] = {0}; - MEMCPY(personalization, PIC(ZCASH_TRANSPARENT_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, 16); - - if (t_inlist_len() + t_outlist_len() > 0) { - const uint8_t *prevout_digest = input + NU5_INDEX_HASH_PREVOUTSHASH; - const uint8_t *sequence_digest = input + NU5_INDEX_HASH_SEQUENCEHASH; - const uint8_t *outputs_digest = input + NU5_INDEX_HASH_OUTPUTSHASH; - - cx_hash_no_throw(&ctx.header, 0, prevout_digest, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, sequence_digest, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, CX_LAST, outputs_digest, HASH_SIZE, output, - HASH_SIZE); - } else { - cx_hash_no_throw(&ctx.header, CX_LAST, NULL, 0, output, HASH_SIZE); + if (input == NULL || output == NULL) { + return zxerr_no_data; } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_TRANSPARENT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + if ((t_inlist_len() + t_outlist_len()) == 0) { + return cx_hash_no_throw(&ctx.header, CX_LAST, NULL, 0, output, HASH_SIZE) == CX_OK ? zxerr_ok : zxerr_unknown; + } + + const uint8_t *prevout_digest = input + NU5_INDEX_HASH_PREVOUTSHASH; + const uint8_t *sequence_digest = input + NU5_INDEX_HASH_SEQUENCEHASH; + const uint8_t *outputs_digest = input + NU5_INDEX_HASH_OUTPUTSHASH; + + if (cx_hash_no_throw(&ctx.header, 0, prevout_digest, HASH_SIZE, NULL, 0) != CX_OK || + cx_hash_no_throw(&ctx.header, 0, sequence_digest, HASH_SIZE, NULL, 0) != CX_OK || + cx_hash_no_throw(&ctx.header, CX_LAST, outputs_digest, HASH_SIZE, output,HASH_SIZE) != CX_OK) { + + return zxerr_unknown; + } + + return zxerr_ok; } -void transparent_sig_digest(const uint8_t *input, uint8_t *start_signdata, - uint8_t index, signable_input type, - uint8_t *output) { +zxerr_t transparent_sig_digest(const uint8_t *input, uint8_t *start_signdata, + uint8_t index, signable_input type, uint8_t *output) { zemu_log_stack("transparent_sig_digest"); + if (input == NULL || start_signdata == NULL || output == NULL) { + return zxerr_no_data; + } if (t_inlist_len() == 0) { - hash_transparent_txid_data(start_signdata, output); - } else { - // the following implies that flag_anyonecanpay = flag_single = flag_none = - // false - uint8_t hash_type = SIGHASH_ALL; - - const uint8_t *prevout_digest = - start_signdata + NU5_INDEX_HASH_PREVOUTSHASH; - - // compute amounts digest - cx_blake2b_t ctx_amounts; - uint8_t personalization[16] = {0}; - MEMCPY(personalization, PIC(ZCASH_TRANSPARENT_AMOUNTS_HASH_PERSONALIZATION), - 16); - cx_blake2b_init2_no_throw(&ctx_amounts, 256, NULL, 0, - (uint8_t *)personalization, 16); - uint64_t amount = 0; - uint8_t amounts_digest[HASH_SIZE] = {0}; - for (uint8_t i = 0; i < t_inlist_len() - 1; ++i) { - amount = t_inlist_retrieve_item_amount(i); - cx_hash_no_throw(&ctx_amounts.header, 0, (uint8_t *)&amount, - sizeof(uint64_t), NULL, 0); - } - amount = t_inlist_retrieve_item_amount(t_inlist_len() - 1); - cx_hash_no_throw(&ctx_amounts.header, CX_LAST, (uint8_t *)&amount, - sizeof(uint64_t), amounts_digest, HASH_SIZE); - MEMZERO(personalization, 16); - - cx_blake2b_t ctx_scripts; - MEMCPY(personalization, PIC(ZCASH_TRANSPARENT_SCRIPTS_HASH_PERSONALIZATION), - 16); - cx_blake2b_init2_no_throw(&ctx_scripts, 256, NULL, 0, - (uint8_t *)personalization, 16); - uint8_t scripts[SCRIPT_SIZE]; - uint8_t scripts_digest[HASH_SIZE] = {0}; - for (uint8_t i = 0; i < t_inlist_len() - 1; ++i) { - t_inlist_retrieve_item_script(i, scripts); - cx_hash_no_throw(&ctx_scripts.header, 0, scripts, sizeof(scripts), NULL, - 0); - MEMZERO(scripts, SCRIPT_SIZE); - } - t_inlist_retrieve_item_script(t_inlist_len() - 1, scripts); - cx_hash_no_throw(&ctx_scripts.header, CX_LAST, scripts, SCRIPT_SIZE, - scripts_digest, HASH_SIZE); - MEMZERO(personalization, 16); - - const uint8_t *sequence_digest = - start_signdata + NU5_INDEX_HASH_SEQUENCEHASH; - const uint8_t *outputs_digest = start_signdata + NU5_INDEX_HASH_OUTPUTSHASH; - - cx_blake2b_t ctx_txin_sig_digest; - uint8_t txin_sig_digest[HASH_SIZE] = {0}; - MEMCPY(personalization, PIC(ZCASH_TRANSPARENT_INPUT_HASH_PERSONALIZATION), - 16); - cx_blake2b_init2_no_throw(&ctx_txin_sig_digest, 256, NULL, 0, - (uint8_t *)personalization, 16); - if (type == transparent) { - const t_input_item_t *item = t_inlist_retrieve_item(index); - - const uint8_t *prevout_data = - input + index * T_IN_TX_LEN + INDEX_TIN_PREVOUT; - cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, prevout_data, - PREVOUT_SIZE, NULL, 0); - - uint64_t value = item->value; - cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, (uint8_t *)&value, - sizeof(uint64_t), NULL, 0); - - const uint8_t *script = item->script; - cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, script, SCRIPT_SIZE, - NULL, 0); - - const uint8_t *sequence_data = - input + index * T_IN_TX_LEN + INDEX_TIN_SEQ; - cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, sequence_data, - SEQUENCE_SIZE, NULL, 0); - } - cx_hash_no_throw(&ctx_txin_sig_digest.header, CX_LAST, NULL, 0, - txin_sig_digest, HASH_SIZE); - MEMZERO(personalization, 16); - - cx_blake2b_t ctx; - MEMCPY(personalization, PIC(ZCASH_TRANSPARENT_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, - 16); - - cx_hash_no_throw(&ctx.header, 0, &hash_type, sizeof(uint8_t), NULL, 0); - cx_hash_no_throw(&ctx.header, 0, prevout_digest, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, amounts_digest, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, scripts_digest, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, sequence_digest, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, outputs_digest, HASH_SIZE, NULL, 0); - - cx_hash_no_throw(&ctx.header, CX_LAST, txin_sig_digest, HASH_SIZE, output, - HASH_SIZE); + return hash_transparent_txid_data(start_signdata, output); + } + + // the following implies that flag_anyonecanpay = flag_single = flag_none = false + uint8_t hash_type = SIGHASH_ALL; + const uint8_t *prevout_digest = start_signdata + NU5_INDEX_HASH_PREVOUTSHASH; + + // compute amounts digest + cx_blake2b_t ctx_amounts = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx_amounts, 256, NULL, 0, (uint8_t*)ZCASH_TRANSPARENT_AMOUNTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + uint64_t amount = 0; + uint8_t amounts_digest[HASH_SIZE] = {0}; + for (uint8_t i = 0; i < t_inlist_len() - 1; ++i) { + amount = t_inlist_retrieve_item_amount(i); + CHECK_CX_OK(cx_hash_no_throw(&ctx_amounts.header, 0, (uint8_t *)&amount,sizeof(uint64_t), NULL, 0)); + } + + // t_inlist_len will be >0 + amount = t_inlist_retrieve_item_amount(t_inlist_len() - 1); + CHECK_CX_OK(cx_hash_no_throw(&ctx_amounts.header, CX_LAST, (uint8_t *)&amount, sizeof(uint64_t), amounts_digest, HASH_SIZE)); + + cx_blake2b_t ctx_scripts = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx_scripts, 256, NULL, 0, (uint8_t*)ZCASH_TRANSPARENT_SCRIPTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + uint8_t scripts[SCRIPT_SIZE] = {0}; + uint8_t scripts_digest[HASH_SIZE] = {0}; + for (uint8_t i = 0; i < t_inlist_len() - 1; ++i) { + t_inlist_retrieve_item_script(i, scripts); + CHECK_CX_OK(cx_hash_no_throw(&ctx_scripts.header, 0, scripts, sizeof(scripts), NULL,0)); + MEMZERO(scripts, SCRIPT_SIZE); + } + t_inlist_retrieve_item_script(t_inlist_len() - 1, scripts); + CHECK_CX_OK(cx_hash_no_throw(&ctx_scripts.header, CX_LAST, scripts, SCRIPT_SIZE,scripts_digest, HASH_SIZE)); + + const uint8_t *sequence_digest = start_signdata + NU5_INDEX_HASH_SEQUENCEHASH; + const uint8_t *outputs_digest = start_signdata + NU5_INDEX_HASH_OUTPUTSHASH; + + cx_blake2b_t ctx_txin_sig_digest = {0}; + uint8_t txin_sig_digest[HASH_SIZE] = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx_txin_sig_digest, 256, NULL, 0, (uint8_t*)ZCASH_TRANSPARENT_INPUT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + if (type == transparent) { + const t_input_item_t *item = t_inlist_retrieve_item(index); + + const uint8_t *prevout_data = input + index * T_IN_TX_LEN + INDEX_TIN_PREVOUT; + CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, prevout_data,PREVOUT_SIZE, NULL, 0)); + + uint64_t value = item->value; + CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, (uint8_t *)&value,sizeof(uint64_t), NULL, 0)); + + const uint8_t *script = item->script; + CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, script, SCRIPT_SIZE,NULL, 0)); + + const uint8_t *sequence_data = input + index * T_IN_TX_LEN + INDEX_TIN_SEQ; + CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, sequence_data, SEQUENCE_SIZE, NULL, 0)); } + + CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, CX_LAST, NULL, 0, txin_sig_digest, HASH_SIZE)); + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_TRANSPARENT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, &hash_type, sizeof(uint8_t), NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, prevout_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, amounts_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, scripts_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, sequence_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, outputs_digest, HASH_SIZE, NULL, 0)); + + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, txin_sig_digest, HASH_SIZE, output,HASH_SIZE)); + + return zxerr_ok; } -void hash_sapling_txid_data(const uint8_t *input, uint8_t *output) { +zxerr_t hash_sapling_txid_data(const uint8_t *input, uint8_t *output) { zemu_log_stack("hash_sapling_txid_data"); - cx_blake2b_t ctx; - uint8_t personalization[16] = {0}; - MEMCPY(personalization, PIC(ZCASH_SAPLING_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, 16); - - if (spendlist_len() + outputlist_len() > 0) { - const uint8_t *hash_sapling_spends = - input + NU5_INDEX_HASH_SHIELDEDSPENDHASH; - const uint8_t *hash_sapling_outputs = - input + NU5_INDEX_HASH_SHIELDEDOUTPUTHASH; - const uint8_t *value_balance = input + NU5_INDEX_HASH_VALUEBALANCE; - - cx_hash_no_throw(&ctx.header, 0, hash_sapling_spends, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, 0, hash_sapling_outputs, HASH_SIZE, NULL, 0); - cx_hash_no_throw(&ctx.header, CX_LAST, value_balance, NU5_VALUEBALANCE_SIZE, - output, HASH_SIZE); - } else { - cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE); + if (input == NULL || output == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + if (spendlist_len() + outputlist_len() == 0) { + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; } + + const uint8_t *hash_sapling_spends = input + NU5_INDEX_HASH_SHIELDEDSPENDHASH; + const uint8_t *hash_sapling_outputs = input + NU5_INDEX_HASH_SHIELDEDOUTPUTHASH; + const uint8_t *value_balance = input + NU5_INDEX_HASH_VALUEBALANCE; + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, hash_sapling_spends, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, hash_sapling_outputs, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, value_balance, NU5_VALUEBALANCE_SIZE,output, HASH_SIZE)); + + return zxerr_ok; } -void hash_empty_orchard_txid_data(uint8_t *output) { - cx_blake2b_t ctx; - uint8_t personalization[16] = {0}; - MEMCPY(personalization, PIC(ZCASH_ORCHARD_HASH_PERSONALIZATION), 16); - cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, 16); +zxerr_t hash_empty_orchard_txid_data(uint8_t *output) { + if (output == NULL) { + return zxerr_no_data; + } + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_ORCHARD_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); - cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE); + return zxerr_ok; } diff --git a/app/src/txid.h b/app/src/txid.h index 156df9ec..1b463db0 100644 --- a/app/src/txid.h +++ b/app/src/txid.h @@ -16,24 +16,24 @@ #pragma once -void nu5_transparent_prevouts_hash(const uint8_t *input, uint8_t *output); +zxerr_t nu5_transparent_prevouts_hash(const uint8_t *input, uint8_t *output); -void nu5_transparent_sequence_hash(const uint8_t *input, uint8_t *output); +zxerr_t nu5_transparent_sequence_hash(const uint8_t *input, uint8_t *output); -void nu5_transparent_outputs_hash(uint8_t *output); +zxerr_t nu5_transparent_outputs_hash(uint8_t *output); -void nu5_hash_sapling_spends(const uint8_t *input, uint8_t *output); +zxerr_t nu5_hash_sapling_spends(const uint8_t *input, uint8_t *output); -void nu5_hash_sapling_outputs(const uint8_t *input, uint8_t *output); +zxerr_t nu5_hash_sapling_outputs(const uint8_t *input, uint8_t *output); -void hash_header_txid_data(const uint8_t *input, uint8_t *output); +zxerr_t hash_header_txid_data(const uint8_t *input, uint8_t *output); -void hash_transparent_txid_data(const uint8_t *input, uint8_t *output); +zxerr_t hash_transparent_txid_data(const uint8_t *input, uint8_t *output); -void transparent_sig_digest(const uint8_t *input, uint8_t *start_signdata, +zxerr_t transparent_sig_digest(const uint8_t *input, uint8_t *start_signdata, uint8_t index, signable_input type, uint8_t *output); -void hash_sapling_txid_data(const uint8_t *input, uint8_t *output); +zxerr_t hash_sapling_txid_data(const uint8_t *input, uint8_t *output); -void hash_empty_orchard_txid_data(uint8_t *output); +zxerr_t hash_empty_orchard_txid_data(uint8_t *output); diff --git a/app/src/zcash_utils.h b/app/src/zcash_utils.h new file mode 100644 index 00000000..81442753 --- /dev/null +++ b/app/src/zcash_utils.h @@ -0,0 +1,37 @@ +/******************************************************************************* + * (c) 2018 -2023 Zondax AG + * + * 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 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cx.h" +#include "zxerror.h" + + +#define CHECK_CX_OK(CALL) \ + do { \ + cx_err_t __cx_err = CALL; \ + if (__cx_err != CX_OK) { \ + return zxerr_unknown; \ + } \ + } while (0) + + +#ifdef __cplusplus +} +#endif From 2583789606d8b994f134e91522974e8efae6041f Mon Sep 17 00:00:00 2001 From: ainhoa-a <95368257+ainhoa-a@users.noreply.github.com> Date: Mon, 11 Dec 2023 09:56:05 +0100 Subject: [PATCH 6/6] link app description to the hub Add description to install via the hub --- README.md | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e59dbd9e..4a5bbecb 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,9 @@ _Please visit our website at [zondax.ch](https://www.zondax.ch)_ **This app is still work in progress!** -This project contains the Zcash app for Ledger Nano S, S+ and X. - -- Ledger BOLOS app -- Specs / Documentation -- C++ unit tests -- Rust unit tests -- Zemu tests +## Description of the Project +Welcome to the Ledger Zcash app repository developed by Zondax. This project contains the Zcash application for Ledger Nano S+ and X, providing users with the ability to securely manage their ZEC assets. +This application supports sapling, enabling transfers between shielded and non shielded addresses. ## ATTENTION @@ -30,8 +26,15 @@ Please: - **Do not use a Ledger device with funds for development purposes.** - **Have a separate and marked device that is used ONLY for development and testing** -Tip: +This repository contains + +- Ledger BOLOS app +- Specs / Documentation +- C++ unit tests +- Rust unit tests +- Zemu tests +Tip: - In releases, you will find a precompiled test app. If you are just curious, you can run `installer_s.sh` and avoid building. ## Download and install @@ -39,7 +42,12 @@ Tip: *Once the app is approved by Ledger, it will be available in their app store (Ledger Live). You can get builds generated by CircleCI from the release tab. THESE ARE UNVETTED DEVELOPMENT RELEASES* -Download a release from here (https://github.com/Zondax/ledger-zcash/releases). You only need `zxtool.sh` +With our Zondax Hub you can install asset apps to your Ledger device and test them. This can be done with both released and unreleased versions developed by the zondax team. To install the Ledger Zcash App on your Ledger device, you can simply: +1. Go to http://hub.zondax.ch/ +2. Connect your wallet +3. Install the app + +Another way to install the app is by downloading the installer script from the release page (https://github.com/Zondax/ledger-zcash/releases) and follow these commands. You only need `zxtool.sh` If the file is not executable, run ```sh @@ -52,8 +60,14 @@ then run: ./installer_s.sh load ``` -# Development +## Troubleshooting +If you encounter any issues while using the Ledger Zcash App, please create and issue in this repository and the team will review it. You can also send an email to ledger@zondax.ch + +## Contact Information/Support +For support, feedback, or inquiries, please reach out to us at: ledger@zondax.ch + +# Development ## Preconditions - Be sure you checkout submodules too: @@ -212,3 +226,6 @@ The Makefile will build the firmware in a docker container and leave the binary ## APDU Specifications - [APDU Protocol](docs/APDUSPEC.md) + ``` + make load # Builds and loads the app to the device + ```