diff --git a/.circleci/bash_env.sh b/.circleci/bash_env.sh new file mode 100755 index 0000000..b4a04ee --- /dev/null +++ b/.circleci/bash_env.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +bashrc_env_file="~/.bashrc" +emscripten_env_file="/root/emsdk-portable/emsdk_env.sh" + +[ -f "${bashrc_env_file}" ] && source "${bashrc_env_file}" +[ -f "${emscripten_env_file}" ] && source "${emscripten_env_file}" diff --git a/.circleci/build_emscripten.sh b/.circleci/build_emscripten.sh new file mode 100755 index 0000000..659be9d --- /dev/null +++ b/.circleci/build_emscripten.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +emconfigure cmake -DBUILD_WEBASSEMBLY=ON -DCMAKE_BUILD_TYPE=Release +emmake make + +# FIXME: Disable .mem for node.js until this gets fixed: https://github.com/kripken/emscripten/issues/2542 +emcc --bind libjsqrl.so -s DISABLE_EXCEPTION_CATCHING=0 -O3 --memory-init-file 0 -o libjsqrl.js +emcc --bind libjsqrl.so -s DISABLE_EXCEPTION_CATCHING=0 -O3 -s WASM=1 -o web-libjsqrl.js +echo "QRLLIB=Module;" >> web-libjsqrl.js + +# Fix paths of web-libjsqrl.wasm for web clients +sed -i 's/web-libjsqrl\.wasm/\/web-libjsqrl\.wasm/g' web-libjsqrl.js + +# Copy to local dir in case it is run locally, the output is shared +if test -d /tmp/_circleci_local_build_repo; then cp *.js /tmp/_circleci_local_build_repo/tests/js/tmp/; fi +if test -d /tmp/_circleci_local_build_repo; then cp *.wasm /tmp/_circleci_local_build_repo/tests/js/tmp/; fi +if test -d /tmp/_circleci_local_build_repo; then chmod 777 /tmp/_circleci_local_build_repo/tests/js/tmp/*; fi + +cp *.js tests/js/tmp/ +cp *.wasm tests/js/tmp/ + +cp *.js build/ +cp *.wasm build/ diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..a3fea1e --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,125 @@ +version: 2 +jobs: + build: + docker: + - image: zondax/qrl-build-images:xenial-qrllib + steps: + - checkout + - run: git submodule update --init --recursive + - run: cmake -DBUILD_PYTHON=ON -DCMAKE_C_COMPILER=gcc-5 -DCMAKE_CXX_COMPILER=g++-5 + - run: make + - run: export GTEST_COLOR=1 && ctest -VV + + test_python: + docker: + - image: zondax/qrl-build-images:xenial-qrllib + steps: + - checkout + - run: git submodule update --init --recursive + - run: python3 setup.py test + + build_emscripten: + docker: + - image: zondax/qrl-build-images:emscripten + environment: + BASH_ENV: ".circleci/bash_env.sh" + steps: + - checkout + - run: + name: Update submodules + command: git submodule update --init --recursive + + - run: + name: Build webassembly + command: ./.circleci/build_emscripten.sh + + - run: + name: Install latest node/npm + command: ./.circleci/install_node.sh + + - run: + name: run the tests + command: cd tests/js && npm install && npm test + + deploy_pypi: + docker: + - image: qrledger/qrl-docker:xenial + steps: + - checkout + - run: git submodule update --init --recursive + - run: python3 setup.py build sdist + - run: pip install twine + - run: twine upload -u $PYPI_USERNAME -p $PYPI_PASSWORD dist/* + + deploy_npm: + docker: + - image: zondax/qrl-build-images:emscripten + environment: + BASH_ENV: ".circleci/bash_env.sh" + steps: + - checkout + - run: + name: Update submodules + command: git submodule update --init --recursive + + # Building again and avoiding complex workspaces until they are supported in the CLI + - run: + name: Build webassembly + command: ./.circleci/build_emscripten.sh + + - run: + name: Install latest node/npm + command: ./.circleci/install_node.sh + + - run: + name: Authenticate with registry + command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > /root/project/.npmrc + + - run: + name: Update tag + command: npm --no-git-tag-version version $CIRCLE_TAG + + - run: + name: Publish package + command: npm publish + +workflows: + version: 2 + build_all: + jobs: + - build: + filters: + tags: + only: /.*/ + + - test_python: + filters: + tags: + only: /.*/ + + - build_emscripten: + filters: + tags: + only: /.*/ + + - deploy_pypi: + requires: + - build + - test_python + - build_emscripten + filters: + branches: + ignore: /.*/ + tags: + only: /^v[0-9]+(\.[0-9]+)*/ + + - deploy_npm: + requires: + - build + - test_python + - build_emscripten + filters: + branches: + ignore: /.*/ + tags: + only: /^v[0-9]+(\.[0-9]+)*/ diff --git a/.circleci/install_node.sh b/.circleci/install_node.sh new file mode 100755 index 0000000..4b31b58 --- /dev/null +++ b/.circleci/install_node.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.5/install.sh | bash +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm +[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion + +nvm install node +npm install -g npm@latest + +echo "Node Version :" $(node -v) +echo "NPM Version :" $(npm -v) +echo diff --git a/.gitignore b/.gitignore index 402440d..acf1799 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,6 @@ gtest\.pc qrllib_test cmake-build-onlylib/ -build/ \.idea/workspace\.xml \.coverage coverage\.xml @@ -67,3 +66,9 @@ pyqrllib/kyber\.py pyqrllib/kyberPYTHON_wrap\.cxx pyqrllib/qrlPYTHON_wrap\.cxx +.pytest_cache +tests/js/node_modules +tests/js/tmp/*.js +tests/js/tmp/*.wasm + +\.npmrc diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 330132d..0000000 --- a/.travis.yml +++ /dev/null @@ -1,119 +0,0 @@ -sudo: required -dist: trusty -services: docker -language: python -python: 3.5 -cache: - timeout: 600 - -cache: - directories: - - $HOME/Library/Caches/Homebrew - -notifications: - webhooks: - urls: - - secure: "0sb4pr3j+oKITR6A3dfrX7+ZE3kJ73hmDMaHgzM6wuQ+KiXMlGcFWEkWCOPUkF/oYeTRlTct27oXj+RKkOaebF6sZ24SwCyKq/zpoawIjmDNi1IqIyqh90UZ1F0FpV+SZL93ge6L3+W5a+ruCDDrlBStAUUH9s1tuWft2LTxewGCdrOm/ZYtEdPGcQ5qjtXP7ZMikkJ7eYIppFfmM9oAL3eiq9FoVxX1X+S4BdIBG8IrZLmiTkvWe7cTZItzAcMzEco2+TnqjUgJ6lV0Ud0lr7iP5WcW2n34MDirQgA2YfJMPMqRUlb3wZ+o/cUrW/G3Qri4e9U9vidgH1G/cfNiER6YKHNt9izWvF7RImBs7wS+Zcmpq90ADXdCDKlCH9YIicngf8vJ7dSXGn+j1Aoba5yvImPK4eueay7SJFfWR29ClsHQgkhfXBCHaO2yHMTbo5ondCP5TcQVkqeuZvKpEG8IsFYQu9v4O9qzePcKF65SimIxIlvf76J8eHJtn+VguV8Dxa+5ixNNJalLcDlwWdlJm26A729fZ4Pl+JWdpTcn72yzRoCPXYh1L0oZzZDx8fp1W0RuvDW0sVwVhod4O63NtMbW58L9g5LjzeQ7EFlUlEDR8v+x8oCowir7T9NGAnGdO/gvVd3rJODf9olNyqZ53nHHRwFc+wtF8lKqDy4=" - -######################## -######################## -jobs: - include: - ######################## XENIAL - OLD COMPILER (Useful for Raspberry Pi) - - stage: build+test - os: linux - env: - - CMAKE_ARGS='-DBUILD_TESTS=ON' - - TEST='TRUE' - - CC_VER="4.9" - - PLATFORM='xenial' - script: "./travis/build.sh" - - ######################## XENIAL - TESTS - - stage: build+test - os: linux - env: - - CMAKE_ARGS='-DBUILD_TESTS=ON' - - TEST='TRUE' - - CC_VER="5" - - PLATFORM='xenial' - script: "./travis/build.sh" - - ######################## XENIAL - PYQRLLIB - - stage: build+test - os: linux - env: - - CMAKE_ARGS='-DBUILD_PYTHON=ON' - - TEST='TRUE' - - CC_VER="5" - - PLATFORM='xenial' - script: "./travis/build.sh" - - ######################## XENIAL-EMSCRIPTEN - - stage: build+test - os: linux - env: - - PLATFORM='xenial-emscripten' - script: "./travis/build.sh" - -# ######################## OSX + TESTS -# - stage: build+test -# os: osx -# if: branch = master -# env: -# - CMAKE_ARGS='-DBUILD_TESTS=ON' -# - TEST='TRUE' -# script: -# - "./travis/build.sh" -# -# ######################## OSX - PYQRLLIB -# - stage: build+test -# os: osx -# if: branch = master -# env: -# - CMAKE_ARGS='-DBUILD_PYTHON=ON' -# script: -# - "./travis/build.sh" - - ######################## - - stage: publish - if: tag =~ ^v - os: linux - env: - - CC_VER="5" - - PLATFORM='xenial' - - DEPLOY='TRUE' - script: - - sudo pip install -U pip setuptools twine - - "./travis/build.sh" - - deploy: - provider: pypi - skip_cleanup: true - user: jleni - password: - secure: LEHilAb+FXCKVvd1/AEmVlUPyf8sOVYt/rMLZPr3bMEiwgK//lFJWlBPli9+G9ed4HjDpq/YFGpTKsRs9Etl4MWSnEJwYJPL0qBTWRCvEn1Py1kTI68dqRKR6oLpssj2BsLpuZvLt+2kE9PVvLSTGbwUGrnvob2AX2suUZcxnZD2q25TOnbZS2/M2F7SOy/0rVn6jlvGPwhMbdsmiLBStsx4rdiu84e1aryUDELSNTP7GtX61dmZs3et2Tpfz7uHXF++mxuT4hzjRe6mUKbtBekCy5EuAzI8vUTmys/m0llmB++gORSLeM22jfpGyfT7AxlkAxO3vlX3XLIythPIYcAEEjBA2xdt8GRlLWH3XLJJYWVEQgdA21sQLuQEGBepc44oKsdUH5t1Ok7kBYjvtQWJCa1/gv+GowKnU5159iJe6MBL9iJqzaz+tbGqKbQHpCvkPlNmipEBKVUANIx7IoXc/tHruCJtjp/vX4hbbOcT4674UaCcHtWpM3ME6EafC2r/nHNNA7rLoX1CP0RCrbSZJOGzhTZlyY9lB0qAmJe+3NDVSiY+6wO2qDFDN7nSl7BUBppPWHkhCVdXq3647RJB31djCguNfnjJLT7hoKkFTMFrrpkpvYUdPkJUAPqh3VZdl+esfMQnHctqBk0D8B+0lX6IJ9v8I5R/kyBs7/g= - on: - tags: true - all_branches: true - - ######################## - - stage: publish - if: tag =~ ^v - os: linux - env: - - PLATFORM='xenial-emscripten' - script: - - "./travis/build.sh" - - "./travis/patch_npmversion.sh" - - before_deploy: npm version - - deploy: - provider: npm - skip_cleanup: true - email: "info@theqrl.org" - api_key: $NPM_API_KEY - on: - tags: true - all_branches: true diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b9f07c..614c411 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,16 +6,22 @@ project(qrllib) set(CMAKE_CXX_STANDARD 14) -set(CMAKE_VERBOSE_MAKEFILE FALSE) +set(CMAKE_VERBOSE_MAKEFILE TRUE) set(CMAKE_ERROR_DEPRECATED FALSE) set(CMAKE_WARN_DEPRECATED FALSE) option(BUILD_TESTS "Enable tests" ON ) option(BUILD_GO "Enable go wrapper" OFF ) option(BUILD_PYTHON "Enable python wrapper" OFF) -option(BUILD_PYTHON_LOCALDEPLOY "Deploy python locally" OFF) option(BUILD_WEBASSEMBLY "Enable emscripten build" OFF) +if (BUILD_WEBASSEMBLY) + message(WARNING "webassembly enabled. Disabling other modules") + set(BUILD_PYTHON 0) + set(BUILD_GO 0) + set(BUILD_TESTS 0) +endif () + message(STATUS "BUILD_TESTS " ${BUILD_TESTS}) message(STATUS "GOLANG WRAPPER " ${BUILD_GO}) message(STATUS "PYTHON WRAPPER " ${BUILD_PYTHON}) @@ -32,15 +38,17 @@ else() endif() if (BUILD_PYTHON OR BUILD_GO) - set(Python_ADDITIONAL_VERSIONS 3 3.6 3.5) - find_package(PythonLibs REQUIRED) - find_package(PythonInterp REQUIRED) - find_package(SWIG REQUIRED) INCLUDE(${SWIG_USE_FILE}) unset(SWIG_LANG_TYPE) endif () +if (BUILD_PYTHON) + set(Python_ADDITIONAL_VERSIONS 3 3.6 3.5) + find_package(PythonLibs REQUIRED) + find_package(PythonInterp REQUIRED) +endif () + set(REF_KYBER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/deps/kyber/ref/kem.c ${CMAKE_CURRENT_SOURCE_DIR}/deps/kyber/ref/poly.c @@ -248,36 +256,46 @@ if (BUILD_PYTHON) ########################################################################### ## qrllib - set(SWIG_INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src/api/qrl.i) + set(SWIG_INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src/api/pyqrllib.i) set(SWIG_MODULE_NAME pyqrllib) set_source_files_properties(${SWIG_INTERFACE} PROPERTIES - CPLUSPLUS ON - SWIG_FLAGS "-I${PROJECT_SOURCE_DIR}/src") - - # Intentionally use a deprecated version to provide support for the raspberry pi - # Basic pyqrllib - XmssBasic, etc. - swig_add_module(${SWIG_MODULE_NAME} python ${SWIG_INTERFACE}) - set(SWIG_MODULE ${SWIG_MODULE_${SWIG_MODULE_NAME}_REAL_NAME}) + CPLUSPLUS ON + SWIG_FLAGS "-I${PROJECT_SOURCE_DIR}/src") + + if(${CMAKE_VERSION} VERSION_LESS 3.12.0) + # Intentionally use a deprecated version to provide support for the raspberry pi + # Basic pyqrllib - XmssBasic, etc. + swig_add_module(${SWIG_MODULE_NAME} python ${SWIG_INTERFACE}) + set(SWIG_MODULE ${SWIG_MODULE_${SWIG_MODULE_NAME}_REAL_NAME}) + + add_custom_command(TARGET ${SWIG_MODULE} + POST_BUILD + COMMENT "Moving SWIG files to output dir" + COMMAND ${CMAKE_COMMAND} -E + copy_if_different $ + ${PROJECT_SOURCE_DIR}/pyqrllib/$) + + add_custom_command(TARGET ${SWIG_MODULE} + POST_BUILD + COMMENT ${swig_extra_generated_files} + COMMAND ${CMAKE_COMMAND} -E + copy_if_different ${swig_extra_generated_files} + ${PROJECT_SOURCE_DIR}/pyqrllib/pyqrllib.py) + else() + swig_add_library(${SWIG_MODULE_NAME} + LANGUAGE python + OUTPUT_DIR ${PROJECT_SOURCE_DIR}/pyqrllib + OUTFILE_DIR ${PROJECT_SOURCE_DIR}/pyqrllib + SOURCES ${SWIG_INTERFACE} + ) + set(SWIG_MODULE ${SWIG_MODULE_${SWIG_MODULE_NAME}_REAL_NAME}) + endif() set_target_properties(${SWIG_MODULE} PROPERTIES DEBUG_POSTFIX "_d") target_link_libraries(${SWIG_MODULE} ${PYTHON_LIBRARIES} qrllib util PicoSHA2) target_include_directories(${SWIG_MODULE} PRIVATE ${PYTHON_INCLUDE_DIRS}) - add_custom_command(TARGET ${SWIG_MODULE} - POST_BUILD - COMMENT "Moving SWIG files to output dir" - COMMAND ${CMAKE_COMMAND} -E - copy_if_different $ - ${PROJECT_SOURCE_DIR}/pyqrllib/$) - - add_custom_command(TARGET ${SWIG_MODULE} - POST_BUILD - COMMENT ${swig_extra_generated_files} - COMMAND ${CMAKE_COMMAND} -E - copy_if_different ${swig_extra_generated_files} - ${PROJECT_SOURCE_DIR}/pyqrllib/pyqrllib.py) - ########################################################################### ## dilithium set(SWIG_INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src/api/dilithium.i) @@ -287,26 +305,36 @@ if (BUILD_PYTHON) CPLUSPLUS ON SWIG_FLAGS "-I${PROJECT_SOURCE_DIR}/src/dilithium") - swig_add_module(${SWIG_MODULE_NAME} python ${SWIG_INTERFACE}) - set(SWIG_MODULE ${SWIG_MODULE_${SWIG_MODULE_NAME}_REAL_NAME}) - set_target_properties(${SWIG_MODULE} PROPERTIES DEBUG_POSTFIX "_d") + if(${CMAKE_VERSION} VERSION_LESS 3.12.0) + swig_add_module(${SWIG_MODULE_NAME} python ${SWIG_INTERFACE}) + set(SWIG_MODULE ${SWIG_MODULE_${SWIG_MODULE_NAME}_REAL_NAME}) + + add_custom_command(TARGET ${SWIG_MODULE} + POST_BUILD + COMMENT "Moving SWIG files to output dir" + COMMAND ${CMAKE_COMMAND} -E + copy_if_different $ + ${PROJECT_SOURCE_DIR}/pyqrllib/$) + + add_custom_command(TARGET ${SWIG_MODULE} + POST_BUILD + COMMENT ${swig_extra_generated_files} + COMMAND ${CMAKE_COMMAND} -E + copy_if_different ${swig_extra_generated_files} ${PROJECT_SOURCE_DIR}/pyqrllib/dilithium.py) + else() + swig_add_library(${SWIG_MODULE_NAME} + LANGUAGE python + OUTPUT_DIR ${PROJECT_SOURCE_DIR}/pyqrllib + OUTFILE_DIR ${PROJECT_SOURCE_DIR}/pyqrllib + SOURCES ${SWIG_INTERFACE} + ) + set(SWIG_MODULE ${SWIG_MODULE_${SWIG_MODULE_NAME}_REAL_NAME}) + endif() + set_target_properties(${SWIG_MODULE} PROPERTIES DEBUG_POSTFIX "_d") target_link_libraries(${SWIG_MODULE} ${PYTHON_LIBRARIES} dilithium_ref dilithium) target_include_directories(${SWIG_MODULE} PRIVATE ${PYTHON_INCLUDE_DIRS}) - add_custom_command(TARGET ${SWIG_MODULE} - POST_BUILD - COMMENT "Moving SWIG files to output dir" - COMMAND ${CMAKE_COMMAND} -E - copy_if_different $ - ${PROJECT_SOURCE_DIR}/pyqrllib/$) - - add_custom_command(TARGET ${SWIG_MODULE} - POST_BUILD - COMMENT ${swig_extra_generated_files} - COMMAND ${CMAKE_COMMAND} -E - copy_if_different ${swig_extra_generated_files} ${PROJECT_SOURCE_DIR}/pyqrllib/dilithium.py) - ########################################################################### ## kyber set(SWIG_INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src/api/kyber.i) @@ -316,25 +344,35 @@ if (BUILD_PYTHON) CPLUSPLUS ON SWIG_FLAGS "-I${PROJECT_SOURCE_DIR}/src/kyber") - swig_add_module(${SWIG_MODULE_NAME} python ${SWIG_INTERFACE}) - set(SWIG_MODULE ${SWIG_MODULE_${SWIG_MODULE_NAME}_REAL_NAME}) - set_target_properties(${SWIG_MODULE} PROPERTIES DEBUG_POSTFIX "_d") + if(${CMAKE_VERSION} VERSION_LESS 3.12.0) + swig_add_module(${SWIG_MODULE_NAME} python ${SWIG_INTERFACE}) + set(SWIG_MODULE ${SWIG_MODULE_${SWIG_MODULE_NAME}_REAL_NAME}) + + add_custom_command(TARGET ${SWIG_MODULE} + POST_BUILD + COMMENT "Moving SWIG files to output dir" + COMMAND ${CMAKE_COMMAND} -E + copy_if_different $ + ${PROJECT_SOURCE_DIR}/pyqrllib/$) + + add_custom_command(TARGET ${SWIG_MODULE} + POST_BUILD + COMMENT ${swig_extra_generated_files} + COMMAND ${CMAKE_COMMAND} -E + copy_if_different ${swig_extra_generated_files} ${PROJECT_SOURCE_DIR}/pyqrllib/kyber.py) + else() + swig_add_library(${SWIG_MODULE_NAME} + LANGUAGE python + OUTPUT_DIR ${PROJECT_SOURCE_DIR}/pyqrllib + OUTFILE_DIR ${PROJECT_SOURCE_DIR}/pyqrllib + SOURCES ${SWIG_INTERFACE} + ) + set(SWIG_MODULE ${SWIG_MODULE_${SWIG_MODULE_NAME}_REAL_NAME}) + endif() + set_target_properties(${SWIG_MODULE} PROPERTIES DEBUG_POSTFIX "_d") target_link_libraries(${SWIG_MODULE} ${PYTHON_LIBRARIES} kyber_ref kyber) target_include_directories(${SWIG_MODULE} PRIVATE ${PYTHON_INCLUDE_DIRS}) - - add_custom_command(TARGET ${SWIG_MODULE} - POST_BUILD - COMMENT "Moving SWIG files to output dir" - COMMAND ${CMAKE_COMMAND} -E - copy_if_different $ - ${PROJECT_SOURCE_DIR}/pyqrllib/$) - - add_custom_command(TARGET ${SWIG_MODULE} - POST_BUILD - COMMENT ${swig_extra_generated_files} - COMMAND ${CMAKE_COMMAND} -E - copy_if_different ${swig_extra_generated_files} ${PROJECT_SOURCE_DIR}/pyqrllib/kyber.py) endif () if (BUILD_WEBASSEMBLY) @@ -342,7 +380,8 @@ if (BUILD_WEBASSEMBLY) set(JS_DILITHIUM_INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src/jswrapper/jsdilwrapper.cpp) set(JS_KYBINTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src/jswrapper/jskybwrapper.cpp) - message(STATUS "webassembly enabled") + message(WARNING "webassembly enabled") + add_library(jsqrl SHARED ${JS_QRL_INTERFACE} ${LIB_QRL_SRC} @@ -350,6 +389,7 @@ if (BUILD_WEBASSEMBLY) ${LIBXMSSALT_SRC} ${LIBUTIL_SRC} ) + set_target_properties(jsqrl PROPERTIES COMPILE_FLAGS "--emscripten-cxx") target_include_directories(jsqrl PRIVATE $ @@ -359,11 +399,10 @@ if (BUILD_WEBASSEMBLY) $ ) - add_library(jsdilithium SHARED - ${JS_DILITHIUM_INTERFACE} - ${LIB_KYBER_SRC} - ${LIBDILITHIUM_SRC} + set_target_properties(jsqrl + PROPERTIES LINK_FLAGS "-s DISABLE_EXCEPTION_CATCHING=0" ) + target_include_directories(jsdilithium PRIVATE $ $ diff --git a/README.md b/README.md index bc3741b..071f07a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ [![PyPI version](https://badge.fury.io/py/pyqrllib.svg)](https://badge.fury.io/py/pyqrllib) [![npm version](https://badge.fury.io/js/qrllib.svg)](https://badge.fury.io/js/qrllib) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/4b34f51616d94362b3447bb2f4df765a)](https://www.codacy.com/app/jleni/qrllib_QRL?utm_source=github.com&utm_medium=referral&utm_content=theQRL/qrllib&utm_campaign=badger) [![Build Status](https://travis-ci.org/theQRL/qrllib.svg?branch=master)](https://travis-ci.org/theQRL/qrllib) -[![Build status](https://ci.appveyor.com/api/projects/status/mrpo1u5cw2f5d0eb?svg=true)](https://ci.appveyor.com/project/jleni/qrllib-oy5qa) +[![CircleCI](https://circleci.com/gh/theQRL/qrllib.svg?style=svg)](https://circleci.com/gh/theQRL/qrllib) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/4b34f51616d94362b3447bb2f4df765a)](https://www.codacy.com/app/jleni/qrllib_QRL?utm_source=github.com&utm_medium=referral&utm_content=theQRL/qrllib&utm_campaign=badger) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/theQRL/qrllib/master/LICENSE) # QRL Core Library @@ -18,7 +18,7 @@ This library currently exposes the following functionality: **Platform support** -| | Linux | OSX
10.12 | Windows
10 | Raspbian
? | +| | Linux | OSX
10.12 | Windows
10 | Raspbian
? | |-----------|:------------:|:-----------:|:--------:|:--------:| |Python 3 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | |Webassembly (JS) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | @@ -75,7 +75,7 @@ Prerequisites: - Install [Build Tools for Visual Studio](https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2017) selecting the *'Visual C++ build tools'* option, or install [Visual Studio Community Edition](https://www.visualstudio.com/vs/community/) selecting the *'Desktop Development for C++ workload'*. - Install [Git for Windows](https://gitforwindows.org/) keeping the default option to use git from the command prompt. - Install the latest stable [CMake x64 for Windows](https://cmake.org/download/), selecting to add CMake to system or user PATH. -- Install [Python 3 Windows x86-64](https://www.python.org/downloads/) selecting the option to '*Add Python 3.x to PATH*'. Optionally change the install location to ```c:\python36```, install the debugging symbols/binaries, and disable the path length limit. +- Install [Python 3 Windows x86-64](https://www.python.org/downloads/) selecting the option to '*Add Python 3.x to PATH*'. Optionally change the install location to ```c:\python37```, install the debugging symbols/binaries, and disable the path length limit. - Download [SWIG](http://swig.org/) *(download swigwin)* and extract archive to ```c:\opt``` - Download [Ninja Build](https://github.com/ninja-build/ninja/releases) and extract ```ninja.exe``` to ```c:\opt\bin``` @@ -96,6 +96,24 @@ python setup.py test python setup.py install ``` +## Development + +#### Emscripten + +In order to compile the webassembly and run node.js tests you first need to install CircleCI CLI: + +https://circleci.com/docs/2.0/local-cli/#installing-the-circleci-local-cli-on-macos-and-linux-distros + +Then run the following command + +``` +circleci build --job build_emscripten +``` + +This will compile and test the webassembly. Output files will be copied over to `tests/js/tmp` + +You can then run node.js locally using npm. + ## License *This library is distributed under the MIT software license, see the accompanying file LICENSE or http://www.opensource.org/licenses/mit-license.php.* diff --git a/goqrlfast/.gitkeep b/build/.gitkeep similarity index 100% rename from goqrlfast/.gitkeep rename to build/.gitkeep diff --git a/build_webassembly.sh b/build_webassembly.sh deleted file mode 100755 index dbd1be7..0000000 --- a/build_webassembly.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -mkdir -p ./build/js -cd ./build/js -echo "Running CMAKE..." -emconfigure cmake -DBUILD_WEBASSEMBLY=ON -DBUILD_PYTHON=OFF -DCMAKE_BUILD_TYPE=Release ../.. - -echo "Building..." -emmake make - -echo "Emscripten Binding/Optimizing..." -emcc --bind libjsqrl.so -O3 -o libjsqrl.js -emcc --bind libjsqrl.so -O3 -s WASM=1 -o web-libjsqrl.js -echo "QRLLIB=Module;" >> web-libjsqrl.js - -echo "Running test" -cp ../../tests/js/test.js . -node test.js diff --git a/package.json b/package.json index 38edd9d..3a088d7 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "__QRLLIB_VERSION__", "description": "QRL Core Library", "scripts": { - "test": "cd build && node test.js" + "test": "cd tests/js && node test.js" }, "repository": { "type": "git", diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..7dfa5e8 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,7 @@ +# content of pytest.ini +[pytest] +addopts = --doctest-modules -sv +testpaths = tests src/qrl +norecursedirs = qrl/generated +flake8-max-line-length = 160 +flake8-ignore = N801 N802 N803 N805 N806 diff --git a/setup.cfg b/setup.cfg index 9e0179c..c5f2c96 100644 --- a/setup.cfg +++ b/setup.cfg @@ -37,6 +37,9 @@ addopts = --cov pyqrllib --cov-report term-missing --cov-report xml --verbose +flake8-max-line-length = 160 +flake8-ignore = N801 N802 N803 N805 N806 + [bdist_wheel] # Use this option if your package is pure-python universal = 0 diff --git a/setup.py b/setup.py index 0edacc1..8ee4761 100644 --- a/setup.py +++ b/setup.py @@ -57,7 +57,7 @@ def setup_package(): cmake = [] # noinspection PyInterpreter - setup(setup_requires=['six', 'pytest-runner', 'pyscaffold>=2.5a0,<2.6a0'] + sphinx + cmake, + setup(setup_requires=['six', 'pytest-runner', 'pyscaffold>3'] + sphinx + cmake, packages=['pyqrllib', ], tests_require=['pytest', 'pytest-cov'], ext_modules=[CMakeExtension('pyqrllib')], diff --git a/src/api/dilithium.i b/src/api/dilithium.i index a3f77e1..5d5f11f 100644 --- a/src/api/dilithium.i +++ b/src/api/dilithium.i @@ -11,6 +11,37 @@ %include "std_shared_ptr.i" %include "exception.i" +%{ +SWIGEXPORT void HandleAllExceptions() +{ + try + { + throw; + } + catch(const std::invalid_argument& e) + { + SWIG_Error(SWIG_ValueError, e.what()); + } + catch(const std::exception& e) + { + SWIG_Error(SWIG_RuntimeError, e.what()); + } + catch (...) + { + SWIG_Error(SWIG_UnknownError, "unknown error"); + } +} +%} + +%exception { + try { $action } + catch (...) { + HandleAllExceptions(); + SWIG_fail; + } +} + + %array_class(unsigned char, ucharCArray) %array_class(unsigned int, uintCArray) %array_class(uint32_t, uint32CArray) diff --git a/src/api/kyber.i b/src/api/kyber.i index 5a55fec..a7748ef 100644 --- a/src/api/kyber.i +++ b/src/api/kyber.i @@ -11,6 +11,36 @@ %include "std_shared_ptr.i" %include "exception.i" +%{ +SWIGEXPORT void HandleAllExceptions() +{ + try + { + throw; + } + catch(const std::invalid_argument& e) + { + SWIG_Error(SWIG_ValueError, e.what()); + } + catch(const std::exception& e) + { + SWIG_Error(SWIG_RuntimeError, e.what()); + } + catch (...) + { + SWIG_Error(SWIG_UnknownError, "unknown error"); + } +} +%} + +%exception { + try { $action } + catch (...) { + HandleAllExceptions(); + SWIG_fail; + } +} + %array_class(unsigned char, ucharCArray) %array_class(unsigned int, uintCArray) %array_class(uint32_t, uint32CArray) diff --git a/src/api/qrl.i b/src/api/pyqrllib.i similarity index 74% rename from src/api/qrl.i rename to src/api/pyqrllib.i index 55856e5..45033c0 100644 --- a/src/api/qrl.i +++ b/src/api/pyqrllib.i @@ -11,6 +11,36 @@ %include "std_shared_ptr.i" %include "exception.i" +%{ +SWIGEXPORT void HandleAllExceptions() +{ + try + { + throw; + } + catch(const std::invalid_argument& e) + { + SWIG_Error(SWIG_ValueError, e.what()); + } + catch(const std::exception& e) + { + SWIG_Error(SWIG_RuntimeError, e.what()); + } + catch (...) + { + SWIG_Error(SWIG_UnknownError, "unknown error"); + } +} +%} + +%exception { + try { $action } + catch (...) { + HandleAllExceptions(); + SWIG_fail; + } +} + %array_class(unsigned char, ucharCArray) %array_class(unsigned int, uintCArray) %array_class(uint32_t, uint32CArray) diff --git a/src/jswrapper/jsqrlwrapper.cpp b/src/jswrapper/jsqrlwrapper.cpp index 697836a..a155a55 100644 --- a/src/jswrapper/jsqrlwrapper.cpp +++ b/src/jswrapper/jsqrlwrapper.cpp @@ -10,162 +10,304 @@ namespace { - class XmssWrapper +class XmssWrapper { + explicit XmssWrapper( + const std::vector& seed, + uint8_t height, + eHashFunction hashFunction) + :_xmss(seed, height, hashFunction) { } +public: + unsigned int getIndex() { - public: - explicit XmssWrapper(const std::vector &seed, unsigned char height) : _xmss(seed, height) {} + return _xmss.getIndex(); + } - TSIGNATURE sign(const TMESSAGE &message) { return _xmss.sign(message); } + int getHeight() + { + return _xmss.getHeight(); + } - TKEY getSK() { return _xmss.getSK(); } - TKEY getPK() { return _xmss.getPK(); } - TSEED getSeed() { return _xmss.getSeed(); } - TSEED getExtendedSeed() { return _xmss.getExtendedSeed(); } - int getHeight() { return _xmss.getHeight(); } + TKEY getPKRaw() + { + return _xmss.getPK(); + } - TKEY getRoot() { return _xmss.getRoot(); } - TKEY getPKSeed() { return _xmss.getPKSeed(); } - TKEY getSKSeed() { return _xmss.getSKSeed(); } - TKEY getSKPRF() { return _xmss.getSKPRF(); } + std::string getPK() + { + return bin2hstr( _xmss.getPK() ); + } - std::vector getAddress() { return _xmss.getAddress(); } + std::vector getAddressRaw() + { + return _xmss.getAddress(); + } - unsigned int getIndex() { return _xmss.getIndex(); } - unsigned int setIndex(unsigned int new_index) { return _xmss.setIndex(new_index); } + std::string getAddress() + { + return 'Q' + bin2hstr(_xmss.getAddress()); + } + + std::string getHexSeed() + { + auto extended_seed = _xmss.getExtendedSeed(); + return bin2hstr(extended_seed); + } - static bool verify(const TMESSAGE &message, - const TSIGNATURE &signature, - const TKEY &pk) - { - return XmssFast::verify(message, signature, pk); - } + std::string getMnemonic() + { + auto extended_seed = _xmss.getExtendedSeed(); + return bin2mnemonic(extended_seed); + } - private: - XmssFast _xmss; - }; + ///////////////////////////////////// + ///////////////////////////////////// - std::string EMSCRIPTEN_KEEPALIVE _bin2hstr(const std::vector &input) { - return bin2hstr(input, 0); + static XmssWrapper fromParameters( + const std::vector& random_bytes, + uint8_t height, + eHashFunction hash_function) + { + return XmssWrapper(random_bytes, height, hash_function); } - std::vector EMSCRIPTEN_KEEPALIVE _hstr2bin(const std::string &input) { - return hstr2bin(input); + static XmssWrapper fromHexSeed(const std::string hexseed) + { + auto extended_seed = hstr2bin(hexseed); + auto descr = QRLDescriptor::fromExtendedSeed(extended_seed); + + auto raw_seed = std::vector( + extended_seed.cbegin()+QRLDescriptor::getSize(), + extended_seed.cend() + ); + + return XmssWrapper( + raw_seed, + descr.getHeight(), + descr.getHashFunction() + ); } - std::vector EMSCRIPTEN_KEEPALIVE _str2bin(const std::string &str) { - return str2bin(str); + static XmssWrapper fromMnemonic(const std::string mnemonic) + { + auto extended_seed = mnemonic2bin(mnemonic); + auto descr = QRLDescriptor::fromExtendedSeed(extended_seed); + + auto raw_seed = std::vector( + extended_seed.cbegin()+QRLDescriptor::getSize(), + extended_seed.cend() + ); + + return XmssWrapper( + raw_seed, + descr.getHeight(), + descr.getHashFunction() + ); } - std::vector EMSCRIPTEN_KEEPALIVE _mnemonic2bin(const std::string &mnemonic) + ///////////////////////////////////// + ///////////////////////////////////// + + unsigned int setIndex(unsigned int new_index) { - return mnemonic2bin(mnemonic); + return _xmss.setIndex(new_index); } - std::string EMSCRIPTEN_KEEPALIVE _bin2mnemonic(const std::vector &vec) + TSIGNATURE sign(const TMESSAGE& message) { - return bin2mnemonic(vec); + return _xmss.sign(message); } - std::string EMSCRIPTEN_KEEPALIVE _getHashFunction(const std::vector &address) + static bool verify( + const TMESSAGE& message, + const TSIGNATURE& signature, + const TKEY& pk) { - if (address.size()& input) +{ + return bin2hstr(input, 0); +} - return "Not recognized"; - } +std::vector EMSCRIPTEN_KEEPALIVE +_hstr2bin(const std::string& input) +{ + return hstr2bin(input); +} - std::string EMSCRIPTEN_KEEPALIVE _getSignatureType(const std::vector &address) - { - if (address.size() EMSCRIPTEN_KEEPALIVE +_str2bin(const std::string& str) +{ + return str2bin(str); +} - auto descr = QRLDescriptor::fromBytes(address[0], address[1], address[2]); +std::vector EMSCRIPTEN_KEEPALIVE +_mnemonic2bin(const std::string& mnemonic) +{ + return mnemonic2bin(mnemonic); +} - switch(descr.getSignatureType()) - { - case eSignatureType::XMSS: - return "XMSS"; - } +std::string EMSCRIPTEN_KEEPALIVE +_bin2mnemonic(const std::vector& vec) +{ + return bin2mnemonic(vec); +} - return "Not recognized"; +std::vector getBinAddress(std::string address_str) +{ + if (address_str.size()<1+2*QRLDescriptor::getSize()) + { + throw std::invalid_argument("Invalid address"); } - uint8_t EMSCRIPTEN_KEEPALIVE _getHeight(const std::vector &address) - { - if (address.size() &address) - { - return QRLHelper::addressIsValid(address); + auto descr = QRLDescriptor::fromBytes( + std::vector( + address.cbegin(), + address.cbegin()+QRLDescriptor::getSize())); + + return descr.getHashFunction(); +} + +eSignatureType EMSCRIPTEN_KEEPALIVE +_getSignatureType(std::string address_str) +{ + auto address = getBinAddress(address_str); + + if (address.size() EMSCRIPTEN_KEEPALIVE _sha2_256(const std::vector &data) + auto descr = QRLDescriptor::fromBytes( + std::vector( + address.cbegin(), + address.cbegin()+QRLDescriptor::getSize())); + + return descr.getSignatureType(); +} + +uint8_t EMSCRIPTEN_KEEPALIVE +_getHeight(std::string address_str) +{ + auto address = getBinAddress(address_str); + + auto descr = QRLDescriptor::fromBytes( + std::vector( + address.cbegin(), + address.cbegin()+QRLDescriptor::getSize())); + + return descr.getHeight(); +} + +std::vector EMSCRIPTEN_KEEPALIVE +_getAddressRaw(const std::vector& epk) +{ + return QRLHelper::getAddress(epk); +} + +std::string EMSCRIPTEN_KEEPALIVE +_getAddress(std::string epk_str) +{ + if (epk_str.size()!=2*67) { - return sha2_256(data); + throw std::invalid_argument("Invalid epk"); } - using namespace emscripten; + auto epk = hstr2bin(epk_str); + return _bin2hstr(_getAddressRaw(epk)); +} + +bool EMSCRIPTEN_KEEPALIVE +_validateAddressRaw(const std::vector& address) +{ + return QRLHelper::addressIsValid(address); +} + +bool EMSCRIPTEN_KEEPALIVE +_validateAddress(std::string address_str) +{ + auto address = getBinAddress(address_str); + return _validateAddressRaw(address); +} - EMSCRIPTEN_BINDINGS(my_module) { - register_vector("VectorUChar"); +std::vector EMSCRIPTEN_KEEPALIVE +_sha2_256(const std::vector& data) +{ + return sha2_256(data); +} + +using namespace emscripten; + +EMSCRIPTEN_BINDINGS(my_module) { + register_vector("Uint8Vector"); + + // HASH FUNCTIONS + function("sha2_256", &_sha2_256); + + // UTILITIES function("bin2hstr", &_bin2hstr); function("hstr2bin", &_hstr2bin); function("str2bin", &_str2bin); - function("mnemonic2bin", &_mnemonic2bin); function("bin2mnemonic", &_bin2mnemonic); + function("getAddress", &_getAddress); + function("getAddressRaw", &_getAddressRaw); + function("validateAddress", &_validateAddress); + function("validateAddressRaw", &_validateAddressRaw); + // DESCRIPTOR function("getHashFunction", &_getHashFunction); function("getSignatureType", &_getSignatureType); function("getHeight", &_getHeight); - function("validateAddress", &_validateAddress); - function("sha2_256", &_sha2_256); + enum_("eHashFunction") + .value("SHA2_256", eHashFunction::SHA2_256) + .value("SHAKE_128", eHashFunction::SHAKE_128) + .value("SHAKE_256", eHashFunction::SHAKE_256) + ; + + enum_("eSignatureType") + .value("XMSS", eSignatureType::XMSS) + ; + // XMSS class_("Xmss") - .constructor() - .function("getPK", &XmssWrapper::getPK) - .function("getSK", &XmssWrapper::getSK) - .function("getSeed", &XmssWrapper::getSeed) - .function("getExtendedSeed", &XmssWrapper::getExtendedSeed) - .function("getHeight", &XmssWrapper::getHeight) + .class_function("fromParameters", &XmssWrapper::fromParameters) + .class_function("fromHexSeed", &XmssWrapper::fromHexSeed) + .class_function("fromMnemonic", &XmssWrapper::fromMnemonic) - .function("getRoot", &XmssWrapper::getRoot) - .function("getPKSeed", &XmssWrapper::getPKSeed) - .function("getSKSeed", &XmssWrapper::getSKSeed) - .function("getSKPRF", &XmssWrapper::getSKPRF) + .function("getIndex", &XmssWrapper::getIndex) + .function("getHeight", &XmssWrapper::getHeight) - .function("getAddress", &XmssWrapper::getAddress) + .function("getPKRaw", &XmssWrapper::getPKRaw) + .function("getPK", &XmssWrapper::getPK) - .function("getIndex", &XmssWrapper::getIndex) - .function("setIndex", &XmssWrapper::setIndex) + .function("getAddressRaw", &XmssWrapper::getAddressRaw) + .function("getAddress", &XmssWrapper::getAddress) - .function("sign", &XmssWrapper::sign) - .class_function("verify", &XmssWrapper::verify) - ; - } + .function("getHexSeed", &XmssWrapper::getHexSeed) + .function("getMnemonic", &XmssWrapper::getMnemonic) + + .function("setIndex", &XmssWrapper::setIndex) + .function("sign", &XmssWrapper::sign) + .class_function("verify", &XmssWrapper::verify); +} } diff --git a/src/qrl/misc.cpp b/src/qrl/misc.cpp index 50c6b35..e51f65c 100644 --- a/src/qrl/misc.cpp +++ b/src/qrl/misc.cpp @@ -47,7 +47,7 @@ unsigned char getHexValue(char c) { return (unsigned char) (tmp - 'a' + 10); } -std::vector hstr2bin(const std::string &s) throw(std::invalid_argument) { +std::vector hstr2bin(const std::string &s) { if (s.size() % 2 != 0) { throw std::invalid_argument("hex string is expected to have an even number of characters"); } @@ -65,7 +65,12 @@ std::vector hstr2bin(const std::string &s) throw(std::invalid_arg return result; } -std::string bin2mnemonic(const std::vector &vec) { +std::string bin2mnemonic(const std::vector &vec) +{ + if (vec.size() % 3 != 0) { + throw std::invalid_argument("byte count needs to be a multiple of 3"); + } + std::stringstream ss; std::string separator; for (int nibble = 0; nibble < vec.size() * 2; nibble += 3) { @@ -80,7 +85,14 @@ std::string bin2mnemonic(const std::vector &vec) { return ss.str(); } -std::vector mnemonic2bin(const std::string &mnemonic) { +std::vector mnemonic2bin(const std::string &mnemonic) +{ + auto word_count = std::count(mnemonic.cbegin(), mnemonic.cend(), ' ') + 1; + if (word_count%2!=0) + { + throw std::invalid_argument("word count = " + std::to_string(word_count) + " must be even "); + } + // Prepare lookup // FIXME: Create the look up in advance std::unordered_map word_lookup; diff --git a/src/qrl/misc.h b/src/qrl/misc.h index 0d6951c..5bda60d 100644 --- a/src/qrl/misc.h +++ b/src/qrl/misc.h @@ -4,8 +4,8 @@ #ifndef QRLLIB_MISC_H #define QRLLIB_MISC_H -#include -#include +#include +#include #include #define ADDRESS_HASH_SIZE 32 @@ -14,7 +14,7 @@ std::string bin2hstr(const std::vector &vec, uint32_t wrap = 0); std::string bin2hstr(const std::string &vec, uint32_t wrap = 0); std::vector str2bin(const std::string &s); -std::vector hstr2bin(const std::string &s) throw(std::invalid_argument); +std::vector hstr2bin(const std::string &s); std::string bin2mnemonic(const std::vector &vec); std::vector mnemonic2bin(const std::string &mnemonic); diff --git a/src/qrl/qrlDescriptor.h b/src/qrl/qrlDescriptor.h index 0cf8a85..626a8e5 100644 --- a/src/qrl/qrlDescriptor.h +++ b/src/qrl/qrlDescriptor.h @@ -5,23 +5,26 @@ #include #include +#include + #include "xmss-alt/eHashFunctions.h" #include "qrlAddressFormat.h" enum eSignatureType { - XMSS = 0, + XMSS = 0, }; class QRLDescriptor { public: QRLDescriptor(eHashFunction hashFunction, - eSignatureType signatureType, - uint8_t height, - eAddrFormatType addrFormatType) : + eSignatureType signatureType, + uint8_t height, + eAddrFormatType addrFormatType) + : _hashFunction(hashFunction), _signatureType(signatureType), _height(height), - _addrFormatType(addrFormatType) {} + _addrFormatType(addrFormatType) { } eHashFunction getHashFunction() { return _hashFunction; } @@ -31,11 +34,40 @@ class QRLDescriptor { eAddrFormatType getAddrFormatType() { return _addrFormatType; } - static QRLDescriptor fromBytes(uint8_t byte0, uint8_t byte1, uint8_t byte2) { - auto hashFunction = static_cast(byte0 & 0x0F); - auto signatureType = static_cast( (byte0 >> 4) & 0xF0); - auto height = static_cast( (byte1 & 0x0F) << 1 ); - auto addrFormatType = static_cast( (byte1 & 0xF0) >> 4 ); + static QRLDescriptor fromExtendedSeed(std::vector extended_seed) + { + if (extended_seed.size()!=51) { + throw std::invalid_argument("Extended seed should be 51 bytes"); + } + + return QRLDescriptor::fromBytes( + std::vector( + extended_seed.cbegin(), + extended_seed.cbegin()+QRLDescriptor::getSize())); + } + + static QRLDescriptor fromExtendedPK(const std::vector& extended_pk) + { + if (extended_pk.size()!=67) { + throw std::invalid_argument("Invalid extended_pk size. It should be 67 bytes"); + } + + return QRLDescriptor::fromBytes( + std::vector( + extended_pk.cbegin(), + extended_pk.cbegin()+QRLDescriptor::getSize())); + } + + static QRLDescriptor fromBytes(std::vector bytes) + { + if (bytes.size()!=3) { + throw std::invalid_argument("Descriptor size should be 3 bytes"); + } + + auto hashFunction = static_cast(bytes[0] & 0x0F); + auto signatureType = static_cast((bytes[0] >> 4) & 0xF0); + auto height = static_cast((bytes[1] & 0x0F) << 1 ); + auto addrFormatType = static_cast((bytes[1] & 0xF0) >> 4 ); return {hashFunction, signatureType, height, addrFormatType}; } @@ -45,7 +77,8 @@ class QRLDescriptor { return 3; } - std::vector getBytes() { + std::vector getBytes() + { // descriptor // 0.. 3 hash function [ SHA2-256, SHA3, .. ] // 4.. 7 signature scheme [ XMSS, XMSS^MT, .. ] @@ -54,8 +87,8 @@ class QRLDescriptor { // 16..23 params3: reserved std::vector descr{ - static_cast( (_signatureType << 4) | (_hashFunction & 0x0F)), - static_cast( (_addrFormatType << 4) | ((_height >> 1) & 0x0F)), + static_cast((_signatureType << 4) | (_hashFunction & 0x0F)), + static_cast((_addrFormatType << 4) | ((_height >> 1) & 0x0F)), 0 }; @@ -69,5 +102,4 @@ class QRLDescriptor { eAddrFormatType _addrFormatType; }; - #endif diff --git a/src/qrl/qrlHelper.h b/src/qrl/qrlHelper.h index bb92408..7158caf 100644 --- a/src/qrl/qrlHelper.h +++ b/src/qrl/qrlHelper.h @@ -12,13 +12,13 @@ class QRLHelper { public: - QRLHelper()= default; + QRLHelper() = default; - static std::vector getAddress(const std::vector&pk) throw(std::invalid_argument) + static std::vector getAddress(const std::vector& extended_pk) { - auto descr = QRLHelper::extractDescriptor(pk); - if (descr.getAddrFormatType()!=eAddrFormatType::SHA256_2X) - { + auto descr = QRLDescriptor::fromExtendedPK(extended_pk); + + if (descr.getAddrFormatType()!=eAddrFormatType::SHA256_2X) { throw std::invalid_argument("Address format type not supported"); } @@ -26,52 +26,45 @@ class QRLHelper { auto address = descrBytes; std::vector hashed_key(ADDRESS_HASH_SIZE, 0); - picosha2::hash256(pk.begin(), pk.end(), hashed_key.begin(), hashed_key.end()); + picosha2::hash256(extended_pk.begin(), extended_pk.end(), hashed_key.begin(), hashed_key.end()); address.insert(address.end(), hashed_key.cbegin(), hashed_key.cend()); std::vector hashed_key2(ADDRESS_HASH_SIZE, 0); picosha2::hash256(address.begin(), address.end(), hashed_key2.begin(), hashed_key2.end()); - address.insert(address.end(), hashed_key2.cend() - 4, hashed_key2.cend()); + address.insert(address.end(), hashed_key2.cend()-4, hashed_key2.cend()); return address; } - static bool addressIsValid(const std::vector&address) + static bool addressIsValid(const std::vector& address) { - try - { - auto descr = QRLHelper::extractDescriptor(address); - if (descr.getAddrFormatType()!=eAddrFormatType::SHA256_2X) - { - throw std::invalid_argument("Address format type not supported"); - } + try { + if (address.size()!=(QRLDescriptor::getSize()+ADDRESS_HASH_SIZE+4)) + return false; - if (address.size()!=(QRLDescriptor::getSize() +ADDRESS_HASH_SIZE+4)) + auto descr = QRLDescriptor::fromBytes( + std::vector( + address.cbegin(), + address.cbegin()+QRLDescriptor::getSize())); + + if (descr.getAddrFormatType()!=eAddrFormatType::SHA256_2X) { return false; + } std::vector hashed_key2(ADDRESS_HASH_SIZE, 0); + picosha2::hash256(address.cbegin(), address.cbegin()+QRLDescriptor::getSize()+ADDRESS_HASH_SIZE, - hashed_key2.begin(), hashed_key2.end()); + hashed_key2.begin(), hashed_key2.end()); - return address[35] == hashed_key2[28] && - address[36] == hashed_key2[29] && - address[37] == hashed_key2[30] && - address[38] == hashed_key2[31]; + return address[35]==hashed_key2[28] && + address[36]==hashed_key2[29] && + address[37]==hashed_key2[30] && + address[38]==hashed_key2[31]; } - catch(...) - { + catch (...) { return false; } } - - static QRLDescriptor extractDescriptor(const std::vector&pk) throw(std::invalid_argument) - { - if (pk.size()<2) { - throw std::invalid_argument("invalid pk size"); - } - return QRLDescriptor::fromBytes(pk[0], pk[1], pk[2]); - } }; - #endif diff --git a/src/qrl/xmssBase.cpp b/src/qrl/xmssBase.cpp index 751f3a5..7d9dac7 100644 --- a/src/qrl/xmssBase.cpp +++ b/src/qrl/xmssBase.cpp @@ -4,36 +4,63 @@ #include #include "qrlHelper.h" -XmssBase::XmssBase(const TSEED &seed, - uint8_t height, - eHashFunction hashFunction, - eAddrFormatType addrFormatType) throw(std::invalid_argument) - : _seed(seed), - _height(height), - _hashFunction(hashFunction), - _addrFormatType(addrFormatType) -{ - if (seed.size() != 48) { +XmssBase::XmssBase(const TSEED& seed, + uint8_t height, + eHashFunction hashFunction, + eAddrFormatType addrFormatType) + :_seed(seed), + _height(height), + _hashFunction(hashFunction), + _addrFormatType(addrFormatType) +{ + if (seed.size()!=48) { throw std::invalid_argument("Seed should be 48 bytes. Other values are not currently supported"); } } +XmssBase::XmssBase(const TSEED& extended_seed) +{ + if (extended_seed.size()!=51) { + throw std::invalid_argument("Extended seed should be 51 bytes. Other values are not currently supported"); + } + + auto desc = QRLDescriptor::fromExtendedSeed(extended_seed); + + _seed = std::vector( + extended_seed.cbegin()+QRLDescriptor::getSize(), + extended_seed.cend()); + + _height = desc.getHeight(); + _hashFunction = desc.getHashFunction(); + _addrFormatType = desc.getAddrFormatType(); +} + uint32_t XmssBase::getSignatureSize() { // 4 + n + (len + h) * n) - // FIXME: There could be consistency problems due to changes in len - return static_cast(4 + 32 + 67 * 32 + _height * 32); + return static_cast(4+32+67*32+_height*32); } uint8_t XmssBase::getHeightFromSigSize(size_t sigSize) { - // FIXME: Clean this up and consider len - return static_cast((sigSize - 4 - 32 - 67 * 32) / 32); + const uint32_t min_size = 4+32+67*32; // FIXME: Move these values to constants + if (sigSize < min_size) + { + throw std::invalid_argument("Invalid signature size"); + } + + if ((sigSize-4)%32!=0) { + throw std::invalid_argument("Invalid signature size"); + } + + auto height = (sigSize - min_size)/32; + + return static_cast(height); } uint32_t XmssBase::getPublicKeySize() { - return QRLDescriptor::getSize() + 64; + return QRLDescriptor::getSize()+64; } uint32_t XmssBase::getSecretKeySize() @@ -56,47 +83,47 @@ uint32_t XmssBase::getSecretKeySize() // FIXME: Use a union for this constexpr size_t OFFSET_IDX = 0; -constexpr size_t OFFSET_SK_SEED = OFFSET_IDX + 4; +constexpr size_t OFFSET_SK_SEED = OFFSET_IDX+4; -constexpr size_t OFFSET_SK_PRF = OFFSET_SK_SEED + 32; +constexpr size_t OFFSET_SK_PRF = OFFSET_SK_SEED+32; -constexpr size_t OFFSET_PUB_SEED = OFFSET_SK_PRF + 32; +constexpr size_t OFFSET_PUB_SEED = OFFSET_SK_PRF+32; -constexpr size_t OFFSET_ROOT = OFFSET_PUB_SEED + 32; +constexpr size_t OFFSET_ROOT = OFFSET_PUB_SEED+32; TKEY XmssBase::getSKSeed() { // FIXME: Use a union for this - return TKEY(_sk.begin() + OFFSET_SK_SEED, _sk.begin() + OFFSET_SK_SEED + 32); + return TKEY(_sk.begin()+OFFSET_SK_SEED, _sk.begin()+OFFSET_SK_SEED+32); } TKEY XmssBase::getSKPRF() { // FIXME: Use a union for this - return TKEY(_sk.begin() + OFFSET_SK_PRF, _sk.begin() + OFFSET_SK_PRF + 32); + return TKEY(_sk.begin()+OFFSET_SK_PRF, _sk.begin()+OFFSET_SK_PRF+32); } TKEY XmssBase::getPKSeed() { // FIXME: Use a union for this - return TKEY(_sk.begin() + OFFSET_PUB_SEED, _sk.begin() + OFFSET_PUB_SEED + 32); + return TKEY(_sk.begin()+OFFSET_PUB_SEED, _sk.begin()+OFFSET_PUB_SEED+32); } TKEY XmssBase::getRoot() { // FIXME: Use a union for this - return TKEY(_sk.begin() + OFFSET_ROOT, _sk.begin() + OFFSET_ROOT + 32); + return TKEY(_sk.begin()+OFFSET_ROOT, _sk.begin()+OFFSET_ROOT+32); } uint32_t XmssBase::getIndex() { - return (_sk[0] << 24) + - (_sk[1] << 16) + - (_sk[2] << 8) + - _sk[3]; + return (_sk[0] << 24)+ + (_sk[1] << 16)+ + (_sk[2] << 8)+ + _sk[3]; } -uint32_t XmssBase::setIndex(uint32_t new_index) throw(std::invalid_argument) +uint32_t XmssBase::setIndex(uint32_t new_index) { _sk[3] = static_cast(new_index & 0xFF); new_index >>= 8; @@ -141,10 +168,10 @@ TSEED XmssBase::getExtendedSeed() QRLDescriptor XmssBase::getDescriptor() { return { - _hashFunction, - eSignatureType::XMSS, - _height, - _addrFormatType + _hashFunction, + eSignatureType::XMSS, + _height, + _addrFormatType }; } @@ -155,45 +182,56 @@ std::vector XmssBase::getDescriptorBytes() std::vector XmssBase::getAddress() { - return QRLHelper::getAddress(getPK()); } -bool XmssBase::verify(const TMESSAGE &message, - const TSIGNATURE &signature, - const TKEY &pk) throw(std::invalid_argument) +bool XmssBase::verify(const TMESSAGE& message, + const TSIGNATURE& signature, + const TKEY& extended_pk) { + try + { + if (extended_pk.size()!=67) { + throw std::invalid_argument("Invalid extended_pk size. It should be 67 bytes"); + } - auto desc = QRLDescriptor::fromBytes(pk[0], pk[1], pk[2]); - if (desc.getSignatureType() != eSignatureType::XMSS) { - return false; - } + auto desc = QRLDescriptor::fromExtendedPK(extended_pk); - const auto height = static_cast (XmssBase::getHeightFromSigSize(signature.size())); + if (desc.getSignatureType()!=eSignatureType::XMSS) { + return false; + } - if (desc.getHeight() != height) { - return false; - } + const auto height = static_cast (XmssBase::getHeightFromSigSize(signature.size())); - auto hashFunction = desc.getHashFunction(); + if (height==0 || desc.getHeight()!=height) { + return false; + } - xmss_params params{}; - const uint32_t k = 2; - const uint32_t w = 16; - const uint32_t n = 32; + auto hashFunction = desc.getHashFunction(); - if (k >= height || (height - k) % 2) { - throw std::invalid_argument("For BDS traversal, H - K must be even, with H > K >= 2!"); - } + xmss_params params{}; + const uint32_t k = 2; + const uint32_t w = 16; + const uint32_t n = 32; - xmss_set_params(¶ms, n, height, w, k); + if (k>=height || (height-k)%2) { + throw std::invalid_argument("For BDS traversal, H - K must be even, with H > K >= 2!"); + } - auto tmp = static_cast(signature); - return xmss_Verifysig(hashFunction, - ¶ms.wots_par, - static_cast(message).data(), - message.size(), - tmp.data(), - pk.data() + QRLDescriptor::getSize(), - height) == 0; + xmss_set_params(¶ms, n, height, w, k); + + auto tmp = static_cast(signature); + + return xmss_Verifysig(hashFunction, + ¶ms.wots_par, + static_cast(message).data(), + message.size(), + tmp.data(), + extended_pk.data()+QRLDescriptor::getSize(), + height)==0; + } + catch(std::invalid_argument&) + { + return false; + } } diff --git a/src/qrl/xmssBase.h b/src/qrl/xmssBase.h index 6b7a67b..ab4f5b7 100644 --- a/src/qrl/xmssBase.h +++ b/src/qrl/xmssBase.h @@ -13,12 +13,26 @@ #define TSEED std::vector #define TKEY std::vector +// TODO: Use a union? to operate on partial fields +// PK format +// 32 root address +// 32 pub_seed +// +// SK format +// 4 idx +// 32 sk_seed +// 32 sk_prf +// 32 pub_seed +// 32 root + class XmssBase { public: XmssBase(const TSEED &seed, uint8_t height, eHashFunction hashFunction, - eAddrFormatType formatType) throw(std::invalid_argument); + eAddrFormatType formatType); + + XmssBase(const TSEED &extended_seed); virtual ~XmssBase() = default; @@ -26,7 +40,7 @@ class XmssBase { static bool verify(const TMESSAGE &message, const TSIGNATURE &signature, - const TKEY &pk) throw(std::invalid_argument); + const TKEY &pk); // TODO: Differentiate between XMSS and WOTS+ keys TKEY getSK(); @@ -59,7 +73,7 @@ class XmssBase { unsigned int getIndex(); - virtual unsigned int setIndex(uint32_t new_index) throw(std::invalid_argument); + virtual unsigned int setIndex(uint32_t new_index); unsigned int getSignatureSize(); diff --git a/src/qrl/xmssBasic.cpp b/src/qrl/xmssBasic.cpp index b587e26..9115405 100644 --- a/src/qrl/xmssBasic.cpp +++ b/src/qrl/xmssBasic.cpp @@ -9,7 +9,7 @@ XmssBasic::XmssBasic(const TSEED &seed, unsigned char height, eHashFunction hashFunction, - eAddrFormatType addrFormatType) throw(std::invalid_argument) + eAddrFormatType addrFormatType) : XmssBase(seed, height, hashFunction, addrFormatType) { // PK format // 32 root address diff --git a/src/qrl/xmssBasic.h b/src/qrl/xmssBasic.h index 6946e36..5ff9222 100644 --- a/src/qrl/xmssBasic.h +++ b/src/qrl/xmssBasic.h @@ -19,7 +19,7 @@ class XmssBasic : public ::XmssBase { XmssBasic(const TSEED &seed, unsigned char height, eHashFunction hashFunction, - eAddrFormatType addrFormatType) throw(std::invalid_argument); + eAddrFormatType addrFormatType); TSIGNATURE sign(const TMESSAGE &message) override; }; diff --git a/src/qrl/xmssFast.cpp b/src/qrl/xmssFast.cpp index bbb1e15..949df2c 100644 --- a/src/qrl/xmssFast.cpp +++ b/src/qrl/xmssFast.cpp @@ -7,22 +7,20 @@ XmssFast::XmssFast(const TSEED &seed, unsigned char height, eHashFunction hashFunction, - eAddrFormatType addrFormatType) throw(std::invalid_argument) + eAddrFormatType addrFormatType) : XmssBase(seed, height, hashFunction, addrFormatType) { -// PK format -// 32 root address -// 32 pub_seed -// -// SK format -// 4 idx -// 32 sk_seed -// 32 sk_prf -// 32 pub_seed -// 32 root -// TODO: Use a union? to operated on partial fields - - // FIXME: Inconsistency here + _initialize_tree(); +} + +XmssFast::XmssFast(const TSEED& extended_seed) + : XmssBase(extended_seed) +{ + _initialize_tree(); +} + +void XmssFast::_initialize_tree() +{ _sk = TKEY(132, 0); auto tmp = TKEY(64, 0); @@ -30,44 +28,44 @@ XmssFast::XmssFast(const TSEED &seed, const uint32_t w = 16; const uint32_t n = 32; - if (k >= height || (height - k) % 2) { + if (k >= _height || (_height - k) % 2) { throw std::invalid_argument("For BDS traversal, H - K must be even, with H > K >= 2!"); } - xmss_set_params(¶ms, n, height, w, k); + xmss_set_params(¶ms, n, _height, w, k); _stackoffset = 0; - _stack = std::vector((height + 1) * n); - _stacklevels = std::vector(height + 1); - _auth = std::vector(height * n); - _keep = std::vector((height >> 1) * n); - _treehash = std::vector(height - k); - _th_nodes = std::vector((height - k) * n); + _stack = std::vector((_height + 1) * n); + _stacklevels = std::vector(_height + 1); + _auth = std::vector(_height * n); + _keep = std::vector((_height >> 1) * n); + _treehash = std::vector(_height - k); + _th_nodes = std::vector((_height - k) * n); _retain = std::vector(((1 << k) - k - 1) * n); - for (int i = 0; i < height - k; i++) { + for (int i = 0; i < _height - k; i++) { _treehash[i].node = &_th_nodes[n * i]; } xmss_set_bds_state(&_state, - _stack.data(), - _stackoffset, - _stacklevels.data(), - _auth.data(), - _keep.data(), - _treehash.data(), - _retain.data(), - 0); + _stack.data(), + _stackoffset, + _stacklevels.data(), + _auth.data(), + _keep.data(), + _treehash.data(), + _retain.data(), + 0); xmssfast_Genkeypair(_hashFunction, - ¶ms, - tmp.data(), - _sk.data(), - &_state, - _seed.data()); + ¶ms, + tmp.data(), + _sk.data(), + &_state, + _seed.data()); } -unsigned int XmssFast::setIndex(unsigned int new_index) throw(std::invalid_argument) +unsigned int XmssFast::setIndex(unsigned int new_index) { xmssfast_update(_hashFunction, ¶ms, diff --git a/src/qrl/xmssFast.h b/src/qrl/xmssFast.h index e2008d9..4d62e62 100644 --- a/src/qrl/xmssFast.h +++ b/src/qrl/xmssFast.h @@ -10,20 +10,20 @@ #include class XmssFast : public XmssBase { + void _initialize_tree(); public: - // TODO: Fix constness / passing by copy, this requires changes in the underlying lib - XmssFast(const TSEED &seed, - unsigned char height, - eHashFunction hashFunction = eHashFunction::SHAKE_128, - eAddrFormatType addrFormatType = eAddrFormatType::SHA256_2X ) throw(std::invalid_argument); + XmssFast(const TSEED& seed, + unsigned char height, + eHashFunction hashFunction = eHashFunction::SHAKE_128, + eAddrFormatType addrFormatType = eAddrFormatType::SHA256_2X); - TSIGNATURE sign(const TMESSAGE &message) override; + XmssFast(const TSEED& extended_seed); - unsigned int setIndex(unsigned int new_index) throw(std::invalid_argument); + TSIGNATURE sign(const TMESSAGE& message) override; -protected: - // FIXME: This needs refactoring (encapsulate) + unsigned int setIndex(unsigned int new_index) override; +protected: bds_state _state; unsigned int _stackoffset = 0; std::vector _stack; diff --git a/src/xmss-alt/algsxmss.c b/src/xmss-alt/algsxmss.c index 1be6a1b..8d60585 100644 --- a/src/xmss-alt/algsxmss.c +++ b/src/xmss-alt/algsxmss.c @@ -42,7 +42,7 @@ void get_seed(eHashFunction hash_func, * Computes the leaf at a given address. First generates the WOTS key pair, then computes leaf using l_tree. As this happens position independent, we only require that addr encodes the right ltree-address. */ -static void gen_leaf_wots(eHashFunction hash_func, +void gen_leaf_wots(eHashFunction hash_func, unsigned char *leaf, const unsigned char *sk_seed, const xmss_params *params, diff --git a/src/xmss-alt/algsxmss.h b/src/xmss-alt/algsxmss.h index 603128a..fd474aa 100644 --- a/src/xmss-alt/algsxmss.h +++ b/src/xmss-alt/algsxmss.h @@ -15,6 +15,14 @@ int xmss_Genkeypair(eHashFunction hash_func, int xmss_updateSK(unsigned char *sk, unsigned long k); +void gen_leaf_wots(eHashFunction hash_func, + unsigned char *leaf, + const unsigned char *sk_seed, + const xmss_params *params, + const unsigned char *pub_seed, + uint32_t ltree_addr[8], + uint32_t ots_addr[8]); + int xmss_Signmsg(eHashFunction hash_func, xmss_params *params, unsigned char *sk, diff --git a/src/xmss-alt/algsxmss_fast.c b/src/xmss-alt/algsxmss_fast.c index c94ced6..4cd26f5 100644 --- a/src/xmss-alt/algsxmss_fast.c +++ b/src/xmss-alt/algsxmss_fast.c @@ -143,7 +143,8 @@ static void treehash_setup(eHashFunction hash_func, lastnode = idx + (1 << height); - for (i = 0; i < h - k; i++) { + const int bound = h - k; + for (i = 0; i < bound; i++) { state->treehash[i].h = i; state->treehash[i].completed = 1; state->treehash[i].stackusage = 0; diff --git a/tests/cpp/qrl/misc_test.cpp b/tests/cpp/qrl/misc_test.cpp index 9c9c9ae..8c1cc3a 100644 --- a/tests/cpp/qrl/misc_test.cpp +++ b/tests/cpp/qrl/misc_test.cpp @@ -37,52 +37,56 @@ namespace { EXPECT_EQ(mnemonic, ""); } - TEST(Misc, bin2mnemonic_simple1) { - std::vector input = {0x12, 0x34, 0x56, 0x78}; + TEST(Misc, bin2mnemonic_3_bytes) { + std::vector input = {0x00, 0x00, 0x00}; auto mnemonic = bin2mnemonic(input); - EXPECT_EQ(mnemonic, "base elbow knew"); + EXPECT_EQ(mnemonic, "aback aback"); } - TEST(Misc, bin2mnemonic_simple2) { - std::vector input = {0x12, 0x34, 0x56, 0x78, 0x00}; + TEST(Misc, bin2mnemonic_3_bytes_b) { + std::vector input = {0x00, 0x01, 0x00}; auto mnemonic = bin2mnemonic(input); - EXPECT_EQ(mnemonic, "base elbow knew aback"); + EXPECT_EQ(mnemonic, "aback badge"); } - TEST(Misc, bin2mnemonic_simple3) { - std::vector input = {0x12, 0x34, 0x56, 0x78, 0x01}; + TEST(Misc, bin2mnemonic_3_bytes_c) { + std::vector input = {0x00, 0x02, 0x00}; auto mnemonic = bin2mnemonic(input); - EXPECT_EQ(mnemonic, "base elbow knew badge"); + EXPECT_EQ(mnemonic, "aback bunny"); } - TEST(Misc, bin2mnemonic_simple3b) { - std::vector input = {0x12, 0x34, 0x56, 0x78, 0x01, 0x00}; + TEST(Misc, bin2mnemonic_4_bytes_a) { + std::vector input = {0x12, 0x34, 0x56, 0x78}; - auto mnemonic = bin2mnemonic(input); - EXPECT_EQ(mnemonic, "base elbow knew badge"); + EXPECT_THROW(bin2mnemonic(input), std::invalid_argument); } - TEST(Misc, bin2mnemonic_simple4) { - std::vector input = {0x00}; + TEST(Misc, bin2mnemonic_5_bytes_b) { + std::vector input = {0x12, 0x34, 0x56, 0x78, 0x00}; + EXPECT_THROW(bin2mnemonic(input), std::invalid_argument); + } + + TEST(Misc, bin2mnemonic_6_bytes_a) { + std::vector input = {0x12, 0x34, 0x56, 0x78, 0x01, 0x00}; auto mnemonic = bin2mnemonic(input); - EXPECT_EQ(mnemonic, "aback"); + EXPECT_EQ(mnemonic, "base elbow knew badge"); } - TEST(Misc, bin2mnemonic_simple5) { - std::vector input = {0x01}; + TEST(Misc, bin2mnemonic_6_bytes_b) { + std::vector input = {0x12, 0x34, 0x56, 0x78, 0x01, 0x09}; auto mnemonic = bin2mnemonic(input); - EXPECT_EQ(mnemonic, "absorb"); + EXPECT_EQ(mnemonic, "base elbow knew bald"); } TEST(Misc, mnemonic2bin_simple1) { - std::string input = "base elbow knew aback"; + std::string input = "base elbow knew aback bag bunny"; auto data = mnemonic2bin(input); - EXPECT_EQ(bin2hstr(data), "123456780000"); + EXPECT_EQ(bin2hstr(data), "123456780000102200"); } TEST(Misc, mnemonic2bin_simple2) { @@ -92,6 +96,12 @@ namespace { EXPECT_EQ(bin2hstr(data), "123456780102"); } + TEST(Misc, mnemonic2bin_unknown) { + std::string input = "base elbow knew unknown"; + EXPECT_THROW(mnemonic2bin(input), std::invalid_argument); + } + + TEST(Misc, mnemonic2bin_long) { std::string input = "law bruise screen lunar than loft but franc strike asleep dwarf tavern dragon alarm " "snack queen meadow thing far cotton add emblem strive probe zurich edge peer alight " diff --git a/tests/cpp/qrl/qrlDescriptor.cpp b/tests/cpp/qrl/qrlDescriptor.cpp index 6bd1809..9063068 100644 --- a/tests/cpp/qrl/qrlDescriptor.cpp +++ b/tests/cpp/qrl/qrlDescriptor.cpp @@ -6,53 +6,56 @@ namespace { - TEST(QRL_Descriptor, checkAttributes1) { - QRLDescriptor desc( - eHashFunction::SHA2_256, - eSignatureType::XMSS, - 10, - eAddrFormatType::SHA256_2X - ); - - EXPECT_TRUE(desc.getHashFunction() == eHashFunction::SHA2_256); - EXPECT_TRUE(desc.getHashFunction() != eHashFunction::SHAKE_128); - EXPECT_TRUE(desc.getSignatureType() == eSignatureType::XMSS); - - EXPECT_EQ(10, desc.getHeight()); - - std::vector expected_descriptor_bytes{0x00, 0x05, 0x00}; - EXPECT_EQ(expected_descriptor_bytes, desc.getBytes()); - } - - TEST(QRL_Descriptor, checkAttributes2) { - QRLDescriptor desc( - eHashFunction::SHAKE_128, - eSignatureType::XMSS, - 16, - eAddrFormatType::SHA256_2X - ); - - EXPECT_TRUE(desc.getHashFunction() != eHashFunction::SHA2_256); - EXPECT_TRUE(desc.getHashFunction() == eHashFunction::SHAKE_128); - EXPECT_TRUE(desc.getSignatureType() == eSignatureType::XMSS); - EXPECT_TRUE(desc.getAddrFormatType() == eAddrFormatType::SHA256_2X); - EXPECT_EQ(16, desc.getHeight()); - - std::vector expected_descriptor_bytes{0x01, 0x08, 0x00}; - EXPECT_EQ(expected_descriptor_bytes, desc.getBytes()); - } - - TEST(QRL_Descriptor, checkAttributesFromBytes) { - QRLDescriptor desc = QRLDescriptor::fromBytes(0x01, 0x08, 0x00); - - EXPECT_TRUE(desc.getHashFunction() != eHashFunction::SHA2_256); - EXPECT_TRUE(desc.getHashFunction() == eHashFunction::SHAKE_128); - EXPECT_TRUE(desc.getSignatureType() == eSignatureType::XMSS); - EXPECT_TRUE(desc.getAddrFormatType() == eAddrFormatType::SHA256_2X); - EXPECT_EQ(16, desc.getHeight()); - - std::vector expected_descriptor_bytes{0x01, 0x08, 0x00}; - EXPECT_EQ(expected_descriptor_bytes, desc.getBytes()); - } +TEST(QRL_Descriptor, checkAttributes1) +{ + QRLDescriptor desc( + eHashFunction::SHA2_256, + eSignatureType::XMSS, + 10, + eAddrFormatType::SHA256_2X + ); + + EXPECT_TRUE(desc.getHashFunction()==eHashFunction::SHA2_256); + EXPECT_TRUE(desc.getHashFunction()!=eHashFunction::SHAKE_128); + EXPECT_TRUE(desc.getSignatureType()==eSignatureType::XMSS); + + EXPECT_EQ(10, desc.getHeight()); + + std::vector expected_descriptor_bytes{0x00, 0x05, 0x00}; + EXPECT_EQ(expected_descriptor_bytes, desc.getBytes()); +} + +TEST(QRL_Descriptor, checkAttributes2) +{ + QRLDescriptor desc( + eHashFunction::SHAKE_128, + eSignatureType::XMSS, + 16, + eAddrFormatType::SHA256_2X + ); + + EXPECT_TRUE(desc.getHashFunction()!=eHashFunction::SHA2_256); + EXPECT_TRUE(desc.getHashFunction()==eHashFunction::SHAKE_128); + EXPECT_TRUE(desc.getSignatureType()==eSignatureType::XMSS); + EXPECT_TRUE(desc.getAddrFormatType()==eAddrFormatType::SHA256_2X); + EXPECT_EQ(16, desc.getHeight()); + + std::vector expected_descriptor_bytes{0x01, 0x08, 0x00}; + EXPECT_EQ(expected_descriptor_bytes, desc.getBytes()); +} + +TEST(QRL_Descriptor, checkAttributesFromBytes) +{ + QRLDescriptor desc = QRLDescriptor::fromBytes({0x01, 0x08, 0x00}); + + EXPECT_TRUE(desc.getHashFunction()!=eHashFunction::SHA2_256); + EXPECT_TRUE(desc.getHashFunction()==eHashFunction::SHAKE_128); + EXPECT_TRUE(desc.getSignatureType()==eSignatureType::XMSS); + EXPECT_TRUE(desc.getAddrFormatType()==eAddrFormatType::SHA256_2X); + EXPECT_EQ(16, desc.getHeight()); + + std::vector expected_descriptor_bytes{0x01, 0x08, 0x00}; + EXPECT_EQ(expected_descriptor_bytes, desc.getBytes()); +} } diff --git a/tests/cpp/qrl/qrlHelper.cpp b/tests/cpp/qrl/qrlHelper.cpp index 68a8c45..582a124 100644 --- a/tests/cpp/qrl/qrlHelper.cpp +++ b/tests/cpp/qrl/qrlHelper.cpp @@ -5,24 +5,34 @@ #include "gtest/gtest.h" namespace { - TEST(QRL_Helper, validateAddress) { - std::vector pk(QRLDescriptor::getSize() + 32, 0); +TEST(QRL_Helper, validateAddress) +{ + std::vector pk(QRLDescriptor::getSize()+64, 0); - auto address = QRLHelper::getAddress(pk); + auto address = QRLHelper::getAddress(pk); - std::cout << std::endl; - std::cout << bin2hstr(address) << std::endl; + std::cout << std::endl; + std::cout << bin2hstr(address) << std::endl; - EXPECT_TRUE(QRLHelper::addressIsValid(address)); + EXPECT_TRUE(QRLHelper::addressIsValid(address)); - auto address2 = address; - address2[2]=23; - EXPECT_FALSE(QRLHelper::addressIsValid(address2)); + auto address2 = address; + address2[2] = 23; + EXPECT_FALSE(QRLHelper::addressIsValid(address2)); - address2 = address; - EXPECT_TRUE(QRLHelper::addressIsValid(address2)); + address2 = address; + EXPECT_TRUE(QRLHelper::addressIsValid(address2)); - address2[1] = 1; - EXPECT_FALSE(QRLHelper::addressIsValid(address2)); - } + address2[1] = 1; + EXPECT_FALSE(QRLHelper::addressIsValid(address2)); +} + +TEST(QRL_Helper, validateAddressEmpty) +{ + auto address = std::vector(); + std::cout << std::endl; + std::cout << bin2hstr(address) << std::endl; + + EXPECT_FALSE(QRLHelper::addressIsValid(address)); +} } diff --git a/tests/cpp/qrl/xmssBasic_test.cpp b/tests/cpp/qrl/xmssBasic_test.cpp index 4751c32..da1df64 100644 --- a/tests/cpp/qrl/xmssBasic_test.cpp +++ b/tests/cpp/qrl/xmssBasic_test.cpp @@ -10,120 +10,165 @@ namespace { #define XMSS_HEIGHT 4 - TEST(XmssBasic_Default, Instantiation) { - std::vector seed(48, 0); +TEST(XmssBasic_Default, Instantiation) +{ + std::vector seed(48, 0); - XmssBasic xmss(seed, XMSS_HEIGHT, eHashFunction::SHAKE_128, eAddrFormatType::SHA256_2X); + XmssBasic xmss(seed, XMSS_HEIGHT, eHashFunction::SHAKE_128, eAddrFormatType::SHA256_2X); - auto pk = xmss.getPK(); - auto sk = xmss.getSK(); + auto pk = xmss.getPK(); + auto sk = xmss.getSK(); - std::cout << std::endl; - std::cout << std::endl; - std::cout << "seed:" << seed.size() << " bytes\n" << bin2hstr(seed, 16) << std::endl; - std::cout << "pk :" << pk.size() << " bytes\n" << bin2hstr(pk, 16) << std::endl; - std::cout << "sk :" << sk.size() << " bytes\n" << bin2hstr(sk, 16) << std::endl; - std::cout << "descr:" << bin2hstr(xmss.getDescriptor().getBytes()) << std::endl; - std::cout << "addr :" << bin2hstr(xmss.getAddress()) << std::endl; + std::cout << std::endl; + std::cout << std::endl; + std::cout << "seed:" << seed.size() << " bytes\n" << bin2hstr(seed, 16) << std::endl; + std::cout << "pk :" << pk.size() << " bytes\n" << bin2hstr(pk, 16) << std::endl; + std::cout << "sk :" << sk.size() << " bytes\n" << bin2hstr(sk, 16) << std::endl; + std::cout << "descr:" << bin2hstr(xmss.getDescriptor().getBytes()) << std::endl; + std::cout << "addr :" << bin2hstr(xmss.getAddress()) << std::endl; - EXPECT_EQ(seed, xmss.getSeed()); - EXPECT_EQ("000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000", - bin2hstr(xmss.getSeed())); + EXPECT_EQ(seed, xmss.getSeed()); + EXPECT_EQ("000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000", + bin2hstr(xmss.getSeed())); - EXPECT_TRUE(xmss.getDescriptor().getHashFunction() == eHashFunction::SHAKE_128); - EXPECT_TRUE(xmss.getDescriptor().getAddrFormatType() == eAddrFormatType::SHA256_2X); + EXPECT_TRUE(xmss.getDescriptor().getHashFunction()==eHashFunction::SHAKE_128); + EXPECT_TRUE(xmss.getDescriptor().getAddrFormatType()==eAddrFormatType::SHA256_2X); - EXPECT_EQ("010200", bin2hstr(xmss.getDescriptor().getBytes())); - EXPECT_EQ("0102000000000000000000000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000", - bin2hstr(xmss.getExtendedSeed())); + EXPECT_EQ("010200", bin2hstr(xmss.getDescriptor().getBytes())); + EXPECT_EQ("0102000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000", + bin2hstr(xmss.getExtendedSeed())); - EXPECT_EQ(51, xmss.getExtendedSeed().size()); + EXPECT_EQ(51, xmss.getExtendedSeed().size()); - std::string s = "absorb bunny aback aback aback aback aback aback aback aback aback aback aback aback aback " - "aback aback aback aback aback aback aback aback aback aback aback aback aback aback aback " - "aback aback aback aback"; + std::string s = "absorb bunny aback aback aback aback aback aback aback aback aback aback aback aback aback " + "aback aback aback aback aback aback aback aback aback aback aback aback aback aback aback " + "aback aback aback aback"; - EXPECT_EQ(s, bin2mnemonic(xmss.getExtendedSeed())); - EXPECT_EQ(xmss.getExtendedSeed(), mnemonic2bin(s)); + EXPECT_EQ(s, bin2mnemonic(xmss.getExtendedSeed())); + EXPECT_EQ(xmss.getExtendedSeed(), mnemonic2bin(s)); - EXPECT_EQ("01020095f03f084bcb29b96b0529c17ce92c54c1e8290193a93803812ead95e8e6902506b67897", - bin2hstr(xmss.getAddress())); + EXPECT_EQ("01020095f03f084bcb29b96b0529c17ce92c54c1e8290193a93803812ead95e8e6902506b67897", + bin2hstr(xmss.getAddress())); - EXPECT_EQ("01020095f03f084bcb29b96b0529c17ce92c54c1e8290193a93803812ead95e8e6902506b67897", - bin2hstr(QRLHelper::getAddress( xmss.getPK()))); - } + EXPECT_EQ("01020095f03f084bcb29b96b0529c17ce92c54c1e8290193a93803812ead95e8e6902506b67897", + bin2hstr(QRLHelper::getAddress(xmss.getPK()))); +} + +TEST(XmssBasic_Default, getHeightFromSigSize) +{ + EXPECT_EQ(8, XmssBase::getHeightFromSigSize(2436)); + EXPECT_EQ(10, XmssBase::getHeightFromSigSize(2500)); + EXPECT_THROW(XmssBase::getHeightFromSigSize(2437), std::invalid_argument); + EXPECT_THROW(XmssBase::getHeightFromSigSize(1000), std::invalid_argument); +} + +TEST(XmssBasic_Default, SignatureLen) +{ + std::vector seed(48, 0); - TEST(XmssBasic_Default, SignatureLen) { - std::vector seed(48, 0); + XmssBasic xmss4(seed, 4, eHashFunction::SHAKE_128, eAddrFormatType::SHA256_2X); + EXPECT_EQ(2308, xmss4.getSignatureSize()); - XmssBasic xmss4(seed, 4, eHashFunction::SHAKE_128, eAddrFormatType::SHA256_2X); - EXPECT_EQ(2308, xmss4.getSignatureSize()); + XmssBasic xmss6(seed, 6, eHashFunction::SHAKE_128, eAddrFormatType::SHA256_2X); + EXPECT_EQ(2372, xmss6.getSignatureSize()); +} + +TEST(XmssBasic_Default, Sign) +{ + std::vector seed(48, 0); - XmssBasic xmss6(seed, 6, eHashFunction::SHAKE_128, eAddrFormatType::SHA256_2X); - EXPECT_EQ(2372, xmss6.getSignatureSize()); - } + XmssBasic xmss(seed, XMSS_HEIGHT, eHashFunction::SHAKE_128, eAddrFormatType::SHA256_2X); - TEST(XmssBasic_Default, Sign) { - std::vector seed(48, 0); + std::string message = "This is a test message"; + std::vector data(message.begin(), message.end()); + EXPECT_EQ(xmss.getIndex(), 0); - XmssBasic xmss(seed, XMSS_HEIGHT, eHashFunction::SHAKE_128, eAddrFormatType::SHA256_2X); + auto signature = xmss.sign(data); - std::string message = "This is a test message"; - std::vector data(message.begin(), message.end()); - EXPECT_EQ(xmss.getIndex(), 0); + std::cout << std::endl; + std::cout << std::endl; + std::cout << "data :" << data.size() << " bytes\n" << bin2hstr(data, 64) << std::endl; + std::cout << "signature :" << signature.size() << " bytes\n" << bin2hstr(signature, 64) << std::endl; + EXPECT_EQ(xmss.getIndex(), 1); - auto signature = xmss.sign(data); + auto signature2 = xmss.sign(data); - std::cout << std::endl; - std::cout << std::endl; - std::cout << "data :" << data.size() << " bytes\n" << bin2hstr(data, 64) << std::endl; - std::cout << "signature :" << signature.size() << " bytes\n" << bin2hstr(signature, 64) << std::endl; - EXPECT_EQ(xmss.getIndex(), 1); + std::cout << std::endl; + std::cout << std::endl; + std::cout << "data :" << data.size() << " bytes\n" << bin2hstr(data, 64) << std::endl; + std::cout << "signature :" << signature.size() << " bytes\n" << bin2hstr(signature, 64) << std::endl; - auto signature2 = xmss.sign(data); + EXPECT_NE(bin2hstr(signature), bin2hstr(signature2)); + EXPECT_EQ(xmss.getIndex(), 2); +} - std::cout << std::endl; - std::cout << std::endl; - std::cout << "data :" << data.size() << " bytes\n" << bin2hstr(data, 64) << std::endl; - std::cout << "signature :" << signature.size() << " bytes\n" << bin2hstr(signature, 64) << std::endl; +TEST(XmssBasic_Default, Verify) +{ + std::vector seed; + for (unsigned char i = 0; i<48; i++) + seed.push_back(i); - EXPECT_NE(bin2hstr(signature), bin2hstr(signature2)); - EXPECT_EQ(xmss.getIndex(), 2); - } + XmssBasic xmss(seed, XMSS_HEIGHT, eHashFunction::SHAKE_128, eAddrFormatType::SHA256_2X); + std::string message = "This is a test message"; + std::vector data_ref(message.begin(), message.end()); + std::vector data(message.begin(), message.end()); - TEST(XmssBasic_Default, Verify) { - std::vector seed; - for(unsigned char i=0; i<48; i++) - seed.push_back(i); + auto pk = xmss.getPK(); + auto sk = xmss.getSK(); + std::cout << std::endl; + std::cout << "seed:" << seed.size() << " bytes\n" << bin2hstr(seed, 32) << std::endl; + std::cout << "pk :" << pk.size() << " bytes\n" << bin2hstr(pk, 32) << std::endl; + std::cout << "sk :" << sk.size() << " bytes\n" << bin2hstr(sk, 32) << std::endl; - XmssBasic xmss(seed, XMSS_HEIGHT, eHashFunction::SHAKE_128, eAddrFormatType::SHA256_2X); + auto signature = xmss.sign(data); - std::string message = "This is a test message"; - std::vector data_ref(message.begin(), message.end()); - std::vector data(message.begin(), message.end()); + EXPECT_EQ(data, data_ref); - auto pk = xmss.getPK(); - auto sk = xmss.getSK(); - std::cout << std::endl; - std::cout << "seed:" << seed.size() << " bytes\n" << bin2hstr(seed, 32) << std::endl; - std::cout << "pk :" << pk.size() << " bytes\n" << bin2hstr(pk, 32) << std::endl; - std::cout << "sk :" << sk.size() << " bytes\n" << bin2hstr(sk, 32) << std::endl; + std::cout << std::endl; + std::cout << std::endl; + std::cout << "data :" << data.size() << " bytes\n" << bin2hstr(data, 64) << std::endl; + std::cout << "signature :" << signature.size() << " bytes\n" << bin2hstr(signature, 64) << std::endl; - auto signature = xmss.sign(data); + EXPECT_TRUE(XmssBasic::verify(data, signature, pk)); - EXPECT_EQ(data, data_ref); + signature[1] += 1; + EXPECT_FALSE(XmssBasic::verify(data, signature, xmss.getPK())); +} - std::cout << std::endl; - std::cout << std::endl; - std::cout << "data :" << data.size() << " bytes\n" << bin2hstr(data, 64) << std::endl; - std::cout << "signature :" << signature.size() << " bytes\n" << bin2hstr(signature, 64) << std::endl; +TEST(XmssBasic_Default, VerifyBadSig) +{ + std::vector seed; + for (unsigned char i = 0; i<48; i++) + seed.push_back(i); - EXPECT_TRUE(XmssBasic::verify(data, signature, pk)); + XmssBasic xmss(seed, XMSS_HEIGHT, eHashFunction::SHAKE_128, eAddrFormatType::SHA256_2X); - signature[1] += 1; - EXPECT_FALSE(XmssBasic::verify(data, signature, xmss.getPK())); - } + std::string message = "This is a test message"; + std::vector data_ref(message.begin(), message.end()); + std::vector data(message.begin(), message.end()); + + auto pk = xmss.getPK(); + auto sk = xmss.getSK(); + std::cout << std::endl; + std::cout << "seed:" << seed.size() << " bytes\n" << bin2hstr(seed, 32) << std::endl; + std::cout << "pk :" << pk.size() << " bytes\n" << bin2hstr(pk, 32) << std::endl; + std::cout << "sk :" << sk.size() << " bytes\n" << bin2hstr(sk, 32) << std::endl; + + auto signature = xmss.sign(data); + + EXPECT_EQ(data, data_ref); + + std::cout << std::endl; + std::cout << std::endl; + std::cout << "data :" << data.size() << " bytes\n" << bin2hstr(data, 64) << std::endl; + std::cout << "signature :" << signature.size() << " bytes\n" << bin2hstr(signature, 64) << std::endl; + + EXPECT_TRUE(XmssBasic::verify(data, signature, pk)); + + signature[1] += 1; + EXPECT_FALSE(XmssBasic::verify(data, signature, xmss.getPK())); +} } diff --git a/tests/cpp/qrl/xmssFastSHA2_test.cpp b/tests/cpp/qrl/xmssFastSHA2_test.cpp index 5686a0e..f7ede2e 100644 --- a/tests/cpp/qrl/xmssFastSHA2_test.cpp +++ b/tests/cpp/qrl/xmssFastSHA2_test.cpp @@ -128,7 +128,7 @@ namespace { TEST(XmssFastSHA2, BadInputVerify) { TMESSAGE message(2, 0); TSIGNATURE signature(48, 0); - TKEY pk(48, 0); + TKEY pk(67, 0); EXPECT_FALSE(XmssFast::verify(message, signature, pk)); diff --git a/tests/cpp/qrl/xmssFast_test.cpp b/tests/cpp/qrl/xmssFast_test.cpp index 48ee5a5..292e7bf 100644 --- a/tests/cpp/qrl/xmssFast_test.cpp +++ b/tests/cpp/qrl/xmssFast_test.cpp @@ -134,7 +134,7 @@ TEST(XmssFast, BadInputVerify) { TMESSAGE message(2, 0); TSIGNATURE signature(48, 0); - TKEY pk(48, 0); + TKEY pk(67, 0); EXPECT_FALSE(XmssFast::verify(message, signature, pk)); diff --git a/tests/js/old_examples.js b/tests/js/old_examples.js new file mode 100755 index 0000000..04b4a95 --- /dev/null +++ b/tests/js/old_examples.js @@ -0,0 +1,98 @@ +var libqrl = require('./libjsqrl.js'); +const crypto = require('crypto'); +var assert = require('assert'); + + +console.log("\n========== CREATE RANDOM SEED ========"); + +const seed_random = crypto.randomBytes(48); +// TODO: Provide automatic conversion between Nodejs Buffer and libqrl.VectorUChar [ std::vector ] +seed_random2 = new libqrl.VectorUChar(); +for (var i = 0; i < 48; i++) { + // Put some data + seed_random2.push_back(seed_random[i]); +} + +mnemonic_random = libqrl.bin2mnemonic(seed_random2); +console.log("Seed : ", libqrl.bin2hstr(seed_random2)); +console.log("Mnemonic: ", mnemonic_random); + + +console.log("\n========== CREATE FIXED SEED ========"); +seed_in = new libqrl.VectorUChar(); +for (var i = 0; i < 48; i++) { + // Put some data + seed_in.push_back(i); +} + +mnemonic = libqrl.bin2mnemonic(seed_in); +console.log("Seed : ", libqrl.bin2hstr(seed_in)); +console.log("Mnemonic: ", mnemonic); +seed_out = libqrl.mnemonic2bin(mnemonic); + +assert(libqrl.bin2hstr(seed_in) === libqrl.bin2hstr(seed_out), "Seeds after mnemonic conversion do not match"); + +tree_height = 4; +console.log("\n========== CREATE TREE ========"); + +known_address = "Q67b08ac802fc97ad513836296bdd4017d7c58352a36b517af02ec948ec326302753f2fc9"; + +xmss = new libqrl.Xmss(seed_in, tree_height); +console.log("Address : ", xmss.getAddress()); +console.log("PK : ", libqrl.bin2hstr(xmss.getPK())); +console.log("SK : ", libqrl.bin2hstr(xmss.getSK())); +console.log("Seed : ", libqrl.bin2hstr(xmss.getSeed())); +console.log("Height : ", xmss.getHeight()); +console.log("Index : ", xmss.getIndex()); + +console.log("Root : ", libqrl.bin2hstr(xmss.getRoot())); +console.log("PKSeed : ", libqrl.bin2hstr(xmss.getPKSeed())); +console.log("SKSeed : ", libqrl.bin2hstr(xmss.getSKSeed())); +console.log("SKPRF : ", libqrl.bin2hstr(xmss.getSKPRF())); + + +assert(xmss.getAddress() === known_address, "ADDRESS DOES NOT MATCH"); + + +console.log("\n========== PREPARE MESSAGE ========"); +message_str = "This is a test message"; + +message_hstr = "5468697320697320612074657374206d657373616765" +signature1_known_hstr = "000000004c05b01a39c1daad3c6d7d9613a643022e39800766d452df9d31dd0da35ddb35a526d296f624ab22250939cbe709f0788ac3431391881476ff9765b7227e8c50933a5d1e4aa01aa2ef43a7ae170b1ba17e542248c5f7134c402b53138c5566b0be0ceaa5ebd96a525f949a37a68b4d477989a9e3a561dd928cd3b5fce34d673eae989bfb54cb4690d44c5bee8606fb12b13cd1c77f974c0c6a652ff3aef840491a57645acdb0b1f160b92514417fc5c6f487790d2f2372d1de32b1a37da33adced758350e2e21692667405c190ed434287c4618735979fdda2b0101cb8eda97bc7543645a37605497cddeb364011d8b50da45f0f77e81fd27a54b3cdd358a2ba893b49a7b64dad523b1298f39ed77f48a85d85b90631100af0daf3a5cf0830c374609a4ce5de4b4ffcce92b8031c37b2ad145c8e89e667a4b73d9f1543bbb8196263a3d105f8475398dcc8f85a5001a0b0c8c7f54ec17adbbd48ad35a959e2f4f814a75112d0a9f679aaac9013f85c328f3b47fa4b2401582364142fe10f6a2fb37856f6c2ba4037ce14db5c58623ecd9d3fb23da8f1d55c1b387550b107368a8b149425239510eacb66a7971da731d00722b106e5686c0ffe3fcdb128ece59a75ff6e2d1aa408eac8390b2e57c0dbcd41162698e7310f750eb7101422a568267ebf64a13b84d6fbe2a74b0f300d732f16f57ee3cf685f5e3c0899beb20a338581791dcd98956c4df70ff26443293d6eda0b6f681852445fbb52bb7b0e0a5f3d91c4745d049e63d8a79347ae4d651a3da307e99dbcc3005047e3160092f2b1d1fbceec5801506e08d1b9c56f50b0c89e7950e22d4cd2b81c25314386cd5c14d9539ff3d02539a6349c653d498bd9c7969d56df0405066e7ec471988c87ac8043e9471ccea27ca78e9516fae7e57eb5167c618d673d8cbe739b614a4b9d8e97bd25324a511a991268ee93bb43589ac0d3298f13aaaa19787fd7a97d65c37af08ca2a611337fd4ac19406602077455611a09947fc88d528938659eeeb99f36caf88e8d56233b2fb02e825a4da00cbd5a04447988971bff67e7404f5e148575aed5c94f9d61eb9264e432a45845e39bb49355eb70cb45f0a0857f74ea6d1d65a53e5f1620c7ead472064fd963776baf682fb55c9668e2642695e516181a80494e21ec59ddb06dcbcabb9e025f61df617d6695136fb84fc6ae994422f7fe2cc88f9bf467bfe1bad9769597aad9d59ba0a6c22a4ab287d24453ee0115b5b9115ca8d15c4aa7cff39d4b78c716e4f372628f301c10d1a7026b4ca0ba395fbc3b826f883a9567b5c074342fb296f9fd073ccd83b78a7f69e515aaad764b73056ea3b98dc11fd076e11a91979978b10c23b9b100f8e80f80b215bbaa4164b10e0897d93e1a50473a22d237f533a33717268065d76c85d1771eb2cda0b33ff30114faf89703f5860a2ba8986dc8a3695eed2bba62879dc44adf6bd1635f7cfaefbeba094c7173f6711dfb634006beb0e0a77eaacd2e44ccc3402ee248c4a4a4c6f0780f09a71ece9b5de26138ca74835315d247aa4225c5a9292c19dcdc51fe27eef0c1bbe1f14eca1ef2d24e1190444978aa92919199f838dd484738a59bd3305b426f8b4c848ca11f115ac631e042d5a4986efac85710e94b6570b57abf8e14d996a13393154943578c147f3c5cf8f1544b699a4d36cce7e50de2391f6ae7173a1dd8d1f05687b92326baa6259179d8c0bb60ef2ae804fc07ae8e0f3c4c94a1be128be74ac38a7ea36faf61030d025d1e8e527769a1ce21f89ba0a997c7fd716b74683e678f90a20c6c5ddb9513fc696f269803e21b913ed4819b15f7962e4dc647d0ad4f817fd9e6d604e64f382d39407bbe8ad6a197151c54467691035e459bbed25a9a35161db4a07398818f23f83410e89a61e4e8ce3cd6c9837d081c52e344f4ec0c2cc9812687aa5c6baee1a307c5aff76609c4ff4b0bb7244b866015d46e142417d1b498015a11c8a3b3698f49869296f5f61c308af9e395a916418ff1da8b33702f7f80cb4b6b1b4f68aab219022b3e1983e64a9b94919eaf283e5ca37bd51c64e4c28e3b721582c4178c5262264a114233e8548fb42e5c4e6a8501a6f31cb873fd9eff21d4a587f0415af8349f9729c5b2061b3947443d300bbfd2053eb3f8722bfcc513ebc6fda66a9f0b2d5df56e681ac6c6fd4606da7edf2256b131f6d28835a9368a1190b81f1f7aae0f630e537d1984c6d22c24157ba5b4823f90efaa5c1cde59501351e96e2866fe7d13cacedca66726da9d419505c23c94fa220634a7f329c7708fb1d4d6ea5283dd7ec0d076d93538047ed531c5351796134c3b00c8316cff76652d159cad9c951d16eeac9d1cdf07eb26215e1f0971821de7832855505225df608beef4af9d81334330dcdeee51c3f78a2caf64d889c5aca839ad4941bfa0f217b506703711bd5f7c70f716f0ae7b0013db9de6f47449c5e9883dae394fbf842e80697bfa69f9c30895dd58ac44ba1b7e45f988f0d95259cc58f537f31dd465587aba80bd54e1a34b2e1bcf6b70345e5b28b223057d889369774db37dd77aa2e90e89642e2d47a7fed0fc9298355034e28fbb1dd1ccbe1b22f60b8c31c36635105ff4dd69bf9793415389fe5051dab296667f517c889806c8b633041be3e750714831a996eb6a442459231e04916e09ddbf4af1e78de40ba57c3c05633eda3da57ccde811d9c1765420e213611b5a544bb231dfd90bb1cf1b351857f499cf7b7f86beb78266ccb62d4f92b791fd66c2afc018068129321911431f3b16824c1abcf66b8f01e0a5e61152acee229174fb0e34425ec168c6b475c84dd6cb852e12b6d1905cfe907873615a508e81c64cde0cf6df37bf80f71f8bc4e79a24c3507ec7f80bfd0263b466dbbdadea18de21fe7571454abb0f03fb0ea7560d7dad7b3d8c75931e337c54843965e5f888ab05428849c6ec28624db89961041d5ac178f928371abba40db39457db29c248bfb3de2eff322ff6eda98c3695c379ddc11c56ff01f08e68826a379c12954140febf7b2de4dcc119accf23a95b477ad3d08b0151778f45418fb24b4b83170bb48ebc3128600c3be554b2e122165afe3ae34dac6486e03b8e2baa1616b58e72ce38a65274db488246ed68a70b294928da27ef9b24ee592c723d91a02d23ee960072cc5fc1220bc78f7867e3286722fef6edef3f0ce090450041db3cadab736f254b68bf7ad63c7085789c2b651a94"; + +signature2_known_hstr = "00000001fef8018b2189071448c2fe98452154a375ca0b17a022241e9f41e164e0c07b54ed8c2d9cf20b82673354f30421296048e3bcb924be528121da929e6476a431a717d9fe4a83dffff1eded12b65ac77fc7f52592180de42d760beadb61dba1a2554ed5d6e706af55ae15ceefd9f79b8cf29f039c0c9e1f42c155964a7a9ed26fadb4440f4d3a2417694850d556a5e0d01e573121321252ae69b86efb393217d60da1e63e82f18ee0bc9090417a0d12be6328deadca0f6705d10b30d21dc0d625c92ce4c3bd2d80cf8c43fc1fec330fa6349fd808017df24fc04ce283106f5b5c8d1097f482aa218c726070a5910ad104e7da646206b3d58838836d045ed06db9d1543f83b967ada6163e69d6a392c570f115e9e1df6dbe5523e31166a8e68e7020a176bdead8968f37094119a8148705c5259ed9777de63db4e5cc17b731548acd16bd99d02480bfafc1fa979f68fe4af98809e96bf5a8e7879e53abb91e74e70c90f8323c6980412611d893ef8981117259a800ab8f5606975b1757befd01c8d94a183801814071c49a3235fbb7cd6510f5a9c90683cec13b42d25e4ae475e801b5991275755517fed9175618b95e39f7f4857203463205a8b12999699f44bbafae14d9c51d4fb25b01208cd04a084f2f6f5d7c23a2940d581f606d74621f561f91ed46f96ecc742b0773b1c0551995fae26f937a4e2c9474433680855c5fad6d3e837bff7c0accaac60344c915f567b7aeff23649e478f913d8e7c252988441acea0f106b89204e7fe91b957b615e3b1497827b2fb61ee1142f57bf80aa45472713bf81ec616f86d78e27768dcb7a2b7209e8c2f6400a8cd113d36e58e6ecfedd69b68d8a3e685e38ee36b8179484e05132e0d7a5e6656b75c179b26ad70430b4b0ef68ab96a9024b00ed64fe6f1210871880f1cf4247afa381a02be9c7bbbab9c860e6a6d59171167884ac5d73fca8eb0b6253c2008eba6f4811f387f06d7843e96875386c104001f9ba0922592847e2eb60145d61449253dd046f21553a5fe693adefc5aa1b1a5e9f4e3d8fe48bb86cdd4e98028240f0c6877593a3993c6415673879d617eda983500ab7b5e36f8e9e3eed104c10783a90b35789428b20b75bcc6fe4dcd05b281bc7610e3ea213afba88c5169a7c86ad00d67b0d94f2aec5fb6ef44fb307189f4469668e04d12bb9622e3fb09228320484c4308af19ec9c577494c67c949b3fba1fba28964ff8f884e3403d58bc7289027e119508115075c53810a804d11ebc24f27a8faf5a0f75d1473c340c104f3845bb5327b37ea021dd3f6ad5f4a37916a2846957f6c39a40b19242e0a2cec5fb7ff43695d8f14d80fdd5206787edd151516f519657893d9d3a1d006ef0d28401913ac02bc9bae493f1a9a3f9c9fe4b9224293f4e425f0ed6f5f11cd06be601c331bcd2df70e3ec5d82a6fec3967dcc0022d1833fa25fb45fef232cacb210317e8ed009c26507454c34edddeb3ab8ddd865f996d745c1ca0dd7dcd20f4532150c357a95d28e6139bb73ddf8aa5d69b438206c64ec3f2e65d0273cce9dd49baf91ebf2b3659f1c876bf0a729592374f99ed543f5545c5a487c0044ba37a6b5d12b45445cfe5624241a136d3f19e2c04d8bcc7db95fcb86ecc2ecc2f7205ed3709237cc8fc8304bf584cb4e0734f9ee1a389dfd5ed13ea377776cc588ec46b8335b7e00b3cb55a9d82a42ccb6a5978e3223fca7a5aa1e3ae65b78a3738159e5b5cb9379aceff0418e4ddca22c85e55b1abc7da76fda02c57e30b03a295c1e4b654eb5cb678e3853e1cbe8c07ace0b2e15f3d8dc1ba59db936ee74172076db7bf76dff27d55538261dff86b65ee39ff51d5f9755cbee7bcb82b25df626b14b42ceb787184a14069a1fa080d24d629793efb261cb0d366e9ab036577d7e72d357e169a6854378a7619ddb8a8e89e2f67c94f5ebe0937b6c639ece114a40de31fac55bd9df095db2620cf8994d6c7db6c7bb058b2aa7d19c619124aef735b7c1a50318af3fd05d19f14683cfee0997bf20cf9a1c32494fbde96cc35416b31a52319380d6746ad525e907be03dc5d24c791c78b589d4010ddbd5b25ab9b0883c98706ddbde9b93f992c67848fa4648d4fe0cf28b95148ce78abf99dbccd03e97c3deb0fc3762b8d606584d4ae6a777c7930ae7366c05e1d07ebde0e92ef8b544b15e6933298e790f87305a9d28e57e1f206c6c7b645b36731adc71f7b17dd55a231a46c146f8afdca222dcd829940685878e6244760f3e0350b647e75d8f53d36acd292e9bc4eb7e04a48a851d4b4bcf64cc8adc67011f1a04db38278b63a0c575221136db4f59194929c262e470cebcdf2323f91e9fe9d6a7f8e57a1cc4a2529957bea4f26e5af6837c5c38df64497525301466bcd86bef8eda9b751a05bea63559db8c58cbd00e67895b9b316bf7b258ea37841867191a1c7c14f7d1cb650e61bc5b02c8272402469b3d9b5df2f526db5b9828734622ef492b3f7a6dd8f5b27f8191c6c5389c1146ba3f22ea7ac91ca6a634b1249ed49dad63fc9b0e8f612ac384f48f8a2b414419bd940d0ccbb106f1e527a64a76ca328284ee7905a2ed5f3a86212fef94e3e823d68ec672e01ad10776dfaae35df787c88a314a73aba97a3e03a467a56b4c0c80921bc534368933ae6b1227dca177127d061ceda52b8ec85261bf714c63da1d785f6931f8f80c01dba151e567f6dcfaf9a3b57bc3abdfc89435e5a47543ec7c430d0df86313f9c8f40087e95765b8c94f561203727e393bc9970330768a89401f4f2fb4b123a6c6160f4a6a68070bc0ac10bb8c888e9f70eb741583e7f8c7d120fe4b1188209f1f2650a6b01c057097b4925a3b3401f5137fd6fca6df01889b9c634946d7b5cd3b8f8815b715c08fa6e590a271a5b68ec44580fec18a726d4d3d73f66fa85aa4a0f316544f6db8e36756e89e6b2f92c96bffbf690ab10c5e6b484726f2bf0d6e4051348b568d83f02d89a53159b0f48ff0421ce645303a1ff54397fa621b610ef2e6314f7ba6721fb3ac89039a0f6745adc574325f1ff11833f4ce9b71b6baab172a7835b21d49baada73d36f0676d8b9da6cb12d481631d3084e2170eafe3ae34dac6486e03b8e2baa1616b58e72ce38a65274db488246ed68a70b294928da27ef9b24ee592c723d91a02d23ee960072cc5fc1220bc78f7867e3286722fef6edef3f0ce090450041db3cadab736f254b68bf7ad63c7085789c2b651a94"; + +pk_known_hstr = "16ecb9f39b9f4275d5a49e232346a15ae2fa8c50a2927daeac189b8c5f2d18bc4e3983bd564298c49ae2e7fa6e28d4b954d8cd59398f1225b08d6144854aee0e"; +sk_known_hstr = "000000000c459bb1b4d1cd8cdec0209f37d4c91597896ce8de0911bd021db47029d70dc332ad39708e20dfe28f325b63beffe4f841aa834d46f740d3d988a3bcef678de74e3983bd564298c49ae2e7fa6e28d4b954d8cd59398f1225b08d6144854aee0e16ecb9f39b9f4275d5a49e232346a15ae2fa8c50a2927daeac189b8c5f2d18bc"; + +msg_in = new libqrl.str2bin(message_str); +console.log("Message: ", libqrl.bin2hstr(msg_in)); +sigpk = xmss.getPK(); +sigsk = xmss.getSK(); +sigheight = xmss.getHeight(); + +assert(libqrl.bin2hstr(sigpk) === pk_known_hstr, "PK DOES NOT MATCH"); +assert(libqrl.bin2hstr(sigsk) === sk_known_hstr, "SK DOES NOT MATCH"); +assert(libqrl.bin2hstr(msg_in) === message_hstr, "MSG DOES NOT MATCH"); + + +console.log("\n========== FIRST SIGNATURE ========"); +console.log("Index : ", xmss.getIndex()); +signature1 = xmss.sign(msg_in); +console.log("Sig1 : ", libqrl.bin2hstr(signature1)); +assert(libqrl.bin2hstr(signature1) === signature1_known_hstr, "SIGNATURE DOES NOT MATCH"); + + +console.log("\n========== SECOND SIGNATURE ========"); +console.log("Index : ", xmss.getIndex()); +signature2 = xmss.sign(msg_in); +console.log("Sig2 : ", libqrl.bin2hstr(signature2)); +assert(libqrl.bin2hstr(signature2) === signature2_known_hstr, "SIGNATURE DOES NOT MATCH"); + +console.log("\n========== VERIFY SIGNATURE ========"); + +verification1 = libqrl.Xmss.verify(msg_in, signature1, sigpk); +verification2 = libqrl.Xmss.verify(msg_in, signature2, sigpk); + +console.log("Verif1 : ", verification1); +console.log("Verif2 : ", verification2); \ No newline at end of file diff --git a/tests/js/package-lock.json b/tests/js/package-lock.json new file mode 100644 index 0000000..8b8a06f --- /dev/null +++ b/tests/js/package-lock.json @@ -0,0 +1,1133 @@ +{ + "name": "js_webassembly_test", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ascli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz", + "integrity": "sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=", + "requires": { + "colour": "0.7.1", + "optjs": "3.2.2" + } + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + }, + "bytebuffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", + "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", + "requires": { + "long": "3.2.0" + } + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "chai": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", + "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", + "requires": { + "assertion-error": "1.1.0", + "check-error": "1.0.2", + "deep-eql": "3.0.1", + "get-func-name": "2.0.0", + "pathval": "1.1.0", + "type-detect": "4.0.8" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "colour": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/colour/-/colour-0.7.1.tgz", + "integrity": "sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=" + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "requires": { + "type-detect": "4.0.8" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "fs-extra": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz", + "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==", + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "growl": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", + "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==" + }, + "grpc": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.10.1.tgz", + "integrity": "sha512-xmhA11h2XhqpSVzDAmoQAYdNQ+swILXpKOiRpAEQ2kX55ioxVADc6v7SkS4zQBxm4klhQHgGqpGKvoL6LGx4VQ==", + "requires": { + "lodash": "4.17.5", + "nan": "2.10.0", + "node-pre-gyp": "0.7.0", + "protobufjs": "5.0.2" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true + }, + "ajv": { + "version": "5.5.2", + "bundled": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.3.5" + } + }, + "asn1": { + "version": "0.2.3", + "bundled": true + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true + }, + "aws-sign2": { + "version": "0.7.0", + "bundled": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "4.3.1", + "bundled": true, + "requires": { + "hoek": "4.2.1" + } + }, + "brace-expansion": { + "version": "1.1.8", + "bundled": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "caseless": { + "version": "0.12.0", + "bundled": true + }, + "co": { + "version": "4.6.0", + "bundled": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "combined-stream": { + "version": "1.0.6", + "bundled": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "cryptiles": { + "version": "3.1.2", + "bundled": true, + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "bundled": true, + "requires": { + "hoek": "4.2.1" + } + } + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.4.2", + "bundled": true + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "bundled": true + }, + "extsprintf": { + "version": "1.3.0", + "bundled": true + }, + "fast-deep-equal": { + "version": "1.1.0", + "bundled": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "bundled": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "2.3.2", + "bundled": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.18" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.2" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "requires": { + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "har-schema": { + "version": "2.0.0", + "bundled": true + }, + "har-validator": { + "version": "5.0.3", + "bundled": true, + "requires": { + "ajv": "5.5.2", + "har-schema": "2.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "hawk": { + "version": "6.0.2", + "bundled": true, + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.1", + "sntp": "2.1.0" + } + }, + "hoek": { + "version": "4.2.1", + "bundled": true + }, + "http-signature": { + "version": "1.2.0", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.1" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.5", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "bundled": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "jsprim": { + "version": "1.4.1", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "mime-db": { + "version": "1.33.0", + "bundled": true + }, + "mime-types": { + "version": "2.1.18", + "bundled": true, + "requires": { + "mime-db": "1.33.0" + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true + } + } + }, + "ms": { + "version": "2.0.0", + "bundled": true + }, + "node-pre-gyp": { + "version": "0.7.0", + "bundled": true, + "requires": { + "detect-libc": "1.0.3", + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.2", + "rc": "1.2.6", + "request": "2.83.0", + "rimraf": "2.6.2", + "semver": "5.5.0", + "tar": "2.2.1", + "tar-pack": "3.4.1" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "requires": { + "abbrev": "1.1.1", + "osenv": "0.1.5" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "performance-now": { + "version": "2.1.0", + "bundled": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true + }, + "punycode": { + "version": "1.4.1", + "bundled": true + }, + "qs": { + "version": "6.5.1", + "bundled": true + }, + "rc": { + "version": "1.2.6", + "bundled": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.5", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + } + }, + "readable-stream": { + "version": "2.3.5", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.83.0", + "bundled": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "bundled": true + }, + "semver": { + "version": "5.5.0", + "bundled": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "sntp": { + "version": "2.1.0", + "bundled": true, + "requires": { + "hoek": "4.2.1" + } + }, + "sshpk": { + "version": "1.14.1", + "bundled": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.3", + "bundled": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "stringstream": { + "version": "0.0.5", + "bundled": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.4.1", + "bundled": true, + "requires": { + "debug": "2.6.9", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.3.5", + "rimraf": "2.6.2", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "tough-cookie": { + "version": "2.3.4", + "bundled": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "uuid": { + "version": "3.2.1", + "bundled": true + }, + "verror": { + "version": "1.10.0", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + } + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "4.1.11" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "1.0.0" + } + }, + "lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" + }, + "long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.1.0.tgz", + "integrity": "sha512-d6RWgYPILd+AoWVOxiD0UwUqRicnE1inTxMr40CXOgqYve1MvnKntoLAtLIcxjEeVjEoYYTe5QAq3mUc6/ySjQ==", + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.11.0", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.3", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "4.4.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "optjs": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/optjs/-/optjs-3.2.2.tgz", + "integrity": "sha1-aabOicRCpEQDFBrS+bNwvVu29O4=" + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" + }, + "protobufjs": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-5.0.2.tgz", + "integrity": "sha1-WXSNfc8D0tsiwT2p/rAk4Wq4DJE=", + "requires": { + "ascli": "1.0.1", + "bytebuffer": "5.0.1", + "glob": "7.1.2", + "yargs": "3.32.0" + } + }, + "rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "requires": { + "has-flag": "2.0.0" + } + }, + "temp": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", + "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", + "requires": { + "os-tmpdir": "1.0.2", + "rimraf": "2.2.8" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, + "universalify": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", + "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" + }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yargs": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "requires": { + "camelcase": "2.1.1", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "os-locale": "1.4.0", + "string-width": "1.0.2", + "window-size": "0.1.4", + "y18n": "3.2.1" + } + } + } +} diff --git a/tests/js/package.json b/tests/js/package.json new file mode 100644 index 0000000..670adac --- /dev/null +++ b/tests/js/package.json @@ -0,0 +1,18 @@ +{ + "name": "js_webassembly_test", + "version": "1.0.0", + "description": "js tests for webassembly", + "main": "index.js", + "scripts": { + "test": "./node_modules/.bin/mocha" + }, + "author": "", + "license": "ISC", + "dependencies": { + "chai": "^4.1.2", + "fs-extra": "^5.0.0", + "grpc": "^1.9.1", + "mocha": "^5.0.1", + "temp": "^0.8.3" + } +} diff --git a/tests/js/test.js b/tests/js/test.js old mode 100644 new mode 100755 index 0e86203..9866d4c --- a/tests/js/test.js +++ b/tests/js/test.js @@ -1,102 +1,223 @@ -var libqrl = require('./libjsqrl.js'); +const assert = require('assert'); const crypto = require('crypto'); -var assert = require('assert'); +const libqrl = require('./tmp/libjsqrl.js'); +// TODO: Move this to another file with all the helper functions -console.log("\n========== CREATE RANDOM SEED ========"); +function ToArray(vec) { + let arr = new Uint8Array(vec.size()); + for (let i = 0; i < vec.size(); i++) { + arr[i] = vec.get(i); + } + return arr; +} -const seed_random = crypto.randomBytes(48); -// TODO: Provide automatic conversion between Nodejs Buffer and libqrl.VectorUChar [ std::vector ] -seed_random2 = new libqrl.VectorUChar(); -for(var i =0; i<48; i++) -{ - // Put some data - seed_random2.push_back( seed_random[i] ); +function ToUint8Vector(arr) { + let vec = new libqrl.Uint8Vector(); + for (let i = 0; i < arr.length; i++) { + vec.push_back(arr[i]) + } + return vec; } -mnemonic_random = libqrl.bin2mnemonic(seed_random2); -console.log("Seed : ", libqrl.bin2hstr(seed_random2)); -console.log("Mnemonic: ", mnemonic_random); +describe('libjsqrl', function () { + describe('helpers', function () { + it('arr -> vec', function () { + tmp_arr = Uint8Array.from([1, 2, 3, 4, 5]); + tmp_vec = ToUint8Vector(tmp_arr); + + assert.equal(5, tmp_vec.size()); + for (let i = 0; i < tmp_vec.size(); i++) { + assert.equal(i + 1, tmp_vec.get(i)); + } + }); + it('data -> vec', function () { + tmp_vec = ToUint8Vector([1, 2, 3, 4, 5]); + + assert.equal(5, tmp_vec.size()); + for (let i = 0; i < tmp_vec.size(); i++) { + assert.equal(i + 1, tmp_vec.get(i)); + } + }); + it('data -> vec', function () { + tmp_vec = ToUint8Vector([1, 2, 3, 4, 5]); + tmp_arr = ToArray(tmp_vec); + + assert.equal(5, tmp_arr.length); + for (let i = 0; i < tmp_arr.length; i++) { + assert.equal(i + 1, tmp_arr[i]); + } + }); + }); + describe('sha2_256', function () { + it('hello', function () { + data = [1,2,3,4,5]; + data_vec = ToUint8Vector(data); + hash_vec = libqrl.sha2_256( data_vec ); + + assert.equal(32, ToArray(hash_vec).length); + assert.equal( + libqrl.bin2hstr( hash_vec ), + '74f81fe167d99b4cb41d6d0ccda82278caee9f3e2f25d5e5a3936ff3dcec60d0'); + }); + }); + + describe('address from epk', function () { + it('basic', function () { + let expected_address = 'Q000200baea487e62a96f32a2c427def90f020880d2fb0bff756ff6450186904dcc0c88e9018879'; -console.log("\n========== CREATE FIXED SEED ========"); -seed_in = new libqrl.VectorUChar(); -for(i =0; i<48; i++) -{ - // Put some data - seed_in.push_back(i); -} + // Object a + let hexseed = '0002006963291e58d6e776fe25932964748e774fb22cff112fbf5ece45b17965704697550064a60f40ba7c742694346761d5cc'; + xmss = libqrl.Xmss.fromHexSeed(hexseed); + epk = xmss.getPK(); + + address = 'Q'+libqrl.getAddress(epk); + + assert.equal(expected_address, address); + }); + }); + + describe('bin2mnemonic', function () { + it('[0,1,2,3,4,5] should return aback bag adrift dream', function () { + data = ToUint8Vector([0, 1, 2, 3, 4, 5]); + assert.equal('aback bag adrift dream', libqrl.bin2mnemonic(data)); + }); + + it('[1,2,3] should return aback bag', function () { + data = ToUint8Vector([0, 1, 2]); + assert.equal('aback bag', libqrl.bin2mnemonic(data)); + }); + + it('aback bag to binary and back', function () { + tmp_bin = libqrl.mnemonic2bin('aback bag'); + tmp_mnemonic = libqrl.bin2mnemonic(tmp_bin); + + assert.equal('aback bag', tmp_mnemonic); + }); + }); + + describe('xmss', function () { + it('create tree from parameters', function () { + + let seed_vector = ToUint8Vector(new Uint8Array(48)); + let height = 4; + let hash_func = libqrl.eHashFunction.SHA2_256; + + xmss = libqrl.Xmss.fromParameters(seed_vector, height, hash_func); + + /////////////////////////// + + assert.equal(0, xmss.getIndex()); + + assert.equal(4, xmss.getHeight()); + + assert.equal( + xmss.getAddress(), + 'Q00020096e5c065cf961565169e795803c1e60f521af7a3ea0326b42aa40c0e75390e5d8f4336de'); + + assert.equal( + libqrl.bin2hstr(xmss.getAddressRaw()), + '00020096e5c065cf961565169e795803c1e60f521af7a3ea0326b42aa40c0e75390e5d8f4336de'); + + assert.equal( + xmss.getHexSeed(), + '000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'); + + assert.equal( + xmss.getMnemonic(), + 'aback bunny aback aback aback aback aback aback aback aback aback aback aback aback aback aback aback ' + + 'aback aback aback aback aback aback aback aback aback aback aback aback aback aback aback aback aback'); + }); + + it('create tree from hexseed', function () { + let hexseed = '0002006963291e58d6e776fe25932964748e774fb22cff112fbf5ece45b17965704697550064a60f40ba7c742694346761d5cc'; + xmss = libqrl.Xmss.fromHexSeed(hexseed); + + /////////////////////////// + + assert.equal(0, xmss.getIndex()); + + assert.equal(4, xmss.getHeight()); -mnemonic = libqrl.bin2mnemonic(seed_in); -console.log("Seed : ", libqrl.bin2hstr(seed_in)); -console.log("Mnemonic: ", mnemonic); -seed_out = libqrl.mnemonic2bin(mnemonic); + assert.equal( + xmss.getAddress(), + 'Q000200baea487e62a96f32a2c427def90f020880d2fb0bff756ff6450186904dcc0c88e9018879'); -assert(libqrl.bin2hstr(seed_in) === libqrl.bin2hstr(seed_out), "Seeds after mnemonic conversion do not match"); + assert.equal( + libqrl.bin2hstr(xmss.getAddressRaw()), + '000200baea487e62a96f32a2c427def90f020880d2fb0bff756ff6450186904dcc0c88e9018879'); -tree_height = 4; -console.log("\n========== CREATE TREE ========"); + assert.equal( + xmss.getHexSeed(), + '0002006963291e58d6e776fe25932964748e774fb22cff112fbf5ece45b17965704697550064a60f40ba7c742694346761d5cc'); -known_address = "Q67b08ac802fc97ad513836296bdd4017d7c58352a36b517af02ec948ec326302753f2fc9"; + assert.equal( + xmss.getMnemonic(), + 'aback bunny heroic crazy brown miss torch inhere cater crazy hammer ethic kidnap wire clutch vat cope '+ + 'walnut sodden gather lame free enable juicy aboard exert awhile artful leg during neatly employ gritty gill'); + }); -xmss = new libqrl.Xmss(seed_in, tree_height); -console.log("Address : ", xmss.getAddress()); -console.log("PK : ", libqrl.bin2hstr(xmss.getPK())); -console.log("SK : ", libqrl.bin2hstr(xmss.getSK())); -console.log("Seed : ", libqrl.bin2hstr(xmss.getSeed())); -console.log("Height : ", xmss.getHeight()); -console.log("Index : ", xmss.getIndex()); + it('create tree from mnemonic', function () { -console.log("Root : ", libqrl.bin2hstr(xmss.getRoot())); -console.log("PKSeed : ", libqrl.bin2hstr(xmss.getPKSeed())); -console.log("SKSeed : ", libqrl.bin2hstr(xmss.getSKSeed())); -console.log("SKPRF : ", libqrl.bin2hstr(xmss.getSKPRF())); + let mnemonic = + 'aback bunny heroic crazy brown miss torch inhere cater crazy hammer ethic kidnap wire clutch vat cope '+ + 'walnut sodden gather lame free enable juicy aboard exert awhile artful leg during neatly employ gritty gill'; + xmss = libqrl.Xmss.fromMnemonic(mnemonic); -assert(xmss.getAddress() === known_address, "ADDRESS DOES NOT MATCH"); + /////////////////////////// + assert.equal(0, xmss.getIndex()); + assert.equal(4, xmss.getHeight()); -console.log("\n========== PREPARE MESSAGE ========"); -message_str = "This is a test message"; + assert.equal( + xmss.getAddress(), + 'Q000200baea487e62a96f32a2c427def90f020880d2fb0bff756ff6450186904dcc0c88e9018879'); -message_hstr = "5468697320697320612074657374206d657373616765" -signature1_known_hstr = "000000004c05b01a39c1daad3c6d7d9613a643022e39800766d452df9d31dd0da35ddb35a526d296f624ab22250939cbe709f0788ac3431391881476ff9765b7227e8c50933a5d1e4aa01aa2ef43a7ae170b1ba17e542248c5f7134c402b53138c5566b0be0ceaa5ebd96a525f949a37a68b4d477989a9e3a561dd928cd3b5fce34d673eae989bfb54cb4690d44c5bee8606fb12b13cd1c77f974c0c6a652ff3aef840491a57645acdb0b1f160b92514417fc5c6f487790d2f2372d1de32b1a37da33adced758350e2e21692667405c190ed434287c4618735979fdda2b0101cb8eda97bc7543645a37605497cddeb364011d8b50da45f0f77e81fd27a54b3cdd358a2ba893b49a7b64dad523b1298f39ed77f48a85d85b90631100af0daf3a5cf0830c374609a4ce5de4b4ffcce92b8031c37b2ad145c8e89e667a4b73d9f1543bbb8196263a3d105f8475398dcc8f85a5001a0b0c8c7f54ec17adbbd48ad35a959e2f4f814a75112d0a9f679aaac9013f85c328f3b47fa4b2401582364142fe10f6a2fb37856f6c2ba4037ce14db5c58623ecd9d3fb23da8f1d55c1b387550b107368a8b149425239510eacb66a7971da731d00722b106e5686c0ffe3fcdb128ece59a75ff6e2d1aa408eac8390b2e57c0dbcd41162698e7310f750eb7101422a568267ebf64a13b84d6fbe2a74b0f300d732f16f57ee3cf685f5e3c0899beb20a338581791dcd98956c4df70ff26443293d6eda0b6f681852445fbb52bb7b0e0a5f3d91c4745d049e63d8a79347ae4d651a3da307e99dbcc3005047e3160092f2b1d1fbceec5801506e08d1b9c56f50b0c89e7950e22d4cd2b81c25314386cd5c14d9539ff3d02539a6349c653d498bd9c7969d56df0405066e7ec471988c87ac8043e9471ccea27ca78e9516fae7e57eb5167c618d673d8cbe739b614a4b9d8e97bd25324a511a991268ee93bb43589ac0d3298f13aaaa19787fd7a97d65c37af08ca2a611337fd4ac19406602077455611a09947fc88d528938659eeeb99f36caf88e8d56233b2fb02e825a4da00cbd5a04447988971bff67e7404f5e148575aed5c94f9d61eb9264e432a45845e39bb49355eb70cb45f0a0857f74ea6d1d65a53e5f1620c7ead472064fd963776baf682fb55c9668e2642695e516181a80494e21ec59ddb06dcbcabb9e025f61df617d6695136fb84fc6ae994422f7fe2cc88f9bf467bfe1bad9769597aad9d59ba0a6c22a4ab287d24453ee0115b5b9115ca8d15c4aa7cff39d4b78c716e4f372628f301c10d1a7026b4ca0ba395fbc3b826f883a9567b5c074342fb296f9fd073ccd83b78a7f69e515aaad764b73056ea3b98dc11fd076e11a91979978b10c23b9b100f8e80f80b215bbaa4164b10e0897d93e1a50473a22d237f533a33717268065d76c85d1771eb2cda0b33ff30114faf89703f5860a2ba8986dc8a3695eed2bba62879dc44adf6bd1635f7cfaefbeba094c7173f6711dfb634006beb0e0a77eaacd2e44ccc3402ee248c4a4a4c6f0780f09a71ece9b5de26138ca74835315d247aa4225c5a9292c19dcdc51fe27eef0c1bbe1f14eca1ef2d24e1190444978aa92919199f838dd484738a59bd3305b426f8b4c848ca11f115ac631e042d5a4986efac85710e94b6570b57abf8e14d996a13393154943578c147f3c5cf8f1544b699a4d36cce7e50de2391f6ae7173a1dd8d1f05687b92326baa6259179d8c0bb60ef2ae804fc07ae8e0f3c4c94a1be128be74ac38a7ea36faf61030d025d1e8e527769a1ce21f89ba0a997c7fd716b74683e678f90a20c6c5ddb9513fc696f269803e21b913ed4819b15f7962e4dc647d0ad4f817fd9e6d604e64f382d39407bbe8ad6a197151c54467691035e459bbed25a9a35161db4a07398818f23f83410e89a61e4e8ce3cd6c9837d081c52e344f4ec0c2cc9812687aa5c6baee1a307c5aff76609c4ff4b0bb7244b866015d46e142417d1b498015a11c8a3b3698f49869296f5f61c308af9e395a916418ff1da8b33702f7f80cb4b6b1b4f68aab219022b3e1983e64a9b94919eaf283e5ca37bd51c64e4c28e3b721582c4178c5262264a114233e8548fb42e5c4e6a8501a6f31cb873fd9eff21d4a587f0415af8349f9729c5b2061b3947443d300bbfd2053eb3f8722bfcc513ebc6fda66a9f0b2d5df56e681ac6c6fd4606da7edf2256b131f6d28835a9368a1190b81f1f7aae0f630e537d1984c6d22c24157ba5b4823f90efaa5c1cde59501351e96e2866fe7d13cacedca66726da9d419505c23c94fa220634a7f329c7708fb1d4d6ea5283dd7ec0d076d93538047ed531c5351796134c3b00c8316cff76652d159cad9c951d16eeac9d1cdf07eb26215e1f0971821de7832855505225df608beef4af9d81334330dcdeee51c3f78a2caf64d889c5aca839ad4941bfa0f217b506703711bd5f7c70f716f0ae7b0013db9de6f47449c5e9883dae394fbf842e80697bfa69f9c30895dd58ac44ba1b7e45f988f0d95259cc58f537f31dd465587aba80bd54e1a34b2e1bcf6b70345e5b28b223057d889369774db37dd77aa2e90e89642e2d47a7fed0fc9298355034e28fbb1dd1ccbe1b22f60b8c31c36635105ff4dd69bf9793415389fe5051dab296667f517c889806c8b633041be3e750714831a996eb6a442459231e04916e09ddbf4af1e78de40ba57c3c05633eda3da57ccde811d9c1765420e213611b5a544bb231dfd90bb1cf1b351857f499cf7b7f86beb78266ccb62d4f92b791fd66c2afc018068129321911431f3b16824c1abcf66b8f01e0a5e61152acee229174fb0e34425ec168c6b475c84dd6cb852e12b6d1905cfe907873615a508e81c64cde0cf6df37bf80f71f8bc4e79a24c3507ec7f80bfd0263b466dbbdadea18de21fe7571454abb0f03fb0ea7560d7dad7b3d8c75931e337c54843965e5f888ab05428849c6ec28624db89961041d5ac178f928371abba40db39457db29c248bfb3de2eff322ff6eda98c3695c379ddc11c56ff01f08e68826a379c12954140febf7b2de4dcc119accf23a95b477ad3d08b0151778f45418fb24b4b83170bb48ebc3128600c3be554b2e122165afe3ae34dac6486e03b8e2baa1616b58e72ce38a65274db488246ed68a70b294928da27ef9b24ee592c723d91a02d23ee960072cc5fc1220bc78f7867e3286722fef6edef3f0ce090450041db3cadab736f254b68bf7ad63c7085789c2b651a94"; + assert.equal( + libqrl.bin2hstr(xmss.getAddressRaw()), + '000200baea487e62a96f32a2c427def90f020880d2fb0bff756ff6450186904dcc0c88e9018879'); -signature2_known_hstr = "00000001fef8018b2189071448c2fe98452154a375ca0b17a022241e9f41e164e0c07b54ed8c2d9cf20b82673354f30421296048e3bcb924be528121da929e6476a431a717d9fe4a83dffff1eded12b65ac77fc7f52592180de42d760beadb61dba1a2554ed5d6e706af55ae15ceefd9f79b8cf29f039c0c9e1f42c155964a7a9ed26fadb4440f4d3a2417694850d556a5e0d01e573121321252ae69b86efb393217d60da1e63e82f18ee0bc9090417a0d12be6328deadca0f6705d10b30d21dc0d625c92ce4c3bd2d80cf8c43fc1fec330fa6349fd808017df24fc04ce283106f5b5c8d1097f482aa218c726070a5910ad104e7da646206b3d58838836d045ed06db9d1543f83b967ada6163e69d6a392c570f115e9e1df6dbe5523e31166a8e68e7020a176bdead8968f37094119a8148705c5259ed9777de63db4e5cc17b731548acd16bd99d02480bfafc1fa979f68fe4af98809e96bf5a8e7879e53abb91e74e70c90f8323c6980412611d893ef8981117259a800ab8f5606975b1757befd01c8d94a183801814071c49a3235fbb7cd6510f5a9c90683cec13b42d25e4ae475e801b5991275755517fed9175618b95e39f7f4857203463205a8b12999699f44bbafae14d9c51d4fb25b01208cd04a084f2f6f5d7c23a2940d581f606d74621f561f91ed46f96ecc742b0773b1c0551995fae26f937a4e2c9474433680855c5fad6d3e837bff7c0accaac60344c915f567b7aeff23649e478f913d8e7c252988441acea0f106b89204e7fe91b957b615e3b1497827b2fb61ee1142f57bf80aa45472713bf81ec616f86d78e27768dcb7a2b7209e8c2f6400a8cd113d36e58e6ecfedd69b68d8a3e685e38ee36b8179484e05132e0d7a5e6656b75c179b26ad70430b4b0ef68ab96a9024b00ed64fe6f1210871880f1cf4247afa381a02be9c7bbbab9c860e6a6d59171167884ac5d73fca8eb0b6253c2008eba6f4811f387f06d7843e96875386c104001f9ba0922592847e2eb60145d61449253dd046f21553a5fe693adefc5aa1b1a5e9f4e3d8fe48bb86cdd4e98028240f0c6877593a3993c6415673879d617eda983500ab7b5e36f8e9e3eed104c10783a90b35789428b20b75bcc6fe4dcd05b281bc7610e3ea213afba88c5169a7c86ad00d67b0d94f2aec5fb6ef44fb307189f4469668e04d12bb9622e3fb09228320484c4308af19ec9c577494c67c949b3fba1fba28964ff8f884e3403d58bc7289027e119508115075c53810a804d11ebc24f27a8faf5a0f75d1473c340c104f3845bb5327b37ea021dd3f6ad5f4a37916a2846957f6c39a40b19242e0a2cec5fb7ff43695d8f14d80fdd5206787edd151516f519657893d9d3a1d006ef0d28401913ac02bc9bae493f1a9a3f9c9fe4b9224293f4e425f0ed6f5f11cd06be601c331bcd2df70e3ec5d82a6fec3967dcc0022d1833fa25fb45fef232cacb210317e8ed009c26507454c34edddeb3ab8ddd865f996d745c1ca0dd7dcd20f4532150c357a95d28e6139bb73ddf8aa5d69b438206c64ec3f2e65d0273cce9dd49baf91ebf2b3659f1c876bf0a729592374f99ed543f5545c5a487c0044ba37a6b5d12b45445cfe5624241a136d3f19e2c04d8bcc7db95fcb86ecc2ecc2f7205ed3709237cc8fc8304bf584cb4e0734f9ee1a389dfd5ed13ea377776cc588ec46b8335b7e00b3cb55a9d82a42ccb6a5978e3223fca7a5aa1e3ae65b78a3738159e5b5cb9379aceff0418e4ddca22c85e55b1abc7da76fda02c57e30b03a295c1e4b654eb5cb678e3853e1cbe8c07ace0b2e15f3d8dc1ba59db936ee74172076db7bf76dff27d55538261dff86b65ee39ff51d5f9755cbee7bcb82b25df626b14b42ceb787184a14069a1fa080d24d629793efb261cb0d366e9ab036577d7e72d357e169a6854378a7619ddb8a8e89e2f67c94f5ebe0937b6c639ece114a40de31fac55bd9df095db2620cf8994d6c7db6c7bb058b2aa7d19c619124aef735b7c1a50318af3fd05d19f14683cfee0997bf20cf9a1c32494fbde96cc35416b31a52319380d6746ad525e907be03dc5d24c791c78b589d4010ddbd5b25ab9b0883c98706ddbde9b93f992c67848fa4648d4fe0cf28b95148ce78abf99dbccd03e97c3deb0fc3762b8d606584d4ae6a777c7930ae7366c05e1d07ebde0e92ef8b544b15e6933298e790f87305a9d28e57e1f206c6c7b645b36731adc71f7b17dd55a231a46c146f8afdca222dcd829940685878e6244760f3e0350b647e75d8f53d36acd292e9bc4eb7e04a48a851d4b4bcf64cc8adc67011f1a04db38278b63a0c575221136db4f59194929c262e470cebcdf2323f91e9fe9d6a7f8e57a1cc4a2529957bea4f26e5af6837c5c38df64497525301466bcd86bef8eda9b751a05bea63559db8c58cbd00e67895b9b316bf7b258ea37841867191a1c7c14f7d1cb650e61bc5b02c8272402469b3d9b5df2f526db5b9828734622ef492b3f7a6dd8f5b27f8191c6c5389c1146ba3f22ea7ac91ca6a634b1249ed49dad63fc9b0e8f612ac384f48f8a2b414419bd940d0ccbb106f1e527a64a76ca328284ee7905a2ed5f3a86212fef94e3e823d68ec672e01ad10776dfaae35df787c88a314a73aba97a3e03a467a56b4c0c80921bc534368933ae6b1227dca177127d061ceda52b8ec85261bf714c63da1d785f6931f8f80c01dba151e567f6dcfaf9a3b57bc3abdfc89435e5a47543ec7c430d0df86313f9c8f40087e95765b8c94f561203727e393bc9970330768a89401f4f2fb4b123a6c6160f4a6a68070bc0ac10bb8c888e9f70eb741583e7f8c7d120fe4b1188209f1f2650a6b01c057097b4925a3b3401f5137fd6fca6df01889b9c634946d7b5cd3b8f8815b715c08fa6e590a271a5b68ec44580fec18a726d4d3d73f66fa85aa4a0f316544f6db8e36756e89e6b2f92c96bffbf690ab10c5e6b484726f2bf0d6e4051348b568d83f02d89a53159b0f48ff0421ce645303a1ff54397fa621b610ef2e6314f7ba6721fb3ac89039a0f6745adc574325f1ff11833f4ce9b71b6baab172a7835b21d49baada73d36f0676d8b9da6cb12d481631d3084e2170eafe3ae34dac6486e03b8e2baa1616b58e72ce38a65274db488246ed68a70b294928da27ef9b24ee592c723d91a02d23ee960072cc5fc1220bc78f7867e3286722fef6edef3f0ce090450041db3cadab736f254b68bf7ad63c7085789c2b651a94"; + assert.equal( + xmss.getHexSeed(), + '0002006963291e58d6e776fe25932964748e774fb22cff112fbf5ece45b17965704697550064a60f40ba7c742694346761d5cc'); -pk_known_hstr = "16ecb9f39b9f4275d5a49e232346a15ae2fa8c50a2927daeac189b8c5f2d18bc4e3983bd564298c49ae2e7fa6e28d4b954d8cd59398f1225b08d6144854aee0e"; -sk_known_hstr = "000000000c459bb1b4d1cd8cdec0209f37d4c91597896ce8de0911bd021db47029d70dc332ad39708e20dfe28f325b63beffe4f841aa834d46f740d3d988a3bcef678de74e3983bd564298c49ae2e7fa6e28d4b954d8cd59398f1225b08d6144854aee0e16ecb9f39b9f4275d5a49e232346a15ae2fa8c50a2927daeac189b8c5f2d18bc"; + assert.equal( + xmss.getMnemonic(), + 'aback bunny heroic crazy brown miss torch inhere cater crazy hammer ethic kidnap wire clutch vat cope '+ + 'walnut sodden gather lame free enable juicy aboard exert awhile artful leg during neatly employ gritty gill'); + }); -msg_in = new libqrl.str2bin(message_str); -console.log("Message: ", libqrl.bin2hstr(msg_in)); -sigpk = xmss.getPK(); -sigsk = xmss.getSK(); -sigheight = xmss.getHeight(); + it('get height from address', function () { + let some_address = 'Q00020096e5c065cf961565169e795803c1e60f521af7a3ea0326b42aa40c0e75390e5d8f4336de'; + assert.equal(libqrl.getHeight(some_address), 4); + }); -assert(libqrl.bin2hstr(sigpk) === pk_known_hstr, "PK DOES NOT MATCH"); -assert(libqrl.bin2hstr(sigsk) === sk_known_hstr, "SK DOES NOT MATCH"); -assert(libqrl.bin2hstr(msg_in) === message_hstr, "MSG DOES NOT MATCH"); + it('get hash function from address', function () { + let some_address = 'Q00020096e5c065cf961565169e795803c1e60f521af7a3ea0326b42aa40c0e75390e5d8f4336de'; + hash_function = libqrl.getHashFunction(some_address); + assert.equal(hash_function, libqrl.eHashFunction.SHA2_256); + }); -console.log("\n========== FIRST SIGNATURE ========"); -console.log("Index : ", xmss.getIndex()); -signature1 = xmss.sign(msg_in); -console.log("Sig1 : ", libqrl.bin2hstr(signature1)); -assert(libqrl.bin2hstr(signature1) === signature1_known_hstr, "SIGNATURE DOES NOT MATCH"); + it('get signature type from address', function () { + let some_address = 'Q00020096e5c065cf961565169e795803c1e60f521af7a3ea0326b42aa40c0e75390e5d8f4336de'; + signature_type = libqrl.getSignatureType(some_address); -console.log("\n========== SECOND SIGNATURE ========"); -console.log("Index : ", xmss.getIndex()); -signature2 = xmss.sign(msg_in); -console.log("Sig2 : ", libqrl.bin2hstr(signature2)); -assert(libqrl.bin2hstr(signature2) === signature2_known_hstr, "SIGNATURE DOES NOT MATCH"); + assert.equal(signature_type, libqrl.eSignatureType.XMSS); + }); -console.log("\n========== VERIFY SIGNATURE ========"); + it('get descriptor', function () { + let some_address = 'Q0105000c10421ed6eebb1fb8f066ac50678961f60b516d98ab83bee92278f6fd238306e1424918'; -verification1 = libqrl.Xmss.verify(msg_in, signature1, sigpk); -verification2 = libqrl.Xmss.verify(msg_in, signature2, sigpk); + assert.equal(libqrl.getHeight(some_address), 10); + assert.equal(libqrl.getHashFunction(some_address), libqrl.eHashFunction.SHAKE_128); + assert.equal(libqrl.getSignatureType(some_address), libqrl.eSignatureType.XMSS); + }); -console.log("Verif1 : ", verification1); -console.log("Verif2 : ", verification2); + }); +}); diff --git a/pyxmss/__init__.py b/tests/js/tmp/.gitkeep similarity index 100% rename from pyxmss/__init__.py rename to tests/js/tmp/.gitkeep diff --git a/tests/python/test_dilithium.py b/tests/python/test_dilithium.py index b7c1670..4059f3e 100644 --- a/tests/python/test_dilithium.py +++ b/tests/python/test_dilithium.py @@ -195,7 +195,6 @@ def test_dilithium_reference(self): print(bin2hstr(dilithium.getPK())) print(bin2hstr(dilithium.getSK())) - def test_dilithium_reference2(self): pk = bytes(hstr2bin(self.PK1_HSTR)) sk = bytes(hstr2bin(self.SK1_HSTR)) diff --git a/tests/python/test_misc.py b/tests/python/test_misc.py index 2ac3a89..246c933 100644 --- a/tests/python/test_misc.py +++ b/tests/python/test_misc.py @@ -6,6 +6,7 @@ from unittest import TestCase from pyqrllib import pyqrllib +from pyqrllib.pyqrllib import mnemonic2bin, bin2mnemonic class TestMisc(TestCase): @@ -20,17 +21,38 @@ def test_data_to_hex2(self): hexstring = pyqrllib.bin2hstr('test', 0) self.assertEqual(hexstring, '74657374') + def test_mnemonic_words_odd_1(self): + with self.assertRaises(ValueError): + mnemonic2bin('absorb') + + def test_mnemonic_words_odd_2(self): + with self.assertRaises(ValueError): + mnemonic2bin('absorb bunny bunny') + + def test_mnemonic1(self): + result = mnemonic2bin('aback absorb') + self.assertEqual(tuple([0, 0, 16]), result) + + def test_mnemonic2(self): + result = mnemonic2bin('absorb absorb') + self.assertEqual(tuple([1, 0, 16]), result) + + def test_mnemonic3(self): + long_mnemonic = "law bruise screen lunar than loft but franc strike asleep dwarf tavern dragon alarm " + \ + "snack queen meadow thing far cotton add emblem strive probe zurich edge peer alight " + \ + "libel won corn medal" + exp_result = '7ad1e6c1083de2081221056dd8b0c142cdfa3fd053cd4ae288ee324cd30e027462d8eaaffff445a1105b7e4fc1302894' + + self.assertEqual(exp_result, pyqrllib.bin2hstr(mnemonic2bin(long_mnemonic))) + + def test_mnemonic4(self): + bin = mnemonic2bin('absorb absorb') + tmp_mnemonic = bin2mnemonic(bin) + self.assertEqual('absorb absorb', tmp_mnemonic) + def test_exception(self): - i = 0 - try: - x = pyqrllib.hstr2bin('Z') - except Exception as e: - i = 1 - self.assertEqual(i, 1) - - i = 0 - try: - x = pyqrllib.hstr2bin('Z0') - except Exception as e: - i = 1 - self.assertEqual(i, 1) + with self.assertRaises(ValueError): + pyqrllib.hstr2bin('Z') + + with self.assertRaises(ValueError): + pyqrllib.hstr2bin('Z0') diff --git a/tests/python/test_qrlhelper.py b/tests/python/test_qrlhelper.py new file mode 100644 index 0000000..8914647 --- /dev/null +++ b/tests/python/test_qrlhelper.py @@ -0,0 +1,17 @@ +# Distributed under the MIT software license, see the accompanying +# file LICENSE or http://www.opensource.org/licenses/mit-license.php. + + +from __future__ import print_function + +from unittest import TestCase + +from pyqrllib import pyqrllib + + +class TestHelper(TestCase): + def __init__(self, *args, **kwargs): + super(TestHelper, self).__init__(*args, **kwargs) + + def test_empty(self): + self.assertFalse(pyqrllib.QRLHelper.addressIsValid(b'')) diff --git a/tests/python/test_shake.py b/tests/python/test_shake.py index f4bfd44..d0764a0 100644 --- a/tests/python/test_shake.py +++ b/tests/python/test_shake.py @@ -17,8 +17,6 @@ def __init__(self, *args, **kwargs): super(TestShake128, self).__init__(*args, **kwargs) def check_shake_result(self, data_text, expected): - size_out = 32 - hex_in_before = pyqrllib.bin2hstr(pyqrllib.str2bin(data_text)) data_out = pyqrllib.shake128(32, pyqrllib.str2bin(data_text)) diff --git a/tests/python/test_xmss.py b/tests/python/test_xmss.py index 446bb09..2931375 100644 --- a/tests/python/test_xmss.py +++ b/tests/python/test_xmss.py @@ -32,7 +32,7 @@ def test_xmss_creation_height4(self): tmp_addr = pyqrllib.QRLHelper.getAddress(xmss.getPK()) self.assertEqual(expected_address, pyqrllib.bin2hstr(tmp_addr)) - descr = pyqrllib.QRLHelper.extractDescriptor(xmss.getPK()) + descr = pyqrllib.QRLDescriptor.fromExtendedPK(xmss.getPK()) self.assertEqual(4, descr.getHeight()) self.assertEqual(pyqrllib.SHAKE_128, descr.getHashFunction()) @@ -55,7 +55,7 @@ def test_xmss_creation_height6(self): tmp_addr = pyqrllib.QRLHelper.getAddress(xmss.getPK()) self.assertEqual(expected_address, pyqrllib.bin2hstr(tmp_addr)) - descr = pyqrllib.QRLHelper.extractDescriptor(xmss.getPK()) + descr = pyqrllib.QRLDescriptor.fromExtendedPK(xmss.getPK()) self.assertEqual(6, descr.getHeight()) self.assertEqual(pyqrllib.SHAKE_128, descr.getHashFunction()) @@ -122,12 +122,12 @@ def test_xmss_exception_constructor(self): seed = pyqrllib.ucharVector(48, 0) with pytest.raises(ValueError): - xmss = pyqrllib.XmssFast(seed, HEIGHT, pyqrllib.SHAKE_128) + pyqrllib.XmssFast(seed, HEIGHT, pyqrllib.SHAKE_128) def test_xmss_exception_verify(self): message = pyqrllib.ucharVector(48, 0) signature = pyqrllib.ucharVector(2287, 0) - pk = pyqrllib.ucharVector(48, 0) + pk = pyqrllib.ucharVector(67, 0) self.assertFalse(pyqrllib.XmssFast.verify(message, signature, pk)) @@ -161,4 +161,4 @@ def test_xmss_change_index(self): xmss = pyqrllib.XmssFast(seed, HEIGHT, pyqrllib.SHAKE_128) xmss.setIndex(0) - self.assertEqual(0, xmss.getIndex()) \ No newline at end of file + self.assertEqual(0, xmss.getIndex()) diff --git a/travis/Dockerfile.xenial b/travis/Dockerfile.xenial deleted file mode 100644 index 211e26d..0000000 --- a/travis/Dockerfile.xenial +++ /dev/null @@ -1 +0,0 @@ -FROM zondax/qrl-build-images:xenial-qrllib diff --git a/travis/Dockerfile.xenial-emscripten b/travis/Dockerfile.xenial-emscripten deleted file mode 100644 index 0b3c4e9..0000000 --- a/travis/Dockerfile.xenial-emscripten +++ /dev/null @@ -1 +0,0 @@ -FROM zondax/qrl-build-images:xenial-emscripten diff --git a/travis/build.sh b/travis/build.sh deleted file mode 100755 index 7a0c80d..0000000 --- a/travis/build.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash - -set -e - -source ./travis/prepare.sh - -case "${TRAVIS_OS_NAME}" in - osx) - echo "OSX BUILD" - - export BUILD_DIR=build - mkdir -p ${BUILD_DIR} - cd ${BUILD_DIR} - cmake ${CMAKE_ARGS} .. - make - - if [ -n "${TEST:+1}" ]; then - echo "Running Tests" - export GTEST_COLOR=1 - ctest -VV - fi - ;; - - linux) - echo "LINUX BUILD " ${PLATFORM} - - USER_INFO="$( id -u ${USER} ):$( id -g ${USER} )" - SHARE_USER_INFO="-v /etc/group:/etc/group:ro -v /etc/passwd:/etc/passwd:ro -u ${USER_INFO}" - SHARE_SRC="-v $(pwd):/travis" - - docker stop $(docker ps -aq --filter name=builder) || true - docker rm $(docker ps -aq --filter name=builder) || true - docker build --file travis/Dockerfile.${PLATFORM} -t builder-${PLATFORM} . - docker run -d --name builder ${SHARE_SRC} ${SHARE_USER_INFO} builder-${PLATFORM} tail -f /dev/null - - docker exec -t -e CC_VER=${CC_VER} -e CMAKE_ARGS=${CMAKE_ARGS} -e TEST=${TEST} -e DEPLOY=${DEPLOY} builder /build.sh - ;; - *) - echo "UNSUPPORTED OS" - exit 1 - ;; -esac diff --git a/travis/clean_docker.sh b/travis/clean_docker.sh deleted file mode 100755 index 30d80bb..0000000 --- a/travis/clean_docker.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -docker stop builder -docker rm builder - diff --git a/travis/patch_npmversion.sh b/travis/patch_npmversion.sh deleted file mode 100755 index caa2f01..0000000 --- a/travis/patch_npmversion.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -pushd . > /dev/null -cd $( dirname "${BASH_SOURCE[0]}" ) -cd .. - -set -e -QRLLIB_VERSION=$(git describe --tags) - -sed -i 's|__QRLLIB_VERSION__|'${QRLLIB_VERSION}'|g' package.json - -popd > /dev/null diff --git a/travis/prepare.sh b/travis/prepare.sh deleted file mode 100755 index 5cb28ca..0000000 --- a/travis/prepare.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -echo "TRAVIS_OS_NAME" ${TRAVIS_OS_NAME} -echo "PLATFORM" ${PLATFORM} - -case "${TRAVIS_OS_NAME}" in - osx) - echo "OSX PREPARE" - brew install python3 swig - brew outdated boost || brew upgrade boost - brew outdated cmake || brew upgrade cmake - sudo pip3 install -U pip setuptools twine - ;; - - linux) - echo "LINUX PREPARE " ${PLATFORM} - ;; - *) - echo "UNSUPPORTED OS" - exit 1 - ;; -esac