From efd4d59d9f1ef27c482cba90fac7a51ae0ab89ad Mon Sep 17 00:00:00 2001 From: Carlos Medeiros Date: Fri, 15 Mar 2024 14:58:13 +0000 Subject: [PATCH] add jubjub support masp keys generation --- CMakeLists.txt | 59 +++++ app/Makefile | 21 +- app/rust/.cargo/.gitignore | 4 + app/rust/.cargo/config | 12 + app/rust/.gitignore | 1 + app/rust/Cargo.lock | 195 ++++++++++++++++ app/rust/Cargo.toml | 37 +++ app/rust/include/rslib.h | 11 + app/rust/src/constants.rs | 52 +++++ app/rust/src/lib.rs | 170 ++++++++++++++ app/src/blake2s/blake2-impl.h | 160 +++++++++++++ app/src/blake2s/blake2.h | 128 +++++++++++ app/src/blake2s/blake2s-ref.c | 395 ++++++++++++++++++++++++++++++++ app/src/crypto_helper.c | 117 ++++++++++ app/src/crypto_helper.h | 23 ++ app/src/keys_def.h | 67 ++++++ app/src/keys_personalizations.h | 41 ++++ tests/keps.cpp | 139 +++++++++++ 18 files changed, 1627 insertions(+), 5 deletions(-) create mode 100644 app/rust/.cargo/.gitignore create mode 100644 app/rust/.cargo/config create mode 100644 app/rust/.gitignore create mode 100644 app/rust/Cargo.lock create mode 100644 app/rust/Cargo.toml create mode 100644 app/rust/include/rslib.h create mode 100644 app/rust/src/constants.rs create mode 100644 app/rust/src/lib.rs create mode 100644 app/src/blake2s/blake2-impl.h create mode 100644 app/src/blake2s/blake2.h create mode 100644 app/src/blake2s/blake2s-ref.c create mode 100644 app/src/keys_def.h create mode 100644 app/src/keys_personalizations.h create mode 100644 tests/keps.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 638e2e1b..b156a795 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,6 +126,8 @@ file(GLOB_RECURSE LIB_SRC ${CMAKE_CURRENT_SOURCE_DIR}/app/src/leb128.c ${CMAKE_CURRENT_SOURCE_DIR}/app/src/txn_validator.c ${CMAKE_CURRENT_SOURCE_DIR}/app/src/txn_delegation.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}) @@ -136,10 +138,64 @@ target_include_directories(app_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/app/src/lib ${CMAKE_CURRENT_SOURCE_DIR}/app/src/common ${CMAKE_CURRENT_SOURCE_DIR}/deps/picohash/ + ### + ${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 ${CMAKE_CURRENT_SOURCE_DIR}/tests/*.cpp) @@ -152,11 +208,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/app/Makefile b/app/Makefile index a344ded2..6fc58a18 100755 --- a/app/Makefile +++ b/app/Makefile @@ -65,18 +65,29 @@ $(error ICONNAME is not set) endif include $(CURDIR)/../deps/ledger-zxlib/makefiles/Makefile.platform - -DEFINES += HAVE_HASH HAVE_RIPEMD160 HAVE_SHA256 -CFLAGS += -Wvla +# 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" + cd rust && RUSTC_BOOTSTRAP=1 CARGO_HOME="$(CURDIR)/rust/.cargo" cargo build --target $(RUST_TARGET) --release + +# Before linking, we need to be sure rust lib is there +bin/app.elf: rust .PHONY: rust_clean rust_clean: - @echo "No rust code" + cd rust && CARGO_HOME="$(CURDIR)/rust/.cargo" cargo clean clean: rust_clean diff --git a/app/rust/.cargo/.gitignore b/app/rust/.cargo/.gitignore new file mode 100644 index 00000000..bd6ca668 --- /dev/null +++ b/app/rust/.cargo/.gitignore @@ -0,0 +1,4 @@ +registry/ +.package-cache +.package-cache-mutate + diff --git a/app/rust/.cargo/config b/app/rust/.cargo/config new file mode 100644 index 00000000..c2caf751 --- /dev/null +++ b/app/rust/.cargo/config @@ -0,0 +1,12 @@ +[build] + +[target.thumbv6m-none-eabi] +rustflags = [ + "--emit", "asm", + "-C", "relocation-model=ropi", + "-C", "link-arg=-nostartfiles", + "-C", "link-arg=-Tlink.ld", +] +[unstable] +build-std=["core"] +build-std-features=["panic_immediate_abort"] diff --git a/app/rust/.gitignore b/app/rust/.gitignore new file mode 100644 index 00000000..2f7896d1 --- /dev/null +++ b/app/rust/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/app/rust/Cargo.lock b/app/rust/Cargo.lock new file mode 100644 index 00000000..beefd997 --- /dev/null +++ b/app/rust/Cargo.lock @@ -0,0 +1,195 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "binary-ff1" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc06816e140b48224e496b9a8c63db381583782627a718cf945acd03fe2ef57" +dependencies = [ + "cipher", +] + +[[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 = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[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 = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[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 = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[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 = [ + "aes", + "binary-ff1", + "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 = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[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 new file mode 100644 index 00000000..a45c4984 --- /dev/null +++ b/app/rust/Cargo.toml @@ -0,0 +1,37 @@ +[package] +authors = ["Zondax AG "] +name = "rslib" +version = "0.0.1" +edition = "2021" +readme = "README.md" +resolver = "2" + +[lib] +name = "rslib" +crate-type = ["staticlib"] + +[dependencies] +jubjub = { version = "0.10.0", default-features = false } +aes = { version = "0.7", default-features = false } +binary-ff1 = { version = "0.2", default-features = false } + +[target.thumbv6m-none-eabi.dev-dependencies] +panic-halt = "0.2.0" + +[profile.release] +lto = false +codegen-units = 1 +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 new file mode 100644 index 00000000..70a710a9 --- /dev/null +++ b/app/rust/include/rslib.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include "parser_common.h" +#include "keys_def.h" + +/* 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]); +parser_error_t get_default_diversifier_list_start_index(const uint8_t dk[32], uint8_t di[11], uint8_t d_l[44]); +parser_error_t get_pkd(const uint8_t ivk_ptr[32], uint8_t div_hash[32], uint8_t pk_d[32]); diff --git a/app/rust/src/constants.rs b/app/rust/src/constants.rs new file mode 100644 index 00000000..209d73ae --- /dev/null +++ b/app/rust/src/constants.rs @@ -0,0 +1,52 @@ +/******************************************************************************* +* (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([ + 0xec75_293d_8124_8452, + 0x39f5_b033_80af_6020, + 0xf831_c2b1_9fec_6026, + 0x5b38_9522_a9e8_1532, + ]), + Fq::from_raw([ + 0x14b6_2623_a186_b4b1, + 0x2012_d031_f624_fd52, + 0x75de_fecf_f1f4_9ef2, + 0x0cbc_5f9f_1e52_e0ab, + ]), +) +.to_niels(); + +pub const PROOF_GENERATION_KEY_GENERATOR: AffineNielsPoint = AffinePoint::from_raw_unchecked( + Fq::from_raw([ + 0x5f3c_723a_a253_1b66, + 0x1e24_f832_67f1_5abd, + 0x4ba1_f065_e719_fd03, + 0x4caa_eaca_af28_ed4b, + ]), + Fq::from_raw([ + 0xfe6f_96be_c575_bff8, + 0x36b4_9c71_a2af_0708, + 0xc654_dfdd_3600_4de9, + 0x0093_0d67_d690_6365, + ]), +) +.to_niels(); + +pub const DIV_SIZE: usize = 11; +pub const DIV_DEFAULT_LIST_LEN: usize = 4; diff --git a/app/rust/src/lib.rs b/app/rust/src/lib.rs new file mode 100644 index 00000000..42763ee8 --- /dev/null +++ b/app/rust/src/lib.rs @@ -0,0 +1,170 @@ +/******************************************************************************* +* (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. +********************************************************************************/ +#![no_std] +#![no_main] +#![no_builtins] +#![allow(dead_code, unused_imports)] + +use core::panic::PanicInfo; + +use constants::{DIV_DEFAULT_LIST_LEN, DIV_SIZE, SPENDING_KEY_GENERATOR}; +mod constants; +use aes::Aes256; +use aes::cipher::{ + BlockCipher, BlockEncrypt, BlockDecrypt, NewBlockCipher, + generic_array::{GenericArray,typenum::U32}, +}; +use binary_ff1::BinaryFF1; +use jubjub::{AffinePoint, ExtendedPoint, Fr}; + + +fn debug(_msg: &str) {} + +// 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, +} + +#[repr(C)] +pub enum ConstantKey { + SpendingKeyGenerator, + ProofGenerationKeyGenerator, + PublicKeyGenerator, +} + +#[no_mangle] +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 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()); + } + + ParserError::ParserOk +} + +#[inline(never)] +pub fn get_diversifiers( + dk: &[u8; 32], + start_index: &mut [u8; 11], + result: &mut [u8; 44], +) { + // Initialize cipher + let key = GenericArray::from_slice(dk); + let cipher = Aes256::new(&key); + let mut scratch = [0; 12]; + + let mut ff1 = BinaryFF1::new(&cipher, 11, &[], &mut scratch).unwrap(); + + let mut d: [u8; 11]; + let size = 4; + + for c in 0..size { + d = *start_index; + ff1.encrypt(&mut d).unwrap(); + result[c * 11..(c + 1) * 11].copy_from_slice(&d); + for k in 0..11 { + start_index[k] = start_index[k].wrapping_add(1); + if start_index[k] != 0 { + // No overflow + break; + } + } + } +} + +#[no_mangle] +pub extern "C" fn get_default_diversifier_list_start_index( + dk: &[u8; 32], + di: &mut [u8; 11], + d_l: &mut [u8; 44], +) -> ParserError { + let start = &mut *di; + let diversifier = &mut *d_l; + get_diversifiers(dk, start, diversifier); + ParserError::ParserOk +} + +#[no_mangle] +pub extern "C" fn get_pkd( + ivk_ptr: &[u8; 32], + div_hash: & [u8; 32], + pk_d: &mut [u8; 32], +) -> ParserError { + + let extended = ExtendedPoint::from(AffinePoint::from_bytes(*div_hash).unwrap()); + let cofactor = extended.mul_by_cofactor(); + let p = cofactor.to_niels().multiply_bits(ivk_ptr); + *pk_d = AffinePoint::from(p).to_bytes(); + + ParserError::ParserOk +} + +#[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 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); + // } + +} diff --git a/app/src/blake2s/blake2-impl.h b/app/src/blake2s/blake2-impl.h new file mode 100644 index 00000000..c1df82e0 --- /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 00000000..845226ee --- /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 00000000..84fd5cf8 --- /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/crypto_helper.c b/app/src/crypto_helper.c index 115c0ee4..d29b2b6f 100644 --- a/app/src/crypto_helper.c +++ b/app/src/crypto_helper.c @@ -20,6 +20,9 @@ #include "leb128.h" #include "zxmacros.h" +#include "keys_personalizations.h" +#include "rslib.h" + #ifdef LEDGER_SPECIFIC #include "bolos_target.h" #endif @@ -27,10 +30,13 @@ #if defined(TARGET_NANOS) || defined(TARGET_NANOS2) || defined(TARGET_NANOX) || defined(TARGET_STAX) #include "cx.h" #include "cx_sha256.h" + #include "cx_blake2b.h" #else #include "picohash.h" + #include "blake2.h" #define CX_SHA256_SIZE 32 #endif +#include "blake2.h" uint32_t hdPath[HDPATH_LEN_DEFAULT]; @@ -258,3 +264,114 @@ zxerr_t crypto_serializeData(const uint64_t dataSize, uint8_t *buffer, uint16_t (*dataInfoSize)++; return zxerr_ok; } + +// MASP Section +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); + } 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); + scalar_multiplication(tmpExpandedKey, keyType, output); + + return parser_ok; +} + +parser_error_t computeIVK(const ak_t ak, const nk_t nk, ivk_t ivk) { +#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 *)CRH_IVK_PERSONALIZATION, + sizeof(CRH_IVK_PERSONALIZATION))); + ASSERT_CX_OK(cx_blake2b_update(&ctx, ak, KEY_LENGTH)); + ASSERT_CX_OK(cx_blake2b_update(&ctx, nk, KEY_LENGTH)); + cx_blake2b_final(&ctx, ivk); +#else + 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); +#endif + ivk[31] &= 0x07; + + return parser_ok; +} + +parser_error_t computeMasterFromSeed(const uint8_t seed[KEY_LENGTH], uint8_t master_sk[EXTENDED_KEY_LENGTH]) { +#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 *)SAPLING_MASTER_PERSONALIZATION, + sizeof(SAPLING_MASTER_PERSONALIZATION))); + ASSERT_CX_OK(cx_blake2b_update(&ctx, seed, KEY_LENGTH)); + cx_blake2b_final(&ctx, master_sk); +#else + blake2b_state state = {0}; + blake2b_init_with_personalization(&state, BLAKE2B_OUTPUT_LEN, (const uint8_t *)SAPLING_MASTER_PERSONALIZATION, + sizeof(SAPLING_MASTER_PERSONALIZATION)); + blake2b_update(&state, seed, KEY_LENGTH); + blake2b_final(&state, master_sk, EXTENDED_KEY_LENGTH); +#endif + + return parser_ok; +} + +parser_error_t computeDiversifiers(const uint8_t dk[KEY_LENGTH], uint8_t di[11], uint8_t d_l[44]) { + return get_default_diversifier_list_start_index(dk, di, d_l); +} + +parser_error_t computePkd(const uint8_t ivk[KEY_LENGTH], const uint8_t d[DIVERSIFIER_LENGTH], uint8_t pk_d[KEY_LENGTH]) { + uint8_t hash[32] = {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 *)KEY_DIVERSIFICATION_PERSONALIZATION, + sizeof(KEY_DIVERSIFICATION_PERSONALIZATION))); + ASSERT_CX_OK(cx_blake2b_update(&ctx, (uint8_t *)GH_FIRST_BLOCK, sizeof(GH_FIRST_BLOCK))); + ASSERT_CX_OK(cx_blake2b_update(&ctx, d, DIVERSIFIER_LENGTH)); + cx_blake2b_final(&ctx, hash); +#else + blake2b_state state = {0}; + blake2b_init_with_personalization(&state, 32, (const uint8_t *)KEY_DIVERSIFICATION_PERSONALIZATION, + sizeof(KEY_DIVERSIFICATION_PERSONALIZATION)); + blake2b_update(&state, (uint8_t *)GH_FIRST_BLOCK, sizeof(GH_FIRST_BLOCK)); + blake2b_update(&state, d, DIVERSIFIER_LENGTH); + blake2b_final(&state, hash, KEY_LENGTH); +#endif + + return get_pkd(ivk, hash, pk_d); +} diff --git a/app/src/crypto_helper.h b/app/src/crypto_helper.h index 803ab69f..d9580e63 100644 --- a/app/src/crypto_helper.h +++ b/app/src/crypto_helper.h @@ -23,12 +23,26 @@ extern "C" { #include #include "zxerror.h" #include "parser_common.h" +#include "keys_def.h" #define CODE_HASH_SIZE 32 #define TIMESTAMP_SIZE 14 #define CODE_HASH_INFO_SIZE 2 +#define MODIFIER_ASK 0x00 +#define MODIFIER_NSK 0x01 +#define MODIFIER_OVK 0x02 +#define MODIFIER_DK 0x10 + + +#define ASSERT_CX_OK(CALL) \ + do { \ + cx_err_t __cx_err = CALL; \ + if (__cx_err != CX_OK) { \ + return parser_unexpected_error; \ + } \ + } while (0) uint8_t crypto_encodePubkey_ed25519(uint8_t *buffer, uint16_t bufferLen, const uint8_t *pubkey); @@ -40,6 +54,15 @@ zxerr_t crypto_hashDataSection(const section_t *data, uint8_t *output, uint32_t zxerr_t crypto_hashCodeSection(const section_t *section, uint8_t *output, uint32_t outputLen); zxerr_t crypto_hashExtraDataSection(const section_t *section, uint8_t *output, uint32_t outputLen); + +// MASP SECTION +parser_error_t convertKey(const uint8_t spendingKey[KEY_LENGTH], const uint8_t modifier, uint8_t outputKey[KEY_LENGTH], bool reduceWideByte); +parser_error_t generate_key(const uint8_t expandedKey[KEY_LENGTH], constant_key_t keyType, uint8_t output[KEY_LENGTH]); +parser_error_t computeIVK(const ak_t ak, const nk_t nk, ivk_t ivk); +parser_error_t computeMasterFromSeed(const uint8_t seed[KEY_LENGTH], uint8_t master_sk[EXTENDED_KEY_LENGTH]); +parser_error_t computeDiversifiers(const uint8_t dk[KEY_LENGTH], uint8_t di[DIVERSIFIER_LENGTH], uint8_t d_l[44]); +parser_error_t computePkd(const uint8_t ivk[KEY_LENGTH], const uint8_t d[DIVERSIFIER_LENGTH], uint8_t pk_d[KEY_LENGTH]); + #ifdef __cplusplus } #endif diff --git a/app/src/keys_def.h b/app/src/keys_def.h new file mode 100644 index 00000000..0d5cbcbc --- /dev/null +++ b/app/src/keys_def.h @@ -0,0 +1,67 @@ +/******************************************************************************* + * (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 "parser_types.h" + +typedef enum { + SpendingKeyGenerator, + ProofGenerationKeyGenerator, + PublicKeyGenerator, + InvalidKey, +} constant_key_t; + +#define KEY_LENGTH 32 +#define EXTENDED_KEY_LENGTH 64 +#define DIVERSIFIER_LENGTH 11 +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 dk_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; + }; + dk_t dk; + 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 00000000..643a58e9 --- /dev/null +++ b/app/src/keys_personalizations.h @@ -0,0 +1,41 @@ +/******************************************************************************* + * (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 SAPLING_MASTER_PERSONALIZATION[16] = "MASP_IP32Sapling"; +const char EXPANDED_SPEND_BLAKE2_KEY[16] = "MASP__ExpandSeed"; +const char CRH_IVK_PERSONALIZATION[8] = "MASP_ivk"; +const char KEY_DIVERSIFICATION_PERSONALIZATION[8] = "MASP__gd"; +const char GH_FIRST_BLOCK[64] = "096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0"; +#ifdef __cplusplus +} +#endif + + diff --git a/tests/keps.cpp b/tests/keps.cpp new file mode 100644 index 00000000..f76ff6f9 --- /dev/null +++ b/tests/keps.cpp @@ -0,0 +1,139 @@ +/******************************************************************************* + * (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 + +#include +#include + +#include "crypto_helper.h" +#include "gmock/gmock.h" +#include "keys_def.h" +#include "parser_txdef.h" +#include "rslib.h" + +using namespace std; +struct NamadaKeys { + string ask; + string nsk; + string ovk; + string dk; + string ak; + string nk; + string ivk; + string d0; +}; + +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(); +} + +NamadaKeys tv_not_hardened = { + "ac4da2a5e0a5e3ec2dcbd704f1b08d850fe140ea61072ce3f870e270aecd8f05", + "47293fb1e93a8663f9a9125652b6dc3d561789c03b674a4cc738a9249aaf0809", + "cf6bedb6c5494ebab77f58a8573559c5d2683a25224649cb8d4480e8a05458d6", + "abcb9e0a9bb077b434506896de929a7ac37feaa81bec17e03b60d0605ef7bc42", + "f65d7b4ab9715c07c6b78bd822ac39a78481eb36079d06dc8679daabab920055", + "2b41553f32a2b660e1726c313319d35533166ccf52c15ac23cbde3d20d55cb01", + "8c90b787364dd12911b64b1ebf8bfc04bdc55f97ae851eb3962775564242a102", + "993f455b74159e49f9cf33", +}; + +TEST(Keys, AK_NK_IVK_NON_HARDENED) { + + keys_t keys; + // Genereric seed from os_derive_bip32_with_seed_no_throw + uint8_t seed[32] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}; + + // Get master spending key + // master secret key sk = tmp[..32] + // chain = tmp[32..] + uint8_t masterSpendingKey[64] = {0}; + ASSERT_EQ(computeMasterFromSeed(seed, masterSpendingKey), parser_ok); + memcpy(keys.spendingKey, masterSpendingKey, 32); + + // Compute ask, nsk, ovk + ASSERT_EQ(convertKey(keys.spendingKey, MODIFIER_ASK, keys.ask, true), parser_ok); + const string ask_str = toHexString(keys.ask, sizeof(keys.ask)); + EXPECT_EQ(ask_str, tv_not_hardened.ask); + + ASSERT_EQ(convertKey(keys.spendingKey, MODIFIER_NSK, keys.nsk, true), parser_ok); + const string nsk_str = toHexString(keys.nsk, sizeof(keys.nsk)); + EXPECT_EQ(nsk_str, tv_not_hardened.nsk); + + ASSERT_EQ(convertKey(keys.spendingKey, MODIFIER_OVK, keys.ovk, false), parser_ok); + const string ovk_str = toHexString(keys.ovk, sizeof(keys.ovk)); + EXPECT_EQ(ovk_str, tv_not_hardened.ovk); + + // Compute diversifier key - dk + ASSERT_EQ(convertKey(masterSpendingKey, MODIFIER_DK, keys.dk, false), parser_ok); + const string dk_str = toHexString(keys.dk, sizeof(keys.dk)); + EXPECT_EQ(dk_str, tv_not_hardened.dk); + + // NOT Hardened + // compute fvk ak+nk+ovk + // compute ak + generate_key(keys.ask, SpendingKeyGenerator, keys.ak); + const string ak_str = toHexString(keys.ak, sizeof(keys.ak)); + EXPECT_EQ(ak_str, tv_not_hardened.ak); + + // compute nk + uint8_t nk[32] = {0}; + generate_key(keys.nsk, ProofGenerationKeyGenerator, keys.nk); + const string nk_str = toHexString(keys.nk, sizeof(keys.nk)); + EXPECT_EQ(nk_str, tv_not_hardened.nk); + + // compute ivk + computeIVK(keys.ak, keys.nk, keys.ivk); + const string ivk_str = toHexString(keys.ivk, 32); + EXPECT_EQ(ivk_str, tv_not_hardened.ivk); + + // compute diversifier d0 + uint8_t di[11] = {0}; + uint8_t d_index[11] = {0}; + uint8_t diversifier_list[44] = {0}; + computeDiversifiers(keys.dk, d_index, diversifier_list); + uint8_t d0[11] = {0}; + memcpy(d0, diversifier_list, 11); + const string d0_str = toHexString(d0, 11); + EXPECT_EQ(d0_str, tv_not_hardened.d0); + } + +TEST(Keys, ADDRESS_NON_HARDENED) { + + keys_t keys; + + // TEST ADDRESS + uint8_t ivk[32] = { + 0xdf, 0x4a, 0xfb, 0x34, 0x37, 0x3a, 0x88, 0x4f, 0x8d, 0x86, 0x53, 0x5a, 0x2c, 0x45, + 0xd6, 0xd3, 0x21, 0x66, 0x9e, 0xbf, 0xb8, 0x59, 0x99, 0x03, 0xa6, 0x40, 0x7d, 0xd3, + 0x82, 0x09, 0x76, 0x01 + }; + + const uint8_t default_d[11] = { + 0xa1, 0xe0, 0xf5, 0x3c, 0x47, 0x3e, 0xd9, 0x8c, 0x17, 0xb6, 0xd0 + }; + + uint8_t address[32] = {0}; + computePkd(ivk, default_d, address); +}