Skip to content

Commit

Permalink
Merge pull request LedgerHQ#6 from nimiq/develop
Browse files Browse the repository at this point in the history
Nimiq App Version 2.0
  • Loading branch information
lpascal-ledger authored Oct 30, 2024
2 parents 6fba06a + 1f8177e commit 2a4efb9
Show file tree
Hide file tree
Showing 770 changed files with 5,531 additions and 3,104 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/build_and_functional_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Build and run functional tests using ragger through reusable workflow

# This workflow will build the app and then run functional tests using the Ragger framework upon Speculos emulation.
# It calls a reusable workflow developed by Ledger's internal developer team to build the application and upload the
# resulting binaries.
# It then calls another reusable workflow to run the Ragger tests on the compiled application binary.
#
# While this workflow is optional, having functional testing on your application is mandatory and this workflow and
# tooling environment is meant to be easy to use and adapt after forking your application

on:
workflow_dispatch:
push:
branches:
- master
- main
- develop
pull_request:

jobs:
build_application:
name: Build application using the reusable workflow
uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1
with:
upload_app_binaries_artifact: "compiled_app_binaries"

ragger_tests:
name: Run ragger tests using the reusable workflow
needs: build_application
uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_ragger_tests.yml@v1
with:
download_app_binaries_artifact: "compiled_app_binaries"
43 changes: 43 additions & 0 deletions .github/workflows/codeql_checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: "CodeQL"

on:
workflow_dispatch:
push:
branches: ["main", "master", "develop"]
pull_request:
branches: ["main", "master", "develop"]
# Excluded path: add the paths you want to ignore instead of deleting the workflow
paths-ignore:
- '.github/workflows/*.yml'
- 'tests/*'

jobs:
analyse:
name: Analyse
strategy:
matrix:
sdk: [ "$NANOS_SDK", "$NANOX_SDK", "$NANOSP_SDK", "$STAX_SDK", "$FLEX_SDK" ]
#'cpp' covers C and C++
language: [ 'cpp' ]
runs-on: ubuntu-latest
container:
image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest

steps:
- name: Clone
uses: actions/checkout@v3
with:
submodules: recursive
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: security-and-quality

# CodeQL will create the database during the compilation
- name: Build
run: |
make BOLOS_SDK=${{ matrix.sdk }}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
13 changes: 7 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
build
bin
debug
dep
obj
src/glyphs.c
src/glyphs.h
.idea
nano-sdk
blue-sdk

# Temporary directory with snapshots taken during test runs
tests/snapshots-tmp/

# Output folder of clang static analyzer scan-build, see Makefile.rules-generic in Ledger SDK
output-scan-build
220 changes: 97 additions & 123 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,139 +18,113 @@
ifeq ($(BOLOS_SDK),)
$(error Environment variable BOLOS_SDK is not set)
endif

include $(BOLOS_SDK)/Makefile.defines

APPNAME = Nimiq
APP_LOAD_PARAMS=--appFlags 0x240 --path "44'/242'" --curve ed25519 $(COMMON_LOAD_PARAMS)

APPVERSION_M=1
APPVERSION_N=4
APPVERSION_P=6
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)

#prepare hsm generation
ifeq ($(TARGET_NAME),TARGET_BLUE)
ICONNAME=blue_app_nimiq.gif
else ifeq ($(TARGET_NAME),TARGET_NANOS)
ICONNAME=nanos_app_nimiq.gif
else
ICONNAME=nanox_app_nimiq.gif
endif

################
# Default rule #
################
all: default
##############################
# App description #
##############################

############
# Platform #
############
# Application name
APPNAME = Nimiq

DEFINES += OS_IO_SEPROXYHAL
DEFINES += HAVE_BAGL HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U
DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=4 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P)
# Application version
APPVERSION_M = 2
APPVERSION_N = 0
APPVERSION_P = 0
APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)"

# Setting to allow building variant applications. For now, there are no variants, only the main Nimiq app.
VARIANT_PARAM = COIN
VARIANT_VALUES = nimiq


##############################
# Source files #
##############################

# Application source files
APP_SOURCE_PATH += src

# For now, don't include standard app files, as our code is not currently using the new common / standard app utilities,
# with the advantage of not including any utilities we don't use, but of the downside of having to maintain these common
# code utilities ourselves.
DISABLE_STANDARD_APP_FILES = 1

# Application icons following the guidelines:
# https://developers.ledger.com/docs/device-app/deliver/deliverables/icons
# Notes on how to create such icons in GIMP:
# - Open an SVG of the Nimiq logo and set the image width to the size of the safe area for the intended image size, e.g.
# 30px for the 32pxx32px image. Also import the paths.
# - Layer > Transparency > Remove Alpha Channel.
# - Edit > Fill the image with white.
# - Edit > Fill Path with black, or Select > From Path and fill the selection with a radial gradient, potentially with
# an adequate offset set.
# - Set Image > Mode to indexed and for 1bit-per-pixel images (Nano devices) use a color palette with just black and
# white, and for 4bit-per-pixel images (e-ink devices) use a color palette with 16 colors 0x00, 0x11, 0x22, ..., 0xff.
# If desired, enable dithering and experiment with different modes. Mode "positioned" looks quite nice. For more
# control, also Colors > Dither might be used.
# - Set the Layer > Layer Boundary Size to the intended size of the final image, centering the content. Then Image > Fit
# Canvas to Layers.
# - Save the icon as xcf with the indexed color map which can be used for future changes to the image.
# - For binary black/white icons: export the icon with indexed color mode as gif, which will save as 1bit-per-pixel.
# For grayscale icons: The guidelines_enforcer.yml workflow expects grayscale images to have 8bit-per-pixel depth
# (even though the glyph build task seems to be compatible with lower bit-per-pixel), therefore change the Image >
# Mode to Grayscale and then export as gif. Do not overwrite the xcf file, to keep it in indexed mode.
# For some reason, for glyphs/app_nimiq_64px.gif, but not for the other icons, this made the glyph build task complain
# that the image is not indexed. So not quite sure yet, what the proper procedure would be here. Also tried, re-export
# of app_nimiq_64px.gif via https://www.photopea.com/, which exports with a color map with 256 entries, excess entries
# simply being filled up as black, but that still had 4bpp depth the enforcer complained about. Switching to Grayscale
# and then back to an indexed palette with 32 shades of gray seems to have done the trick.
# Note that for checking for the bit depth, ImageMagick's identify can be used: identify -verbose /path/to/icon.gif
ICON_NANOS = icons/app_nimiq_16px.gif
ICON_NANOX = icons/app_nimiq_14px.gif
ICON_NANOSP = icons/app_nimiq_14px.gif
ICON_STAX = icons/app_nimiq_32px.gif
ICON_FLEX = icons/app_nimiq_40px.gif


##############################
# Permissions and features #
##############################

# Application allowed derivation curves.
CURVE_APP_LOAD_PARAMS = ed25519

# Application allowed derivation paths.
PATH_APP_LOAD_PARAMS = "44'/242'"

# See SDK `include/appflags.h` for the purpose of each permission
HAVE_APPLICATION_FLAG_GLOBAL_PIN = 1
#HAVE_APPLICATION_FLAG_BOLOS_SETTINGS = 1 # Automatically set in Makefile.standard_app for devices with bluetooth

ENABLE_BLUETOOTH = 1
ENABLE_NBGL_QRCODE = 1

# U2F
# U2F has been deprecated by Ledger, disabled in most apps and is not configured in $(BOLOS_SDK)/Makefile.standard_app,
# but we keep it for now as Nimiq is a browser centric coin, and Firefox and Safari don't support WebHID or WebUSB yet.
# Note though that U2F is somewhat memory hungry, apart from the significant UX flaws. Also see:
# https://www.ledger.com/windows-10-update-sunsetting-u2f-tunnel-transport-for-ledger-devices
# https://developers.ledger.com/docs/connectivity/ledgerJS/faq/U2F
DEFINES += HAVE_IO_U2F
DEFINES += U2F_PROXY_MAGIC=\"w0w\"
DEFINES += U2F_REQUEST_TIMEOUT=28000 # 28 seconds
DEFINES += USB_SEGMENT_SIZE=64
DEFINES += BLE_SEGMENT_SIZE=32 #max MTU, min 20
DEFINES += UNUSED\(x\)=\(void\)x
DEFINES += APPVERSION=\"$(APPVERSION)\"

#WEBUSB_URL = www.ledgerwallet.com
#DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=$(shell echo -n $(WEBUSB_URL) | wc -c) WEBUSB_URL=$(shell echo -n $(WEBUSB_URL) | sed -e "s/./\\\'\0\\\',/g")
DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL=""

ifeq ($(TARGET_NAME),TARGET_NANOX)
DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000
DEFINES += HAVE_BLE_APDU # basic ledger apdu transport over BLE
endif

ifeq ($(TARGET_NAME),TARGET_NANOS)
DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=128
else
DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300
DEFINES += HAVE_GLO096
DEFINES += HAVE_BAGL BAGL_WIDTH=128 BAGL_HEIGHT=64
DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature
DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX
DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX
DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX
DEFINES += HAVE_UX_FLOW
endif


# Enabling debug PRINTF
DEBUG = 0
ifneq ($(DEBUG),0)

ifeq ($(TARGET_NAME),TARGET_NANOS)
DEFINES += HAVE_PRINTF PRINTF=screen_printf
else
DEFINES += HAVE_PRINTF PRINTF=mcu_usb_printf
endif
else
DEFINES += PRINTF\(...\)=
endif



##############
# Compiler #
##############
ifneq ($(BOLOS_ENV),)
$(info BOLOS_ENV=$(BOLOS_ENV))
CLANGPATH := $(BOLOS_ENV)/clang-arm-fropi/bin/
GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-5_3-2016q1/bin/
else
$(info BOLOS_ENV is not set: falling back to CLANGPATH and GCCPATH)
SDK_SOURCE_PATH += lib_u2f

# Enabling DEBUG flag will enable PRINTF and disable optimizations
# Instead of setting it here you can also enable this flag during compilation via `make DEBUG=1`
#DEBUG = 1
# Make the debug flag available in the code as NIMIQ_DEBUG preprocessor define.
ifneq ($(DEBUG), 0)
DEFINES += NIMIQ_DEBUG
endif
ifeq ($(CLANGPATH),)
$(info CLANGPATH is not set: clang will be used from PATH)
endif
ifeq ($(GCCPATH),)
$(info GCCPATH is not set: arm-none-eabi-* will be used from PATH)
endif

CC := $(CLANGPATH)clang

#CFLAGS += -O0
CFLAGS += -O3 -Os

AS := $(GCCPATH)arm-none-eabi-gcc

LD := $(GCCPATH)arm-none-eabi-gcc
LDFLAGS += -O3 -Os
LDLIBS += -lm -lgcc -lc

# import rules to compile glyphs(/pone)
include $(BOLOS_SDK)/Makefile.glyphs

### computed variables
APP_SOURCE_PATH += src
SDK_SOURCE_PATH += lib_stusb
SDK_SOURCE_PATH += lib_stusb_impl
SDK_SOURCE_PATH += lib_u2f
SDK_SOURCE_PATH += lib_ux

ifeq ($(TARGET_NAME),TARGET_NANOX)
SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl
endif

load: all
python -m ledgerblue.loadApp $(APP_LOAD_PARAMS)

delete:
python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS)

# import generic rules from the sdk
include $(BOLOS_SDK)/Makefile.rules

#add dependency on custom makefile filename
dep/%.d: %.c Makefile.genericwallet
# Extend the base Makefile for standard apps
include $(BOLOS_SDK)/Makefile.standard_app

listvariants:
@echo VARIANTS COIN nimiq
# Makes a detailed report of code and data size in debug/size-report.txt
# More useful for production builds with DEBUG=0
size-report: bin/app.elf
arm-none-eabi-nm --print-size --size-sort --radix=d bin/app.elf >debug/size-report.txt
38 changes: 17 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
# Nimiq app for the Ledger Nano S and Ledger Blue
# Nimiq app for Ledger devices

## Introduction

This is a wallet app for the [Ledger Nano S](https://www.ledgerwallet.com/products/ledger-nano-s) and [Ledger Blue](https://www.ledgerwallet.com/products/ledger-blue) that makes it possible to store your [Nimiq](https://nimiq.com/)-based assets on those devices.
This is a device app for the [Ledger Hardware Wallets](https://www.ledger.com/) which makes it possible to store your
[Nimiq token (NIM)](https://nimiq.com/) on those devices (more precisely use the associated private key for NIM related
operations).

A companion [Javascript library](https://github.com/LedgerHQ/ledgerjs) is available to communicate with this app.
A companion [Javascript library](https://github.com/nimiq/ledger-api) is available to communicate with this app.

To learn how to use this library you can take look at the [demo project](https://github.com/jeffesquivels/ledgerjs-nimiq).
## Development Setup

## Building and installing

To build and install the app on your Nano S or Blue you must set up the Ledger Nano S or Blue build environment. Please follow the Getting Started instructions at the [Ledger Nano S github repository](https://github.com/LedgerHQ/ledger-nano-s).

Alternatively, you can set up the Vagrant Virtualbox Ledger environment maintained [here](https://github.com/fix/ledger-vagrant). This sets up an Ubuntu virtual machine with the Ledger build environment already set up. Note that if you are on a Mac, at the time of this writing this seems to be the only way to build and load the app.

The command to compile and load the app onto the device is:

```$ make load```

To remove the app from the device do:

```$ make delete```
For build and installation instructions, please refer to:
- The README of the [Ledger Boilerplate App](https://github.com/LedgerHQ/app-boilerplate)
- [Usage instructions of Ledger's VSCode extension](https://marketplace.visualstudio.com/items?itemName=LedgerHQ.ledger-dev-tools)
and the associated [quickstart guide](https://developers.ledger.com/docs/device-app/beginner/vscode-extension),
or the underlying [ledger-app-builder docker images](https://github.com/LedgerHQ/ledger-app-builder/), if you prefer
to use them directly, without the VSCode extension. Here at Nimiq, mainly the docker images have been used directly
for building and testing the application via the [Speculos](https://github.com/LedgerHQ/speculos) emulator, on real
devices and via [Ragger](https://github.com/LedgerHQ/ragger) functional tests.

## Testing

The `./test` directory contains files for testing the transaction parser and some printing utilities. To build and execute the tests run `./test.sh`.

## Key pair validation
The project contains functional tests powered by [Ragger](https://github.com/LedgerHQ/ragger). They can be launched via
the VSCode extension or docker images as described in the section [Development Setup](#development-setup).

The operation to retrieve the public key implements an optional keypair verification method. Along with the request to retrieve the public key a small message is sent that is to be signed by the device. Back on the host the returned signature can be checked against the returned public key. This is to guard against incompatibility between the keypairs generated by the Ledger device and the ones expected by the Nimiq network, whatever the reason for this might be. The extra precaution prevents users from sending funds to an address they are not able to sign transactions for.
Additionally, the project contains [unit-tests](https://github.com/nimiq/ledger-app-nimiq/tree/master/unit-tests).
Binary file removed ble_app_nimiq.gif
Binary file not shown.
Loading

0 comments on commit 2a4efb9

Please sign in to comment.