diff --git a/.gitignore b/.gitignore index 6dd1d06..b432952 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Created by .ignore support plugin (hsz.mobi) -### C template +### C Ironfish # Prerequisites *.d @@ -76,3 +76,5 @@ tests_zemu/yarn.lock tests_tools/target fuzz-*.log /scan-build +app/rust/.cargo/registry +app/rust/.cargo/.package-cache* diff --git a/.gitmodules b/.gitmodules index 2b8daae..87f3031 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "deps/stax-secure-sdk"] path = deps/stax-secure-sdk url = https://github.com/LedgerHQ/ledger-secure-sdk +[submodule "deps/blake2"] + path = deps/blake2 + url = https://github.com/Zondax/BLAKE2.git diff --git a/CMakeLists.txt b/CMakeLists.txt index a086e3c..3b89d3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,11 +14,11 @@ #* limitations under the License. #******************************************************************************** cmake_minimum_required(VERSION 3.0) -project(ledger-template VERSION 0.0.0) +project(ledger-ironfish VERSION 0.0.0) enable_testing() cmake_policy(SET CMP0025 NEW) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 20) option(ENABLE_FUZZING "Build with fuzzing instrumentation and build fuzz targets" OFF) option(ENABLE_COVERAGE "Build with source code coverage instrumentation" OFF) @@ -116,6 +116,11 @@ file(GLOB_RECURSE LIB_SRC #### ${CMAKE_CURRENT_SOURCE_DIR}/app/src/parser.c ${CMAKE_CURRENT_SOURCE_DIR}/app/src/parser_impl.c + #### + ${CMAKE_CURRENT_SOURCE_DIR}/app/src/crypto_helper.c + #### + ${CMAKE_CURRENT_SOURCE_DIR}/deps/blake2/ref/blake2b-ref.c + ${CMAKE_CURRENT_SOURCE_DIR}/app/src/blake2s/blake2s-ref.c ) add_library(app_lib STATIC ${LIB_SRC}) @@ -125,9 +130,63 @@ target_include_directories(app_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/app/src ${CMAKE_CURRENT_SOURCE_DIR}/app/src/lib ${CMAKE_CURRENT_SOURCE_DIR}/app/src/common + ### + ${CMAKE_CURRENT_SOURCE_DIR}/app/rust/include + ### + ${CMAKE_CURRENT_SOURCE_DIR}/deps/blake2/ref + ) ############################################################## +## Rust library for CPP tests +set(RUST_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/app/rust") + +# Determine the Rust target triple based on the host system +if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "aarch64") + set(RUST_TARGET_TRIPLE "aarch64-unknown-linux-gnu") + elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "x86_64") + set(RUST_TARGET_TRIPLE "x86_64-unknown-linux-gnu") + else() + message(FATAL_ERROR "Unsupported processor: ${CMAKE_HOST_SYSTEM_PROCESSOR}") + endif() +elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "arm64") + set(RUST_TARGET_TRIPLE "aarch64-apple-darwin") + elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "x86_64") + set(RUST_TARGET_TRIPLE "x86_64-apple-darwin") + else() + message(FATAL_ERROR "Unsupported processor: ${CMAKE_HOST_SYSTEM_PROCESSOR}") + endif() +else() + message(FATAL_ERROR "Unsupported host system: ${CMAKE_HOST_SYSTEM_NAME}") +endif() + +# Use debug mode for debugging tests +set(RUST_TARGET_DIR "${RUST_LIB_DIR}/target/${RUST_TARGET_TRIPLE}/debug") + +# Custom target for the Rust library +add_custom_target(RustLibClean + COMMAND cargo clean + WORKING_DIRECTORY ${RUST_LIB_DIR} +) +add_custom_target(RustLibBuild + COMMAND cargo build --target ${RUST_TARGET_TRIPLE} --features cpp_tests + WORKING_DIRECTORY ${RUST_LIB_DIR} + DEPENDS RustLibClean +) + +# Assuming the Rust library outputs a file named librslib.a +set(RUST_LIB "${RUST_TARGET_DIR}/librslib.a") + +# Ensure the Rust library is built before the C++ project +add_library(rslib STATIC IMPORTED) +set_property(TARGET rslib PROPERTY IMPORTED_LOCATION ${RUST_LIB}) +add_dependencies(rslib RustLibBuild) + +# Ensure your C++ targets depend on the Rust library being built first +# For example, for your app_lib static library: +add_dependencies(app_lib rslib) ############################################################## # Tests file(GLOB_RECURSE TESTS_SRC @@ -141,11 +200,14 @@ target_include_directories(unittests PRIVATE ${CONAN_INCLUDE_DIRS_JSONCPP} ${CMAKE_CURRENT_SOURCE_DIR}/app/src ${CMAKE_CURRENT_SOURCE_DIR}/app/src/lib + ### + ${CMAKE_CURRENT_SOURCE_DIR}/deps/blake2/ref ) target_link_libraries(unittests PRIVATE gtest_main app_lib + rslib CONAN_PKG::fmt CONAN_PKG::jsoncpp) 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 33cef67..8f84086 100755 --- a/app/Makefile +++ b/app/Makefile @@ -1,6 +1,6 @@ #******************************************************************************* # Ledger App -# (c) 2018 - 2023 Zondax AG +# (c) 2018 - 2024 Zondax AG # (c) 2017 Ledger # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -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 @@ -71,39 +64,30 @@ $(error ICONNAME is not set) endif include $(CURDIR)/../deps/ledger-zxlib/makefiles/Makefile.platform -CFLAGS += -Wvla -# #{TODO} --> Need Rust? -# LDFLAGS += -z muldefs -# LDLIBS += -Lrust/target/thumbv6m-none-eabi/release -lrslib -# APP_SOURCE_PATH += $(CURDIR)/rust/include -# #{TODO} --> Need Rust? +# Add SDK BLAKE2b +DEFINES += HAVE_HASH HAVE_BLAKE2 +INCLUDES_PATH += $(BOLOS_SDK)/lib_cxng/src + + +# Building Rust +LDFLAGS += -z muldefs +LDLIBS += -L$(MY_DIR)rust/target/$(RUST_TARGET)/release -lrslib + +APP_SOURCE_PATH += $(CURDIR)/rust/include +APP_CUSTOM_LINK_DEPENDENCIES = rust +RUST_TARGET:=thumbv6m-none-eabi + .PHONY: rust rust: - @echo "No rust code" - -# Before linking, we need to be sure rust lib is there -bin/app.elf: rust + cd rust && RUSTC_BOOTSTRAP=1 CARGO_HOME="$(CURDIR)/rust/.cargo" cargo build --target $(RUST_TARGET) --release .PHONY: rust_clean rust_clean: - @echo "No rust code" + cd rust && CARGO_HOME="$(CURDIR)/rust/.cargo" cargo clean clean: rust_clean -# .PHONY: rust -# rust: -# cd rust && CARGO_HOME="$(CURDIR)/rust/.cargo" cargo build --target thumbv6m-none-eabi --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 - -# clean: rust_clean - include $(CURDIR)/../deps/ledger-zxlib/makefiles/Makefile.side_loading # Import generic rules from the SDK @@ -113,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/rust/.cargo/config b/app/rust/.cargo/config new file mode 100644 index 0000000..90cae2f --- /dev/null +++ b/app/rust/.cargo/config @@ -0,0 +1,13 @@ +[build] + +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +rustflags = [ + "--emit", "asm", + "-C", "relocation-model=ropi", + "-C", "link-arg=-nostartfiles", + "-C", "link-arg=-Tlink.ld", + "-C", "inline-threshold=0" +] +[unstable] +build-std=["core"] +build-std-features=["panic_immediate_abort"] diff --git a/app/rust/Cargo.lock b/app/rust/Cargo.lock new file mode 100644 index 0000000..6858d7f --- /dev/null +++ b/app/rust/Cargo.lock @@ -0,0 +1,114 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "bls12_381" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc6d6292be3a19e6379786dac800f551e5865a5bb51ebbe3064ab80433f403" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "jubjub" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8499f7a74008aafbecb2a2e608a3e13e4dd3e84df198b604451efe93f2de6e61" +dependencies = [ + "bitvec", + "bls12_381", + "ff", + "group", + "rand_core", + "subtle", +] + +[[package]] +name = "panic-halt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rslib" +version = "0.0.1" +dependencies = [ + "jubjub", + "panic-halt", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/app/rust/Cargo.toml b/app/rust/Cargo.toml index 08fcd9f..2ce3b04 100644 --- a/app/rust/Cargo.toml +++ b/app/rust/Cargo.toml @@ -1,47 +1,35 @@ [package] authors = ["Zondax AG "] name = "rslib" -version = "0.1.0" -edition = "2018" +version = "0.0.1" +edition = "2021" readme = "README.md" +resolver = "2" [lib] name = "rslib" crate-type = ["staticlib"] [dependencies] -rand={ version = "0.7.3", default-features = false} -merlin = {version = "2.0.0", default-features=false} -zeroize = {version = "1.1.1", default-features=false} - -[target.'cfg(target_arch = "x86_64")'.dependencies] -getrandom = {version="0.1.14", default-features=false} - -[dependencies.curve25519-dalek] -version = "3.0.0" -default-features = false -features=["u32_backend"] - -[dependencies.schnorrkel] -version = "0.9.1" -default-features = false -features=["u32_backend"] - -[dev-dependencies] -hex-literal = "0.2.1" -hex = "0.4.2" -env_logger = "0.7.1" -log = "0.4.8" +jubjub = { version = "0.10.0", default-features = false } [target.thumbv6m-none-eabi.dev-dependencies] panic-halt = "0.2.0" [profile.release] -lto=false +lto = false codegen-units = 1 -debug=true -opt-level = "s" +debug = false +opt-level = "z" [profile.dev] +lto = "fat" +codegen-units = 1 +debug=true +opt-level = "s" panic = "abort" +[features] +default = [] +# use when compiling this crate as a lib for the cpp_tests suite +cpp_tests = [] diff --git a/app/rust/include/rslib.h b/app/rust/include/rslib.h index 8e26766..72eca71 100644 --- a/app/rust/include/rslib.h +++ b/app/rust/include/rslib.h @@ -1,8 +1,9 @@ #pragma once #include +#include "parser_common.h" +#include "keys_def.h" -void get_sr25519_sk(uint8_t *sk_ed25519_expanded); - -void sign_sr25519_phase1(const uint8_t *sk_ed25519_expanded, const uint8_t *pk, const uint8_t *context_ptr, uint32_t context_len, const uint8_t *msg_ptr, uint32_t msg_len, uint8_t *sig_ptr); -void sign_sr25519_phase2(const uint8_t *sk_ed25519_expanded, const uint8_t *pk, const uint8_t *context_ptr, uint32_t context_len, const uint8_t *msg_ptr, uint32_t msg_len, uint8_t *sig_ptr); +/* Interface functions with jubjub crate */ +parser_error_t from_bytes_wide(const uint8_t input[64], uint8_t output[32]); +parser_error_t scalar_multiplication(const uint8_t input[32], constant_key_t key, uint8_t output[32]); diff --git a/app/rust/src/bolos.rs b/app/rust/src/bolos.rs deleted file mode 100644 index f98ae76..0000000 --- a/app/rust/src/bolos.rs +++ /dev/null @@ -1,84 +0,0 @@ -/******************************************************************************* -* (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. -********************************************************************************/ -//! Rust interfaces to Ledger SDK APIs. -#[cfg(test)] -use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; -use curve25519_dalek::scalar::Scalar; -#[cfg(test)] -#[cfg(target_arch = "x86_64")] -use getrandom::getrandom; -use merlin::TranscriptRng; -use rand::{CryptoRng, RngCore}; - -extern "C" { - fn cx_rng(buffer: *mut u8, len: u32); - fn zemu_log_stack(buffer: *const u8); - fn check_app_canary(); -} - -#[cfg(not(test))] -pub fn c_zemu_log_stack(s: &[u8]) { - unsafe { zemu_log_stack(s.as_ptr()) } -} - -#[cfg(test)] -pub fn c_zemu_log_stack(s: &[u8]) {} - -pub fn c_check_app_canary() { - unsafe { check_app_canary() } -} - -pub struct Trng; - -impl RngCore for Trng { - fn next_u32(&mut self) -> u32 { - let mut out = [0; 4]; - self.fill_bytes(&mut out); - u32::from_le_bytes(out) - } - - fn next_u64(&mut self) -> u64 { - let mut out = [0; 8]; - self.fill_bytes(&mut out); - u64::from_le_bytes(out) - } - - #[cfg(not(target_arch = "x86_64"))] - fn fill_bytes(&mut self, dest: &mut [u8]) { - c_zemu_log_stack(b"fill_bytes\x00".as_ref()); - - unsafe { - cx_rng(dest.as_mut_ptr(), dest.len() as u32); - } - } - - #[cfg(target_arch = "x86_64")] - #[cfg(test)] - fn fill_bytes(&mut self, dest: &mut [u8]) { - getrandom(dest); - } - - #[cfg(target_arch = "x86_64")] - #[cfg(not(test))] - fn fill_bytes(&mut self, _dest: &mut [u8]) {} - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { - self.fill_bytes(dest); - Ok(()) - } -} - -impl CryptoRng for Trng {} diff --git a/app/rust/src/constants.rs b/app/rust/src/constants.rs new file mode 100644 index 0000000..687c472 --- /dev/null +++ b/app/rust/src/constants.rs @@ -0,0 +1,65 @@ +/******************************************************************************* +* (c) 2018 - 2024 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. +********************************************************************************/ + +use jubjub::{AffineNielsPoint, AffinePoint, Fq}; + +pub const SPENDING_KEY_GENERATOR: AffineNielsPoint = AffinePoint::from_raw_unchecked( + Fq::from_raw([ + 0x47bf_4692_0a95_a753, + 0xd5b9_a7d3_ef8e_2827, + 0xd418_a7ff_2675_3b6a, + 0x0926_d4f3_2059_c712, + ]), + Fq::from_raw([ + 0x3056_32ad_aaf2_b530, + 0x6d65_674d_cedb_ddbc, + 0x53bb_37d0_c21c_fd05, + 0x57a1_019e_6de9_b675, + ]), +) +.to_niels(); + +pub const PROOF_GENERATION_KEY_GENERATOR: AffineNielsPoint = AffinePoint::from_raw_unchecked( + Fq::from_raw([ + 0x3af2_dbef_b96e_2571, + 0xadf2_d038_f2fb_b820, + 0x7043_03f1_e890_6081, + 0x1457_a502_31cd_e2df, + ]), + Fq::from_raw([ + 0x467a_f9f7_e05d_e8e7, + 0x50df_51ea_f5a1_49d2, + 0xdec9_0184_0f49_48cc, + 0x54b6_d107_18df_2a7a, + ]), +) +.to_niels(); + +pub const PUBLIC_KEY_GENERATOR: AffineNielsPoint = AffinePoint::from_raw_unchecked( + Fq::from_raw([ + 0x3edc_c85f_4d1a_44cd, + 0x77ff_8c90_a9a0_d8f4, + 0x0daf_03b5_47e2_022b, + 0x6dad_65e6_2328_d37a, + ]), + Fq::from_raw([ + 0x5095_1f1f_eff0_8278, + 0xf0b7_03d5_3a3e_dd4e, + 0xca01_f580_9c00_eee2, + 0x6996_932c_ece1_f4bb, + ]), +) +.to_niels(); diff --git a/app/rust/src/lib.rs b/app/rust/src/lib.rs index 7a5c2e5..2edfd42 100644 --- a/app/rust/src/lib.rs +++ b/app/rust/src/lib.rs @@ -1,5 +1,5 @@ /******************************************************************************* -* (c) 2018 - 2023 Zondax AG +* (c) 2018 - 2024 Zondax AG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,268 +14,90 @@ * limitations under the License. ********************************************************************************/ #![no_std] +#![no_main] #![no_builtins] #![allow(dead_code, unused_imports)] -extern crate core; -#[cfg(test)] -#[macro_use] -extern crate hex_literal; - -use core::convert::TryInto; -use core::mem; use core::panic::PanicInfo; -use core::slice::{from_raw_parts, from_raw_parts_mut}; -use curve25519_dalek::scalar::Scalar; -use merlin::{Transcript, TranscriptRng, TranscriptRngBuilder}; -use rand::RngCore; -use schnorrkel::context::{SigningContext, SigningTranscript}; -use schnorrkel::{PublicKey, SecretKey}; -use zeroize::Zeroize; +use constants::{SPENDING_KEY_GENERATOR}; +mod constants; -use crate::bolos::*; - -mod bolos; +use jubjub::{Fr, AffinePoint, ExtendedPoint}; fn debug(_msg: &str) {} -#[cfg(not(test))] -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - loop {} +// ParserError should mirror parser_error_t from parser_common. +// At the moment, just implement OK or Error +#[repr(C)] +pub enum ParserError { + ParserOk = 0, + ParserUnexpectedError = 5, } -#[inline(never)] -fn mult_with_secret(k: &mut Scalar, sk: &[u8]) { - let mut skbytes = [0u8; 32]; - skbytes.copy_from_slice(&sk[0..32]); - let s = Scalar::from_bits(skbytes); - *k *= s; -} - -#[inline(never)] -fn add_witness(k: &mut Scalar, x: [u8; 32]) -> [u8; 32] { - let r = Scalar::from_bits(x); - *k += r; - k.to_bytes() -} - -#[inline(never)] -fn get_challenge_scalar(k: &mut Scalar, tr: &mut Transcript) { - let mut kbytes = [0u8; 64]; - tr.challenge_bytes(b"sign:c", &mut kbytes); - *k += Scalar::from_bytes_mod_order_wide(&kbytes); -} - -#[inline(never)] -fn get_witness_bytes_custom(br: &mut Transcript, nonce_seeds: &[&[u8]]) -> [u8; 32] { - c_zemu_log_stack(b"witness_bytes\x00".as_ref()); - let mut x = [0u8; 32]; - for ns in nonce_seeds { - br.append_message(b"nonce-bytes", ns); - } - { - let random_bytes = { - let mut bytes = [0u8; 32]; - Trng.fill_bytes(&mut bytes); - bytes - }; - br.append_message(b"rng", &random_bytes); - } - br.challenge_bytes(b"witness-bytes", &mut x); - br.zeroize(); - x +#[repr(C)] +pub enum ConstantKey { + SpendingKeyGenerator, + ProofGenerationKeyGenerator, + PublicKeyGenerator, } #[no_mangle] -pub extern "C" fn sign_sr25519_phase1( - sk_ristretto_expanded_ptr: *const u8, - pk_ptr: *const u8, - context_ptr: *const u8, - context_len: usize, - msg_ptr: *const u8, - msg_len: usize, - sig_ptr: *mut u8, -) { - c_zemu_log_stack(b"sign_sr25519\x00".as_ref()); - - let sk_ristretto_expanded = - unsafe { from_raw_parts(sk_ristretto_expanded_ptr as *const u8, 64) }; - let pk = unsafe { from_raw_parts(pk_ptr as *const u8, 32) }; - let context = unsafe { from_raw_parts(context_ptr as *const u8, context_len) }; - let message = unsafe { from_raw_parts(msg_ptr as *const u8, msg_len) }; - let signature = unsafe { from_raw_parts_mut(sig_ptr as *mut u8, 64) }; - - let mut signtranscript = Transcript::new(b"SigningContext"); - signtranscript.append_message(b"", context); - signtranscript.append_message(b"sign-bytes", message); - signtranscript.append_message(b"proto-name", b"Schnorr-sig"); //proto name - signtranscript.append_message(b"sign:pk", pk); //commitpoint: pk - - let x = get_witness_bytes_custom(&mut signtranscript, &[&sk_ristretto_expanded[32..]]); - signature[32..64].copy_from_slice(&x); +pub extern "C" fn from_bytes_wide(input: &[u8; 64], output: &mut [u8; 32]) -> ParserError { + let result = Fr::from_bytes_wide(input).to_bytes(); + output.copy_from_slice(&result[0..32]); + ParserError::ParserOk } #[no_mangle] -pub extern "C" fn sign_sr25519_phase2( - sk_ristretto_expanded_ptr: *const u8, - pk_ptr: *const u8, - context_ptr: *const u8, - context_len: usize, - msg_ptr: *const u8, - msg_len: usize, - sig_ptr: *mut u8, -) { - c_zemu_log_stack(b"sign_sr25519\x00".as_ref()); - - let sk_ristretto_expanded = - unsafe { from_raw_parts(sk_ristretto_expanded_ptr as *const u8, 64) }; - let pk = unsafe { from_raw_parts(pk_ptr as *const u8, 32) }; - let context = unsafe { from_raw_parts(context_ptr as *const u8, context_len) }; - let message = unsafe { from_raw_parts(msg_ptr as *const u8, msg_len) }; - let signature = unsafe { from_raw_parts_mut(sig_ptr as *mut u8, 64) }; - - let mut signtranscript = Transcript::new(b"SigningContext"); - signtranscript.append_message(b"", context); - signtranscript.append_message(b"sign-bytes", message); - signtranscript.append_message(b"proto-name", b"Schnorr-sig"); //proto name - signtranscript.append_message(b"sign:pk", pk); //commitpoint: pk - signtranscript.append_message(b"sign:R", &signature[0..32]); //commitpoint: pk - - let mut x = [0u8; 32]; - x.copy_from_slice(&signature[32..64]); - - let mut k = Scalar::zero(); - get_challenge_scalar(&mut k, &mut signtranscript); +pub extern "C" fn scalar_multiplication(input: &[u8; 32], key: ConstantKey, output: *mut [u8; 32]) -> ParserError { + let key_point = match key { + ConstantKey::SpendingKeyGenerator => constants::SPENDING_KEY_GENERATOR, + ConstantKey::ProofGenerationKeyGenerator => constants::PROOF_GENERATION_KEY_GENERATOR, + ConstantKey::PublicKeyGenerator => constants::PUBLIC_KEY_GENERATOR, + }; + + let extended_point = key_point.multiply_bits(input); + let result = AffinePoint::from(&extended_point); + + unsafe { + let output_slice = &mut *output; + output_slice.copy_from_slice(&result.to_bytes()); + } - mult_with_secret(&mut k, sk_ristretto_expanded); - signature[32..].copy_from_slice(&add_witness(&mut k, x)); - signature[63] |= 128; + ParserError::ParserOk } -#[no_mangle] -pub extern "C" fn get_sr25519_sk(sk_ed25519_expanded_ptr: *mut u8) { - let sk_ed25519_expanded = unsafe { from_raw_parts_mut(sk_ed25519_expanded_ptr as *mut u8, 64) }; - let secret: SecretKey = SecretKey::from_ed25519_bytes(&sk_ed25519_expanded[..]).unwrap(); - sk_ed25519_expanded.copy_from_slice(&secret.to_bytes()); +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} } + #[cfg(test)] mod tests { - use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; - use curve25519_dalek::edwards::EdwardsPoint; - use curve25519_dalek::scalar::Scalar; - use log::{debug, info}; - use schnorrkel::{context::*, Keypair, PublicKey, SecretKey, Signature}; + // use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT; + // use curve25519_dalek::edwards::EdwardsPoint; + // use curve25519_dalek::scalar::Scalar; + // use log::{debug, info}; + // use schnorrkel::{context::*, Keypair, PublicKey, SecretKey, Signature}; + + // use crate::*; + // use core::ops::Mul; + + // fn init_logging() { + // let _ = env_logger::builder().is_test(true).try_init(); + // } + + // fn ristretto_scalarmult(sk: &[u8], pk: &mut [u8]) { + // let mut seckey = [0u8; 32]; + // seckey.copy_from_slice(&sk[0..32]); + // let pubkey = RISTRETTO_BASEPOINT_POINT + // .mul(Scalar::from_bits(seckey)) + // .compress() + // .0; + // pk.copy_from_slice(&pubkey); + // } - use crate::*; - use core::ops::Mul; - - fn init_logging() { - let _ = env_logger::builder().is_test(true).try_init(); - } - - fn ristretto_scalarmult(sk: &[u8], pk: &mut [u8]) { - let mut seckey = [0u8; 32]; - seckey.copy_from_slice(&sk[0..32]); - let pubkey = RISTRETTO_BASEPOINT_POINT - .mul(Scalar::from_bits(seckey)) - .compress() - .0; - pk.copy_from_slice(&pubkey); - } - - #[test] - fn test_sign_verify() { - let mut sk_ed25519_expanded = [ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - ]; - - let pk_expected = "b65abc66a8fdeac1197d03daa6c3791d0c0799a52db6b7127b1cd12d46e34364"; - - let secret = SecretKey::from_ed25519_bytes(&sk_ed25519_expanded).unwrap(); - - let mut pk = [0u8; 32]; - get_sr25519_sk(sk_ed25519_expanded.as_mut_ptr()); - - ristretto_scalarmult(&sk_ed25519_expanded, &mut pk); - - assert_eq!(hex::encode(pk), pk_expected); - - let context = b"good"; - let msg = b"test message"; - let mut signature = [0u8; 64]; - - sign_sr25519_phase1( - secret.to_bytes().as_ptr(), - pk.as_ptr(), - context.as_ptr(), - context.len(), - msg.as_ptr(), - msg.len(), - signature.as_mut_ptr(), - ); - - let mut x = [0u8; 32]; - x.copy_from_slice(&signature[32..64]); - - ristretto_scalarmult(&x, &mut signature[0..32]); - - sign_sr25519_phase2( - secret.to_bytes().as_ptr(), - pk.as_ptr(), - context.as_ptr(), - context.len(), - msg.as_ptr(), - msg.len(), - signature.as_mut_ptr(), - ); - - let keypair: Keypair = Keypair::from(secret); - - let mut sigledger = [0u8; 64]; - hex::decode_to_slice("48fdbe5cf3524bdd078ac711565d658a3053d10660749959883c4710f49d9948b2d5f829bea6800897dc6ea0150ca11075cc36b75bfcf3712aafb8e1bd10bf8f",&mut sigledger).expect("dec"); - - let self_sig = Signature::from_bytes(&signature).unwrap(); - let self_sig_ledger = Signature::from_bytes(&sigledger).unwrap(); - - let vers = signing_context(context); - - assert!( - keypair.verify(vers.bytes(msg), &self_sig).is_ok(), - "Verification of a valid signature failed!" - ); - assert!( - keypair.verify(vers.bytes(msg), &self_sig_ledger).is_ok(), - "Verification of a valid signature from ledger failed!" - ); - } - - #[test] - fn get_public_key_c() { - init_logging(); - - let mut sk_ed25519_expanded = [ - 0x00, 0x01, 0x02, 0x03, 04, 0x5, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 04, 0x5, 0x06, - 0x07, 0x00, 0x01, 0x02, 0x03, 04, 0x5, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 04, 0x5, - 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 04, 0x5, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 04, - 0x5, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 04, 0x5, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, - 04, 0x5, 0x06, 0x07, - ]; - - let pk_expected = "b65abc66a8fdeac1197d03daa6c3791d0c0799a52db6b7127b1cd12d46e34364"; - - let mut pk = [0u8; 32]; - get_sr25519_sk(sk_ed25519_expanded.as_mut_ptr()); - - ristretto_scalarmult(&sk_ed25519_expanded, &mut pk); - - info!("{:?}", hex::encode(pk)); - assert_eq!(hex::encode(pk), pk_expected); - } } diff --git a/app/src/addr.c b/app/src/addr.c index 8617ff9..cf87f91 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,30 @@ 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"); + const char* address = (const char*)G_io_apdu_buffer; + pageStringHex(outVal, outValLen, address, KEY_LENGTH, pageIdx, pageCount); + break; + case 1: + snprintf(outKey, outKeyLen, "IVK"); + const char* ivk = (const char*)G_io_apdu_buffer + KEY_LENGTH; + pageStringHex(outVal, outValLen, ivk, KEY_LENGTH, pageIdx, pageCount); + break; + case 2: + snprintf(outKey, outKeyLen, "OVK"); + const char* ovk = (const char*)G_io_apdu_buffer + 2 * KEY_LENGTH; + pageStringHex(outVal, outValLen, ovk, 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/blake2s/blake2-impl.h b/app/src/blake2s/blake2-impl.h new file mode 100644 index 0000000..c1df82e --- /dev/null +++ b/app/src/blake2s/blake2-impl.h @@ -0,0 +1,160 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2_IMPL_H +#define BLAKE2_IMPL_H + +#include +#include + +#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) + #if defined(_MSC_VER) + #define BLAKE2_INLINE __inline + #elif defined(__GNUC__) + #define BLAKE2_INLINE __inline__ + #else + #define BLAKE2_INLINE + #endif +#else + #define BLAKE2_INLINE inline +#endif + +static BLAKE2_INLINE uint32_t load32( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint32_t )( p[0] ) << 0) | + (( uint32_t )( p[1] ) << 8) | + (( uint32_t )( p[2] ) << 16) | + (( uint32_t )( p[3] ) << 24) ; +#endif +} + +static BLAKE2_INLINE uint64_t load64( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint64_t )( p[0] ) << 0) | + (( uint64_t )( p[1] ) << 8) | + (( uint64_t )( p[2] ) << 16) | + (( uint64_t )( p[3] ) << 24) | + (( uint64_t )( p[4] ) << 32) | + (( uint64_t )( p[5] ) << 40) | + (( uint64_t )( p[6] ) << 48) | + (( uint64_t )( p[7] ) << 56) ; +#endif +} + +static BLAKE2_INLINE uint16_t load16( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint16_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return ( uint16_t )((( uint32_t )( p[0] ) << 0) | + (( uint32_t )( p[1] ) << 8)); +#endif +} + +static BLAKE2_INLINE void store16( void *dst, uint16_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; +#endif +} + +static BLAKE2_INLINE void store32( void *dst, uint32_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); +#endif +} + +static BLAKE2_INLINE void store64( void *dst, uint64_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); + p[4] = (uint8_t)(w >> 32); + p[5] = (uint8_t)(w >> 40); + p[6] = (uint8_t)(w >> 48); + p[7] = (uint8_t)(w >> 56); +#endif +} + +static BLAKE2_INLINE uint64_t load48( const void *src ) +{ + const uint8_t *p = ( const uint8_t * )src; + return (( uint64_t )( p[0] ) << 0) | + (( uint64_t )( p[1] ) << 8) | + (( uint64_t )( p[2] ) << 16) | + (( uint64_t )( p[3] ) << 24) | + (( uint64_t )( p[4] ) << 32) | + (( uint64_t )( p[5] ) << 40) ; +} + +static BLAKE2_INLINE void store48( void *dst, uint64_t w ) +{ + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); + p[4] = (uint8_t)(w >> 32); + p[5] = (uint8_t)(w >> 40); +} + +static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 32 - c ) ); +} + +static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 64 - c ) ); +} + +/* prevents compiler optimizing out memset() */ +static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n) +{ + static void *(*const volatile memset_v)(void *, int, size_t) = &memset; + memset_v(v, 0, n); +} + +#endif diff --git a/app/src/blake2s/blake2.h b/app/src/blake2s/blake2.h new file mode 100644 index 0000000..845226e --- /dev/null +++ b/app/src/blake2s/blake2.h @@ -0,0 +1,128 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2_H +#define BLAKE2_H + +#include +#include + +#if defined(_MSC_VER) +#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop)) +#else +#define BLAKE2_PACKED(x) x __attribute__((packed)) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + enum blake2s_constant + { + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 + }; + + typedef struct blake2s_state__ + { + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[BLAKE2S_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; + } blake2s_state; + + typedef struct blake2sp_state__ + { + blake2s_state S[8][1]; + blake2s_state R[1]; + uint8_t buf[8 * BLAKE2S_BLOCKBYTES]; + size_t buflen; + size_t outlen; + } blake2sp_state; + + BLAKE2_PACKED(struct blake2s_param__ + { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint16_t xof_length; /* 14 */ + uint8_t node_depth; /* 15 */ + uint8_t inner_length; /* 16 */ + /* uint8_t reserved[0]; */ + uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ + uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ + }); + + typedef struct blake2s_param__ blake2s_param; + + typedef struct blake2b_param__ blake2b_param; + + typedef struct blake2xs_state__ + { + blake2s_state S[1]; + blake2s_param P[1]; + } blake2xs_state; + + /* Padded structs result in a compile-time error */ + enum { + BLAKE2_DUMMY_1 = 1/(int)(sizeof(blake2s_param) == BLAKE2S_OUTBYTES), + // BLAKE2_DUMMY_2 = 1/(int)(sizeof(blake2b_param) == BLAKE2B_OUTBYTES) + }; + + /* Streaming API */ + int blake2s_init( blake2s_state *S, size_t outlen ); + int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2s_init_param( blake2s_state *S, const blake2s_param *P ); + int blake2s_update( blake2s_state *S, const void *in, size_t inlen ); + int blake2s_final( blake2s_state *S, void *out, size_t outlen ); + + int blake2sp_init( blake2sp_state *S, size_t outlen ); + int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2s_init_with_personalization( blake2s_state *S, size_t outlen, const uint8_t* personalization, uint8_t personalizationlen ); + int blake2sp_update( blake2sp_state *S, const void *in, size_t inlen ); + int blake2sp_final( blake2sp_state *S, void *out, size_t outlen ); + + /* Variable output length API */ + int blake2xs_init( blake2xs_state *S, const size_t outlen ); + int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen ); + int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen ); + int blake2xs_final(blake2xs_state *S, void *out, size_t outlen); + + /* Simple API */ + int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + int blake2xs( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + int blake2xb( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + /* This is simply an alias for blake2b */ + int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/app/src/blake2s/blake2s-ref.c b/app/src/blake2s/blake2s-ref.c new file mode 100644 index 0000000..84fd5cf --- /dev/null +++ b/app/src/blake2s/blake2s-ref.c @@ -0,0 +1,395 @@ +/* + Oficial BLAKE2 implementation tweak by Zondax AG + + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +static const uint32_t blake2s_IV[8] = +{ + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL +}; + +static const uint8_t blake2s_sigma[10][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , +}; + +static void blake2s_set_lastnode( blake2s_state *S ) +{ + S->f[1] = (uint32_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int blake2s_is_lastblock( const blake2s_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2s_set_lastblock( blake2s_state *S ) +{ + if( S->last_node ) blake2s_set_lastnode( S ); + + S->f[0] = (uint32_t)-1; +} + +static void blake2s_increment_counter( blake2s_state *S, const uint32_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + +static void blake2s_init0( blake2s_state *S ) +{ + size_t i; + memset( S, 0, sizeof( blake2s_state ) ); + + for( i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i]; +} + +/* init2 xors IV with input parameter block */ +int blake2s_init_param( blake2s_state *S, const blake2s_param *P ) +{ + const unsigned char *p = ( const unsigned char * )( P ); + size_t i; + + blake2s_init0( S ); + + /* IV XOR ParamBlock */ + for( i = 0; i < 8; ++i ) + S->h[i] ^= load32( &p[i * 4] ); + + S->outlen = P->digest_length; + return 0; +} + + +/* Sequential blake2s initialization */ +int blake2s_init( blake2s_state *S, size_t outlen ) +{ + blake2s_param P[1]; + + /* Move interval verification here? */ + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved) ); */ + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2s_init_param( S, P ); +} + +/* blake2s init with personalization */ +int blake2s_init_with_personalization( blake2s_state *S, size_t outlen, const uint8_t* personalization, uint8_t personalizationlen ) +{ + blake2s_param P[1]; + + /* Move interval verification here? */ + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + if ( ( !personalization ) || ( personalizationlen > sizeof(P->personal) ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved) ); */ + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + memcpy(P->personal, personalization, personalizationlen); + + return blake2s_init_param( S, P ); +} + +int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2s_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2S_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store16( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + /* memset(P->reserved, 0, sizeof(P->reserved) ); */ + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2s_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2S_BLOCKBYTES]; + memset( block, 0, BLAKE2S_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2s_update( S, block, BLAKE2S_BLOCKBYTES ); + secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2s_sigma[r][2*i+0]]; \ + d = rotr32(d ^ a, 16); \ + c = c + d; \ + b = rotr32(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2*i+1]]; \ + d = rotr32(d ^ a, 8); \ + c = c + d; \ + b = rotr32(b ^ c, 7); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + +static void blake2s_compress( blake2s_state *S, const uint8_t in[BLAKE2S_BLOCKBYTES] ) +{ + uint32_t m[16]; + uint32_t v[16]; + size_t i; + + for( i = 0; i < 16; ++i ) { + m[i] = load32( in + i * sizeof( m[i] ) ); + } + + for( i = 0; i < 8; ++i ) { + v[i] = S->h[i]; + } + + v[ 8] = blake2s_IV[0]; + v[ 9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; + + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + + for( i = 0; i < 8; ++i ) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int blake2s_update( blake2s_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2S_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); /* Fill buffer */ + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + blake2s_compress( S, S->buf ); /* Compress */ + in += fill; inlen -= fill; + while(inlen > BLAKE2S_BLOCKBYTES) { + blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES); + blake2s_compress( S, in ); + in += BLAKE2S_BLOCKBYTES; + inlen -= BLAKE2S_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + +int blake2s_final( blake2s_state *S, void *out, size_t outlen ) +{ + uint8_t buffer[BLAKE2S_OUTBYTES] = {0}; + size_t i; + + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2s_is_lastblock( S ) ) + return -1; + + blake2s_increment_counter( S, ( uint32_t )S->buflen ); + blake2s_set_lastblock( S ); + memset( S->buf + S->buflen, 0, BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */ + blake2s_compress( S, S->buf ); + + for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store32( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, outlen ); + memset(buffer, 0 ,sizeof(buffer)); + return 0; +} + +int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + blake2s_state S[1]; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if ( NULL == key && keylen > 0) return -1; + + if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1; + + if( keylen > BLAKE2S_KEYBYTES ) return -1; + + if( keylen > 0 ) + { + if( blake2s_init_key( S, outlen, key, keylen ) < 0 ) return -1; + } + else + { + if( blake2s_init( S, outlen ) < 0 ) return -1; + } + + blake2s_update( S, ( const uint8_t * )in, inlen ); + blake2s_final( S, out, outlen ); + return 0; +} + +#if defined(SUPERCOP) +int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen ) +{ + return blake2s( out, BLAKE2S_OUTBYTES, in, inlen, NULL, 0 ); +} +#endif + +#if defined(BLAKE2S_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2S_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step; + + for( i = 0; i < BLAKE2S_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + /* Test simple API */ + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2S_OUTBYTES]; + blake2s( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES ); + + if( 0 != memcmp( hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) { + for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + uint8_t hash[BLAKE2S_OUTBYTES]; + blake2s_state S; + uint8_t * p = buf; + size_t mlen = i; + int err = 0; + + if( (err = blake2s_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2s_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2s_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2s_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2s_keyed_kat[i], BLAKE2S_OUTBYTES)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif 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 2a0e254..9be5b4d 100644 --- a/app/src/crypto.c +++ b/app/src/crypto.c @@ -19,10 +19,81 @@ #include "coin.h" #include "cx.h" #include "zxmacros.h" +#include "keys_def.h" +#include "crypto_helper.h" uint32_t hdPath[HDPATH_LEN_DEFAULT]; -// #{TODO} --> Check pubkey and sign methods +#define CHECK_PARSER_OK(CALL) \ + do { \ + cx_err_t __cx_err = CALL; \ + if (__cx_err != parser_ok) { \ + return zxerr_unknown; \ + } \ + } while (0) + +static zxerr_t computeKeys(keys_t * saplingKeys) { + if (saplingKeys == NULL) { + return zxerr_no_data; + } + + // Compute ask, nsk + CHECK_PARSER_OK(convertKey(saplingKeys->spendingKey, MODIFIER_ASK, saplingKeys->ask, true)); + CHECK_PARSER_OK(convertKey(saplingKeys->spendingKey, MODIFIER_NSK, saplingKeys->nsk, true)); + + // Compute ak, nsk + // This function will make a copy of the first param --> There shouldn't be problems to overwrite the union + CHECK_PARSER_OK(generate_key(saplingKeys->ask, SpendingKeyGenerator, saplingKeys->ak)); + CHECK_PARSER_OK(generate_key(saplingKeys->nsk, ProofGenerationKeyGenerator, saplingKeys->nk)); + + // Compute ivk and ovk + CHECK_PARSER_OK(computeIVK(saplingKeys->ak, saplingKeys->nk, saplingKeys->ivk)); + CHECK_PARSER_OK(convertKey(saplingKeys->spendingKey, MODIFIER_OVK, saplingKeys->ovk, false)); + + // Compute public address + CHECK_PARSER_OK(generate_key(saplingKeys->ivk, PublicKeyGenerator, saplingKeys->address)); + + return zxerr_ok; +} + +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; + 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_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, cx_privateKey.d, KEY_LENGTH); + error = computeKeys(&saplingKeys); + + // Copy keys + if (error == zxerr_ok) { + memcpy(output, saplingKeys.address, KEY_LENGTH); + memcpy(output + KEY_LENGTH, saplingKeys.ivk, KEY_LENGTH); + 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; +} + zxerr_t crypto_extractPublicKey(uint8_t *pubKey, uint16_t pubKeyLen) { if (pubKey == NULL || pubKeyLen < PK_LEN_25519) { @@ -91,32 +162,14 @@ zxerr_t crypto_sign(uint8_t *signature, uint16_t signatureMaxlen, const uint8_t return error; } -static uint8_t crypto_encodePubkey(uint8_t *buffer, uint16_t buffer_len, const uint8_t *pubkey) { - UNUSED(buffer); - UNUSED(buffer_len); - UNUSED(pubkey); - // #{TODO} --> Generate address - // pubkey ---> address ---> copy into buffer - uint8_t address_len = 20; - return address_len; -} - zxerr_t crypto_fillAddress(uint8_t *buffer, uint16_t bufferLen, uint16_t *addrResponseLen) { - // #{TODO} --> Check pubkey len + address len - if (bufferLen < PK_LEN_25519 + SS58_ADDRESS_MAX_LEN) { + if (buffer == NULL || addrResponseLen == NULL) { return zxerr_unknown; } MEMZERO(buffer, bufferLen); - CHECK_ZXERR(crypto_extractPublicKey(buffer, bufferLen)) - - const uint8_t outLen = crypto_encodePubkey(buffer + PK_LEN_25519, bufferLen - PK_LEN_25519, buffer); - - if (outLen == 0) { - MEMZERO(buffer, bufferLen); - return zxerr_encoding_failed; - } + CHECK_ZXERR(crypto_generateSaplingKeys(buffer, bufferLen)); + *addrResponseLen = 3 * KEY_LENGTH; - *addrResponseLen = PK_LEN_25519 + outLen; return zxerr_ok; } diff --git a/app/src/crypto_helper.c b/app/src/crypto_helper.c new file mode 100644 index 0000000..46d4d8b --- /dev/null +++ b/app/src/crypto_helper.c @@ -0,0 +1,87 @@ +/******************************************************************************* + * (c) 2018 - 2024 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. + ********************************************************************************/ +#include "crypto_helper.h" +#include "keys_personalizations.h" +#include +#include "zxformat.h" + +#include "rslib.h" + + #if defined (LEDGER_SPECIFIC) + #include "cx.h" + #include "cx_blake2b.h" +#endif + #include "blake2.h" + +static void swap_endian(uint8_t *data, int8_t len) { + for (int8_t i = 0; i < len / 2; i++) { + uint8_t t = data[len - i - 1]; + data[len - i - 1] = data[i]; + data[i] = t; + } +} + +parser_error_t convertKey(const uint8_t spendingKey[KEY_LENGTH], const uint8_t modifier, uint8_t outputKey[KEY_LENGTH], bool reduceWideByte) { + uint8_t output[64] = {0}; +#if defined (LEDGER_SPECIFIC) + cx_blake2b_t ctx = {0}; + ASSERT_CX_OK(cx_blake2b_init2_no_throw(&ctx, BLAKE2B_OUTPUT_LEN, NULL, 0, (uint8_t *)EXPANDED_SPEND_BLAKE2_KEY, sizeof(EXPANDED_SPEND_BLAKE2_KEY))); + ASSERT_CX_OK(cx_blake2b_update(&ctx, spendingKey, KEY_LENGTH)); + ASSERT_CX_OK(cx_blake2b_update(&ctx, &modifier, 1)); + cx_blake2b_final(&ctx, output); +#else + blake2b_state state = {0}; + blake2b_init_with_personalization(&state, BLAKE2B_OUTPUT_LEN, (const uint8_t*)EXPANDED_SPEND_BLAKE2_KEY, sizeof(EXPANDED_SPEND_BLAKE2_KEY)); + blake2b_update(&state, spendingKey, KEY_LENGTH); + blake2b_update(&state, &modifier, 1); + blake2b_final(&state, output, sizeof(output)); +#endif + + if (reduceWideByte) { + from_bytes_wide(output, outputKey); + swap_endian(outputKey, KEY_LENGTH); + } else { + memcpy(outputKey, output, KEY_LENGTH); + } + + return parser_ok; +} + +parser_error_t generate_key(const uint8_t expandedKey[KEY_LENGTH], constant_key_t keyType, uint8_t output[KEY_LENGTH]) { + if (keyType >= InvalidKey) { + return parser_value_out_of_range; + } + uint8_t tmpExpandedKey[KEY_LENGTH] = {0}; + memcpy(tmpExpandedKey, expandedKey, KEY_LENGTH); + swap_endian(tmpExpandedKey, KEY_LENGTH); + scalar_multiplication(tmpExpandedKey, keyType, output); + return parser_ok; +} + +parser_error_t computeIVK(const ak_t ak, const nk_t nk, ivk_t ivk) { + blake2s_state state = {0}; + blake2s_init_with_personalization(&state, 32, (const uint8_t*)CRH_IVK_PERSONALIZATION, sizeof(CRH_IVK_PERSONALIZATION)); + blake2s_update(&state, ak, KEY_LENGTH); + blake2s_update(&state, nk, KEY_LENGTH); + blake2s_final(&state, ivk, KEY_LENGTH); + + ivk[31] &= 0x07; + swap_endian(ivk, KEY_LENGTH); + // if ivk == [0; 32] { + // return Err(IronfishError::new(IronfishErrorKind::InvalidViewingKey)); + // } + return parser_ok; +} diff --git a/app/src/crypto_helper.h b/app/src/crypto_helper.h new file mode 100644 index 0000000..cfe4b35 --- /dev/null +++ b/app/src/crypto_helper.h @@ -0,0 +1,46 @@ +/******************************************************************************* + * (c) 2018 - 2024 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 +#include +#include +#include "parser_common.h" +#include "keys_def.h" + +#define ASSERT_CX_OK(CALL) \ + do { \ + cx_err_t __cx_err = CALL; \ + if (__cx_err != CX_OK) { \ + return parser_unexpected_error; \ + } \ + } while (0) + +#define MODIFIER_ASK 0x00 +#define MODIFIER_NSK 0x01 +#define MODIFIER_OVK 0x02 + +parser_error_t convertKey(const uint8_t spendingKey[32], const uint8_t modifier, uint8_t outputKey[32], bool reduceWideByte); +parser_error_t generate_key(const uint8_t expandedKey[32], constant_key_t keyType, uint8_t output[32]); +parser_error_t computeIVK(const ak_t ak, const nk_t nk, ivk_t ivk); + +#ifdef __cplusplus +} +#endif diff --git a/app/src/keys_def.h b/app/src/keys_def.h new file mode 100644 index 0000000..c850366 --- /dev/null +++ b/app/src/keys_def.h @@ -0,0 +1,69 @@ +/******************************************************************************* + * (c) 2018 - 2024 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 +#include +typedef struct { + uint8_t *ptr; + uint16_t len; +} bytes_t; + + +typedef enum { + SpendingKeyGenerator, + ProofGenerationKeyGenerator, + PublicKeyGenerator, + InvalidKey, +} constant_key_t; + +#define KEY_LENGTH 32 + +typedef uint8_t spending_key_t[KEY_LENGTH]; +typedef uint8_t ask_t[KEY_LENGTH]; +typedef uint8_t nsk_t[KEY_LENGTH]; + +typedef uint8_t ak_t[KEY_LENGTH]; +typedef uint8_t nk_t[KEY_LENGTH]; + +typedef uint8_t ivk_t[KEY_LENGTH]; +typedef uint8_t ovk_t[KEY_LENGTH]; + +typedef uint8_t public_address_t[KEY_LENGTH]; + +typedef struct { + spending_key_t spendingKey; + union { + ask_t ask; + ak_t ak; + }; + union { + nsk_t nsk; + nk_t nk; + }; + + ivk_t ivk; + ovk_t ovk; + public_address_t address; +} keys_t; + +#ifdef __cplusplus +} +#endif diff --git a/app/src/keys_personalizations.h b/app/src/keys_personalizations.h new file mode 100644 index 0000000..577a211 --- /dev/null +++ b/app/src/keys_personalizations.h @@ -0,0 +1,39 @@ +/******************************************************************************* + * (c) 2018 - 2024 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 +#include + +#if defined (LEDGER_SPECIFIC) +// blake2 needs to define output size in bits 512 bits = 64 bytes +#define BLAKE2B_OUTPUT_LEN 512 +#else +#define BLAKE2B_OUTPUT_LEN 64 +#endif + +const char EXPANDED_SPEND_BLAKE2_KEY[16] = "Iron Fish Money "; +const char CRH_IVK_PERSONALIZATION[8] = "Zcashivk"; + +#ifdef __cplusplus +} +#endif + + diff --git a/deps/blake2 b/deps/blake2 new file mode 160000 index 0000000..93fefa2 --- /dev/null +++ b/deps/blake2 @@ -0,0 +1 @@ +Subproject commit 93fefa278c1a738685ce1a118ead7c85b5babc58 diff --git a/deps/ledger-zxlib b/deps/ledger-zxlib index 59b3f8f..f19112b 160000 --- a/deps/ledger-zxlib +++ b/deps/ledger-zxlib @@ -1 +1 @@ -Subproject commit 59b3f8f9ea68334acee0720a722a85f30954ae74 +Subproject commit f19112bb6340721c276af459924b3c4261c0291a diff --git a/deps/nanos-secure-sdk b/deps/nanos-secure-sdk index 29a7527..62dd047 160000 --- a/deps/nanos-secure-sdk +++ b/deps/nanos-secure-sdk @@ -1 +1 @@ -Subproject commit 29a7527e7e79c0625eeee1f75db98c07fa5c3d45 +Subproject commit 62dd047774b5e8a6b4e6158b493ee029453b5bae diff --git a/deps/nanosplus-secure-sdk b/deps/nanosplus-secure-sdk index 158f76d..e98fad9 160000 --- a/deps/nanosplus-secure-sdk +++ b/deps/nanosplus-secure-sdk @@ -1 +1 @@ -Subproject commit 158f76d7367351453b0076a35ba56f32c6c42557 +Subproject commit e98fad9fe6b1b726a7563274659f94ba258e547c diff --git a/deps/nanox-secure-sdk b/deps/nanox-secure-sdk index 158f76d..e98fad9 160000 --- a/deps/nanox-secure-sdk +++ b/deps/nanox-secure-sdk @@ -1 +1 @@ -Subproject commit 158f76d7367351453b0076a35ba56f32c6c42557 +Subproject commit e98fad9fe6b1b726a7563274659f94ba258e547c diff --git a/deps/stax-secure-sdk b/deps/stax-secure-sdk index 158f76d..e98fad9 160000 --- a/deps/stax-secure-sdk +++ b/deps/stax-secure-sdk @@ -1 +1 @@ -Subproject commit 158f76d7367351453b0076a35ba56f32c6c42557 +Subproject commit e98fad9fe6b1b726a7563274659f94ba258e547c diff --git a/js/README.md b/js/README.md index 22a3628..d02ea92 100644 --- a/js/README.md +++ b/js/README.md @@ -1,9 +1,9 @@ -# @zondax/ledger-template +# @zondax/ledger-ironfish [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![npm version](https://badge.fury.io/js/%40zondax%2Fledger-template.svg)](https://badge.fury.io/js/%40zondax%2Fledger-template) +[![npm version](https://badge.fury.io/js/%40zondax%2Fledger-ironfish.svg)](https://badge.fury.io/js/%40zondax%2Fledger-ironfish) -This package provides a basic client library to communicate with the Template App running in a Ledger Nano S/X +This package provides a basic client library to communicate with the Ironfish App running in a Ledger Nano S/X We recommend using the npmjs package in order to receive updates/fixes. diff --git a/js/package.json b/js/package.json index 05cd220..e832037 100644 --- a/js/package.json +++ b/js/package.json @@ -1,44 +1,44 @@ { - "name": "@zondax/ledger-template", + "name": "@zondax/ledger-ironfish", "author": "Zondax AG", "license": "Apache-2.0", "version": "0.0.1", - "description": "Node API for the Template App (Ledger Nano S/X/S+)", + "description": "Node API for the Ironfish App (Ledger Nano S/X/S+)", "main": "./dist/index.js", "typings": "./dist/index.d.ts", "types": "./dist/index.d.ts", - "homepage": "https://github.com/zondax/ledger-template", + "homepage": "https://github.com/zondax/ledger-ironfish", "repository": { "type": "git", - "url": "git+https://github.com/zondax/ledger-template.git" + "url": "git+https://github.com/zondax/ledger-ironfish.git" }, "keywords": [ "Zondax", "Ledger", "Javascript", - "Template" + "Ironfish" ], "scripts": { "build": "tsc" }, "bugs": { - "url": "https://github.com/zondax/ledger-template/issues" + "url": "https://github.com/zondax/ledger-ironfish/issues" }, "dependencies": { "@zondax/ledger-js": "^0.2.1" }, "devDependencies": { - "@types/node": "^20.11.17", - "@typescript-eslint/eslint-plugin": "^7.0.1", - "@typescript-eslint/parser": "^7.0.1", - "eslint": "^8.56.0", + "@types/node": "^20.11.27", + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-config-standard-with-typescript": "^43.0.1", "eslint-plugin-import": "^2.29.1", "eslint-plugin-n": "^16.6.2", "eslint-plugin-promise": "^6.1.1", "prettier": "^3.2.5", - "typescript": "^5.3.3" + "typescript": "^5.4.2" }, "files": [ "dist/**/*" diff --git a/js/src/consts.ts b/js/src/consts.ts index c9c0064..3b35c61 100644 --- a/js/src/consts.ts +++ b/js/src/consts.ts @@ -1,9 +1,12 @@ -export const APP_KEY = "TEMPLATE"; +export const APP_KEY = "Ironfish"; export const P2_VALUES = { DEFAULT: 0x00, }; +export const KEY_LENGTH = 32; + + export const PKLEN = 65; export const ADDRLEN = 32; export const PRINCIPAL_LEN = 29; diff --git a/js/src/helper.ts b/js/src/helper.ts index 9856a9e..c546dc9 100644 --- a/js/src/helper.ts +++ b/js/src/helper.ts @@ -1,28 +1,24 @@ import { errorCodeToString } from "@zondax/ledger-js"; -import { ADDRLEN, PKLEN, PRINCIPAL_LEN } from "./consts"; +import { ADDRLEN, KEY_LENGTH, PRINCIPAL_LEN } from "./consts"; import { ResponseAddress } from "./types"; export function processGetAddrResponse(response: Buffer): ResponseAddress { const errorCodeData = response.subarray(-2); const returnCode = errorCodeData[0] * 256 + errorCodeData[1]; - const publicKey = Buffer.from(response.subarray(0, PKLEN)); - response = response.subarray(PKLEN); + const publicAddress = Buffer.from(response.subarray(0, KEY_LENGTH)); + response = response.subarray(KEY_LENGTH); - const principal = Buffer.from(response.subarray(0, PRINCIPAL_LEN)); - response = response.subarray(PRINCIPAL_LEN); + const ivk = Buffer.from(response.subarray(0, KEY_LENGTH)); + response = response.subarray(KEY_LENGTH); - const address = Buffer.from(response.subarray(0, ADDRLEN)); - response = response.subarray(ADDRLEN); + const ovk = Buffer.from(response.subarray(0, KEY_LENGTH)); + response = response.subarray(KEY_LENGTH); - const principalText = Buffer.from(response.subarray(0, -2)) - .toString() - .replace(/(.{5})/g, "$1-"); return { - publicKey, - principal, - address, - principalText, + publicAddress, + ivk, + ovk, returnCode, errorMessage: errorCodeToString(returnCode), }; diff --git a/js/src/index.ts b/js/src/index.ts index 4b0ea3b..9e12d69 100644 --- a/js/src/index.ts +++ b/js/src/index.ts @@ -15,7 +15,7 @@ * limitations under the License. ******************************************************************************* */ import { P2_VALUES, PREHASH_LEN, SIGRSLEN } from "./consts"; -import { ResponseAddress, ResponseSign, TemplateIns } from "./types"; +import { ResponseAddress, ResponseSign, IronfishIns } from "./types"; import GenericApp, { ConstructorParams, @@ -29,8 +29,8 @@ import { processGetAddrResponse } from "./helper"; export * from "./types"; -export default class TemplateApp extends GenericApp { - readonly INS!: TemplateIns; +export default class IronfishApp extends GenericApp { + readonly INS!: IronfishIns; constructor(transport: Transport) { if (transport == null) throw new Error("Transport has not been defined"); diff --git a/js/src/types.ts b/js/src/types.ts index 6616f7b..9b9dee7 100644 --- a/js/src/types.ts +++ b/js/src/types.ts @@ -1,16 +1,15 @@ import { INSGeneric, ResponseBase } from "@zondax/ledger-js"; -export interface TemplateIns extends INSGeneric { +export interface IronfishIns extends INSGeneric { GET_VERSION: 0x00; GET_ADDR: 0x01; SIGN: 0x02; } export interface ResponseAddress extends ResponseBase { - publicKey?: Buffer; - principal?: Buffer; - address?: Buffer; - principalText?: string; + publicAddress?: Buffer; + ivk?: Buffer; + ovk?: Buffer; } export interface ResponseSign extends ResponseBase { diff --git a/tests/keys.cpp b/tests/keys.cpp new file mode 100644 index 0000000..9c04b85 --- /dev/null +++ b/tests/keys.cpp @@ -0,0 +1,305 @@ +/******************************************************************************* +* (c) 2018 - 2024 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. +********************************************************************************/ +#include "gmock/gmock.h" + +#include +#include +#include +#include "parser_txdef.h" +#include "keys_def.h" +#include "crypto_helper.h" +#include "rslib.h" + +using namespace std; +struct IronfishKeys { + string spendingKey; + string spendAuthorizationKey; //ask + string proofAuthorizationKey; //nsk + string authorizing_key; //ak + string nullifier_deriving_key; //nk + string viewKey; //full viewing key (FVK) + string incomingViewingKey; //ivk + string outgoingViewingKey; //ovk + string publicAddress; +}; + +string toHexString(const uint8_t* data, size_t length) { + std::stringstream hexStream; + hexStream << std::hex << std::setfill('0'); + for (size_t i = 0; i < length; ++i) { + hexStream << std::setw(2) << static_cast(data[i]); + } + return hexStream.str(); +} + +// Generated using ironfish SDK (public_address_generation) +vector testvectors { + { + "0000000000000000000000000000000000000000000000000000000000000000", + "02dddb7d511f89769aaaefa94c08a0cc64f8f962fb1484fb58f24e3b6191a813", + "0123383cde1dc45f757e9852e650b38d222563386c55335b322ca8aec65e4bda", + "94c0bf0aff4653756184e7564d6bace42ba28ded17cb6969bd3db2b5bb813183", + "be0383711ddcb0beaa8b7ef72fc20f1798f813e3008bb9d704a5da590d967ed7", + "94c0bf0aff4653756184e7564d6bace42ba28ded17cb6969bd3db2b5bb813183be0383711ddcb0beaa8b7ef72fc20f1798f813e3008bb9d704a5da590d967ed7", + "03171a55bcdd54018c224a261cdc99badce181a60ba4d4f6be401dc9841e07bb", + "efd8642e69a4bf55196ed4d4528fcf50a842319284332f708fc1254c8358ae1e", + "4f766c63bf2a18f2434add5dfda393886c80b1fe4ef1d968c7c87dc0484b5c9d" + }, + { + "0000000000000000000000000000000000000000000000000000000000000001", + "029b909181abb2a48bf09a6274179836eb125cb7b58ec9c049e2cc242b95dc77", + "0af942f4f07578aa419d06ab11580238211e4ed5e78e21df08c26eb5d2c79cec", + "46095954bc6e220bceb8e9dd92ad551c241df5fc78575e09b457a3b5c7ccfa59", + "71a7ec7feae16363b6daff256f8033778fdff4404af51f4702f6bb3723441fc3", + "46095954bc6e220bceb8e9dd92ad551c241df5fc78575e09b457a3b5c7ccfa5971a7ec7feae16363b6daff256f8033778fdff4404af51f4702f6bb3723441fc3", + "01e8b953ebef20c9df67ac99075f7fff3bc2f1ca93822299d6f6247617e2efd4", + "1824f96c702f47b199457273994c35d7e9343bc1a8aff9b4037fdd06d0b3a660", + "796d7ecc523ae042265314f70641daa158576f537fbb408e8ce7f17e0900fc99" + }, + { + "71af0f431ad2b93fdc9bbe907b03314f607c09461c421a2873d4807f8841bbc7", + "07e7ec847e4a0eb7bcdf8682568cac4aef8189d379e96154eb170289d1bb50fb", + "0c76463c6c683187511a59c9a0bb72a398656f35aaefc4fb03509c513d09f960", + "283e16fc078a556b2be63e7f4661474cbffa5397ececee7376e144abb5aff71e", + "f68210181abe9d2d1178773eeda7d869f619db56b6ed928b79474b532158d267", + "283e16fc078a556b2be63e7f4661474cbffa5397ececee7376e144abb5aff71ef68210181abe9d2d1178773eeda7d869f619db56b6ed928b79474b532158d267", + "035c7bcf0c6f8ffd2c5afd44fda50eda233f0b2b9747154d66fe2a827a35a78d", + "86be13371588a5e3803dc57678578aba2877f4b0212c994727197df2307d9691", + "f308f7b7c1dcea1d5c9c2ae9085afcbc476e2916ce58c3ed142336884919959a" + }, + { + "36dea1c88f60c02b01ab6a0494e16e6d939b44a2a3dd75e9e0360399dc8650f4", + "0dbe2541a65fe65aa63170bb687b53edcd66173cd1850bb8e5a42b232a2b09db", + "04eae190efdd076715dfd439acf64228e14e0fc96da8bf131eb71002c0d3233e", + "c8117bd8d872097494bff6ce631e7d84bc5ab4113d2a04eeb24f1717fad833e1", + "90a7eb4c20f5993c791de70d3da81501da041744c27a5ad135b3ea1618870330", + "c8117bd8d872097494bff6ce631e7d84bc5ab4113d2a04eeb24f1717fad833e190a7eb4c20f5993c791de70d3da81501da041744c27a5ad135b3ea1618870330", + "07d77856b0a3d2a7b6fdba054beeb199d7ddd9dd66ad3e6287f00b405b1535ec", + "25f0fa2b575874eb93644e81c44c2631efe5a1ab5d1ab7258060847670367068", + "3f88c1b9f3c4338d9445ade292f2838c2aa2de712b62250ed1ae172090c6f037" + }, + { + "b4334a7fb7f3795906688fef68dbbaf714739691fca288f722e54136ffa0d327", + "0cccedb48d345c193a64a2a830277f00a8cf315b8ba3a9073dbb041bf8b6698e", + "061af229deed0a4e5aa4632b88b6fdf8295163821d0fbf37c876fe3f2a86cd7c", + "d2ee54d95d8410fe79968df4add0bbb46c7db66c256957b965d8f4295acd1cf1", + "011abad7ce51e5163e5d46cccfa323d458ffb1c6fafb3bea42cb96df70378870", + "d2ee54d95d8410fe79968df4add0bbb46c7db66c256957b965d8f4295acd1cf1011abad7ce51e5163e5d46cccfa323d458ffb1c6fafb3bea42cb96df70378870", + "04f81f076f6d0d3509171033e837e966c48dbdbc85063ffc5ab4053fc7d00839", + "323d72bcfa2f7b2702744c3253753d0b749849cf3aa4f179e65c7b7617f4b057", + "4d30630129be18acf77b5297d5bfd7ac2f49009d50676d9cf31e1175e35203b1" + }, + { + "994f855e8e49063b1c58e348bdf80f513cb2ea24d4d3b238f77484ede3c2d92a", + "03f3a7fd902fa5d081fd04fdbd21c61f3434f9264213e19582c1078c45514b03", + "01fe8df4ca283ac4e921ab95cffead22b9cc26b4144cb18c265a0eb187f4a727", + "14f9260c82a77d7f171dfd97df572b4103cf91d89c15b55450144c99fb5d9d3e", + "b430f67ce7fbd4d3a1126b7e339db35fe6060bbe98cbda062118a9fc166213a1", + "14f9260c82a77d7f171dfd97df572b4103cf91d89c15b55450144c99fb5d9d3eb430f67ce7fbd4d3a1126b7e339db35fe6060bbe98cbda062118a9fc166213a1", + "047228f8313b24db2ad37a552cc15279dd515d156ac39f57da1a4d4dd40a4a61", + "c1068c4c44619ac9fa1294475de5f42d1f9257984c7792fdda241d7b127be8c8", + "3d8288b5df34654ba97c23e1914a1a2392d4798be05aa420895dddd2eecbd953" + }, + { + "b75e9a8a5f24d3299a196cb4b4124a211dd4f253a9d227290b0b3f72313a5532", + "041f1e202aa64ecb9151272257837b9b06866816246143d5fcd2567bd764d77a", + "04acf490916df2031404a4b2ecc50f5c43d7d0838a8aef5cbafb370df6467ea6", + "e616286d0f2729f3fa26a5f4d89fa03214b4310c7f7a40b9ed703361e6b40b3e", + "98f87650c039a601e875ca924b8fd48a17b443da3ce0536bef019bdc20db2c1b", + "e616286d0f2729f3fa26a5f4d89fa03214b4310c7f7a40b9ed703361e6b40b3e98f87650c039a601e875ca924b8fd48a17b443da3ce0536bef019bdc20db2c1b", + "0163e0f0202685ec96529cf5c5edf69327a292f82c77ef3204814c6e939c9b7e", + "784ffe8b8cd62e7be3e2b0a34e38ec63cd6b9739a2573c312daef3d7bb3ae262", + "fb721350fa746a9dab381c534eeeeb9edf49f07dd5fb397fee46313c2c8c5c40" + }, + { + "683f1521a8c6f76d4835f87ecee51cf899ec71555102e595e5bc2c8ed6c1ff82", + "07917c5521adf7d07f284e376312f992ac71721cc162ecae09f5a53726e6b887", + "080df08692a104f94ce208a328cdbcd9ed0b073d3c850987a4101c64d3c97f6c", + "c9305843719d27ca9a35bd165651b210a087fe0a6c3e906dbb7e3018ec016e39", + "cfd751257c062c86b1e4461ed2370ec98dd4f2e7e22331ce315f6ee1c42544c1", + "c9305843719d27ca9a35bd165651b210a087fe0a6c3e906dbb7e3018ec016e39cfd751257c062c86b1e4461ed2370ec98dd4f2e7e22331ce315f6ee1c42544c1", + "0428f0f7d4a43973d7535c47adbd16752fd54105ecf1e6e346a1ac029c4ca85b", + "b4c1fa6741f7250188c42947a9012c0ca7f863695a93b1d71fb22dc063143c77", + "cbcb4371bc45865bcdd40ab17f0bd7b015dc0a5328850c203cbf669fed38cb90" + }, + { + "c81b034031656bfceb51300a0088b012eafe1700b22f115d747e23d5e76f66dd", + "078e175c2a111900c703685793183696fe8bf0ad341e285179fee178d694129a", + "0041f378cfc074626c63ff318cf79faf18162c030f8655e36c53890a032e2457", + "fee8c30df362ec50f8169441c95b860a00c8b9d57f020a9946c54ab47484c026", + "aa46f2468269142649f58c42a272cbbdf3791c2dc0242c715ccd12acda2ab361", + "fee8c30df362ec50f8169441c95b860a00c8b9d57f020a9946c54ab47484c026aa46f2468269142649f58c42a272cbbdf3791c2dc0242c715ccd12acda2ab361", + "04c6e8fc3a669acacc5b0b078125cca65ca63424c06b3ac36565a65280958c3b", + "c0cf9084ad644b5005fac345a40b38392759194bd7488f434af8ecbac9b6224f", + "752b5325119879d1427d8df427e28206a59819acc69e4003db656812bda6cc4e" + }, + { + "9e0de76b502d8fea848086e90cb776832516e68fa7715758410a11dac33279a5", + "0590d7a189c8de9fa423dda7cd2c9d7513e47c76ae52f89ce41e01185fe1e6bb", + "0be98efdb1a394a97922fbc9b687fd984d0db6cd4bba37a00157528fe0ba9b96", + "f83d80b645d4fda5c5e5b598ce855f96abc8fb7c385a406f8c2d32b1cc4b089b", + "3fa04bab93e6a17eb3b98b0371ac4c46194b1ab3b0f5472ae76e830e51b068c2", + "f83d80b645d4fda5c5e5b598ce855f96abc8fb7c385a406f8c2d32b1cc4b089b3fa04bab93e6a17eb3b98b0371ac4c46194b1ab3b0f5472ae76e830e51b068c2", + "06009065dc3b4eb05b3c238d20e2e6d897a2bd13e0359846c80fc0814b22667e", + "fa46321b8da3da8282df1f8cdb980be5c9606e55200c110c8b500b330f84ecfc", + "a31441f468d12e4ced4677f7e1b2b89e6d6efe4dec940f13d8d4880034282e51" + }, + { + "6171008a41c077d30853dbd4a365d44f5df46e3d84974acf64aec45d3dfa8518", + "06074714498be4d8c55ca6b25de8ec2be2d4d60edc016f2f339db397a6e06cc6", + "05b9dfc1859fe50046e6dd85dd496baeee26b7595732c422d2c2bd63eb8daf97", + "8c3337ccc68bf985094ff4099f40d136662e840adcad8b3e4398ac1c2e3cc30b", + "a3f9d913b854a7f8bfea0575b5447dad7caeb5384bcf127178ba2bfffe99cfd0", + "8c3337ccc68bf985094ff4099f40d136662e840adcad8b3e4398ac1c2e3cc30ba3f9d913b854a7f8bfea0575b5447dad7caeb5384bcf127178ba2bfffe99cfd0", + "0688006785e98dbc7754eff5e8077abbda8e3c731f91ad1a14d69fc5d2627783", + "ff403d8ab3394b14a1d1dc35c07797755e27a39ad140ab32d046fc8f4636c74c", + "649b86129fd4ca89cff804a98f63cc023200f9aeb486b9cd60458b456ec96eac" + }, + { + "eb18bb634960b813b7d876fb30fc13fb0786d6a43d4b66622c56665d2fbdaf76", + "03f29b56313cda55b140e0438564846653cec507c32e605f12de186cb4520214", + "0d2b2af96208d61b73c29ee85899a9bd1d05d4bf3758c3b56e123eb5787bc338", + "c1a69c99d0b31e6e1f8084fd19985144a66fa7985614dfc524d2f8d2da293a3a", + "6356136ea5c85f2c082c42e5db40de5f788eb5cf94992cc8d1f2391d1a646596", + "c1a69c99d0b31e6e1f8084fd19985144a66fa7985614dfc524d2f8d2da293a3a6356136ea5c85f2c082c42e5db40de5f788eb5cf94992cc8d1f2391d1a646596", + "05ad202783a7ecbb734eb405831a2a2fe32d6916135451a4e81a825cf6152666", + "12e5048f89d52d5ed178d5da49e4e7fe6d597bffc855b56c72334f04a462c4d1", + "566399b7710d75a20246d7e36fa3b4f4d3b0d7b7ced586be9f31c78fb1688595" + }, + { + "6ed609b68227ccdb65f13f4119301fd03f392276aa50e6c5fbc1dd24eb448a6e", + "0b5ee2715d224575fa47846bf5a6655d2f377c5a42e6e6561b1eef9f181c9909", + "006d75e2183b7d4152c14a84e88ad44c67707176e0abd9a3c69c3cfe96afcfff", + "57fe8e536aa4d64b2af0186be557aedabc88bc68471d1f92346bef86af459e10", + "431cee7e49cf5097ea1c8c56b2e54fa9cdbb63310fac0a2b48a55842ab335e8e", + "57fe8e536aa4d64b2af0186be557aedabc88bc68471d1f92346bef86af459e10431cee7e49cf5097ea1c8c56b2e54fa9cdbb63310fac0a2b48a55842ab335e8e", + "033013c1407fecb398c16f144e4bba03efd5cbbf8ceead92f05b57cdd1a6b44c", + "7ddee0eda90360658301542af1dbb08566db8e4bf0e4d3a8679fa01cf6361799", + "8ddca1d54e02bb2d13a3f0a485820a20908427c2067c78490a3072afb6b4efa9" + }, + { + "7b94d9ceffcf2d7a764a16146ce7ce90cd710f717cd9812b8bc85555364c06f3", + "0c8505f1ef2b5c18d93d95674b531098bc2bba4f18410e6920a0b016ea5009ba", + "0bb1f088ff779da607dc22968ff239d6878e9f605dd3185861b4679ba0aa5702", + "aeeeb23556eba42bf22632c7ba5f9871f9b34196f6c87091fb82111668edfd41", + "36b6122e6dbe1d04f6cfa16edd03f25e54397cfa02f1d2fc3c529fd3888980e2", + "aeeeb23556eba42bf22632c7ba5f9871f9b34196f6c87091fb82111668edfd4136b6122e6dbe1d04f6cfa16edd03f25e54397cfa02f1d2fc3c529fd3888980e2", + "03a3e8d415ef18aca5f4b16e2d2b89ec7ec1439b062d217896625aeb0bbbb8a4", + "88fcbdd13b18a27f1f0c0507384e1716d5004ef0edcbbe7e5fce63c3ba29a8c4", + "cfbe977de06351c864bd35b942e1715d0f9efa78b2e3c79d28e0f5d7f1b5b03c" + }, + { + "4c7da515de11409b3101665a6c91fbccfc9f4ff77076b8dd71bcfef34533e9be", + "000ff60e8c05f36fd4edb66a82e22152dd6d5cd887234e8a648e51acb3c7ca55", + "0212a1850d2830b52aea267cc188fa5ed0a67d1e0e8a134cdee8900217be212c", + "49a722eee2330bd3ec9f00ce2d76f51ede01db1f2584f02f941eff01ca3732af", + "531bf079f72b51eeeec7a8ba7e17687fe1bdf2dd437abeed7d80d23675dcc89b", + "49a722eee2330bd3ec9f00ce2d76f51ede01db1f2584f02f941eff01ca3732af531bf079f72b51eeeec7a8ba7e17687fe1bdf2dd437abeed7d80d23675dcc89b", + "01b0c1949caefe5b1ae6619165c2c8b844cc48b60fad8bbc225301f1a5482236", + "1c7b2453eb96c94a07337a4d6e233fa4d8bdab2f0129d5ebdbbbb6ff92fa5988", + "fe7f51c8d744d29323862d5c80e58575d539995413f01d99e35ceccf1464e884" + }, + { + "bb20c0b30bfd58582994c99d5096928574786600de6e5068d6578793f810778c", + "05605dc6766494b5adf665fc306dddefe84b8556fc7486879d5d1b06987f95ba", + "0c8c40a559828fe9b87e650eaa4f37eebd3a0076085b141d232a49471d5e80bd", + "0e2f36dc1d56cc8000175f330606849ad725aa8dfa775e618d57e76992dea3ef", + "276a2d02fc6dd50fb4e7e471fd46e2c4c0545d48fd34dcdaf8b1361ea0f73618", + "0e2f36dc1d56cc8000175f330606849ad725aa8dfa775e618d57e76992dea3ef276a2d02fc6dd50fb4e7e471fd46e2c4c0545d48fd34dcdaf8b1361ea0f73618", + "072f1e5b04f3af53d19728dd147efcbf3693e5471798d44a0d304c546aa653e3", + "87f244bce4971951a25a9cfcf5b17300314f737c274ff49ec3c7c1795759538b", + "6a8e8ccd89e684f41656985c642316a7457865c03a916cdb5bbe84e0174f0d4b" + }, + { + "9c9a9edaeb2d4c671f797d80f253a0b274bdd635b1e09d4223d05c84bb69f42c", + "09e1d308114cacc0fbf65167b4654196a92d51622411e9bb63103c188d6948e7", + "0d72a3f8abfa526afd1d7a0f529ccfe92439fe784a331e9ae5ba21beebdc2d7b", + "07313b1fe45c897f9a3cb09b0bfde097cbec0ea2912f14e0229cd4230fb6e9be", + "2421e49f1195516b6366fee8a6f0e617b24284c3942bdfe121755c8ca31154cd", + "07313b1fe45c897f9a3cb09b0bfde097cbec0ea2912f14e0229cd4230fb6e9be2421e49f1195516b6366fee8a6f0e617b24284c3942bdfe121755c8ca31154cd", + "050305d983a25a349b8c6a98a37573eba02bc02db5d606d398f5a4698073e3e4", + "a6e0bd607f94019525a75c9f3b87b40e0844757cd782fa8abebadbffe378c133", + "911f0a4dc6db375ab01357959581f626a3d8d0681b764c5ee960f9dd542719c3" + }, + { + "5ecd495e8d1a3aa3fe9a0f038c2b984d361df073202d2d9e48d2a592960adf8c", + "0bd9d324949da2664db619d7707a4874fc8b7687d4be046e7d776fa791792c11", + "04b597a4a3f6e60eb59ecd09828224ab9a849c1a0d0229e4cbd5cfed6db2979b", + "8f2111bea95fb2056fd78b9b035c1e1c776f01aea3777a0ca4c28f0f87c98758", + "91e874444a8c49b5b46ba831db44f783c6d172b81df00ee05bf47bb9baaecc81", + "8f2111bea95fb2056fd78b9b035c1e1c776f01aea3777a0ca4c28f0f87c9875891e874444a8c49b5b46ba831db44f783c6d172b81df00ee05bf47bb9baaecc81", + "064f88f47275e77c362390ef04b1bd657e31fe1a0bdce74b84e494e6276bb625", + "cc691cbcb17a713f67eb2977d735c5f34e28ca885d10e78a93106198f333fd85", + "a944ec349e29edde71ce202384d3b2b65cb7e86f9ec43d7757097e8597f47ced" + }, + // Keys from Zemu tests + { + "e89dab1a3e40eb2c120defd577ce743ba0893df22aaec97de46a62cd934b1257", + "0ddce28653e08c129da8b1c6485a8a7f2d987163742c91a26209014cf92ee6de", + "010cd3f2276aeac2b3a6a98278bacb878606d4fa3301f70713425b5761facdd4", + "bdd8b8dd269e11c0f9ff401e284fb19ea2cfc008c791590c08e3616865ece534", + "fc912a61108229dc6af38809fa3c938d6b3d0bce2de236751a445a72f061e488", + "bdd8b8dd269e11c0f9ff401e284fb19ea2cfc008c791590c08e3616865ece534fc912a61108229dc6af38809fa3c938d6b3d0bce2de236751a445a72f061e488", + "043e34aa9a6323b82a899d984081ce53e3bb47b2ffa18a0dcfa6910a6d278c73", + "316c96f058f7e188acc90d90d1d765bd9b9ce9e5fa3655c74e8450df0191ee21", + "b3ad098e86bc31de35ec5a77cce6aed08d5336bf273abef5e7eb420278a0c19c" + }, +}; + + +TEST(Keys, SpendingAuthorizationKey) { + for (const auto& testcase : testvectors) { + keys_t keys = {0}; + + // Read spendingKey from testvectors + parseHexString(keys.spendingKey, sizeof(keys.spendingKey), testcase.spendingKey.c_str()); + + // Compute ask and nsk + ASSERT_EQ(convertKey(keys.spendingKey, MODIFIER_ASK, keys.ask, true), parser_ok); + const string ask = toHexString(keys.ask, 32); + EXPECT_EQ(ask, testcase.spendAuthorizationKey); + + ASSERT_EQ(convertKey(keys.spendingKey, MODIFIER_NSK, keys.nsk, true), parser_ok); + const string nsk = toHexString(keys.nsk, 32); + EXPECT_EQ(nsk, testcase.proofAuthorizationKey); + + // Compute ak and nk + generate_key(keys.ask, SpendingKeyGenerator, keys.ak); + const string ak = toHexString(keys.ak, 32); + EXPECT_EQ(ak, testcase.authorizing_key); + + generate_key(keys.nsk, ProofGenerationKeyGenerator, keys.nk); + const string nk = toHexString(keys.nk, 32); + EXPECT_EQ(nk, testcase.nullifier_deriving_key); + + const string viewKey = ak + nk; + EXPECT_EQ(viewKey, testcase.viewKey); + + // Compute ivk and ovk + computeIVK(keys.ak, keys.nk, keys.ivk); + const string ivk = toHexString(keys.ivk, 32); + EXPECT_EQ(ivk, testcase.incomingViewingKey); + + ASSERT_EQ(convertKey(keys.spendingKey, MODIFIER_OVK, keys.ovk, false), parser_ok); + const string ovk = toHexString(keys.ovk, 32); + EXPECT_EQ(ovk, testcase.outgoingViewingKey); + + + ASSERT_EQ(generate_key(keys.ivk, PublicKeyGenerator, keys.address), parser_ok); + const string address = toHexString(keys.address, 32); + EXPECT_EQ(address, testcase.publicAddress); + } +} 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/snapshots/s-mainmenu/00000.png b/tests_zemu/snapshots/s-mainmenu/00000.png index 90c22db..c931308 100644 Binary files a/tests_zemu/snapshots/s-mainmenu/00000.png and b/tests_zemu/snapshots/s-mainmenu/00000.png differ diff --git a/tests_zemu/snapshots/s-mainmenu/00004.png b/tests_zemu/snapshots/s-mainmenu/00004.png index 9d8bf30..0fb4e37 100644 Binary files a/tests_zemu/snapshots/s-mainmenu/00004.png and b/tests_zemu/snapshots/s-mainmenu/00004.png differ diff --git a/tests_zemu/snapshots/s-mainmenu/00010.png b/tests_zemu/snapshots/s-mainmenu/00010.png index 9d8bf30..0fb4e37 100644 Binary files a/tests_zemu/snapshots/s-mainmenu/00010.png and b/tests_zemu/snapshots/s-mainmenu/00010.png differ diff --git a/tests_zemu/snapshots/s-mainmenu/00012.png b/tests_zemu/snapshots/s-mainmenu/00012.png index 90c22db..c931308 100644 Binary files a/tests_zemu/snapshots/s-mainmenu/00012.png and b/tests_zemu/snapshots/s-mainmenu/00012.png differ diff --git a/tests_zemu/snapshots/s-show_address/00000.png b/tests_zemu/snapshots/s-show_address/00000.png new file mode 100644 index 0000000..e813248 Binary files /dev/null and b/tests_zemu/snapshots/s-show_address/00000.png differ diff --git a/tests_zemu/snapshots/s-show_address/00001.png b/tests_zemu/snapshots/s-show_address/00001.png new file mode 100644 index 0000000..1fc7ae4 Binary files /dev/null and b/tests_zemu/snapshots/s-show_address/00001.png differ diff --git a/tests_zemu/snapshots/s-show_address/00002.png b/tests_zemu/snapshots/s-show_address/00002.png new file mode 100644 index 0000000..4b1f015 Binary files /dev/null and b/tests_zemu/snapshots/s-show_address/00002.png differ diff --git a/tests_zemu/snapshots/s-show_address/00003.png b/tests_zemu/snapshots/s-show_address/00003.png new file mode 100644 index 0000000..c29cd8c Binary files /dev/null and b/tests_zemu/snapshots/s-show_address/00003.png differ diff --git a/tests_zemu/snapshots/s-show_address/00004.png b/tests_zemu/snapshots/s-show_address/00004.png new file mode 100644 index 0000000..693d659 Binary files /dev/null and b/tests_zemu/snapshots/s-show_address/00004.png differ diff --git a/tests_zemu/snapshots/s-show_address/00005.png b/tests_zemu/snapshots/s-show_address/00005.png new file mode 100644 index 0000000..d8c951c Binary files /dev/null and b/tests_zemu/snapshots/s-show_address/00005.png differ diff --git a/tests_zemu/snapshots/s-show_address/00006.png b/tests_zemu/snapshots/s-show_address/00006.png new file mode 100644 index 0000000..d038e88 Binary files /dev/null and b/tests_zemu/snapshots/s-show_address/00006.png differ diff --git a/tests_zemu/snapshots/s-show_address/00007.png b/tests_zemu/snapshots/s-show_address/00007.png new file mode 100644 index 0000000..006c26a Binary files /dev/null and b/tests_zemu/snapshots/s-show_address/00007.png differ diff --git a/tests_zemu/snapshots/s-show_address/00008.png b/tests_zemu/snapshots/s-show_address/00008.png new file mode 100644 index 0000000..c931308 Binary files /dev/null and b/tests_zemu/snapshots/s-show_address/00008.png differ diff --git a/tests_zemu/snapshots/sp-mainmenu/00000.png b/tests_zemu/snapshots/sp-mainmenu/00000.png index 44d5e0f..f0fb480 100644 Binary files a/tests_zemu/snapshots/sp-mainmenu/00000.png and b/tests_zemu/snapshots/sp-mainmenu/00000.png differ diff --git a/tests_zemu/snapshots/sp-mainmenu/00001.png b/tests_zemu/snapshots/sp-mainmenu/00001.png index e10e004..8472e5d 100644 Binary files a/tests_zemu/snapshots/sp-mainmenu/00001.png and b/tests_zemu/snapshots/sp-mainmenu/00001.png differ diff --git a/tests_zemu/snapshots/sp-mainmenu/00002.png b/tests_zemu/snapshots/sp-mainmenu/00002.png index 7e236da..f792167 100644 Binary files a/tests_zemu/snapshots/sp-mainmenu/00002.png and b/tests_zemu/snapshots/sp-mainmenu/00002.png differ diff --git a/tests_zemu/snapshots/sp-mainmenu/00003.png b/tests_zemu/snapshots/sp-mainmenu/00003.png index e10e004..8472e5d 100644 Binary files a/tests_zemu/snapshots/sp-mainmenu/00003.png and b/tests_zemu/snapshots/sp-mainmenu/00003.png differ diff --git a/tests_zemu/snapshots/sp-mainmenu/00004.png b/tests_zemu/snapshots/sp-mainmenu/00004.png index 4764b26..dd39ad8 100644 Binary files a/tests_zemu/snapshots/sp-mainmenu/00004.png and b/tests_zemu/snapshots/sp-mainmenu/00004.png differ diff --git a/tests_zemu/snapshots/sp-mainmenu/00010.png b/tests_zemu/snapshots/sp-mainmenu/00010.png index 4764b26..dd39ad8 100644 Binary files a/tests_zemu/snapshots/sp-mainmenu/00010.png and b/tests_zemu/snapshots/sp-mainmenu/00010.png differ diff --git a/tests_zemu/snapshots/sp-mainmenu/00011.png b/tests_zemu/snapshots/sp-mainmenu/00011.png index e10e004..8472e5d 100644 Binary files a/tests_zemu/snapshots/sp-mainmenu/00011.png and b/tests_zemu/snapshots/sp-mainmenu/00011.png differ diff --git a/tests_zemu/snapshots/sp-mainmenu/00012.png b/tests_zemu/snapshots/sp-mainmenu/00012.png index 44d5e0f..f0fb480 100644 Binary files a/tests_zemu/snapshots/sp-mainmenu/00012.png and b/tests_zemu/snapshots/sp-mainmenu/00012.png differ diff --git a/tests_zemu/snapshots/sp-show_address/00000.png b/tests_zemu/snapshots/sp-show_address/00000.png new file mode 100644 index 0000000..31051f8 Binary files /dev/null and b/tests_zemu/snapshots/sp-show_address/00000.png differ diff --git a/tests_zemu/snapshots/sp-show_address/00001.png b/tests_zemu/snapshots/sp-show_address/00001.png new file mode 100644 index 0000000..4558367 Binary files /dev/null and b/tests_zemu/snapshots/sp-show_address/00001.png differ diff --git a/tests_zemu/snapshots/sp-show_address/00002.png b/tests_zemu/snapshots/sp-show_address/00002.png new file mode 100644 index 0000000..16f7ab8 Binary files /dev/null and b/tests_zemu/snapshots/sp-show_address/00002.png differ diff --git a/tests_zemu/snapshots/sp-show_address/00003.png b/tests_zemu/snapshots/sp-show_address/00003.png new file mode 100644 index 0000000..668c489 Binary files /dev/null and b/tests_zemu/snapshots/sp-show_address/00003.png differ diff --git a/tests_zemu/snapshots/sp-show_address/00004.png b/tests_zemu/snapshots/sp-show_address/00004.png new file mode 100644 index 0000000..3f24353 Binary files /dev/null and b/tests_zemu/snapshots/sp-show_address/00004.png differ diff --git a/tests_zemu/snapshots/sp-show_address/00005.png b/tests_zemu/snapshots/sp-show_address/00005.png new file mode 100644 index 0000000..b93a32d Binary files /dev/null and b/tests_zemu/snapshots/sp-show_address/00005.png differ diff --git a/tests_zemu/snapshots/sp-show_address/00006.png b/tests_zemu/snapshots/sp-show_address/00006.png new file mode 100644 index 0000000..dae3f76 Binary files /dev/null and b/tests_zemu/snapshots/sp-show_address/00006.png differ diff --git a/tests_zemu/snapshots/sp-show_address/00007.png b/tests_zemu/snapshots/sp-show_address/00007.png new file mode 100644 index 0000000..3654452 Binary files /dev/null and b/tests_zemu/snapshots/sp-show_address/00007.png differ diff --git a/tests_zemu/snapshots/sp-show_address/00008.png b/tests_zemu/snapshots/sp-show_address/00008.png new file mode 100644 index 0000000..1e4be69 Binary files /dev/null and b/tests_zemu/snapshots/sp-show_address/00008.png differ diff --git a/tests_zemu/snapshots/sp-show_address/00009.png b/tests_zemu/snapshots/sp-show_address/00009.png new file mode 100644 index 0000000..f0fb480 Binary files /dev/null and b/tests_zemu/snapshots/sp-show_address/00009.png differ diff --git a/tests_zemu/snapshots/x-mainmenu/00000.png b/tests_zemu/snapshots/x-mainmenu/00000.png index 44d5e0f..f0fb480 100644 Binary files a/tests_zemu/snapshots/x-mainmenu/00000.png and b/tests_zemu/snapshots/x-mainmenu/00000.png differ diff --git a/tests_zemu/snapshots/x-mainmenu/00004.png b/tests_zemu/snapshots/x-mainmenu/00004.png index 4764b26..dd39ad8 100644 Binary files a/tests_zemu/snapshots/x-mainmenu/00004.png and b/tests_zemu/snapshots/x-mainmenu/00004.png differ diff --git a/tests_zemu/snapshots/x-mainmenu/00010.png b/tests_zemu/snapshots/x-mainmenu/00010.png index 4764b26..dd39ad8 100644 Binary files a/tests_zemu/snapshots/x-mainmenu/00010.png and b/tests_zemu/snapshots/x-mainmenu/00010.png differ diff --git a/tests_zemu/snapshots/x-mainmenu/00012.png b/tests_zemu/snapshots/x-mainmenu/00012.png index 44d5e0f..f0fb480 100644 Binary files a/tests_zemu/snapshots/x-mainmenu/00012.png and b/tests_zemu/snapshots/x-mainmenu/00012.png differ diff --git a/tests_zemu/snapshots/x-show_address/00000.png b/tests_zemu/snapshots/x-show_address/00000.png new file mode 100644 index 0000000..31051f8 Binary files /dev/null and b/tests_zemu/snapshots/x-show_address/00000.png differ diff --git a/tests_zemu/snapshots/x-show_address/00001.png b/tests_zemu/snapshots/x-show_address/00001.png new file mode 100644 index 0000000..4558367 Binary files /dev/null and b/tests_zemu/snapshots/x-show_address/00001.png differ diff --git a/tests_zemu/snapshots/x-show_address/00002.png b/tests_zemu/snapshots/x-show_address/00002.png new file mode 100644 index 0000000..16f7ab8 Binary files /dev/null and b/tests_zemu/snapshots/x-show_address/00002.png differ diff --git a/tests_zemu/snapshots/x-show_address/00003.png b/tests_zemu/snapshots/x-show_address/00003.png new file mode 100644 index 0000000..668c489 Binary files /dev/null and b/tests_zemu/snapshots/x-show_address/00003.png differ diff --git a/tests_zemu/snapshots/x-show_address/00004.png b/tests_zemu/snapshots/x-show_address/00004.png new file mode 100644 index 0000000..3f24353 Binary files /dev/null and b/tests_zemu/snapshots/x-show_address/00004.png differ diff --git a/tests_zemu/snapshots/x-show_address/00005.png b/tests_zemu/snapshots/x-show_address/00005.png new file mode 100644 index 0000000..b93a32d Binary files /dev/null and b/tests_zemu/snapshots/x-show_address/00005.png differ diff --git a/tests_zemu/snapshots/x-show_address/00006.png b/tests_zemu/snapshots/x-show_address/00006.png new file mode 100644 index 0000000..dae3f76 Binary files /dev/null and b/tests_zemu/snapshots/x-show_address/00006.png differ diff --git a/tests_zemu/snapshots/x-show_address/00007.png b/tests_zemu/snapshots/x-show_address/00007.png new file mode 100644 index 0000000..3654452 Binary files /dev/null and b/tests_zemu/snapshots/x-show_address/00007.png differ diff --git a/tests_zemu/snapshots/x-show_address/00008.png b/tests_zemu/snapshots/x-show_address/00008.png new file mode 100644 index 0000000..1e4be69 Binary files /dev/null and b/tests_zemu/snapshots/x-show_address/00008.png differ diff --git a/tests_zemu/snapshots/x-show_address/00009.png b/tests_zemu/snapshots/x-show_address/00009.png new file mode 100644 index 0000000..f0fb480 Binary files /dev/null and b/tests_zemu/snapshots/x-show_address/00009.png differ 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)