From 22401f15666dd5e679085f71ecce63e3cad17fca Mon Sep 17 00:00:00 2001 From: ftheirs Date: Wed, 13 Mar 2024 17:41:04 -0300 Subject: [PATCH] Zemu tests address --- .gitignore | 2 +- Makefile | 2 +- README.md | 10 ++-- app/Makefile | 22 +++----- app/src/addr.c | 35 +++++++----- app/src/coin.h | 12 ++--- app/src/crypto.c | 20 +++---- tests/keys.cpp | 12 +++++ tests_zemu/package.json | 12 ++--- tests_zemu/tests/standard.test.ts | 88 +++++++++++++++---------------- 10 files changed, 110 insertions(+), 105 deletions(-) diff --git a/.gitignore b/.gitignore index 5d3399a..b432952 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Created by .ignore support plugin (hsz.mobi) -### C template +### C Ironfish # Prerequisites *.d diff --git a/Makefile b/Makefile index dafdc3c..52c95b4 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ # BOLOS_SDK IS DEFINED We use the plain Makefile for Ledger # BOLOS_SDK NOT DEFINED We use a containerized build approach -TESTS_JS_PACKAGE = "@zondax/ledger-template" +TESTS_JS_PACKAGE = "@zondax/ledger-ironfish" TESTS_JS_DIR = $(CURDIR)/js ifeq ($(BOLOS_SDK),) diff --git a/README.md b/README.md index 70f29cb..ad476c8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Ledger Template app +# Ledger Ironfish app [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![GithubActions](https://github.com/Zondax/ledger-template/actions/workflows/main.yml/badge.svg)](https://github.com/Zondax/ledger-template/blob/main/.github/workflows/main.yaml) +[![GithubActions](https://github.com/Zondax/ledger-ironfish/actions/workflows/main.yml/badge.svg)](https://github.com/Zondax/ledger-ironfish/blob/main/.github/workflows/main.yaml) --- @@ -11,9 +11,9 @@ _Please visit our website at [zondax.ch](https://www.zondax.ch)_ --- -This project contains the Template app for Ledger Nano S Nano S+ and X. +This project contains the Ironfish app for Ledger Nano S Nano S+ and X. -- Ledger Nano S/S+/X Template app +- Ledger Nano S/S+/X Ironfish app - Specs / Documentation - C++ unit tests - Zemu tests @@ -32,7 +32,7 @@ Please: *Once the app is approved by Ledger, it will be available in their app store (Ledger Live). You can get builds generated by Github Actions from the release tab. THESE ARE UNVETTED DEVELOPMENT RELEASES* -Download a release from here (https://github.com/Zondax/ledger-template/releases). You only need `installer.sh` +Download a release from here (https://github.com/Zondax/ledger-ironfish/releases). You only need `installer.sh` If the file is not executable, run ```sh diff --git a/app/Makefile b/app/Makefile index 7fa6601..8f84086 100755 --- a/app/Makefile +++ b/app/Makefile @@ -30,25 +30,18 @@ $(info ************ TARGET_NAME = [$(TARGET_NAME)]) include $(CURDIR)/../deps/ledger-zxlib/makefiles/Makefile.app_testing -# #{TODO} --> Need for an special mode? -# DEFINES += REVIEW_SCREEN_ENABLED APP_BLIND_MODE_ENABLED - ifndef COIN -COIN=TODO +COIN=IRON endif include $(CURDIR)/Makefile.version $(info COIN = [$(COIN)]) -ifeq ($(COIN),TODO) +ifeq ($(COIN),IRON) # Main app configuration -DEFINES += APP_STANDARD -ifneq ($(TARGET_NAME),TARGET_NANOS) -DEFINES += SUBSTRATE_PARSER_FULL -endif -APPNAME = "Template" -APPPATH = "44'/283'" +APPNAME = "Ironfish" +APPPATH = "44'/133'" else define error_message @@ -59,7 +52,7 @@ endef $(error "$(error_message)") endif -APP_LOAD_PARAMS = --curve secp256k1 --delete $(COMMON_LOAD_PARAMS) --path $(APPPATH) +APP_LOAD_PARAMS = --curve ed25519 --delete $(COMMON_LOAD_PARAMS) --path $(APPPATH) include $(CURDIR)/../deps/ledger-zxlib/makefiles/Makefile.devices @@ -89,9 +82,6 @@ RUST_TARGET:=thumbv6m-none-eabi rust: cd rust && RUSTC_BOOTSTRAP=1 CARGO_HOME="$(CURDIR)/rust/.cargo" cargo build --target $(RUST_TARGET) --release -# Before linking, we need to be sure rust lib is there -bin/app.elf: rust - .PHONY: rust_clean rust_clean: cd rust && CARGO_HOME="$(CURDIR)/rust/.cargo" cargo clean @@ -107,7 +97,7 @@ include $(BOLOS_SDK)/Makefile.rules dep/%.d: %.c Makefile listvariants: - @echo VARIANTS COIN template + @echo VARIANTS COIN IRON .PHONY: version version: diff --git a/app/src/addr.c b/app/src/addr.c index 8617ff9..6127102 100644 --- a/app/src/addr.c +++ b/app/src/addr.c @@ -22,13 +22,15 @@ #include "zxerror.h" #include "zxformat.h" #include "zxmacros.h" +#include "keys_def.h" +#include "os.h" zxerr_t addr_getNumItems(uint8_t *num_items) { - zemu_log_stack("addr_getNumItems"); - *num_items = 1; - if (app_mode_expert()) { - *num_items = 2; + if (num_items == NULL) { + return zxerr_no_data; } + // Display [public address | ivk | ovk | path] + *num_items = 4; return zxerr_ok; } @@ -39,20 +41,27 @@ zxerr_t addr_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, char * switch (displayIdx) { case 0: snprintf(outKey, outKeyLen, "Address"); - pageString(outVal, outValLen, (char *)(G_io_apdu_buffer + PK_LEN_25519), pageIdx, pageCount); - return zxerr_ok; - case 1: { - if (!app_mode_expert()) { - return zxerr_no_data; - } - - snprintf(outKey, outKeyLen, "Your Path"); + pageStringHex(outVal, outValLen, G_io_apdu_buffer, KEY_LENGTH, pageIdx, pageCount); + break; + case 1: + snprintf(outKey, outKeyLen, "IVK"); + pageStringHex(outVal, outValLen, G_io_apdu_buffer + KEY_LENGTH, KEY_LENGTH, pageIdx, pageCount); + break; + case 2: + snprintf(outKey, outKeyLen, "OVK"); + pageStringHex(outVal, outValLen, G_io_apdu_buffer + 2 * KEY_LENGTH, KEY_LENGTH, pageIdx, pageCount); + break; + case 3: { + snprintf(outKey, outKeyLen, "HD Path"); char buffer[300]; bip32_to_str(buffer, sizeof(buffer), hdPath, HDPATH_LEN_DEFAULT); pageString(outVal, outValLen, buffer, pageIdx, pageCount); - return zxerr_ok; + break; } + default: return zxerr_no_data; } + + return zxerr_ok; } diff --git a/app/src/coin.h b/app/src/coin.h index 4a84714..2498756 100644 --- a/app/src/coin.h +++ b/app/src/coin.h @@ -24,7 +24,7 @@ extern "C" { #define HDPATH_LEN_DEFAULT 5 #define HDPATH_0_DEFAULT (0x80000000u | 0x2c) // 44 -#define HDPATH_1_DEFAULT (0x80000000u | 0x11b) // 283 +#define HDPATH_1_DEFAULT (0x80000000u | 0x85) // 133 #define HDPATH_2_DEFAULT (0x80000000u | 0u) #define HDPATH_3_DEFAULT (0u) @@ -39,18 +39,14 @@ extern "C" { #define ED25519_SIGNATURE_SIZE 64u #define PK_LEN_25519 32u -#define SS58_ADDRESS_MAX_LEN 60u - -#define MAX_SIGN_SIZE 256u -#define BLAKE2B_DIGEST_SIZE 32u #define COIN_AMOUNT_DECIMAL_PLACES 6 -#define COIN_TICKER "TODO " +#define COIN_TICKER "IRON " -#define MENU_MAIN_APP_LINE1 "Template" +#define MENU_MAIN_APP_LINE1 "Ironfish" #define MENU_MAIN_APP_LINE2 "Ready" #define MENU_MAIN_APP_LINE2_SECRET "???" -#define APPVERSION_LINE1 "Template" +#define APPVERSION_LINE1 "Ironfish" #define APPVERSION_LINE2 "v" APPVERSION #ifdef __cplusplus diff --git a/app/src/crypto.c b/app/src/crypto.c index c25a22c..9be5b4d 100644 --- a/app/src/crypto.c +++ b/app/src/crypto.c @@ -60,30 +60,25 @@ zxerr_t crypto_generateSaplingKeys(uint8_t *output, uint16_t outputLen) { if (output == NULL || outputLen < 3 * KEY_LENGTH) { return zxerr_buffer_too_small; } - zxerr_t error = zxerr_unknown; + zxerr_t error = zxerr_unknown; + MEMZERO(output, outputLen); // Generate spending key cx_ecfp_private_key_t cx_privateKey = {0}; uint8_t privateKeyData[SK_LEN_25519] = {0}; CATCH_CXERROR(os_derive_bip32_with_seed_no_throw(HDW_NORMAL, - CX_CURVE_256K1, + CX_CURVE_Ed25519, hdPath, HDPATH_LEN_DEFAULT, privateKeyData, NULL, NULL, 0)); - + CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_Ed25519, privateKeyData, 32, &cx_privateKey)); keys_t saplingKeys = {0}; - memcpy(saplingKeys.spendingKey, privateKeyData, KEY_LENGTH); + memcpy(saplingKeys.spendingKey, cx_privateKey.d, KEY_LENGTH); error = computeKeys(&saplingKeys); -catch_cx_error: - MEMZERO(&cx_privateKey, sizeof(cx_privateKey)); - MEMZERO(privateKeyData, sizeof(privateKeyData)); - - MEMZERO(output, outputLen); - // Copy keys if (error == zxerr_ok) { memcpy(output, saplingKeys.address, KEY_LENGTH); @@ -91,6 +86,11 @@ zxerr_t crypto_generateSaplingKeys(uint8_t *output, uint16_t outputLen) { memcpy(output + 2*KEY_LENGTH, saplingKeys.ovk, KEY_LENGTH); } +catch_cx_error: + MEMZERO(&cx_privateKey, sizeof(cx_privateKey)); + MEMZERO(privateKeyData, sizeof(privateKeyData)); + MEMZERO(&saplingKeys, sizeof(saplingKeys)); + return error; } diff --git a/tests/keys.cpp b/tests/keys.cpp index 86af855..9c04b85 100644 --- a/tests/keys.cpp +++ b/tests/keys.cpp @@ -245,6 +245,18 @@ vector testvectors { "cc691cbcb17a713f67eb2977d735c5f34e28ca885d10e78a93106198f333fd85", "a944ec349e29edde71ce202384d3b2b65cb7e86f9ec43d7757097e8597f47ced" }, + // Keys from Zemu tests + { + "e89dab1a3e40eb2c120defd577ce743ba0893df22aaec97de46a62cd934b1257", + "0ddce28653e08c129da8b1c6485a8a7f2d987163742c91a26209014cf92ee6de", + "010cd3f2276aeac2b3a6a98278bacb878606d4fa3301f70713425b5761facdd4", + "bdd8b8dd269e11c0f9ff401e284fb19ea2cfc008c791590c08e3616865ece534", + "fc912a61108229dc6af38809fa3c938d6b3d0bce2de236751a445a72f061e488", + "bdd8b8dd269e11c0f9ff401e284fb19ea2cfc008c791590c08e3616865ece534fc912a61108229dc6af38809fa3c938d6b3d0bce2de236751a445a72f061e488", + "043e34aa9a6323b82a899d984081ce53e3bb47b2ffa18a0dcfa6910a6d278c73", + "316c96f058f7e188acc90d90d1d765bd9b9ce9e5fa3655c74e8450df0191ee21", + "b3ad098e86bc31de35ec5a77cce6aed08d5336bf273abef5e7eb420278a0c19c" + }, }; diff --git a/tests_zemu/package.json b/tests_zemu/package.json index 0d05012..6871fdb 100644 --- a/tests_zemu/package.json +++ b/tests_zemu/package.json @@ -18,18 +18,18 @@ "test": "yarn clean && jest tests/standard.test.ts" }, "dependencies": { - "@zondax/ledger-template": "../js", - "@zondax/zemu": "^0.46.2" + "@zondax/ledger-ironfish": "../js", + "@zondax/zemu": "^0.47.0" }, "devDependencies": { "@types/jest": "^29.5.11", "@types/ledgerhq__hw-transport": "^4.21.8", - "@typescript-eslint/eslint-plugin": "^7.0.1", - "@typescript-eslint/parser": "^7.0.1", + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", "blakejs": "^1.1.1", "crypto-js": "4.2.0", "ed25519-supercop": "^2.0.1", - "eslint": "^8.56.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.29.1", "eslint-plugin-jest": "^27.6.1", @@ -39,6 +39,6 @@ "prettier": "^3.1.1", "ts-jest": "^29.0.3", "ts-node": "^10.9.2", - "typescript": "^5.3.3" + "typescript": "^5.4.2" } } diff --git a/tests_zemu/tests/standard.test.ts b/tests_zemu/tests/standard.test.ts index f23d082..9f00aa2 100644 --- a/tests_zemu/tests/standard.test.ts +++ b/tests_zemu/tests/standard.test.ts @@ -14,16 +14,17 @@ * limitations under the License. ******************************************************************************* */ -import Zemu, { zondaxMainmenuNavigation } from '@zondax/zemu' -import TemplateApp from '@zondax/ledger-template' +import Zemu, { ButtonKind, zondaxMainmenuNavigation } from '@zondax/zemu' import { defaultOptions, models, txBlobExample } from './common' +import IronfishApp from '@zondax/ledger-ironfish' -// @ts-expect-error -import ed25519 from 'ed25519-supercop' +jest.setTimeout(60000) -const accountId = 123 +const PATH = "m/44'/133'/0'/0/0" -jest.setTimeout(60000) +const expectedPublicAddress = "b3ad098e86bc31de35ec5a77cce6aed08d5336bf273abef5e7eb420278a0c19c" +const expectedIVK = "043e34aa9a6323b82a899d984081ce53e3bb47b2ffa18a0dcfa6910a6d278c73" +const expectedOVK = "316c96f058f7e188acc90d90d1d765bd9b9ce9e5fa3655c74e8450df0191ee21" describe('Standard', function () { test.concurrent.each(models)('can start and stop container', async function (m) { @@ -50,7 +51,7 @@ describe('Standard', function () { const sim = new Zemu(m.path) try { await sim.start({ ...defaultOptions, model: m.name }) - const app = new TemplateApp(sim.getTransport()) + const app = new IronfishApp(sim.getTransport()) const resp = await app.getVersion() console.log(resp) @@ -66,52 +67,49 @@ describe('Standard', function () { } }) - // test.concurrent.each(models)('get address', async function (m) { - // const sim = new Zemu(m.path) - // try { - // await sim.start({ ...defaultOptions, model: m.name }) - // const app = new TemplateApp(sim.getTransport()) - - // //Define HDPATH - // const resp = await app.getAddressAndPubKey(accountId) + test.concurrent.each(models)('get address', async function (m) { + const sim = new Zemu(m.path) + try { + await sim.start({ ...defaultOptions, model: m.name }) + const app = new IronfishApp(sim.getTransport()) - // console.log(resp) + const resp = await app.getAddressAndPubKey(PATH) + console.log(resp) - // expect(resp.return_code).toEqual(0x9000) - // expect(resp.error_message).toEqual('No errors') + expect(resp.returnCode).toEqual(0x9000) + expect(resp.errorMessage).toEqual('No errors') - // const expected_address = 'BX63ZW4O5PWWFDH3J33QEB5YN7IN5XOKPDUQ5DCZ232EDY4DWN3XKUQRCA' - // const expected_pk = '0dfdbcdb8eebed628cfb4ef70207b86fd0deddca78e90e8c59d6f441e383b377' + expect(resp.publicAddress?.toString('hex')).toEqual(expectedPublicAddress) + expect(resp.ivk?.toString('hex')).toEqual(expectedIVK) + expect(resp.ovk?.toString('hex')).toEqual(expectedOVK) + } finally { + await sim.close() + } + }) - // expect(resp.publicKey).toEqual(expected_pk) - // expect(resp.address).toEqual(expected_address) - // } finally { - // await sim.close() - // } - // }) + test.concurrent.each(models)('show address', async function (m) { + const sim = new Zemu(m.path) + try { + await sim.start({...defaultOptions, model: m.name, + approveKeyword: m.name === 'stax' ? 'QR' : '', + approveAction: ButtonKind.ApproveTapButton,}) + const app = new IronfishApp(sim.getTransport()) - // test.concurrent.each(models)('show address', async function (m) { - // const sim = new Zemu(m.path) - // try { - // await sim.start({...defaultOptions, model: m.name, - // approveKeyword: m.name === 'stax' ? 'QR' : '', - // approveAction: ButtonKind.ApproveTapButton,}) - // const app = new TemplateApp(sim.getTransport()) + const respRequest = app.showAddressAndPubKey(PATH) + // Wait until we are not in the main menu + await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot()) + await sim.compareSnapshotsAndApprove('.', `${m.prefix.toLowerCase()}-show_address`) - // const respRequest = app.getAddressAndPubKey(accountId, true) - // // Wait until we are not in the main menu - // await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot()) - // await sim.compareSnapshotsAndApprove('.', `${m.prefix.toLowerCase()}-show_address`) + const resp = await respRequest + console.log(resp) - // const resp = await respRequest - // console.log(resp) + expect(resp.returnCode).toEqual(0x9000) + expect(resp.errorMessage).toEqual('No errors') - // expect(resp.return_code).toEqual(0x9000) - // expect(resp.error_message).toEqual('No errors') - // } finally { - // await sim.close() - // } - // }) + } finally { + await sim.close() + } + }) // test.concurrent.each(models)('show address - reject', async function (m) { // const sim = new Zemu(m.path)