mirror of
https://github.com/eosswedenorg/libantelope
synced 2026-06-16 11:44:55 +02:00
Compare commits
161 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4787573a76 | |||
| 11e086ee12 | |||
| cadb1ff984 | |||
| 1801c8424a | |||
| afc199e739 | |||
| 12e779c8cf | |||
| 9ad2e3cc00 | |||
| e15a5ede18 | |||
| 7e9bd41a83 | |||
| e0d0bcb0cb | |||
| 84645175c1 | |||
| 93f6b1b030 | |||
| ec7a67ad88 | |||
| c035a804b2 | |||
| 225a1947ae | |||
| 610c32c171 | |||
| 891d2e970d | |||
| be8096ed0f | |||
| 682ea069a2 | |||
| 596cf8c774 | |||
| b7a1298615 | |||
| ee4705e858 | |||
| 62b677d0e0 | |||
| 000876176a | |||
| fa7d3cb2e9 | |||
| b7063f3f3a | |||
| ac3facf30b | |||
| 7fc83991bc | |||
| c06846f7ed | |||
| a22825db9b | |||
| 3e38c587d3 | |||
| 98a1ce7fcc | |||
| aa6bff9a84 | |||
| 923384025a | |||
| 6824a2f49e | |||
| 0cfd459c71 | |||
| 9d11357490 | |||
| 424fe4702d | |||
| 2f56e8b43d | |||
| 18f35c66b5 | |||
| 86d75df2ec | |||
| 33d3440f53 | |||
| abecabba99 | |||
| 6026114869 | |||
| 815ab2569f | |||
| 9819b2b94d | |||
| be6c98f1bd | |||
| abdd84f257 | |||
| 171db63de4 | |||
| 1aa6906ba2 | |||
| ea411793a2 | |||
| 053f91c74b | |||
| 6793762fbb | |||
| 3abfc488e8 | |||
| ebb4219024 | |||
| 9114c17315 | |||
| f8630de098 | |||
| f606f7e263 | |||
| 2b68d7ec32 | |||
| 9ebc1e3aa1 | |||
| f936e1bbbc | |||
| e94b19031f | |||
| ea63d3e4ec | |||
| c4304e3d22 | |||
| 59e8ce473e | |||
| e069c38a15 | |||
| d9f7c41d8b | |||
| f65a7ee6cd | |||
| 91764f43de | |||
| 53e126cb62 | |||
| 259ca0f977 | |||
| 760c50a655 | |||
| b10911b21b | |||
| 78d90b622e | |||
| f920c7edee | |||
| 54fc8614ef | |||
| 2ab5e7b444 | |||
| d737fe4762 | |||
| 9587586968 | |||
| e8ee3fc0de | |||
| 8a55500854 | |||
| d853ed6f62 | |||
| f0ebda6da5 | |||
| 4aa94ebee9 | |||
| 073955ab50 | |||
| d695d1c9ad | |||
| e4150af355 | |||
| 88dacd22f8 | |||
| fdaab853ee | |||
| b1da6552f7 | |||
| 7ead6f6bde | |||
| fe873c1df8 | |||
| 95740d47b3 | |||
| a3efb5a5f2 | |||
| 15eaa97cec | |||
| 7ef801c2a8 | |||
| 640f67a934 | |||
| 73819444e5 | |||
| 8a6b476a8b | |||
| 6eaf6ebe71 | |||
| 171876bbfa | |||
| 4b8c1c7733 | |||
| d904fd38c3 | |||
| 6c6c7e2329 | |||
| b9c9e58050 | |||
| 0c9b867049 | |||
| ab932b92e4 | |||
| 07bee1e9e5 | |||
| 6b0d1aa459 | |||
| d7cdf9476d | |||
| 5f2fa977c3 | |||
| de7f1c3e19 | |||
| 9576e9d36f | |||
| 541eb089e8 | |||
| 2a2360bd7d | |||
| 6a721c4634 | |||
| 7be8afcd88 | |||
| 9e41381798 | |||
| 70866da335 | |||
| 0bc8fde4ad | |||
| c990bae52e | |||
| 65f93f061c | |||
| 12a3be919a | |||
| e712d4ec4d | |||
| 000f45e1f4 | |||
| 3336f8d051 | |||
| 4015399d47 | |||
| 82fc4b60cf | |||
| a99a23ae9b | |||
| ed59959b5b | |||
| a43b913277 | |||
| cc962e7bf8 | |||
| 8764ecc4c1 | |||
| dbbdc896e1 | |||
| 35c2c2fe79 | |||
| 47689bc621 | |||
| 8ec58c385f | |||
| bf73487abc | |||
| 77c93edc13 | |||
| 45c1f2909d | |||
| c17512f6ba | |||
| ae4dd4027f | |||
| d23aea0d19 | |||
| 7f0e3ec5f7 | |||
| c5409589b5 | |||
| 40b60c19be | |||
| a41b79967a | |||
| 569c1989a4 | |||
| 3b7cb0f4f6 | |||
| 2fa6220cea | |||
| 0af91b4fc6 | |||
| eab4aee8af | |||
| 19f6149e1e | |||
| aa70efe4ea | |||
| 56f056551e | |||
| 000f35cd9c | |||
| e7e92d2321 | |||
| c785da97de | |||
| b619ab78d4 | |||
| 45ae0b5791 | |||
| 010cd3a370 |
189 changed files with 70761 additions and 252 deletions
12
.github/workflows/CI.yml
vendored
12
.github/workflows/CI.yml
vendored
|
|
@ -10,10 +10,12 @@ on:
|
|||
jobs:
|
||||
compile:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-16.04, ubuntu-18.04, macos-latest, windows-latest ]
|
||||
os: [ ubuntu-20.04, ubuntu-22.04, macos-latest, windows-latest ]
|
||||
ec_lib: [ openssl, libsecp256k1 ]
|
||||
|
||||
name: ${{matrix.os}}
|
||||
name: ${{matrix.os}} - ${{matrix.ec_lib}}
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
|
|
@ -30,12 +32,16 @@ jobs:
|
|||
if [ "$RUNNER_OS" == "macOS" ]; then
|
||||
SSL_OPTS="-D OPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1"
|
||||
fi
|
||||
cmake ${SSL_OPTS} -B build
|
||||
cmake -DBUILD_TESTING=ON ${SSL_OPTS} -DEC_LIB=${{matrix.ec_lib}} -B build
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: cmake --build build
|
||||
|
||||
- name: Test
|
||||
shell: bash
|
||||
run: ctest --verbose --test-dir build -C Debug
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
|
|
|
|||
4
.github/workflows/package.yml
vendored
4
.github/workflows/package.yml
vendored
|
|
@ -9,7 +9,7 @@ jobs:
|
|||
ubuntu:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-16.04, ubuntu-18.04 ]
|
||||
os: [ ubuntu-20.04, ubuntu-22.04 ]
|
||||
name: ${{matrix.os}}
|
||||
runs-on: ${{matrix.os}}
|
||||
steps:
|
||||
|
|
@ -62,7 +62,7 @@ jobs:
|
|||
id: package
|
||||
run: |
|
||||
cmake --build build --config Release --target package
|
||||
$FILE=(ls build/libeosio*.zip)
|
||||
$FILE=(ls build/libantelope*.zip)
|
||||
echo "::set-output name=filename::$FILE"
|
||||
echo "::set-output name=name::$(([io.fileinfo]"$FILE").basename).zip"
|
||||
|
||||
|
|
|
|||
124
CMakeLists.txt
124
CMakeLists.txt
|
|
@ -5,11 +5,11 @@ cmake_minimum_required(VERSION 3.15)
|
|||
# --------------------------------
|
||||
|
||||
# Project name and version
|
||||
project(libeosio
|
||||
VERSION 0.1.0
|
||||
DESCRIPTION "C++ library for EOSIO"
|
||||
HOMEPAGE_URL "https://github.com/eosswedenorg/libeosio"
|
||||
LANGUAGES CXX
|
||||
project(libantelope
|
||||
VERSION 0.2.2
|
||||
DESCRIPTION "C++ library for Antelope IO"
|
||||
HOMEPAGE_URL "https://github.com/eosswedenorg/libantelope"
|
||||
LANGUAGES C CXX
|
||||
)
|
||||
|
||||
set( PROJECT_MAINTAINER "Henrik Hautakoski <henrik@eossweden.org>")
|
||||
|
|
@ -20,6 +20,12 @@ set( PROJECT_MAINTAINER "Henrik Hautakoski <henrik@eossweden.org>")
|
|||
|
||||
set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake" )
|
||||
|
||||
# --------------------------------
|
||||
# Options
|
||||
# --------------------------------
|
||||
|
||||
option(WITH_BENCHMARK "If tests are enabled (BUILD_TESTING variable), also build benchmark tree." OFF)
|
||||
|
||||
# --------------------------------
|
||||
# Compiler
|
||||
# --------------------------------
|
||||
|
|
@ -28,44 +34,114 @@ set( CMAKE_CXX_STANDARD 11 )
|
|||
set( CMAKE_CXX_STANDARD_REQUIRED ON )
|
||||
set( CMAKE_CXX_EXTENSIONS OFF )
|
||||
|
||||
add_compile_options(
|
||||
"$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wall;-Wconversion;-Wno-sign-conversion;-Wextra>"
|
||||
"$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/W3;-D_CRT_SECURE_NO_WARNINGS=1>"
|
||||
|
||||
# Debug
|
||||
"$<$<CONFIG:Debug>:$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-O0;-g>>"
|
||||
"$<$<CONFIG:Debug>:$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/Od;/Zi>>"
|
||||
|
||||
# Release
|
||||
"$<$<CONFIG:Release>:$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-O3>>"
|
||||
"$<$<CONFIG:Release>:$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/O2>>"
|
||||
|
||||
# MinSizeRel
|
||||
"$<$<CONFIG:MinSizeRel>:$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Os>>"
|
||||
"$<$<CONFIG:MinSizeRel>:$<$<COMPILE_LANG_AND_ID:CXX,MSVC>:/O1>>"
|
||||
)
|
||||
|
||||
# OpenSSL 3.0 deprecates some functions we use.
|
||||
# Adding this flag makes the compiler not spam warnings.
|
||||
add_compile_options(-D OPENSSL_API_COMPAT=0x10100000L)
|
||||
|
||||
# --------------------------------
|
||||
# Options
|
||||
# --------------------------------
|
||||
set(EC_LIB "libsecp256k1" CACHE STRING "What elliptic curve implementation to use")
|
||||
|
||||
# --------------------------------
|
||||
# Library
|
||||
# --------------------------------
|
||||
|
||||
set( LIB_NAME ${PROJECT_NAME} )
|
||||
|
||||
set( LIB_SOURCE
|
||||
add_library( ${LIB_NAME} STATIC
|
||||
src/base58.cpp
|
||||
src/ec.cpp
|
||||
src/WIF.cpp
|
||||
)
|
||||
src/wif/k1.cpp
|
||||
src/wif/legacy.cpp
|
||||
|
||||
# OpenSSL
|
||||
include(OpenSSL)
|
||||
set (LIB_SOURCE ${LIB_SOURCE}
|
||||
src/openssl/ec.cpp
|
||||
src/openssl/hash.cpp
|
||||
)
|
||||
|
||||
add_library( ${LIB_NAME} STATIC ${LIB_SOURCE} )
|
||||
target_include_directories( ${LIB_NAME}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
|
||||
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
# Skip prefix on unix.
|
||||
if (UNIX)
|
||||
set_target_properties(${LIB_NAME} PROPERTIES PREFIX "")
|
||||
endif()
|
||||
|
||||
# OpenSSL
|
||||
include(OpenSSL)
|
||||
target_link_libraries( ${LIB_NAME} PRIVATE OpenSSL::Crypto)
|
||||
|
||||
target_link_libraries( ${LIB_NAME}
|
||||
INTERFACE
|
||||
${OPENSSL_CRYPTO_LIBRARY}
|
||||
)
|
||||
# Hash implementation
|
||||
set( LIBANTELOPE_HASHIMPL_OPENSSL 1 )
|
||||
|
||||
target_include_directories( ${LIB_NAME}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
PRIVATE
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
# EC Implementation
|
||||
if (${EC_LIB} STREQUAL "libsecp256k1")
|
||||
add_subdirectory( vendor/secp256k1 )
|
||||
# Note: this is a big hack to get cmake to not export this library.
|
||||
# Must be a better way, but works so cba.
|
||||
target_include_directories( ${LIB_NAME}
|
||||
PRIVATE $<BUILD_INTERFACE:$<TARGET_PROPERTY:secp256k1,INCLUDE_DIRECTORIES>>
|
||||
)
|
||||
target_sources( ${LIB_NAME} PRIVATE
|
||||
$<TARGET_OBJECTS:secp256k1>
|
||||
src/libsecp256k1/ec.cpp
|
||||
src/libsecp256k1/ecdsa.cpp
|
||||
)
|
||||
|
||||
# Need to link to bcrypt on windows as BCryptGenRandom is
|
||||
# used by fill_random in src/libsecp256k1/rng.h
|
||||
if (WIN32)
|
||||
target_link_libraries( ${LIB_NAME} PRIVATE "bcrypt.lib" )
|
||||
endif (WIN32)
|
||||
|
||||
elseif (${EC_LIB} STREQUAL "openssl")
|
||||
target_sources( ${LIB_NAME} PRIVATE
|
||||
src/openssl/ec.cpp
|
||||
src/openssl/ecdsa.cpp
|
||||
src/openssl/helpers.c
|
||||
src/openssl/recovery.c
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid ec implementation: " ${EC_LIB})
|
||||
endif()
|
||||
|
||||
message("-- Using Elliptic curve library: ${EC_LIB}")
|
||||
|
||||
# Generate config file
|
||||
configure_file(src/config.in.h ${CMAKE_BINARY_DIR}/include/libantelope/config.h)
|
||||
|
||||
# --------------------------------
|
||||
# Tests
|
||||
# --------------------------------
|
||||
|
||||
include(CTest)
|
||||
|
||||
if (BUILD_TESTING)
|
||||
# enable testing functionality
|
||||
enable_testing()
|
||||
add_subdirectory( tests )
|
||||
endif (BUILD_TESTING)
|
||||
|
||||
# --------------------------------
|
||||
# Install
|
||||
|
|
@ -91,7 +167,7 @@ install(TARGETS ${LIB_NAME} EXPORT ${PROJECT_NAME}Targets
|
|||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(DIRECTORY include/ ${CMAKE_BINARY_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
# Readme and license
|
||||
install(FILES README.md LICENSE LICENSE.bitcoin
|
||||
|
|
|
|||
2
LICENSE
2
LICENSE
|
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019-2020 EOS Sw/eden
|
||||
Copyright (c) 2019-2023 EOS Sw/eden
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
110
README.md
110
README.md
|
|
@ -1,114 +1,110 @@
|
|||

|
||||
[](https://github.com/eosswedenorg/libeosio/releases/latest)
|
||||

|
||||
[](https://github.com/eosswedenorg/libantelope/releases/latest)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
|
||||
# libeosio
|
||||
# libantelope
|
||||
|
||||
Independent C++ library for [EOS](https://eos.io/)
|
||||
|
||||
NOTE: This repository has no connection to the official EOS code.
|
||||
libantelope is an independent C++ library designed for Antelope IO (formerly known as libeosio). Please note that this repository is not affiliated with the official Antelope code.
|
||||
|
||||
## Compiling the library
|
||||
|
||||
You will need `openssl` development files (version 1.1 or later) to compile and `cmake 3.15` or later to compile this project.
|
||||
To compile this project, you will need the following:
|
||||
|
||||
- `openssl` development files (version 1.1 or later)
|
||||
- `cmake 3.15` or later
|
||||
|
||||
### Elliptic curve backend
|
||||
|
||||
The library offers two different backend implementations for the elliptic curve functionality:
|
||||
|
||||
- `libsecp256k1`
|
||||
- `OpenSSL`: Although the default is to use `libsecp256k1` for optimization, you still need to link to OpenSSL as other parts of the codebase rely on it.
|
||||
|
||||
To switch the implementation, modify the `EC_LIB` variable in the cmake.
|
||||
|
||||
### CMake
|
||||
|
||||
You can install `cmake` by reading the [official guide](https://cmake.org/install).
|
||||
You can install `cmake` by referring to the [official guide](https://cmake.org/install).
|
||||
|
||||
### Linux
|
||||
|
||||
**NOTE:** Only Ubuntu versions `20.04` and `22.04` are officially supported.
|
||||
|
||||
While the project should compile fine on most versions/distros, it is only tested and distributed for Ubuntu `20.04` and `22.04` by [Sw/eden](https://www.eossweden.org).
|
||||
|
||||
#### Dependencies
|
||||
|
||||
**Ubuntu (or other debian based distros)**
|
||||
**Ubuntu (or other Debian-based distros)**
|
||||
|
||||
First you need to have a compiler, `openssl` and `cmake`. this can be installed with apt.
|
||||
To install the necessary dependencies (compiler, `openssl`, and `cmake`), use the following `apt` command:
|
||||
|
||||
```sh
|
||||
$ apt-get install gcc g++ cmake libssl-dev
|
||||
apt-get install gcc g++ cmake libssl-dev
|
||||
```
|
||||
If you need a newer version of cmake then apt provides.
|
||||
Checkout the official [CMake APT repository](https://apt.kitware.com/).
|
||||
|
||||
If you require a newer version of `cmake`, you can refer to the [official CMake APT repository](https://apt.kitware.com/).
|
||||
|
||||
**Other**
|
||||
|
||||
Consult your package manager's manual for getting `openssl`,`g++` and `cmake` installed.
|
||||
|
||||
If you need a newer version of cmake then your package manager provides. checkout the [official guide](https://cmake.org/install).
|
||||
For other distros, please consult your package manager's manual to install `openssl`, `g++`, and `cmake`. If you need a newer version of `cmake`, you can follow the [official installation guide](https://cmake.org/install).
|
||||
|
||||
### MacOS
|
||||
|
||||
#### Dependencies
|
||||
|
||||
You must have a compiler installed. This project is known to build with `Xcode 11.0` but other versions should work.
|
||||
Ensure that you have a compiler installed. This project is known to build with `Xcode 11.0`, but other versions should work as well.
|
||||
|
||||
To install `openssl` and `cmake`, you can use the following `brew` command:
|
||||
|
||||
You need to have openssl and cmake installed also, this can be done with this `brew` command:
|
||||
```sh
|
||||
$ brew install openssl cmake
|
||||
brew install openssl cmake
|
||||
```
|
||||
|
||||
If you need a newer version of cmake then brew provides. checkout the [official guide](https://cmake.org/install)
|
||||
If you require a newer version of `cmake`, refer to the [official installation guide](https://cmake.org/install).
|
||||
|
||||
#### Build
|
||||
|
||||
```sh
|
||||
$ mkdir build && cd build
|
||||
$ cmake .. && make
|
||||
mkdir build && cd build
|
||||
cmake .. && make
|
||||
```
|
||||
|
||||
**MacOS:** You may need to point `cmake` to `openssl` by passing the argument
|
||||
`-D OPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1` if openssl is not under `/usr/local/opt/openssl@1.1` you need to find the correct path.
|
||||
**MacOS:** If your `openssl` installation is not located at `/usr/local/opt/openssl@1.1`, you may need to pass the argument `-D OPENSSL_ROOT_DIR=/path/to/openssl` to `cmake` and specify the correct path.
|
||||
|
||||
### Windows
|
||||
|
||||
#### Dependencies
|
||||
|
||||
First you will need a compiler.
|
||||
First, ensure that you have a compiler installed.
|
||||
|
||||
[Build Tools for Visual Studio 2019](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16) (Selecting C++ during installation) is recommended.
|
||||
It is recommended to use [Build Tools for Visual Studio 2019](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16) and select C++ during installation.
|
||||
|
||||
By default `cmake` will use the bundled openssl package located at `vendor/openssl-1.1.1e-win-static.zip`
|
||||
By default, `cmake` will utilize the bundled OpenSSL package located at `vendor/openssl-1.1.1e-win-static.zip`. If you prefer to use a different version of OpenSSL, set the `OPENSSL_ROOT_DIR` to the directory where OpenSSL is located on your system:
|
||||
|
||||
If you like to use an other version of OpenSSL then the static one bundled with this repo
|
||||
you need to set `OPENSSL_ROOT_DIR` to the directory where OpenSSL is located on the system.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
C:\repo> cmake -D OPENSSL_ROOT_DIR=C:/path/to/openssl -B build
|
||||
```sh
|
||||
cmake -D OPENSSL_ROOT_DIR=C:/path/to/openssl -B build
|
||||
```
|
||||
|
||||
**NOTE:** `cmake` uses forward slash `/` for path even for windows. so make sure you use that when setting `OPENSSL_ROOT_DIR`
|
||||
**NOTE:** `cmake` uses forward slashes `/` for paths, even on Windows, so ensure that you use them when setting
|
||||
|
||||
#### Build.
|
||||
`OPENSSL_ROOT_DIR`.
|
||||
|
||||
Run cmake
|
||||
#### Build
|
||||
|
||||
```
|
||||
C:\repo> cmake -B build
|
||||
C:\repo> cmake --build build --config Release
|
||||
Run `cmake`:
|
||||
|
||||
```sh
|
||||
cmake -B build
|
||||
cmake --build build --config Release
|
||||
```
|
||||
|
||||
## Security notice
|
||||
## Security Notice
|
||||
|
||||
Keys are generated by `OpenSSL`'s `EC_KEY_generate_key` function. The program will
|
||||
never expose your keys to anything but the computers memory and output of the
|
||||
program. You are free to inspect the source code and compile yourself to verify.
|
||||
The library performs elliptic curve cryptographic operations using either the `OpenSSL` or `libsecp256k1` libraries. The `libantelope` library ensures that sensitive cryptographic information is only stored in computer memory and not exposed to external sources. You are encouraged to inspect the source code and compile it yourself for verification purposes.
|
||||
|
||||
However, use this at your own risk. we cannot guarantee that the keys are
|
||||
cryptographically secure as this depends on OpenSSL's implementation (alto it is
|
||||
widely used and should be safe)
|
||||
However, please use this library at your own risk. While both OpenSSL and libsecp256k1 are widely used and considered safe, we cannot guarantee the cryptographic security of the keys as it depends on the elliptic curve implementation.
|
||||
|
||||
Please read the `LICENSE` file.
|
||||
|
||||
```
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
```
|
||||
Please refer to the `LICENSE` file for more information.
|
||||
|
||||
## Author
|
||||
|
||||
|
|
|
|||
|
|
@ -24,4 +24,5 @@ find_package(OpenSSL 1.1 REQUIRED)
|
|||
# Bug in FindOpenSSL. Win needs to link to these if static libs are used.
|
||||
if (WIN32 AND OPENSSL_USE_STATIC_LIBS)
|
||||
set (OPENSSL_CRYPTO_LIBRARY "${OPENSSL_CRYPTO_LIBRARY};Crypt32;ws2_32")
|
||||
target_link_libraries(OpenSSL::Crypto INTERFACE "Crypt32;ws2_32")
|
||||
endif()
|
||||
|
|
|
|||
26
cmake/libantelopeConfig.cmake.in
Normal file
26
cmake/libantelopeConfig.cmake.in
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# This script provides the libantelope as an import target
|
||||
# ----------------------------------------------------------
|
||||
#
|
||||
# Use find_package() so cmake will find libantelope:
|
||||
#
|
||||
# find_package(libantelope) # No specific version
|
||||
# find_package(libantelope REQUIRED) # No specific version, but the library must be found.
|
||||
# find_package(libantelope 0.1) # any 0.1.x, but the library is optional.
|
||||
# find_package(libeantelope 0.1.0) # 0.1.0 or greater, but the library is optional.
|
||||
#
|
||||
# Then you just link the you target with libantelope target:
|
||||
#
|
||||
# target_link_libraries( ${PROGRAM_EXE} PUBLIC libantelope )
|
||||
#
|
||||
# if you do not specify REQUIRED. you must check the variable libantelope_FOUND
|
||||
# and and only link to it if it's defined:
|
||||
#
|
||||
# if (libantelope_FOUND)
|
||||
# ...
|
||||
# target_link_libraries( ${PROGRAM_EXE} PUBLIC libantelope )
|
||||
# ..
|
||||
# endif()
|
||||
|
||||
set( LIBANTELOPE_VERSION "@PROJECT_VERSION@" )
|
||||
|
||||
include ( "${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake" )
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
# This script provides the libeosio as an import target
|
||||
# ----------------------------------------------------------
|
||||
#
|
||||
# Use find_package() so cmake will find libeosio:
|
||||
#
|
||||
# find_package(libeosio) # No specific version
|
||||
# find_package(libeosio REQUIRED) # No specific version, but the library must be found.
|
||||
# find_package(libeosio 0.1) # any 0.1.x, but the library is optional.
|
||||
# find_package(libeosio 0.1.0) # 0.1.0 or greater, but the library is optional.
|
||||
#
|
||||
# Then you just link the you target with eoskeygen target:
|
||||
#
|
||||
# target_link_libraries( ${PROGRAM_EXE} PUBLIC libeosio )
|
||||
#
|
||||
# if you do not specify REQUIRED. you must check the variable libeosio_FOUND
|
||||
# and and only link to it if it's defined:
|
||||
#
|
||||
# if (libeosio_FOUND)
|
||||
# ...
|
||||
# target_link_libraries( ${PROGRAM_EXE} PUBLIC libeosio )
|
||||
# ..
|
||||
# endif()
|
||||
|
||||
set(LIBEOSIO_VERSION "@PROJECT_VERSION@")
|
||||
|
||||
include ( "${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake" )
|
||||
99
include/libantelope/WIF.hpp
Normal file
99
include/libantelope/WIF.hpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBANTELOPE_WIF_H
|
||||
#define LIBANTELOPE_WIF_H
|
||||
|
||||
#include <string>
|
||||
#include <libantelope/ec.hpp>
|
||||
|
||||
namespace libantelope {
|
||||
|
||||
/**
|
||||
* Key prefixes. (strings that is not equal to these prefixes are treated as legacy format.)
|
||||
*/
|
||||
extern const std::string WIF_PUB_LEG;
|
||||
extern const std::string WIF_PUB_K1;
|
||||
extern const std::string WIF_PVT_LEG;
|
||||
extern const std::string WIF_PVT_K1;
|
||||
extern const std::string WIF_SIG_K1;
|
||||
|
||||
/**
|
||||
* Codecs
|
||||
*/
|
||||
|
||||
// A WIF Codec is an public and private key prefix pair.
|
||||
typedef struct {
|
||||
std::string pub;
|
||||
std::string pvt;
|
||||
} wif_codec_t;
|
||||
|
||||
extern const wif_codec_t WIF_CODEC_K1;
|
||||
extern const wif_codec_t WIF_CODEC_LEG;
|
||||
|
||||
inline wif_codec_t wif_create_legacy_codec(const std::string& pub_prefix) {
|
||||
return { pub_prefix, WIF_PVT_LEG };
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode an EC private key to WIF String.
|
||||
*/
|
||||
std::string wif_priv_encode(const ec_privkey_t& priv, const std::string& prefix = WIF_PVT_K1);
|
||||
|
||||
/**
|
||||
* Decode an WIF String to EC private key
|
||||
*/
|
||||
bool wif_priv_decode(ec_privkey_t& priv, const std::string& data);
|
||||
|
||||
/**
|
||||
* Encode an EC public key to WIF String.
|
||||
*/
|
||||
std::string wif_pub_encode(const ec_pubkey_t& pub, const std::string& prefix = WIF_PUB_K1);
|
||||
|
||||
/**
|
||||
* Decode an WIF String to EC public key
|
||||
*/
|
||||
bool wif_pub_decode(ec_pubkey_t& pub, const std::string& data);
|
||||
|
||||
/**
|
||||
* Prints an EC keypair in WIF format to standard out.
|
||||
*/
|
||||
void wif_print_key(const struct ec_keypair *key, const wif_codec_t& codec = WIF_CODEC_K1);
|
||||
|
||||
/**
|
||||
* Signatures
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encode an EC signature to WIF String.
|
||||
*/
|
||||
std::string wif_sig_encode(const ec_signature_t& sig);
|
||||
|
||||
/**
|
||||
* Decode an WIF String to EC signature
|
||||
*/
|
||||
bool wif_sig_decode(ec_signature_t& sig, const std::string& data);
|
||||
|
||||
} // namespace libantelope
|
||||
|
||||
#endif /* LIBANTELOPE_WIF_H */
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2020 EOS Sw/eden
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -21,26 +21,46 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBEOSIO_BASE58_H
|
||||
#define LIBEOSIO_BASE58_H
|
||||
#ifndef LIBANTELOPE_BASE58_H
|
||||
#define LIBANTELOPE_BASE58_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace libeosio {
|
||||
namespace libantelope {
|
||||
|
||||
/**
|
||||
* Base58 Encoding functions.
|
||||
*/
|
||||
std::string base58_encode(const std::string& str);
|
||||
std::string base58_encode(const std::vector<unsigned char>& vch);
|
||||
std::string base58_encode(const unsigned char* pbegin, const unsigned char* pend);
|
||||
|
||||
|
||||
/**
|
||||
* Base58 Decoding functions.
|
||||
*/
|
||||
bool base58_decode(const char* psz, std::vector<unsigned char>& out);
|
||||
bool base58_decode(const std::string& str, std::vector<unsigned char>& out);
|
||||
|
||||
/**
|
||||
* Returns true if `ch` is a base58 character, false otherwise.
|
||||
*/
|
||||
bool is_base58(char ch);
|
||||
|
||||
// Returns std::string::npos if the string contains only base58 characters
|
||||
// Otherwise the position of the first non base58 character is returned.
|
||||
/**
|
||||
* Returns std::string::npos if the string contains only base58 characters
|
||||
* Otherwise the position of the first non base58 character is returned.
|
||||
*/
|
||||
size_t is_base58(const std::string& str);
|
||||
|
||||
/**
|
||||
* Strips all non-base58 characters from `str`.
|
||||
* The string is modified in place and the same string is
|
||||
* returned without non-base58 chars.
|
||||
*/
|
||||
std::string& base58_strip(std::string& str);
|
||||
|
||||
} //namespace eoskeygen
|
||||
} //namespace libantelope
|
||||
|
||||
#endif /* LIBEOSIO_BASE58_H */
|
||||
#endif /* LIBANTELOPE_BASE58_H */
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2020 EOS Sw/eden
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -21,34 +21,53 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBEOSIO_CHECKSUM_H
|
||||
#define LIBEOSIO_CHECKSUM_H
|
||||
#ifndef LIBANTELOPE_CHECKSUM_H
|
||||
#define LIBANTELOPE_CHECKSUM_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
#include <libeosio/hash.hpp>
|
||||
#include <libantelope/hash.hpp>
|
||||
|
||||
namespace libeosio {
|
||||
namespace libantelope {
|
||||
|
||||
/**
|
||||
* Checksum size (in bytes)
|
||||
*/
|
||||
#define CHECKSUM_SIZE 4
|
||||
|
||||
typedef std::array<unsigned char, CHECKSUM_SIZE> checksum_t;
|
||||
/**
|
||||
* Checksum datatype
|
||||
*/
|
||||
typedef unsigned char checksum_t[CHECKSUM_SIZE];
|
||||
|
||||
/**
|
||||
* Checksum template function.
|
||||
* Template arguments:
|
||||
* - T: Hash type.
|
||||
* - F: Hash calculation function, should have the signature `T* F(const unsigned char *, std::size_t, T*)`
|
||||
*/
|
||||
template <typename T, T* (*F)(const unsigned char *, std::size_t, T*)>
|
||||
inline checksum_t checksum(const unsigned char* data, std::size_t len) {
|
||||
checksum_t crc;
|
||||
inline void checksum(const unsigned char* data, std::size_t len, checksum_t crc) {
|
||||
T hash;
|
||||
|
||||
F(data, len, &hash);
|
||||
std::memcpy(crc.data(), &hash, crc.size());
|
||||
return crc;
|
||||
std::memcpy(crc, &hash, CHECKSUM_SIZE);
|
||||
}
|
||||
|
||||
template <void (*F)(const unsigned char *, std::size_t, checksum_t)>
|
||||
inline bool checksum_validate(const unsigned char* data, std::size_t len) {
|
||||
checksum_t crc;
|
||||
F(data, len - CHECKSUM_SIZE, crc);
|
||||
return !memcmp(crc, data + (len - CHECKSUM_SIZE), CHECKSUM_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checksum implementations.
|
||||
*/
|
||||
#define checksum_sha256 checksum<sha256_t, sha256>
|
||||
#define checksum_sha256d checksum<sha256_t, sha256d>
|
||||
#define checksum_ripemd160 checksum<ripemd160_t, ripemd160>
|
||||
|
||||
} // namespace libeosio
|
||||
} // namespace libantelope
|
||||
|
||||
#endif /* LIBEOSIO_CHECKSUM_H */
|
||||
#endif /* LIBANTELOPE_CHECKSUM_H */
|
||||
140
include/libantelope/ec.hpp
Normal file
140
include/libantelope/ec.hpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBANTELOPE_EC_H
|
||||
#define LIBANTELOPE_EC_H
|
||||
|
||||
#include <libantelope/hash.hpp>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
|
||||
namespace libantelope {
|
||||
|
||||
/**
|
||||
* Elliptic curve private key size (in bytes)
|
||||
*/
|
||||
#define EC_PRIVKEY_SIZE 32
|
||||
|
||||
/**
|
||||
* Elliptic curve public key size (in bytes)
|
||||
*
|
||||
* Compressed format: z||x, where byte z specifies which (of the 2) solutions
|
||||
* of the quadratic equation y is. Each cordinate is 32 bytes.
|
||||
*/
|
||||
#define EC_PUBKEY_SIZE (32 + 1)
|
||||
|
||||
/**
|
||||
* Elliptic curve priv/pub key datastructures.
|
||||
*/
|
||||
typedef std::array<unsigned char, EC_PRIVKEY_SIZE> ec_privkey_t;
|
||||
typedef std::array<unsigned char, EC_PUBKEY_SIZE> ec_pubkey_t;
|
||||
|
||||
/**
|
||||
* Elliptic curve keypair (public + private)
|
||||
*/
|
||||
struct ec_keypair {
|
||||
ec_privkey_t secret;
|
||||
ec_pubkey_t pub;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Elliptic curve recoverable signature
|
||||
*
|
||||
* The signature consist of 2 integers r,s and v where
|
||||
* r: x cordinate of the random point
|
||||
* s: signature proof
|
||||
* v: recovery id (0, 1, 2 or 3), eg. what EC point is the public key.
|
||||
*
|
||||
* The memory layout is as follows:
|
||||
* r(32), s(32), v(1) = 65 bytes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Elliptic curve signature key size (in bytes)
|
||||
*/
|
||||
#define EC_SIGNATURE_SIZE (32 + 32 + 1)
|
||||
|
||||
/**
|
||||
* Elliptic curve signature datastructure.
|
||||
*/
|
||||
typedef std::array<unsigned char, EC_SIGNATURE_SIZE> ec_signature_t;
|
||||
|
||||
/**
|
||||
* Initialize the ec library.
|
||||
*/
|
||||
int ec_init();
|
||||
|
||||
/**
|
||||
* Generates an new random private key using the secp256k1 curve.
|
||||
*/
|
||||
int ec_generate_privkey(ec_privkey_t *priv);
|
||||
|
||||
/**
|
||||
* Get the public key from an private key.
|
||||
*/
|
||||
int ec_get_publickey(const ec_privkey_t *priv, ec_pubkey_t* pub);
|
||||
|
||||
/**
|
||||
* Generates a keypair using the secp256k1 curve.
|
||||
* public key is in compressed format.
|
||||
*/
|
||||
int ec_generate_key(struct ec_keypair *pair);
|
||||
|
||||
|
||||
/**
|
||||
* Sign
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a ECDSA signature, returns -1 if an error occured or zero on success.
|
||||
*/
|
||||
int ecdsa_sign(const ec_privkey_t& key, const sha256_t* digest, ec_signature_t& sig);
|
||||
|
||||
/**
|
||||
* Verify an ECDSA signature,
|
||||
* returns zero if the signature is correct. -1 if the signature is incorrect or an error occured.
|
||||
*/
|
||||
int ecdsa_verify(const sha256_t* digest, const ec_signature_t& sig, const ec_pubkey_t& key);
|
||||
|
||||
/**
|
||||
* Recover the public key from the signature.
|
||||
* returns zero if the public key could be extracted. -1 if an error occured.
|
||||
*/
|
||||
int ecdsa_recover(const sha256_t* digest, const ec_signature_t& sig, ec_pubkey_t& key);
|
||||
|
||||
/**
|
||||
* Shutdown the ec library.
|
||||
*/
|
||||
void ec_shutdown();
|
||||
|
||||
} // namespace libantelope
|
||||
|
||||
|
||||
// Stream operators
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const libantelope::ec_privkey_t& pk);
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const libantelope::ec_pubkey_t& pk);
|
||||
|
||||
#endif /* LIBANTELOPE_EC_H */
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2020 EOS Sw/eden
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -21,19 +21,10 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBEOSIO_EC_H
|
||||
#define LIBEOSIO_EC_H
|
||||
#ifndef LIBANTELOPE_HASH_H
|
||||
#define LIBANTELOPE_HASH_H
|
||||
|
||||
#include <libeosio/types.hpp>
|
||||
#include <libantelope/hash/sha256.hpp>
|
||||
#include <libantelope/hash/ripemd160.hpp>
|
||||
|
||||
namespace libeosio {
|
||||
|
||||
/**
|
||||
* Generates a keypair using the secp256k1 curve.
|
||||
* public key is in compressed format.
|
||||
*/
|
||||
int ec_generate_key(struct ec_keypair *pair);
|
||||
|
||||
} // namespace eoskeygen
|
||||
|
||||
#endif /* LIBEOSIO_EC_H */
|
||||
#endif /* LIBANTELOPE_HASH_H */
|
||||
62
include/libantelope/hash/ripemd160.hpp
Normal file
62
include/libantelope/hash/ripemd160.hpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2023 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBANTELOPE_HASH_RIPEMD160_H
|
||||
#define LIBANTELOPE_HASH_RIPEMD160_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <libantelope/internal/hash.hpp>
|
||||
|
||||
namespace libantelope {
|
||||
|
||||
typedef unsigned char ripemd160_t[20];
|
||||
|
||||
typedef internal::ripemd160_state ripemd160_ctx_t;
|
||||
|
||||
/**
|
||||
* Initialize a ripmemd160_ctx_t structure
|
||||
*/
|
||||
int ripemd160_init(ripemd160_ctx_t* ctx);
|
||||
|
||||
/**
|
||||
* Update the RipeMD160 hash value with the contents in `data` up to `len` bytes.
|
||||
* This can be called repeatedly to hash chunks of data.
|
||||
*/
|
||||
int ripemd160_update(ripemd160_ctx_t* ctx, const void *data, std::size_t len);
|
||||
|
||||
/**
|
||||
* Places the RipeMD160 message digest in out variable.
|
||||
* The ctx's internal state is reset after this operation.
|
||||
*/
|
||||
int ripemd160_final(ripemd160_ctx_t* ctx, ripemd160_t* out);
|
||||
|
||||
/**
|
||||
* RipeMD160 hashing function.
|
||||
* Hashes the content in `data` up to `len` bytes. The result is stored in `out`.
|
||||
* Returns the same pointer as `out`.
|
||||
*/
|
||||
ripemd160_t* ripemd160(const unsigned char *data, std::size_t len, ripemd160_t* out);
|
||||
|
||||
} // namespace libantelope
|
||||
|
||||
#endif /* LIBANTELOPE_RIPEMD160_H */
|
||||
69
include/libantelope/hash/sha256.hpp
Normal file
69
include/libantelope/hash/sha256.hpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2023 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBANTELOPE_HASH_SHA256_H
|
||||
#define LIBANTELOPE_HASH_SHA256_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <libantelope/internal/hash.hpp>
|
||||
|
||||
namespace libantelope {
|
||||
|
||||
typedef unsigned char sha256_t[32];
|
||||
|
||||
typedef internal::sha256_state sha256_ctx_t;
|
||||
|
||||
/**
|
||||
* Initialize a sha256_ctx_t structure
|
||||
*/
|
||||
int sha256_init(sha256_ctx_t* ctx);
|
||||
|
||||
/**
|
||||
* Update the sha256 hash value with the contents in `data` up to `len` bytes.
|
||||
* This can be called repeatedly to hash chunks of data.
|
||||
*/
|
||||
int sha256_update(sha256_ctx_t* ctx, const void *data, std::size_t len);
|
||||
|
||||
/**
|
||||
* Place the message digest in out variable.
|
||||
* The ctx's internal state is reset after this operation.
|
||||
*/
|
||||
int sha256_final(sha256_ctx_t* ctx, sha256_t* out);
|
||||
|
||||
/**
|
||||
* sha256 hashing function.
|
||||
* Hashes the content in `data` up to `len` bytes. The result is stored in `out`.
|
||||
* Returns the same pointer as `out`.
|
||||
*/
|
||||
sha256_t* sha256(const unsigned char *data, std::size_t len, sha256_t* out);
|
||||
|
||||
/**
|
||||
* sha256 double hashing function.
|
||||
* Hashes the content in `data` up to `len` bytes. The result is stored in `out`.
|
||||
* Returns the same pointer as `out`.
|
||||
*/
|
||||
sha256_t* sha256d(const unsigned char *data, std::size_t len, sha256_t* out);
|
||||
|
||||
} // namespace libantelope
|
||||
|
||||
#endif /* LIBANTELOPE_HASH_SHA256_H */
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2020 EOS Sw/eden
|
||||
* Copyright (c) 2019-2023 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -21,21 +22,21 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBEOSIO_HASH_H
|
||||
#define LIBEOSIO_HASH_H
|
||||
#ifndef LIBANTELOPE_INTERNAL_HASH_H
|
||||
#define LIBANTELOPE_INTERNAL_HASH_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <libeosio/types.hpp>
|
||||
#include <libantelope/config.h>
|
||||
|
||||
namespace libeosio {
|
||||
#ifdef LIBANTELOPE_HASHIMPL_OPENSSL
|
||||
|
||||
sha256_t* sha256(const unsigned char *data, std::size_t len, sha256_t* out);
|
||||
namespace libantelope { namespace internal {
|
||||
|
||||
// sha256 double.
|
||||
sha256_t* sha256d(const unsigned char *data, std::size_t len, sha256_t* out);
|
||||
typedef unsigned char sha256_state[112];
|
||||
typedef unsigned char ripemd160_state[96];
|
||||
} } // namespace libantelope::internal
|
||||
|
||||
ripemd160_t* ripemd160(const unsigned char *data, std::size_t len, ripemd160_t* out);
|
||||
#else
|
||||
#error "Missing hash implementation"
|
||||
#endif
|
||||
|
||||
} // namespace libeosio
|
||||
|
||||
#endif /* LIBEOSIO_HASH_H */
|
||||
#endif /* LIBANTELOPE_INTERNAL_INTERNAL_H */
|
||||
139
src/WIF.cpp
139
src/WIF.cpp
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2020 EOS Sw/eden
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -22,45 +22,134 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <libeosio/base58.hpp>
|
||||
#include <libeosio/checksum.hpp>
|
||||
#include <libeosio/WIF.hpp>
|
||||
#include <cstring>
|
||||
#include <libantelope/base58.hpp>
|
||||
#include <libantelope/checksum.hpp>
|
||||
#include <libantelope/WIF.hpp>
|
||||
#include "wif/codec.hpp"
|
||||
|
||||
namespace libeosio {
|
||||
namespace libantelope {
|
||||
|
||||
#define PRIV_KEY_PREFIX 0x80 /* 0x80 for "Bitcoin mainnet". Always used by EOS. */
|
||||
const std::string WIF_PUB_LEG = "EOS";
|
||||
const std::string WIF_PUB_K1 = "PUB_K1_";
|
||||
const std::string WIF_PVT_LEG = "";
|
||||
const std::string WIF_PVT_K1 = "PVT_K1_";
|
||||
const std::string WIF_SIG_K1 = "SIG_K1_";
|
||||
|
||||
std::string wif_priv_encode(ec_privkey_t priv) {
|
||||
const wif_codec_t WIF_CODEC_K1 = { WIF_PUB_K1, WIF_PVT_K1 };
|
||||
const wif_codec_t WIF_CODEC_LEG = wif_create_legacy_codec(WIF_PUB_LEG);
|
||||
|
||||
checksum_t check;
|
||||
// 1 byte extra for prefix.
|
||||
unsigned char buf[1 + EC_PRIVKEY_SIZE + CHECKSUM_SIZE] = { PRIV_KEY_PREFIX };
|
||||
std::string wif_priv_encode(const ec_privkey_t& priv, const std::string& prefix) {
|
||||
|
||||
memcpy(buf + 1, priv.data(), priv.size());
|
||||
// 1 byte extra for legacy prefix prefix.
|
||||
unsigned char buf[1 + EC_PRIVKEY_SIZE + CHECKSUM_SIZE] = { 0 };
|
||||
size_t len;
|
||||
|
||||
// Checksum
|
||||
check = checksum_sha256d(buf, 1 + EC_PRIVKEY_SIZE);
|
||||
memcpy(buf + 1 + EC_PRIVKEY_SIZE, check.data(), check.size());
|
||||
if (prefix == WIF_PVT_K1) {
|
||||
len = internal::priv_encoder_k1(priv, buf);
|
||||
} else if (prefix == WIF_PVT_LEG) {
|
||||
len = internal::priv_encoder_legacy(priv, buf);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
return base58_encode(buf, buf + sizeof(buf));
|
||||
return prefix + base58_encode(buf, buf + len);
|
||||
}
|
||||
|
||||
std::string wif_pub_encode(ec_pubkey_t pub) {
|
||||
bool wif_priv_decode(ec_privkey_t& priv, const std::string& data) {
|
||||
|
||||
std::size_t offset;
|
||||
std::vector<unsigned char> buf;
|
||||
internal::priv_decoder_t decoder = internal::priv_decoder_legacy;
|
||||
|
||||
// Check prefix
|
||||
if (data.substr(0, WIF_PVT_K1.size()) == WIF_PVT_K1) {
|
||||
offset = WIF_PVT_K1.size();
|
||||
decoder = internal::priv_decoder_k1;
|
||||
} else {
|
||||
// Legacy
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (!base58_decode(data.c_str() + offset, buf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return decoder(buf, priv);
|
||||
}
|
||||
|
||||
std::string wif_pub_encode(const ec_pubkey_t& pub, const std::string& prefix) {
|
||||
|
||||
checksum_t check = checksum_ripemd160(pub.data(), pub.size());
|
||||
unsigned char buf[EC_PUBKEY_SIZE + CHECKSUM_SIZE];
|
||||
internal::pub_encoder_t encoder;
|
||||
|
||||
memcpy(buf, pub.data(), pub.size());
|
||||
memcpy(buf + EC_PUBKEY_SIZE, check.data(), check.size());
|
||||
if (prefix == WIF_PUB_K1) {
|
||||
encoder = internal::pub_encoder_k1;
|
||||
}
|
||||
// Legacy
|
||||
else {
|
||||
encoder = internal::pub_encoder_legacy;
|
||||
}
|
||||
|
||||
return "EOS" + base58_encode(buf, buf + sizeof(buf));
|
||||
encoder(pub, buf);
|
||||
|
||||
return prefix + base58_encode(buf, buf + sizeof(buf));
|
||||
}
|
||||
|
||||
void wif_print_key(const struct ec_keypair *key) {
|
||||
bool wif_pub_decode(ec_pubkey_t& pub, const std::string& data) {
|
||||
|
||||
std::cout << "Public: " << wif_pub_encode(key->pub) << std::endl;
|
||||
std::cout << "Private: " << wif_priv_encode(key->secret) << std::endl;
|
||||
internal::pub_decoder_t decoder = internal::pub_decoder_legacy;
|
||||
std::size_t offset;
|
||||
std::vector<unsigned char> buf;
|
||||
|
||||
// Check prefix
|
||||
if (data.substr(0, WIF_PUB_K1.size()) == WIF_PUB_K1) {
|
||||
decoder = internal::pub_decoder_k1;
|
||||
offset = WIF_PUB_K1.size();
|
||||
} else {
|
||||
// Legacy
|
||||
offset = 3;
|
||||
}
|
||||
|
||||
if (!base58_decode(data.c_str() + offset, buf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buf.size() != EC_PUBKEY_SIZE + CHECKSUM_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return decoder(buf, pub);
|
||||
}
|
||||
|
||||
} // namespace libeosio
|
||||
void wif_print_key(const struct ec_keypair *key, const wif_codec_t& codec) {
|
||||
|
||||
std::cout << "Public: " << wif_pub_encode(key->pub, codec.pub) << std::endl;
|
||||
std::cout << "Private: " << wif_priv_encode(key->secret, codec.pvt) << std::endl;
|
||||
}
|
||||
|
||||
bool wif_sig_decode(ec_signature_t& sig, const std::string& data) {
|
||||
|
||||
std::vector<unsigned char> buf;
|
||||
|
||||
if (data.substr(0, WIF_SIG_K1.length()) != WIF_SIG_K1) {
|
||||
// Invalid prefix
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!base58_decode(data.c_str() + WIF_SIG_K1.length(), buf)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return internal::sig_decoder_k1(buf, sig);
|
||||
}
|
||||
|
||||
std::string wif_sig_encode(const ec_signature_t& sig) {
|
||||
|
||||
unsigned char buf[EC_SIGNATURE_SIZE + CHECKSUM_SIZE];
|
||||
internal::sig_encoder_k1(sig, buf);
|
||||
|
||||
return WIF_SIG_K1 + base58_encode(buf, buf + sizeof(buf));
|
||||
}
|
||||
|
||||
} // namespace libantelope
|
||||
|
|
|
|||
|
|
@ -25,13 +25,38 @@
|
|||
* Based on code from https://github.com/bitcoin/bitcoin/blob/f1e2f2a85962c1664e4e55471061af0eaa798d40/src/base58.cpp
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
#include <libeosio/base58.hpp>
|
||||
#include <cstring>
|
||||
#include <libantelope/base58.hpp>
|
||||
|
||||
namespace libeosio {
|
||||
namespace libantelope {
|
||||
|
||||
static const char charmap[59] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
static const int8_t table[256] = {
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,-1,-1,-1,-1,
|
||||
-1, 9,10,11,12,13,14,15, 16,-1,17,18,19,20,21,-1,
|
||||
22,23,24,25,26,27,28,29, 30,31,32,-1,-1,-1,-1,-1,
|
||||
-1,33,34,35,36,37,38,39, 40,41,42,43,-1,44,45,46,
|
||||
47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
|
||||
};
|
||||
|
||||
bool is_space(char c) {
|
||||
return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v';
|
||||
}
|
||||
|
||||
|
||||
std::string base58_encode(const unsigned char* pbegin, const unsigned char* pend) {
|
||||
|
||||
|
|
@ -84,6 +109,62 @@ std::string base58_encode(const std::vector<unsigned char>& vch) {
|
|||
return base58_encode(vch.data(), vch.data() + vch.size());
|
||||
}
|
||||
|
||||
bool base58_decode(const char* psz, std::vector<unsigned char>& out) {
|
||||
// Skip leading spaces.
|
||||
while (*psz && is_space(*psz))
|
||||
psz++;
|
||||
// Skip and count leading '1's.
|
||||
int zeroes = 0;
|
||||
int length = 0;
|
||||
while (*psz == '1') {
|
||||
zeroes++;
|
||||
psz++;
|
||||
}
|
||||
// Allocate enough space in big-endian base256 representation.
|
||||
std::size_t size = strlen(psz) * 733 /1000 + 1; // log(58) / log(256), rounded up.
|
||||
std::vector<unsigned char> b256(size);
|
||||
// Process the characters.
|
||||
|
||||
while (*psz && !is_space(*psz)) {
|
||||
// Decode base58 character
|
||||
int carry = table[(uint8_t)*psz];
|
||||
if (carry == -1) // Invalid b58 character
|
||||
return false;
|
||||
int i = 0;
|
||||
for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); (carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) {
|
||||
carry += 58 * (*it);
|
||||
*it = (unsigned char) (carry % 256);
|
||||
carry /= 256;
|
||||
}
|
||||
assert(carry == 0);
|
||||
length = i;
|
||||
psz++;
|
||||
}
|
||||
|
||||
// Skip trailing spaces.
|
||||
while (is_space(*psz))
|
||||
psz++;
|
||||
|
||||
if (*psz != 0)
|
||||
return false;
|
||||
|
||||
// Skip leading zeroes in b256.
|
||||
std::vector<unsigned char>::iterator it = b256.begin() + (size - length);
|
||||
while (it != b256.end() && *it == 0)
|
||||
it++;
|
||||
|
||||
// Copy result into output vector.
|
||||
out.reserve(zeroes + (b256.end() - it));
|
||||
out.assign(zeroes, 0);
|
||||
while (it != b256.end())
|
||||
out.push_back(*(it++));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool base58_decode(const std::string& str, std::vector<unsigned char>& out) {
|
||||
return base58_decode(str.c_str(), out);
|
||||
}
|
||||
|
||||
bool is_base58(char ch) {
|
||||
for(unsigned int i=0; i < sizeof(charmap); i++) {
|
||||
if (ch == charmap[i]) {
|
||||
|
|
@ -110,4 +191,4 @@ std::string& base58_strip(std::string &str) {
|
|||
return str;
|
||||
}
|
||||
|
||||
} // namespace libeosio
|
||||
} // namespace libantelope
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2020 EOS Sw/eden
|
||||
* Copyright (c) 2019-2023 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -21,19 +21,18 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBEOSIO_WIF_H
|
||||
#define LIBEOSIO_WIF_H
|
||||
#ifndef LIBANTELOPE_CONFIG_H
|
||||
#define LIBANTELOPE_CONFIG_H
|
||||
|
||||
#include <libeosio/types.hpp>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
namespace libeosio {
|
||||
/* Hash implementation */
|
||||
#cmakedefine LIBANTELOPE_HASHIMPL_OPENSSL
|
||||
|
||||
std::string wif_priv_encode(ec_privkey_t priv);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string wif_pub_encode(ec_pubkey_t pub);
|
||||
|
||||
void wif_print_key(const struct ec_keypair *key);
|
||||
|
||||
} // namespace libeosio
|
||||
|
||||
#endif /* LIBEOSIO_WIF_H */
|
||||
#endif /* LIBANTELOPE_CONFIG_H */
|
||||
47
src/ec.cpp
Normal file
47
src/ec.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2023 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <libantelope/ec.hpp>
|
||||
|
||||
std::ostream& _hex(std::ostream& os, const unsigned char *b, std::size_t sz) {
|
||||
os << "[ " << std::hex;
|
||||
for (std::size_t i = 0; i < sz; i++) {
|
||||
unsigned int v = b[i];
|
||||
|
||||
os << "0x";
|
||||
if (v <= 0xF) {
|
||||
os << "0";
|
||||
}
|
||||
os << v;
|
||||
if (i < sz-1) os << ", ";
|
||||
}
|
||||
return os << std::oct << " ]";
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const libantelope::ec_privkey_t& k) {
|
||||
return _hex(os, k.data(), k.size());
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const libantelope::ec_pubkey_t& k) {
|
||||
return _hex(os, k.data(), k.size());
|
||||
}
|
||||
93
src/libsecp256k1/ec.cpp
Normal file
93
src/libsecp256k1/ec.cpp
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_ecdh.h>
|
||||
#include <libantelope/ec.hpp>
|
||||
#include "rng.h"
|
||||
|
||||
namespace libantelope {
|
||||
|
||||
secp256k1_context* ctx;
|
||||
|
||||
int ec_init() {
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
return ctx == NULL ? -1 : 0;
|
||||
}
|
||||
|
||||
void ec_shutdown() {
|
||||
if (ctx) {
|
||||
secp256k1_context_destroy(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ec_generate_privkey(ec_privkey_t *priv) {
|
||||
|
||||
unsigned char randomize[32];
|
||||
|
||||
if (!fill_random(randomize, sizeof(randomize))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (secp256k1_context_randomize(ctx, randomize) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!fill_random(priv->data(), priv->size())) {
|
||||
return -1;
|
||||
}
|
||||
if (secp256k1_ec_seckey_verify(ctx, priv->data())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ec_get_publickey(const ec_privkey_t *priv, ec_pubkey_t* pub) {
|
||||
|
||||
size_t len;
|
||||
secp256k1_pubkey ec_pub;
|
||||
|
||||
if (secp256k1_ec_pubkey_create(ctx, &ec_pub, priv->data()) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = EC_PUBKEY_SIZE;
|
||||
secp256k1_ec_pubkey_serialize(ctx, pub->data(), &len, &ec_pub, SECP256K1_EC_COMPRESSED);
|
||||
|
||||
return len != EC_PUBKEY_SIZE ? -1 : 0;
|
||||
}
|
||||
|
||||
int ec_generate_key(struct ec_keypair *pair) {
|
||||
|
||||
if (ec_generate_privkey(&pair->secret) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ec_get_publickey(&pair->secret, &pair->pub);
|
||||
}
|
||||
|
||||
} // namespace libantelope
|
||||
118
src/libsecp256k1/ecdsa.cpp
Normal file
118
src/libsecp256k1/ecdsa.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_recovery.h>
|
||||
#include <libantelope/ec.hpp>
|
||||
|
||||
namespace libantelope {
|
||||
|
||||
extern secp256k1_context* ctx;
|
||||
|
||||
int is_canonical(const unsigned char *d) {
|
||||
return !(d[1] & 0x80)
|
||||
&& !(d[1] == 0 && !(d[2] & 0x80))
|
||||
&& !(d[33] & 0x80)
|
||||
&& !(d[33] == 0 && !(d[34] & 0x80));
|
||||
}
|
||||
|
||||
static int extended_nonce_function( unsigned char *nonce32, const unsigned char *msg32,
|
||||
const unsigned char *key32, const unsigned char* algo16,
|
||||
void* data, unsigned int attempt ) {
|
||||
(void)attempt; // "use" the variable here to shutup compiler about unsed variable.
|
||||
return secp256k1_nonce_function_rfc6979(nonce32, msg32, key32, algo16, nullptr, *(unsigned int*) data);
|
||||
}
|
||||
|
||||
int ecdsa_sign(const ec_privkey_t& key, const sha256_t* digest, ec_signature_t& sig) {
|
||||
|
||||
for (unsigned int counter = 1; counter < 25; counter++) {
|
||||
|
||||
int v = 0;
|
||||
secp256k1_ecdsa_recoverable_signature s;
|
||||
|
||||
if (!secp256k1_ecdsa_sign_recoverable(ctx, &s, (const unsigned char*) digest, key.data(), extended_nonce_function, &counter)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig.data() + 1, &v, &s);
|
||||
|
||||
if (is_canonical(sig.data())) {
|
||||
sig[0] = (unsigned char) (27 + 4 + v);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ecdsa_verify(const sha256_t* digest, const ec_signature_t& sig, const ec_pubkey_t& key) {
|
||||
|
||||
secp256k1_ecdsa_signature ec_sig;
|
||||
secp256k1_ecdsa_recoverable_signature ec_rec_sig;
|
||||
secp256k1_pubkey pubkey;
|
||||
int recid;
|
||||
|
||||
recid = sig.at(0) - 27 - 4;
|
||||
|
||||
// Parse signature
|
||||
if (!secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &ec_rec_sig, sig.data() + 1, recid)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Parse public key
|
||||
if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, key.data(), key.size())) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Verify
|
||||
secp256k1_ecdsa_recoverable_signature_convert(ctx, &ec_sig, &ec_rec_sig);
|
||||
return secp256k1_ecdsa_verify(ctx, &ec_sig, (const unsigned char*) digest, &pubkey) > 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
int ecdsa_recover(const sha256_t* digest, const ec_signature_t& sig, ec_pubkey_t& pubkey) {
|
||||
|
||||
secp256k1_pubkey ec_pubkey;
|
||||
secp256k1_ecdsa_recoverable_signature ec_sig;
|
||||
size_t len = EC_PUBKEY_SIZE;
|
||||
int recid;
|
||||
|
||||
recid = sig.at(0) - 27 - 4;
|
||||
|
||||
// Parse signature
|
||||
if (!secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &ec_sig, sig.data() + 1, recid)) {
|
||||
std::cout << "parse sig" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Recover public key
|
||||
if (!secp256k1_ecdsa_recover(ctx, &ec_pubkey, &ec_sig, (const unsigned char*) digest)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
secp256k1_ec_pubkey_serialize(ctx, pubkey.data(), &len, &ec_pubkey, SECP256K1_EC_COMPRESSED);
|
||||
|
||||
return len != EC_PUBKEY_SIZE ? -1 : 0;
|
||||
}
|
||||
|
||||
} // namespace libantelope
|
||||
77
src/libsecp256k1/rng.h
Normal file
77
src/libsecp256k1/rng.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*************************************************************************
|
||||
* Copyright (c) 2020-2021 Elichai Turkel *
|
||||
* Distributed under the CC0 software license, see the accompanying file *
|
||||
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef LIBANTELOPE_LIBSECP256K1_RNG_H
|
||||
#define LIBANTELOPE_LIBSECP256K1_RNG_H
|
||||
|
||||
/*
|
||||
* This file is an attempt at collecting best practice methods for obtaining randomness with different operating systems.
|
||||
* It may be out-of-date. Consult the documentation of the operating system before considering to use the methods below.
|
||||
*
|
||||
* Platform randomness sources:
|
||||
* Linux -> `getrandom(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. http://man7.org/linux/man-pages/man2/getrandom.2.html, https://linux.die.net/man/4/urandom
|
||||
* macOS -> `getentropy(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. https://www.unix.com/man-page/mojave/2/getentropy, https://opensource.apple.com/source/xnu/xnu-517.12.7/bsd/man/man4/random.4.auto.html
|
||||
* FreeBSD -> `getrandom(2)`(`sys/random.h`), if not available `kern.arandom` should be used. https://www.freebsd.org/cgi/man.cgi?query=getrandom, https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
|
||||
* OpenBSD -> `getentropy(2)`(`unistd.h`), if not available `/dev/urandom` should be used. https://man.openbsd.org/getentropy, https://man.openbsd.org/urandom
|
||||
* Windows -> `BCryptGenRandom`(`bcrypt.h`). https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
|
||||
*/
|
||||
#if defined(_WIN32)
|
||||
/* Windows throws a bunch of "redefinition" warnings for these headers.
|
||||
So we disable them temporarily */
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable: 4005 )
|
||||
#include <windows.h>
|
||||
#include <ntstatus.h>
|
||||
#pragma warning( pop )
|
||||
#include <bcrypt.h>
|
||||
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <sys/random.h>
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#error "Couldn't identify the OS"
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
static int fill_random(unsigned char* data, size_t size) {
|
||||
#if defined(_WIN32)
|
||||
/* Disable C4267 Warning (dataloss when casting variable to smaller size) temporarily */
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable: 4267 )
|
||||
NTSTATUS res = BCryptGenRandom(NULL, data, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||
#pragma warning( pop )
|
||||
if (res != STATUS_SUCCESS || size > ULONG_MAX) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#elif defined(__linux__) || defined(__FreeBSD__)
|
||||
/* If `getrandom(2)` is not available you should fallback to /dev/urandom */
|
||||
ssize_t res = getrandom(data, size, 0);
|
||||
if (res < 0 || (size_t)res != size ) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
#elif defined(__APPLE__) || defined(__OpenBSD__)
|
||||
/* If `getentropy(2)` is not available you should fallback to either
|
||||
* `SecRandomCopyBytes` or /dev/urandom */
|
||||
int res = getentropy(data, size);
|
||||
if (res == 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* LIBANTELOPE_LIBSECP256K1_RNG_H */
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2020 EOS Sw/eden
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -24,17 +24,16 @@
|
|||
#include <openssl/ec.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <libeosio/ec.hpp>
|
||||
#include <libantelope/ec.hpp>
|
||||
#include "internal.h"
|
||||
|
||||
namespace libeosio {
|
||||
namespace libantelope {
|
||||
|
||||
int ec_generate_key(struct ec_keypair *pair) {
|
||||
BN_CTX *ctx = NULL;
|
||||
EC_KEY *k = NULL;
|
||||
|
||||
int ret = -1;
|
||||
EC_KEY *k;
|
||||
BN_CTX *ctx;
|
||||
int ec_init() {
|
||||
|
||||
// Create BIGNUM context.
|
||||
ctx = BN_CTX_new();
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
|
|
@ -43,12 +42,72 @@ int ec_generate_key(struct ec_keypair *pair) {
|
|||
// Construct curve.
|
||||
k = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
if (k == NULL) {
|
||||
goto fail1;
|
||||
BN_CTX_free(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ec_shutdown() {
|
||||
if (ctx) {
|
||||
BN_CTX_free(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
|
||||
if (k) {
|
||||
EC_KEY_free(k);
|
||||
k = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ec_generate_privkey(ec_privkey_t *priv) {
|
||||
|
||||
// Generate new private key.
|
||||
if (EC_KEY_generate_key(k) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EC_KEY_priv2oct(k, priv->data(), EC_PRIVKEY_SIZE) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ec_get_publickey(const ec_privkey_t *priv, ec_pubkey_t* pub) {
|
||||
|
||||
int rc = -1;
|
||||
const EC_GROUP *group;
|
||||
EC_POINT *point;
|
||||
|
||||
// Load private key
|
||||
if (EC_KEY_oct2priv(k, priv->data(), EC_PRIVKEY_SIZE) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((group = EC_KEY_get0_group(k)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (calculate_pubkey(group, k, &point) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Encode public key
|
||||
if (EC_POINT_encode(group, point, pub->data(), EC_PUBKEY_SIZE, ctx) != 0) {
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
EC_POINT_free(point);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ec_generate_key(struct ec_keypair *pair) {
|
||||
|
||||
// Generate new key pair.
|
||||
if (EC_KEY_generate_key(k) != 1) {
|
||||
goto fail2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Copy private key to binary format.
|
||||
|
|
@ -59,12 +118,7 @@ int ec_generate_key(struct ec_keypair *pair) {
|
|||
EC_KEY_get0_public_key(k), POINT_CONVERSION_COMPRESSED,
|
||||
pair->pub.data(), EC_PUBKEY_SIZE, ctx);
|
||||
|
||||
ret = 0;
|
||||
fail2:
|
||||
EC_KEY_free(k);
|
||||
fail1:
|
||||
BN_CTX_free(ctx);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace libeosio
|
||||
} // namespace libantelope
|
||||
|
|
|
|||
185
src/openssl/ecdsa.cpp
Normal file
185
src/openssl/ecdsa.cpp
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <libantelope/ec.hpp>
|
||||
#include "internal.h"
|
||||
|
||||
namespace libantelope {
|
||||
|
||||
extern BN_CTX *ctx;
|
||||
|
||||
int ecdsa_sign(const ec_privkey_t& key, const sha256_t* digest, ec_signature_t& sig) {
|
||||
|
||||
int rc = -1;
|
||||
EC_POINT *pub;
|
||||
const EC_GROUP *group;
|
||||
ECDSA_SIG *ecdsa_sig;
|
||||
EC_KEY *ec_key;
|
||||
|
||||
if ((ec_key = EC_KEY_new_secp256k1()) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EC_KEY_oct2priv(ec_key, key.data(), key.size()) < 0) {
|
||||
goto err1;
|
||||
}
|
||||
|
||||
group = EC_KEY_get0_group(ec_key);
|
||||
if (group == NULL) {
|
||||
goto err1;
|
||||
}
|
||||
|
||||
if (calculate_pubkey(group, ec_key, &pub) == 0) {
|
||||
goto err2;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int recid = -1;
|
||||
const BIGNUM *r, *s;
|
||||
EC_KEY* tmpk;
|
||||
|
||||
ecdsa_sig = ECDSA_do_sign((const unsigned char*) digest, 32, ec_key);
|
||||
if (ecdsa_sig == NULL) {
|
||||
goto err2;
|
||||
}
|
||||
|
||||
// Get R and S numbers.
|
||||
r = ECDSA_SIG_get0_r(ecdsa_sig);
|
||||
s = ECDSA_SIG_get0_s(ecdsa_sig);
|
||||
|
||||
tmpk = EC_KEY_new_by_curve_name( NID_secp256k1 );
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (ECDSA_SIG_recover_key_GFp(tmpk, r, s, (const unsigned char*) digest, 32, i, 1) == 1) {
|
||||
const EC_POINT *p = EC_KEY_get0_public_key(tmpk);
|
||||
|
||||
// Compare public keys
|
||||
if (EC_POINT_cmp(group, pub, p, ctx) == 0) {
|
||||
recid = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EC_KEY_free( tmpk );
|
||||
|
||||
// Could not find recovery id.
|
||||
if (recid == -1) {
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (ECDSA_SIG_serialize(ecdsa_sig, recid, sig.data()) == 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out: rc = 0;
|
||||
err2:
|
||||
EC_POINT_free(pub);
|
||||
err1:
|
||||
EC_KEY_free(ec_key);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ecdsa_verify(const sha256_t* digest, const ec_signature_t& sig, const ec_pubkey_t& pub) {
|
||||
|
||||
int recid, ret = -1;
|
||||
EC_POINT *point;
|
||||
const EC_GROUP *group;
|
||||
ECDSA_SIG* ecdsa_sig;
|
||||
EC_KEY *ec_key;
|
||||
|
||||
ec_key = EC_KEY_new_by_curve_name( NID_secp256k1 );
|
||||
if (ec_key == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ecdsa_sig = ECDSA_SIG_new()) == NULL) {
|
||||
goto err1;
|
||||
}
|
||||
|
||||
if (ECDSA_SIG_unserialize(sig.data(), ecdsa_sig, &recid) == 0) {
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if ((group = EC_KEY_get0_group(ec_key)) == NULL) {
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if ((point = EC_POINT_new(group)) == NULL) {
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (EC_POINT_oct2point(group, point, pub.data(), EC_PUBKEY_SIZE, ctx) == 0) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
if (EC_KEY_set_public_key(ec_key, point) == 0) {
|
||||
goto err3;
|
||||
}
|
||||
|
||||
if (ECDSA_do_verify((const unsigned char*) digest, 32, ecdsa_sig, ec_key) == 1) {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
err3: EC_POINT_free(point);
|
||||
err2: ECDSA_SIG_free(ecdsa_sig);
|
||||
err1: EC_KEY_free(ec_key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ecdsa_recover(const sha256_t* digest, const ec_signature_t& sig, ec_pubkey_t& key) {
|
||||
|
||||
int recid;
|
||||
int ret = -1;
|
||||
BIGNUM *r, *s;
|
||||
EC_KEY *ec_key;
|
||||
|
||||
// Initialize ec variables.
|
||||
if ((ec_key = EC_KEY_new_secp256k1()) == NULL) goto err1;
|
||||
|
||||
// Unserialize signature into r,s,recid components.
|
||||
ECDSA_SIG_unserialize_rs(sig.data(), &r, &s, &recid);
|
||||
|
||||
// Recover public key.
|
||||
if (ECDSA_SIG_recover_key_GFp(ec_key, r, s, (const unsigned char*) digest, 32, recid, 1) == 1) {
|
||||
|
||||
// Encode point to binary compressed format.
|
||||
const EC_POINT *p = EC_KEY_get0_public_key(ec_key);
|
||||
const EC_GROUP *g = EC_KEY_get0_group(ec_key);
|
||||
if (EC_POINT_encode(g, p, key.data(), EC_PUBKEY_SIZE, ctx) == 0) {
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
err4: BN_free(s);
|
||||
err3: BN_free(r);
|
||||
err2: EC_KEY_free(ec_key);
|
||||
err1: return ret;
|
||||
}
|
||||
|
||||
} // namespace libantelope
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2020 EOS Sw/eden
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -23,21 +23,45 @@
|
|||
*/
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/ripemd.h>
|
||||
#include <libeosio/hash.hpp>
|
||||
#include <libantelope/hash.hpp>
|
||||
|
||||
namespace libeosio {
|
||||
namespace libantelope {
|
||||
|
||||
int sha256_init(sha256_ctx_t* ctx) {
|
||||
return SHA256_Init((SHA256_CTX*)ctx);
|
||||
}
|
||||
|
||||
int sha256_update(sha256_ctx_t* ctx, const void *data, std::size_t len) {
|
||||
return SHA256_Update((SHA256_CTX*)ctx, data, len);
|
||||
}
|
||||
|
||||
int sha256_final(sha256_ctx_t* ctx, sha256_t* out) {
|
||||
return SHA256_Final((unsigned char*) out, (SHA256_CTX*)ctx);
|
||||
}
|
||||
|
||||
sha256_t* sha256(const unsigned char *data, std::size_t len, sha256_t* out) {
|
||||
return (sha256_t *) SHA256(data, len, out->data);
|
||||
return (sha256_t *) SHA256(data, len, (unsigned char*) out);
|
||||
}
|
||||
|
||||
sha256_t* sha256d(const unsigned char *data, std::size_t len, sha256_t* out) {
|
||||
SHA256(data, len, out->data);
|
||||
return (sha256_t *) SHA256(out->data, 32, out->data);
|
||||
SHA256(data, len, (unsigned char*) out);
|
||||
return (sha256_t *) SHA256((unsigned char*) out, 32, (unsigned char*) out);
|
||||
}
|
||||
|
||||
int ripemd160_init(ripemd160_ctx_t* ctx) {
|
||||
return RIPEMD160_Init((RIPEMD160_CTX*)ctx);
|
||||
}
|
||||
|
||||
int ripemd160_update(ripemd160_ctx_t* ctx, const void *data, std::size_t len) {
|
||||
return RIPEMD160_Update((RIPEMD160_CTX*)ctx, data, len);
|
||||
}
|
||||
|
||||
int ripemd160_final(ripemd160_ctx_t* ctx, ripemd160_t* out) {
|
||||
return RIPEMD160_Final((unsigned char*) out, (RIPEMD160_CTX*)ctx);
|
||||
}
|
||||
|
||||
ripemd160_t* ripemd160(const unsigned char *data, std::size_t len, ripemd160_t* out) {
|
||||
return (ripemd160_t *) RIPEMD160(data, len, out->data);
|
||||
return (ripemd160_t *) RIPEMD160(data, len, (unsigned char*) out);
|
||||
}
|
||||
|
||||
} // namespace libeosio
|
||||
} // namespace libantelope
|
||||
|
|
|
|||
101
src/openssl/helpers.c
Normal file
101
src/openssl/helpers.c
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <string.h>
|
||||
|
||||
// Calcualte a public key from a EC_KEY object.
|
||||
int calculate_pubkey(const EC_GROUP *group, const EC_KEY *ec_key, EC_POINT **point) {
|
||||
const BIGNUM* pk;
|
||||
|
||||
// Then get the private key number
|
||||
if ((pk = EC_KEY_get0_private_key(ec_key)) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create a new point.
|
||||
if ((*point = EC_POINT_new(group)) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Multiply curve (group) and private key to get the public key.
|
||||
return EC_POINT_mul(group, *point, pk, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
int ECDSA_SIG_unserialize_rs(const unsigned char *sig, BIGNUM **r, BIGNUM **s, int *recid) {
|
||||
|
||||
*recid = sig[0] - 27 - 4;
|
||||
|
||||
if ((*r = BN_bin2bn(sig + 1, 32, NULL)) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((*s = BN_bin2bn(sig + 33, 32, NULL)) == NULL) {
|
||||
BN_free(*r);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ECDSA_SIG_unserialize(const unsigned char *sig, ECDSA_SIG *ecdsa_sig, int *recid) {
|
||||
|
||||
BIGNUM *r, *s;
|
||||
|
||||
if (ECDSA_SIG_unserialize_rs(sig, &r, &s, recid) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ECDSA_SIG_set0(ecdsa_sig, r, s) == 0) {
|
||||
BN_free(r);
|
||||
BN_free(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// r,s pointers are owned by ECDSA_SIG from this point.
|
||||
// So we should not free them.
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ECDSA_SIG_serialize(const ECDSA_SIG *ecdsa_sig, int recid, unsigned char* sig) {
|
||||
|
||||
unsigned char* der = NULL;
|
||||
int bytes, ret = -1;
|
||||
unsigned char lR, lS;
|
||||
|
||||
bytes = i2d_ECDSA_SIG( ecdsa_sig, &der );
|
||||
lR = der[3];
|
||||
lS = der[5+lR];
|
||||
|
||||
if (lR != 32 || lS != 32) goto err;
|
||||
|
||||
memcpy(sig + 1, &der[4], 32);
|
||||
memcpy(sig + 33, &der[6+32], 32);
|
||||
sig[0] = recid + 27 + 4;
|
||||
|
||||
ret = 0;
|
||||
err:
|
||||
free(der);
|
||||
return ret;
|
||||
}
|
||||
65
src/openssl/internal.h
Normal file
65
src/openssl/internal.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2023 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#ifndef LIBANTELOPE_OPENSSL_INTERNAL_H
|
||||
#define LIBANTELOPE_OPENSSL_INTERNAL_H
|
||||
|
||||
#define EC_KEY_new_secp256k1() (EC_KEY_new_by_curve_name( NID_secp256k1 ))
|
||||
|
||||
#define EC_POINT_encode(group, point, buf, len, ctx) \
|
||||
EC_POINT_point2oct((group), (point), POINT_CONVERSION_COMPRESSED, (buf), (len), (ctx))
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int calculate_pubkey(const EC_GROUP *group, const EC_KEY *ec_key, EC_POINT **point);
|
||||
|
||||
int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, const BIGNUM* r, const BIGNUM* s, const unsigned char *msg, int msglen, int recid, int check);
|
||||
|
||||
/**
|
||||
* Signature serialization function.
|
||||
* sig must be a pointer to a serialized signature and be atleast 65 (32s + 32 + 1) bytes long.
|
||||
*
|
||||
* returns -1 if there was an error. zero otherwise.
|
||||
*/
|
||||
int ECDSA_SIG_serialize(const ECDSA_SIG *ecdsa_sig, int recid, unsigned char* sig);
|
||||
|
||||
/**
|
||||
* Signature unserialization functions.
|
||||
* sig must be a pointer to a serialized signature and be atleast 65 (32s + 32 + 1) bytes long.
|
||||
*
|
||||
* returns -1 if there was an error. zero otherwise.
|
||||
*/
|
||||
int ECDSA_SIG_unserialize(const unsigned char *sig, ECDSA_SIG *ecdsa_sig, int *recid);
|
||||
|
||||
int ECDSA_SIG_unserialize_rs(const unsigned char *sig, BIGNUM **r, BIGNUM **s, int *recid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LIBANTELOPE_OPENSSL_INTERNAL_H */
|
||||
79
src/openssl/recovery.c
Normal file
79
src/openssl/recovery.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright (c) 2009-2013 The Bitcoin developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
//
|
||||
// Taken from https://github.com/bitcoin/bitcoin/blob/9b1200c23bbced3a78b58067c1f6414103653795/src/key.cpp#L56
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/bn.h>
|
||||
|
||||
int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, const BIGNUM* r, const BIGNUM* s, const unsigned char *msg, int msglen, int recid, int check)
|
||||
{
|
||||
if (!eckey) return 0;
|
||||
|
||||
int ret = 0;
|
||||
BN_CTX *ctx = NULL;
|
||||
|
||||
BIGNUM *x = NULL;
|
||||
BIGNUM *e = NULL;
|
||||
BIGNUM *order = NULL;
|
||||
BIGNUM *sor = NULL;
|
||||
BIGNUM *eor = NULL;
|
||||
BIGNUM *field = NULL;
|
||||
EC_POINT *R = NULL;
|
||||
EC_POINT *O = NULL;
|
||||
EC_POINT *Q = NULL;
|
||||
BIGNUM *rr = NULL;
|
||||
BIGNUM *zero = NULL;
|
||||
int n = 0;
|
||||
int i = recid / 2;
|
||||
|
||||
const EC_GROUP *group = EC_KEY_get0_group(eckey);
|
||||
if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
|
||||
BN_CTX_start(ctx);
|
||||
order = BN_CTX_get(ctx);
|
||||
if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
|
||||
x = BN_CTX_get(ctx);
|
||||
if (!BN_copy(x, order)) { ret=-1; goto err; }
|
||||
if (!BN_mul_word(x, i)) { ret=-1; goto err; }
|
||||
if (!BN_add(x, x, r)) { ret=-1; goto err; }
|
||||
field = BN_CTX_get(ctx);
|
||||
if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
|
||||
if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
|
||||
if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
|
||||
if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
|
||||
if (check)
|
||||
{
|
||||
if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
|
||||
if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
|
||||
if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
|
||||
}
|
||||
if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
|
||||
n = EC_GROUP_get_degree(group);
|
||||
e = BN_CTX_get(ctx);
|
||||
if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
|
||||
if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
|
||||
zero = BN_CTX_get(ctx);
|
||||
BN_zero(zero);
|
||||
if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
|
||||
rr = BN_CTX_get(ctx);
|
||||
if (!BN_mod_inverse(rr, r, order, ctx)) { ret=-1; goto err; }
|
||||
sor = BN_CTX_get(ctx);
|
||||
if (!BN_mod_mul(sor, s, rr, order, ctx)) { ret=-1; goto err; }
|
||||
eor = BN_CTX_get(ctx);
|
||||
if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
|
||||
if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
|
||||
if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
if (ctx) {
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
if (R != NULL) EC_POINT_free(R);
|
||||
if (O != NULL) EC_POINT_free(O);
|
||||
if (Q != NULL) EC_POINT_free(Q);
|
||||
return ret;
|
||||
}
|
||||
|
||||
84
src/wif/codec.hpp
Normal file
84
src/wif/codec.hpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBANTELOPE_CODEC_H
|
||||
#define LIBANTELOPE_CODEC_H
|
||||
|
||||
#include <libantelope/WIF.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace libantelope { namespace internal {
|
||||
|
||||
/**
|
||||
* Public-key encoders
|
||||
*/
|
||||
typedef void (*pub_encoder_t)(const ec_pubkey_t& key, unsigned char *buf);
|
||||
|
||||
void pub_encoder_legacy(const ec_pubkey_t& key, unsigned char *buf);
|
||||
|
||||
void pub_encoder_k1(const ec_pubkey_t& key, unsigned char *buf);
|
||||
|
||||
/**
|
||||
* Public-key decoders
|
||||
*/
|
||||
typedef bool (*pub_decoder_t)(const std::vector<unsigned char>& buf, ec_pubkey_t& key);
|
||||
|
||||
bool pub_decoder_legacy(const std::vector<unsigned char>& buf, ec_pubkey_t& key);
|
||||
|
||||
bool pub_decoder_k1(const std::vector<unsigned char>& buf, ec_pubkey_t& key);
|
||||
|
||||
/**
|
||||
* Private-key encoders
|
||||
*/
|
||||
typedef size_t (*priv_encoder_t)(const ec_privkey_t&, unsigned char *);
|
||||
|
||||
size_t priv_encoder_legacy(const ec_privkey_t& priv, unsigned char *buf);
|
||||
|
||||
size_t priv_encoder_k1(const ec_privkey_t& priv, unsigned char *buf);
|
||||
|
||||
/**
|
||||
* Private-key decoders
|
||||
*/
|
||||
typedef bool (*priv_decoder_t)(const std::vector<unsigned char>&, ec_privkey_t&);
|
||||
|
||||
bool priv_decoder_legacy(const std::vector<unsigned char>& buf, ec_privkey_t& priv);
|
||||
|
||||
bool priv_decoder_k1(const std::vector<unsigned char>& buf, ec_privkey_t& priv);
|
||||
|
||||
/**
|
||||
* Signature encoders
|
||||
*/
|
||||
typedef void (*sig_encoder_t)(const ec_signature_t& sig, unsigned char *buf);
|
||||
|
||||
void sig_encoder_k1(const ec_signature_t& sig, unsigned char *buf);
|
||||
|
||||
/**
|
||||
* Signature decoders
|
||||
*/
|
||||
typedef bool (*sig_decoder_t)(const std::vector<unsigned char>& buf, ec_signature_t& sig);
|
||||
|
||||
bool sig_decoder_k1(const std::vector<unsigned char>& buf, ec_signature_t& sig);
|
||||
|
||||
}} // namespace libantelope::internal
|
||||
|
||||
#endif /* LIBANTELOPE_CODEC_H */
|
||||
129
src/wif/k1.cpp
Normal file
129
src/wif/k1.cpp
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <libantelope/checksum.hpp>
|
||||
#include <libantelope/hash/ripemd160.hpp>
|
||||
#include "codec.hpp"
|
||||
|
||||
namespace libantelope { namespace internal {
|
||||
|
||||
// Just to make it "harder" the calculated checksum for a signature (k1) and pub/priv keys in k1/r1 format.
|
||||
// has a suffix that is not present in the WIF encoded string.
|
||||
// So this function is a quick hack to calculate it.
|
||||
void _checksum_suffix(const unsigned char *in, size_t size, checksum_t check) {
|
||||
ripemd160_ctx_t ctx;
|
||||
ripemd160_t md;
|
||||
|
||||
ripemd160_init(&ctx);
|
||||
ripemd160_update(&ctx, in, size);
|
||||
ripemd160_update(&ctx, "K1", 2);
|
||||
ripemd160_final(&ctx, &md);
|
||||
|
||||
std::memcpy(check, md, CHECKSUM_SIZE);
|
||||
}
|
||||
|
||||
void pub_encoder_k1(const ec_pubkey_t& key, unsigned char *buf) {
|
||||
|
||||
checksum_t check;
|
||||
|
||||
_checksum_suffix(key.data(), EC_PUBKEY_SIZE, check);
|
||||
|
||||
memcpy(buf, key.data(), EC_PUBKEY_SIZE);
|
||||
memcpy(buf + EC_PUBKEY_SIZE, check, CHECKSUM_SIZE);
|
||||
}
|
||||
|
||||
bool pub_decoder_k1(const std::vector<unsigned char>& buf, ec_pubkey_t& key) {
|
||||
|
||||
checksum_t check;
|
||||
|
||||
_checksum_suffix(buf.data(), EC_PUBKEY_SIZE, check);
|
||||
|
||||
if (memcmp(buf.data() + EC_PUBKEY_SIZE, check, CHECKSUM_SIZE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(key.data(), buf.data(), EC_PUBKEY_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t priv_encoder_k1(const ec_privkey_t& priv, unsigned char *buf) {
|
||||
checksum_t check;
|
||||
|
||||
_checksum_suffix(priv.data(), EC_PRIVKEY_SIZE, check);
|
||||
|
||||
memcpy(buf, priv.data(), priv.size());
|
||||
memcpy(buf + EC_PRIVKEY_SIZE, check, CHECKSUM_SIZE);
|
||||
|
||||
return EC_PRIVKEY_SIZE + CHECKSUM_SIZE;
|
||||
}
|
||||
|
||||
bool priv_decoder_k1(const std::vector<unsigned char>& buf, ec_privkey_t& priv) {
|
||||
|
||||
if (buf.size() != EC_PRIVKEY_SIZE + CHECKSUM_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
checksum_t check;
|
||||
_checksum_suffix(buf.data(), EC_PRIVKEY_SIZE, check);
|
||||
if (memcmp(buf.data() + EC_PRIVKEY_SIZE, check, CHECKSUM_SIZE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(priv.data(), buf.data(), priv.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
void sig_encoder_k1(const ec_signature_t& sig, unsigned char *buf) {
|
||||
|
||||
checksum_t check;
|
||||
|
||||
_checksum_suffix(sig.data(), EC_SIGNATURE_SIZE, check);
|
||||
|
||||
memcpy(buf, sig.data(), sig.size());
|
||||
memcpy(buf + EC_SIGNATURE_SIZE, check, CHECKSUM_SIZE);
|
||||
}
|
||||
|
||||
bool sig_decoder_k1(const std::vector<unsigned char>& buf, ec_signature_t& sig) {
|
||||
|
||||
checksum_t check;
|
||||
|
||||
if (buf.size() != EC_SIGNATURE_SIZE + CHECKSUM_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate checksum
|
||||
_checksum_suffix(buf.data(), EC_SIGNATURE_SIZE, check);
|
||||
|
||||
// And validate
|
||||
if (memcmp(buf.data() + EC_SIGNATURE_SIZE, check, CHECKSUM_SIZE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy data to output
|
||||
memcpy(sig.data(), buf.data(), sig.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}} // namespace libantelope::internal
|
||||
80
src/wif/legacy.cpp
Normal file
80
src/wif/legacy.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2021 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <libantelope/checksum.hpp>
|
||||
#include "codec.hpp"
|
||||
|
||||
namespace libantelope { namespace internal {
|
||||
|
||||
#define PRIV_KEY_PREFIX 0x80 /* 0x80 for "Bitcoin mainnet". Always used by EOS. */
|
||||
|
||||
void pub_encoder_legacy(const ec_pubkey_t& key, unsigned char *buf) {
|
||||
|
||||
checksum_t check;
|
||||
|
||||
checksum_ripemd160(key.data(), EC_PUBKEY_SIZE, check);
|
||||
|
||||
memcpy(buf, key.data(), EC_PUBKEY_SIZE);
|
||||
memcpy(buf + EC_PUBKEY_SIZE, check, CHECKSUM_SIZE);
|
||||
}
|
||||
|
||||
bool pub_decoder_legacy(const std::vector<unsigned char>& buf, ec_pubkey_t& key) {
|
||||
|
||||
if (!checksum_validate<checksum_ripemd160>(buf.data(), buf.size())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(key.data(), buf.data(), EC_PUBKEY_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t priv_encoder_legacy(const ec_privkey_t& priv, unsigned char *buf) {
|
||||
checksum_t check;
|
||||
|
||||
buf[0] = PRIV_KEY_PREFIX;
|
||||
memcpy(buf + 1, priv.data(), EC_PRIVKEY_SIZE);
|
||||
checksum_sha256d(buf, 1 + EC_PRIVKEY_SIZE, check);
|
||||
memcpy(buf + 1 + EC_PRIVKEY_SIZE, check, CHECKSUM_SIZE);
|
||||
|
||||
return 1 + EC_PRIVKEY_SIZE + CHECKSUM_SIZE;
|
||||
}
|
||||
|
||||
bool priv_decoder_legacy(const std::vector<unsigned char>& buf, ec_privkey_t& priv) {
|
||||
if (buf[0] != PRIV_KEY_PREFIX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buf.size() != 1 + EC_PRIVKEY_SIZE + CHECKSUM_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checksum_validate<checksum_sha256d>(buf.data(), buf.size())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(priv.data(), buf.data() + 1, priv.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
}} // namespace libantelope::internal
|
||||
39
tests/CMakeLists.txt
Normal file
39
tests/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/doctest.cmake)
|
||||
|
||||
set(TEST_SRC
|
||||
main.cpp
|
||||
|
||||
# hash
|
||||
hash/sha256.cpp
|
||||
hash/ripemd160.cpp
|
||||
|
||||
# ec
|
||||
ec/generate.cpp
|
||||
ec/pubkey.cpp
|
||||
ec/ecdsa_sign.cpp
|
||||
ec/ecdsa_recover.cpp
|
||||
ec/ecdsa_verify.cpp
|
||||
|
||||
# Base58
|
||||
base58/encode.cpp
|
||||
base58/decode.cpp
|
||||
base58/is_base58.cpp
|
||||
|
||||
# WIF
|
||||
WIF/priv_encode.cpp
|
||||
WIF/priv_decode.cpp
|
||||
WIF/pub_encode.cpp
|
||||
WIF/pub_decode.cpp
|
||||
WIF/sig_encode.cpp
|
||||
WIF/sig_decode.cpp)
|
||||
|
||||
add_executable(doctest ${TEST_SRC})
|
||||
target_link_libraries(doctest PRIVATE ${LIB_NAME})
|
||||
target_include_directories(doctest PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
|
||||
doctest_discover_tests(doctest)
|
||||
|
||||
if (WITH_BENCHMARK)
|
||||
add_subdirectory( benchmark )
|
||||
endif (WITH_BENCHMARK)
|
||||
59
tests/WIF/priv_decode.cpp
Normal file
59
tests/WIF/priv_decode.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#include <libantelope/WIF.hpp>
|
||||
#include <libantelope/ec.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("WIF::wif_priv_decode [legacy]") {
|
||||
struct testcase {
|
||||
std::string name;
|
||||
std::string key;
|
||||
libantelope::ec_privkey_t expected;
|
||||
};
|
||||
|
||||
|
||||
std::vector<struct testcase> tests {
|
||||
{ "one", "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ", { 0x0C, 0x28, 0xFC, 0xA3, 0x86, 0xC7, 0xA2, 0x27, 0x60, 0x0B, 0x2F, 0xE5, 0x0B, 0x7C, 0xAE, 0x11, 0xEC, 0x86, 0xD3, 0xBF, 0x1F, 0xBE, 0x47, 0x1B, 0xE8, 0x98, 0x27, 0xE1, 0x9D, 0x72, 0xAA, 0x1D } },
|
||||
{ "two", "5K2hm8apqz281ANDQdtVzifpxcXFTqG5E7Fc6Q5V2ssqPRQ3urJ", { 0x9F, 0xE3, 0xE3, 0x2B, 0x3C, 0x4B, 0x6B, 0x91, 0x6E, 0x20, 0x6C, 0xB0, 0x91, 0xDF, 0x1F, 0x5E, 0x34, 0x32, 0x88, 0x0B, 0x41, 0x33, 0x86, 0xBD, 0xF2, 0x92, 0xFF, 0x23, 0x06, 0x43, 0xF2, 0x8C } },
|
||||
{ "three", "5JVanYq9HPvuKgr2FjATYB9NvTsJ4a3CAj5oPYKbr1Ja5MRLsZX", { 0x59, 0x3A, 0x51, 0xB5, 0x5D, 0x56, 0xAA, 0xF0, 0x5B, 0xD9, 0xD1, 0x0E, 0x6B, 0x88, 0x6D, 0xF9, 0xC4, 0x37, 0x09, 0xB2, 0x4C, 0xEC, 0xBB, 0x63, 0x68, 0x92, 0xC2, 0x94, 0x31, 0x48, 0x71, 0x8C } }
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
|
||||
SUBCASE(it->name.c_str()) {
|
||||
|
||||
libantelope::ec_privkey_t result;
|
||||
|
||||
CHECK( libantelope::wif_priv_decode(result, it->key) );
|
||||
CHECK( result == it->expected );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("WIF::wif_priv_decode [K1]") {
|
||||
struct testcase {
|
||||
std::string name;
|
||||
std::string key;
|
||||
libantelope::ec_privkey_t expected;
|
||||
};
|
||||
|
||||
|
||||
std::vector<struct testcase> tests {
|
||||
{ "one", "PVT_K1_6Mcb23muAxyXaSMhmB6B1mqkvLdWhtuFZmnZsxDczHRvQdp32", { 0x0C, 0x28, 0xFC, 0xA3, 0x86, 0xC7, 0xA2, 0x27, 0x60, 0x0B, 0x2F, 0xE5, 0x0B, 0x7C, 0xAE, 0x11, 0xEC, 0x86, 0xD3, 0xBF, 0x1F, 0xBE, 0x47, 0x1B, 0xE8, 0x98, 0x27, 0xE1, 0x9D, 0x72, 0xAA, 0x1D } },
|
||||
{ "two", "PVT_K1_2DRBT8jmXT8k9ywNSSbufvhk1hLFhPzWJBpsE2jo12CDoFhcc1", { 0x9F, 0xE3, 0xE3, 0x2B, 0x3C, 0x4B, 0x6B, 0x91, 0x6E, 0x20, 0x6C, 0xB0, 0x91, 0xDF, 0x1F, 0x5E, 0x34, 0x32, 0x88, 0x0B, 0x41, 0x33, 0x86, 0xBD, 0xF2, 0x92, 0xFF, 0x23, 0x06, 0x43, 0xF2, 0x8C } },
|
||||
{ "three", "PVT_K1_gJCsP4CwMv4gTkDXiZT8QFhs3NrSB7Sv22ANGrc8Svun9uC9C", { 0x59, 0x3A, 0x51, 0xB5, 0x5D, 0x56, 0xAA, 0xF0, 0x5B, 0xD9, 0xD1, 0x0E, 0x6B, 0x88, 0x6D, 0xF9, 0xC4, 0x37, 0x09, 0xB2, 0x4C, 0xEC, 0xBB, 0x63, 0x68, 0x92, 0xC2, 0x94, 0x31, 0x48, 0x71, 0x8C } }
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
|
||||
SUBCASE(it->name.c_str()) {
|
||||
|
||||
libantelope::ec_privkey_t result;
|
||||
|
||||
CHECK( libantelope::wif_priv_decode(result, it->key) );
|
||||
CHECK( result == it->expected );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
51
tests/WIF/priv_encode.cpp
Normal file
51
tests/WIF/priv_encode.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include <libantelope/WIF.hpp>
|
||||
#include <libantelope/ec.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("WIF::wif_priv_encode [Legacy]") {
|
||||
|
||||
struct testcase {
|
||||
std::string name;
|
||||
const std::string prefix;
|
||||
libantelope::ec_privkey_t key;
|
||||
std::string expected;
|
||||
};
|
||||
|
||||
std::vector<struct testcase> tests {
|
||||
{ "one", libantelope::WIF_PVT_LEG, { 0x0C, 0x28, 0xFC, 0xA3, 0x86, 0xC7, 0xA2, 0x27, 0x60, 0x0B, 0x2F, 0xE5, 0x0B, 0x7C, 0xAE, 0x11, 0xEC, 0x86, 0xD3, 0xBF, 0x1F, 0xBE, 0x47, 0x1B, 0xE8, 0x98, 0x27, 0xE1, 0x9D,0x72,0xAA,0x1D}, "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ" },
|
||||
{ "two", libantelope::WIF_PVT_LEG, { 0x9F, 0xE3, 0xE3, 0x2B, 0x3C, 0x4B, 0x6B, 0x91, 0x6E, 0x20, 0x6C, 0xB0, 0x91, 0xDF, 0x1F, 0x5E, 0x34, 0x32, 0x88, 0x0B, 0x41, 0x33, 0x86, 0xBD, 0xF2, 0x92, 0xFF, 0x23, 0x06, 0x43, 0xF2, 0x8C}, "5K2hm8apqz281ANDQdtVzifpxcXFTqG5E7Fc6Q5V2ssqPRQ3urJ" },
|
||||
{ "three", libantelope::WIF_PVT_LEG, { 0x59, 0x3A, 0x51, 0xB5, 0x5D, 0x56, 0xAA, 0xF0, 0x5B, 0xD9, 0xD1, 0x0E, 0x6B, 0x88, 0x6D, 0xF9, 0xC4, 0x37, 0x09, 0xB2, 0x4C, 0xEC, 0xBB, 0x63, 0x68, 0x92, 0xC2, 0x94, 0x31, 0x48, 0x71, 0x8C}, "5JVanYq9HPvuKgr2FjATYB9NvTsJ4a3CAj5oPYKbr1Ja5MRLsZX" }
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
|
||||
SUBCASE(it->name.c_str()) {
|
||||
CHECK( libantelope::wif_priv_encode(it->key, it->prefix) == it->expected );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("WIF::wif_priv_encode [K1]") {
|
||||
|
||||
struct testcase {
|
||||
std::string name;
|
||||
const std::string prefix;
|
||||
libantelope::ec_privkey_t key;
|
||||
std::string expected;
|
||||
};
|
||||
|
||||
std::vector<struct testcase> tests {
|
||||
{ "one", libantelope::WIF_PVT_K1, { 0x0C, 0x28, 0xFC, 0xA3, 0x86, 0xC7, 0xA2, 0x27, 0x60, 0x0B, 0x2F, 0xE5, 0x0B, 0x7C, 0xAE, 0x11, 0xEC, 0x86, 0xD3, 0xBF, 0x1F, 0xBE, 0x47, 0x1B, 0xE8, 0x98, 0x27, 0xE1, 0x9D,0x72,0xAA,0x1D}, "PVT_K1_6Mcb23muAxyXaSMhmB6B1mqkvLdWhtuFZmnZsxDczHRvQdp32" },
|
||||
{ "two", libantelope::WIF_PVT_K1, { 0x9F, 0xE3, 0xE3, 0x2B, 0x3C, 0x4B, 0x6B, 0x91, 0x6E, 0x20, 0x6C, 0xB0, 0x91, 0xDF, 0x1F, 0x5E, 0x34, 0x32, 0x88, 0x0B, 0x41, 0x33, 0x86, 0xBD, 0xF2, 0x92, 0xFF, 0x23, 0x06, 0x43, 0xF2, 0x8C}, "PVT_K1_2DRBT8jmXT8k9ywNSSbufvhk1hLFhPzWJBpsE2jo12CDoFhcc1" },
|
||||
{ "three", libantelope::WIF_PVT_K1, { 0x59, 0x3A, 0x51, 0xB5, 0x5D, 0x56, 0xAA, 0xF0, 0x5B, 0xD9, 0xD1, 0x0E, 0x6B, 0x88, 0x6D, 0xF9, 0xC4, 0x37, 0x09, 0xB2, 0x4C, 0xEC, 0xBB, 0x63, 0x68, 0x92, 0xC2, 0x94, 0x31, 0x48, 0x71, 0x8C}, "PVT_K1_gJCsP4CwMv4gTkDXiZT8QFhs3NrSB7Sv22ANGrc8Svun9uC9C" }
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
|
||||
SUBCASE(it->name.c_str()) {
|
||||
CHECK( libantelope::wif_priv_encode(it->key, it->prefix) == it->expected );
|
||||
}
|
||||
}
|
||||
}
|
||||
61
tests/WIF/pub_decode.cpp
Normal file
61
tests/WIF/pub_decode.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#include <libantelope/WIF.hpp>
|
||||
#include <libantelope/ec.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("WIF::wif_pub_decode [legacy]") {
|
||||
struct testcase {
|
||||
const char* name;
|
||||
std::string key;
|
||||
libantelope::ec_pubkey_t expected;
|
||||
bool expectedRet;
|
||||
};
|
||||
|
||||
std::vector<struct testcase> tests {
|
||||
{ "one", "EOS7kzJ5iFBmQWWT1LiWgAiocESD7TTNuuPCdYREUQysruq8VeFKy", { 0x03, 0x7a, 0x0e, 0x6b, 0xfd, 0xe4, 0xf1, 0xad, 0x36, 0x3f, 0x3a, 0xf9, 0xe0, 0x93, 0x63, 0x5a, 0xa9, 0x99, 0x21, 0x15, 0xbc, 0x23, 0x35, 0x75, 0x13, 0x69, 0x55, 0xee, 0x3f, 0xf8, 0xfd, 0x97, 0xec }, true },
|
||||
{ "two", "EOS5c9HkNCJLDebe2Wvapp8bpB38Pf1QWNpkrsFy3mshg7DZfPNeA", { 0x02, 0x5e, 0x94, 0xa5, 0xe7, 0x9f, 0x66, 0x37, 0x55, 0x7e, 0xc2, 0x28, 0x30, 0x40, 0x82, 0x9a, 0x38, 0x72, 0x10, 0x96, 0x6e, 0x15, 0xb7, 0xa5, 0x8a, 0x27, 0x9a, 0x71, 0x06, 0xa7, 0x64, 0x23, 0x30 }, true },
|
||||
{ "three", "EOS8SwZMY8DChbbmRKS3wdHCAbv1VWgTRmQEDSaLyJk8pG4wm8BJF", { 0x03, 0xd4, 0xc6, 0x2a, 0xdc, 0x11, 0x1c, 0x65, 0x7a, 0x9f, 0x5b, 0xba, 0x96, 0x3f, 0xbb, 0x2a, 0x69, 0x2e, 0xc5, 0x4a, 0x48, 0x3b, 0xa3, 0x5f, 0x2a, 0x37, 0x6c, 0x59, 0x95, 0xb1, 0x95, 0x1c, 0xc9 }, true },
|
||||
{ "wrong_checksum", "EOS8SwZMY8DChbbmRKS3wdHCAbv1VWgTRmQEDSaLyJk8pG4wm8EgC", { 0x0 }, false },
|
||||
{ "wrong_length", "EOS7kzJ5iFBmQWWT1LiWgAiocESD7TT", { 0x0 }, false },
|
||||
{ "not_base58", "EOS7IIIIIOOOO", { 0x0 }, false }
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
|
||||
SUBCASE(it->name) {
|
||||
libantelope::ec_pubkey_t result = { 0x0 };
|
||||
|
||||
CHECK( libantelope::wif_pub_decode(result, it->key) == it->expectedRet );
|
||||
CHECK( result == it->expected );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("WIF::wif_pub_decode [k1]") {
|
||||
struct testcase {
|
||||
const char* name;
|
||||
std::string key;
|
||||
libantelope::ec_pubkey_t expected;
|
||||
bool expectedRet;
|
||||
};
|
||||
|
||||
std::vector<struct testcase> tests {
|
||||
{ "one", "PUB_K1_7kzJ5iFBmQWWT1LiWgAiocESD7TTNuuPCdYREUQysruq7AxzWu", { 0x03, 0x7a, 0x0e, 0x6b, 0xfd, 0xe4, 0xf1, 0xad, 0x36, 0x3f, 0x3a, 0xf9, 0xe0, 0x93, 0x63, 0x5a, 0xa9, 0x99, 0x21, 0x15, 0xbc, 0x23, 0x35, 0x75, 0x13, 0x69, 0x55, 0xee, 0x3f, 0xf8, 0xfd, 0x97, 0xec }, true },
|
||||
{ "two", "PUB_K1_5c9HkNCJLDebe2Wvapp8bpB38Pf1QWNpkrsFy3mshg7DViSUUa", { 0x02, 0x5e, 0x94, 0xa5, 0xe7, 0x9f, 0x66, 0x37, 0x55, 0x7e, 0xc2, 0x28, 0x30, 0x40, 0x82, 0x9a, 0x38, 0x72, 0x10, 0x96, 0x6e, 0x15, 0xb7, 0xa5, 0x8a, 0x27, 0x9a, 0x71, 0x06, 0xa7, 0x64, 0x23, 0x30 }, true },
|
||||
{ "three", "PUB_K1_8SwZMY8DChbbmRKS3wdHCAbv1VWgTRmQEDSaLyJk8pG4wKBXpw", { 0x03, 0xd4, 0xc6, 0x2a, 0xdc, 0x11, 0x1c, 0x65, 0x7a, 0x9f, 0x5b, 0xba, 0x96, 0x3f, 0xbb, 0x2a, 0x69, 0x2e, 0xc5, 0x4a, 0x48, 0x3b, 0xa3, 0x5f, 0x2a, 0x37, 0x6c, 0x59, 0x95, 0xb1, 0x95, 0x1c, 0xc9 }, true },
|
||||
{ "wrong_checksum", "PUB_K1_8SwZMY8DChbbmRKS3wdHCAbv1VWgTRmQEDSaLyJk8pG4wKBXgE", { 0x0 }, false },
|
||||
{ "wrong_length", "PUB_K1_7kzJ5iFBmQWWT1LiWgAiocESD7TT", { 0x0 }, false },
|
||||
{ "not_base58", "PUB_K1_7IIIIIOOOO", { 0x0 }, false }
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
|
||||
SUBCASE(it->name) {
|
||||
libantelope::ec_pubkey_t result = { 0x0 };
|
||||
|
||||
CHECK( libantelope::wif_pub_decode(result, it->key) == it->expectedRet );
|
||||
CHECK( result == it->expected );
|
||||
}
|
||||
}
|
||||
}
|
||||
71
tests/WIF/pub_encode.cpp
Normal file
71
tests/WIF/pub_encode.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#include <libantelope/WIF.hpp>
|
||||
#include <libantelope/ec.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("WIF::wif_pub_encode [legacy]") {
|
||||
struct testcase {
|
||||
std::string name;
|
||||
const std::string prefix;
|
||||
libantelope::ec_pubkey_t key;
|
||||
std::string expected;
|
||||
};
|
||||
|
||||
std::vector<struct testcase> tests {
|
||||
{ "one", libantelope::WIF_PUB_LEG, { 0x03, 0x7a, 0x0e, 0x6b, 0xfd, 0xe4, 0xf1, 0xad, 0x36, 0x3f, 0x3a, 0xf9, 0xe0, 0x93, 0x63, 0x5a, 0xa9, 0x99, 0x21, 0x15, 0xbc, 0x23, 0x35, 0x75, 0x13, 0x69, 0x55, 0xee, 0x3f, 0xf8, 0xfd, 0x97, 0xec }, "EOS7kzJ5iFBmQWWT1LiWgAiocESD7TTNuuPCdYREUQysruq8VeFKy" },
|
||||
{ "two", libantelope::WIF_PUB_LEG, { 0x02, 0x5e, 0x94, 0xa5, 0xe7, 0x9f, 0x66, 0x37, 0x55, 0x7e, 0xc2, 0x28, 0x30, 0x40, 0x82, 0x9a, 0x38, 0x72, 0x10, 0x96, 0x6e, 0x15, 0xb7, 0xa5, 0x8a, 0x27, 0x9a, 0x71, 0x06, 0xa7, 0x64, 0x23, 0x30 }, "EOS5c9HkNCJLDebe2Wvapp8bpB38Pf1QWNpkrsFy3mshg7DZfPNeA" },
|
||||
{ "three", libantelope::WIF_PUB_LEG, { 0x03, 0xd4, 0xc6, 0x2a, 0xdc, 0x11, 0x1c, 0x65, 0x7a, 0x9f, 0x5b, 0xba, 0x96, 0x3f, 0xbb, 0x2a, 0x69, 0x2e, 0xc5, 0x4a, 0x48, 0x3b, 0xa3, 0x5f, 0x2a, 0x37, 0x6c, 0x59, 0x95, 0xb1, 0x95, 0x1c, 0xc9 }, "EOS8SwZMY8DChbbmRKS3wdHCAbv1VWgTRmQEDSaLyJk8pG4wm8BJF" }
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
|
||||
SUBCASE(it->name.c_str()) {
|
||||
CHECK( libantelope::wif_pub_encode(it->key, it->prefix) == it->expected );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("WIF::wif_pub_encode [custom prefix]") {
|
||||
|
||||
struct testcase {
|
||||
std::string name;
|
||||
libantelope::ec_pubkey_t key;
|
||||
std::string expected;
|
||||
};
|
||||
|
||||
std::vector<struct testcase> tests {
|
||||
{ "one", { 0x03, 0xfc, 0xcc, 0xcb, 0x20, 0x5a, 0x04, 0xfe, 0x34, 0x25, 0x1f, 0x1e, 0x75, 0x82, 0x85, 0x13, 0xed, 0xda, 0x6f, 0x33, 0xba, 0xf4, 0xeb, 0xc7, 0x4d, 0xc4, 0xa6, 0xe8, 0x91, 0x4a, 0xf6, 0x81, 0x43 }, "ZYX8kZxzEW6Loj9Nc3SUcHdS1TMH1zfu4JFu239Af1W3dXrA6GfHG" },
|
||||
{ "two", { 0x02, 0x8c, 0x58, 0xcb, 0xd4, 0xa4, 0xef, 0x23, 0xc3, 0xb8, 0x0e, 0x8f, 0xff, 0xe3, 0x4e, 0xe0, 0x1b, 0x64, 0x98, 0xe2, 0x12, 0xc9, 0xda, 0xbd, 0xee, 0x70, 0x7c, 0xf6, 0x6b, 0x2a, 0x15, 0x77, 0x06 }, "ZYX5xJKrJnDZQMzRZEzpm34g3MZxa93sANF5G1m9SnKH5gk7BCmAE" },
|
||||
{ "three", { 0x03, 0xa2, 0xea, 0xad, 0x09, 0x3e, 0x34, 0x31, 0x04, 0xa3, 0x7a, 0xc0, 0x10, 0x29, 0x5d, 0xce, 0x41, 0xb3, 0x60, 0x3a, 0x2d, 0x21, 0xd9, 0x44, 0x0f, 0x7b, 0x4c, 0xad, 0xad, 0x7e, 0x4f, 0x73, 0x78 }, "ZYX84z22iUYZ4tUfNDh8WNvL9wtfMn1mDtYpdezp2v73qcpLTVesz" }
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
|
||||
SUBCASE(it->name.c_str()) {
|
||||
CHECK( libantelope::wif_pub_encode(it->key, "ZYX") == it->expected );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("WIF::wif_pub_encode [k1]") {
|
||||
struct testcase {
|
||||
std::string name;
|
||||
const std::string prefix;
|
||||
libantelope::ec_pubkey_t key;
|
||||
std::string expected;
|
||||
};
|
||||
|
||||
std::vector<struct testcase> tests {
|
||||
{ "one", libantelope::WIF_PUB_K1, { 0x03, 0x7a, 0x0e, 0x6b, 0xfd, 0xe4, 0xf1, 0xad, 0x36, 0x3f, 0x3a, 0xf9, 0xe0, 0x93, 0x63, 0x5a, 0xa9, 0x99, 0x21, 0x15, 0xbc, 0x23, 0x35, 0x75, 0x13, 0x69, 0x55, 0xee, 0x3f, 0xf8, 0xfd, 0x97, 0xec }, "PUB_K1_7kzJ5iFBmQWWT1LiWgAiocESD7TTNuuPCdYREUQysruq7AxzWu" },
|
||||
{ "two", libantelope::WIF_PUB_K1, { 0x02, 0x5e, 0x94, 0xa5, 0xe7, 0x9f, 0x66, 0x37, 0x55, 0x7e, 0xc2, 0x28, 0x30, 0x40, 0x82, 0x9a, 0x38, 0x72, 0x10, 0x96, 0x6e, 0x15, 0xb7, 0xa5, 0x8a, 0x27, 0x9a, 0x71, 0x06, 0xa7, 0x64, 0x23, 0x30 }, "PUB_K1_5c9HkNCJLDebe2Wvapp8bpB38Pf1QWNpkrsFy3mshg7DViSUUa" },
|
||||
{ "three", libantelope::WIF_PUB_K1, { 0x03, 0xd4, 0xc6, 0x2a, 0xdc, 0x11, 0x1c, 0x65, 0x7a, 0x9f, 0x5b, 0xba, 0x96, 0x3f, 0xbb, 0x2a, 0x69, 0x2e, 0xc5, 0x4a, 0x48, 0x3b, 0xa3, 0x5f, 0x2a, 0x37, 0x6c, 0x59, 0x95, 0xb1, 0x95, 0x1c, 0xc9 }, "PUB_K1_8SwZMY8DChbbmRKS3wdHCAbv1VWgTRmQEDSaLyJk8pG4wKBXpw" }
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
|
||||
SUBCASE(it->name.c_str()) {
|
||||
CHECK( libantelope::wif_pub_encode(it->key, it->prefix) == it->expected );
|
||||
}
|
||||
}
|
||||
}
|
||||
100
tests/WIF/sig_decode.cpp
Normal file
100
tests/WIF/sig_decode.cpp
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
#include <libantelope/WIF.hpp>
|
||||
#include <libantelope/ec.hpp>
|
||||
#include <vector>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("WIF::wif_sig_decode") {
|
||||
|
||||
struct testcase {
|
||||
const char *name;
|
||||
std::string input;
|
||||
libantelope::ec_signature_t expected;
|
||||
bool expectedRet;
|
||||
};
|
||||
|
||||
std::vector<testcase> tests = {
|
||||
{
|
||||
"valid #1",
|
||||
"SIG_K1_KYq4LKCQ1Pdk38TY4FqwxiHRQd53b2kffB7G2Lt5WiV8VzZAvwCdbRVC5AjZvEkmXSEwyFkAFACHj1hYos8hB7Ass7RY2f",
|
||||
{
|
||||
0x20,0x1f,0x32,0xfb,0x5f,0x24,0xd2,0x57,
|
||||
0x5c,0xcc,0x51,0xf3,0xf1,0x60,0x47,0xf7,
|
||||
0x5c,0x5e,0x8e,0xb0,0xb1,0xc2,0x6d,0x76,
|
||||
0x07,0xc1,0x9e,0x24,0xd7,0xbb,0xc1,0x69,
|
||||
0x9a,0x04,0xba,0xa7,0x32,0xc7,0xef,0x83,
|
||||
0x1d,0xa9,0x40,0xde,0x9c,0xc8,0xf1,0xd9,
|
||||
0x7b,0xe5,0x0e,0xaf,0x90,0xdf,0xce,0x98,
|
||||
0xc5,0x34,0x55,0x04,0x9b,0x20,0x72,0x9a,
|
||||
0x96
|
||||
},
|
||||
true
|
||||
},
|
||||
{
|
||||
"valid #2",
|
||||
"SIG_K1_K2Liiq4wXeeWfndxGM23xms5AR5oK99RvKRR9NpW9eemKWKD1FmpmnwEbpZUSBzQC77KwYptvW6cwGjWR6D3qDddH3w69J",
|
||||
{
|
||||
0x1f,0x36,0x28,0x1c,0xe3,0xda,0x53,0x40,
|
||||
0x09,0x28,0xa8,0xad,0x68,0xb3,0x3a,0xb7,
|
||||
0x90,0xf7,0x55,0xff,0x60,0xf0,0x51,0x9b,
|
||||
0xb6,0xd8,0x48,0xff,0x09,0xbb,0x5d,0x17,
|
||||
0xa2,0x1a,0xe0,0x55,0xe5,0x75,0xf4,0xb9,
|
||||
0x67,0x5a,0x42,0x2c,0xf3,0x8f,0x40,0x32,
|
||||
0x1d,0x76,0x23,0x54,0xae,0xdc,0xfb,0xb9,
|
||||
0xf3,0x16,0x88,0x3e,0x62,0xec,0x7f,0x0d,
|
||||
0x9f
|
||||
},
|
||||
true
|
||||
},
|
||||
{
|
||||
"valid #3",
|
||||
"SIG_K1_Jxm4D2csP298MurVbsntqZvU6RrMvLufVGQ1URtjdKQ6tdbkkifW5ptcbhW7oGP9nfJ6rzW7Jqhgu2RsDm9ToDyCmy9yk7",
|
||||
{
|
||||
0x1f,0x1a,0xca,0x19,0x60,0x39,0x18,0x63,0x53,0x18,0xea,0x29,0x6e,0x4a,0x16,0x81,0x8f,0xf0,0xdc,0xe,0xad,0x38,0x1e,0x5f,0x0,0xde,0xb1,0xd5,0x1d,0xf5,0xe4,0xfb,0x8e,0x6d,0xdd,0x5d,0x79,0xe2,0x1,0x5d,0xac,0x75,0x72,0xcd,0xe7,0x84,0x47,0x8d,0x49,0x68,0xa0,0x7f,0x31,0x22,0xbb,0x6d,0x49,0x9b,0x43,0x92,0x83,0xec,0xbf,0xf8,0x4
|
||||
},
|
||||
true
|
||||
},
|
||||
{
|
||||
"invalid #1 - prefix",
|
||||
"PREF_KaK2DE1we98JKmQRfEP1TXcySbHAfVqUBCqhZ2VtUo3v4QFyFNPg2YRmsiRHk5ePFxqxhX1Y8VS2NC5DYfhQyTFmouTLBi",
|
||||
{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid #2 - wrong checksum",
|
||||
"SIG_K1_K2Liiq4wXeeWfndxGM23xms5AR5oK99RvKRR9NpW9eemKWKD1FmpmnwEbpZUSBzQC77KwYptvW6cwGjWR6D3qDddH3w6xx",
|
||||
{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid #3 - to long",
|
||||
"SIG_K1_uns8EQ4m3QJgVPPNNNc9HFDgvmsXe7yrAB66nsCnNjhH3zhBvzoBLf22GtWDwmpUQWByr7VExHZ8aZnuTMEDkHEaS4dzP8oT2qupW7HsCzeRKfSXMZ48jKnMV4aqiK8VqH66KD9Mn",
|
||||
{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid #4 - to short",
|
||||
"SIG_K1_8BTSpezp9ywsEwVPhMgMLgDMZV1xHuycq2DNbSrVcSZjriyK2FBrh5p518",
|
||||
{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid #5 - non-base58",
|
||||
"SIG_K1_6sCX2LiY2EpKdJtK7DJMGUETSNdDBNP3MjoZlF1i2V6RFhjoqd1jZbIAobdeARzQxpqHBvJpOWhKxBdA28CsVYJQe0VdcL",
|
||||
{},
|
||||
false,
|
||||
}
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
SUBCASE(it->name) {
|
||||
libantelope::ec_signature_t result;
|
||||
|
||||
CHECK( libantelope::wif_sig_decode(result, it->input) == it->expectedRet );
|
||||
|
||||
if (it->expectedRet == true) {
|
||||
CHECK( result == it->expected );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
53
tests/WIF/sig_encode.cpp
Normal file
53
tests/WIF/sig_encode.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#include <libantelope/WIF.hpp>
|
||||
#include <libantelope/ec.hpp>
|
||||
#include <vector>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("WIF::wif_sig_encode") {
|
||||
|
||||
struct testcase {
|
||||
const char *name;
|
||||
libantelope::ec_signature_t sig;
|
||||
std::string expected;
|
||||
|
||||
};
|
||||
|
||||
std::vector<struct testcase> tests = {
|
||||
{
|
||||
"first",
|
||||
{
|
||||
0x20,0x1f,0x32,0xfb,0x5f,0x24,0xd2,0x57,
|
||||
0x5c,0xcc,0x51,0xf3,0xf1,0x60,0x47,0xf7,
|
||||
0x5c,0x5e,0x8e,0xb0,0xb1,0xc2,0x6d,0x76,
|
||||
0x07,0xc1,0x9e,0x24,0xd7,0xbb,0xc1,0x69,
|
||||
0x9a,0x04,0xba,0xa7,0x32,0xc7,0xef,0x83,
|
||||
0x1d,0xa9,0x40,0xde,0x9c,0xc8,0xf1,0xd9,
|
||||
0x7b,0xe5,0x0e,0xaf,0x90,0xdf,0xce,0x98,
|
||||
0xc5,0x34,0x55,0x04,0x9b,0x20,0x72,0x9a,
|
||||
0x96
|
||||
},
|
||||
"SIG_K1_KYq4LKCQ1Pdk38TY4FqwxiHRQd53b2kffB7G2Lt5WiV8VzZAvwCdbRVC5AjZvEkmXSEwyFkAFACHj1hYos8hB7Ass7RY2f"
|
||||
},
|
||||
{
|
||||
"second",
|
||||
{
|
||||
0x1f,0x36,0x28,0x1c,0xe3,0xda,0x53,0x40,
|
||||
0x09,0x28,0xa8,0xad,0x68,0xb3,0x3a,0xb7,
|
||||
0x90,0xf7,0x55,0xff,0x60,0xf0,0x51,0x9b,
|
||||
0xb6,0xd8,0x48,0xff,0x09,0xbb,0x5d,0x17,
|
||||
0xa2,0x1a,0xe0,0x55,0xe5,0x75,0xf4,0xb9,
|
||||
0x67,0x5a,0x42,0x2c,0xf3,0x8f,0x40,0x32,
|
||||
0x1d,0x76,0x23,0x54,0xae,0xdc,0xfb,0xb9,
|
||||
0xf3,0x16,0x88,0x3e,0x62,0xec,0x7f,0x0d,
|
||||
0x9f
|
||||
},
|
||||
"SIG_K1_K2Liiq4wXeeWfndxGM23xms5AR5oK99RvKRR9NpW9eemKWKD1FmpmnwEbpZUSBzQC77KwYptvW6cwGjWR6D3qDddH3w69J"
|
||||
},
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
SUBCASE(it->name) {
|
||||
CHECK( libantelope::wif_sig_encode(it->sig) == it->expected );
|
||||
}
|
||||
}
|
||||
}
|
||||
48
tests/base58/decode.cpp
Normal file
48
tests/base58/decode.cpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#include <libantelope/base58.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("base58_decode") {
|
||||
struct testcase {
|
||||
const char* name;
|
||||
std::string in;
|
||||
std::string expectedOut;
|
||||
bool expectedReturn;
|
||||
};
|
||||
|
||||
std::vector<testcase> tests = {
|
||||
{"empty", "","", true},
|
||||
{"invalid","OI","",false},
|
||||
{
|
||||
"valid #1",
|
||||
"2nPTv2DT874jRaYBN4uhM9mT2iRiwdJuCXuX5buUHyyvWUSu6cX62i8HYo8PsWqgs9DHbwhpSpV5SVUnCqyLcpxcuGanH68eXgzZTGq",
|
||||
"Quisque ut ipsum lorem. Nullam ac justo elit. Sed gravida convallis mattis.",
|
||||
true
|
||||
},
|
||||
{
|
||||
"valid #2",
|
||||
"5yAgp6rBagDHQZ3GacZSeaEPF2jfuwVHM21aNfXETJgn3EkArxc5UWSq1RM",
|
||||
"Cras fringilla, eros et imperdiet tincidunt",
|
||||
true
|
||||
},
|
||||
{
|
||||
"valid #3",
|
||||
"9P7SxYWTWMq5hHkri53b1CGvWKRXxq3uXWPs5RiVtYagFrsnTXDxvKnk1twkPmV7BuxcRhBHWSwFLXpXbmdfHwZrnDaTB3wrBhsjm2Dd7F95ixh5vQLxajmT8hd22yUbvXuAZci8vTgFWMUyQi5YzWwntQiK5KFDkx3oA7kxvdU5t1yJZur84a9aKTCihEWtvCJ6LoBCpxvyB16YaCKeBQWLbUqoaXvFoDM78BpKD8biYyWQhnzHonjdwAS4KNXs5ByBdBvvPK1Q2Knr8zuFZxKHEFmgZGFTt8SMSsTDjkanUjojbfpJt5gcrHh6UFrt45n7kT9sj9Xsf1UyXZG3E2H85jXSbVnKowz2VPq1TkLLUKG8CSfdH3fVRp2E3yL5cpbbFWngbMzsbBZDgr4kPPcazebvSZ8qm8taBcBmt1ry25ey9TfFbMzP4FR1q9yjvkqGusMtrrBFm8YEeRmoMugMQoXvUgpExh29j",
|
||||
"Praesent massa nibh, feugiat ac aliquet sed, varius quis metus. Fusce auctor imperdiet purus. Vivamus elementum risus vel imperdiet condimentum. Nunc iaculis, sem eu sollicitudin tempus, nibh felis scelerisque orci, a tincidunt felis lectus in nulla. Vestibulum egestas eu elit id luctus. Vivamus eget ipsum neque. Fusce eleifend mauris a tempus vehicula.",
|
||||
true
|
||||
},
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
|
||||
SUBCASE(it->name) {
|
||||
std::vector<unsigned char> result;
|
||||
|
||||
std::vector<unsigned char> expectedOut(it->expectedOut.begin(), it->expectedOut.end());
|
||||
|
||||
CHECK( libantelope::base58_decode(it->in, result) == it->expectedReturn );
|
||||
CHECK( result == expectedOut );
|
||||
}
|
||||
}
|
||||
}
|
||||
34
tests/base58/encode.cpp
Normal file
34
tests/base58/encode.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#include <libantelope/base58.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("base58::base58_encode") {
|
||||
|
||||
struct testcase {
|
||||
const char* name;
|
||||
std::string in;
|
||||
std::string expected;
|
||||
};
|
||||
|
||||
std::vector<struct testcase> tests = {
|
||||
{"empty","",""},
|
||||
{
|
||||
"first",
|
||||
"Quisque ut ipsum lorem. Nullam ac justo elit. Sed gravida convallis mattis.",
|
||||
"2nPTv2DT874jRaYBN4uhM9mT2iRiwdJuCXuX5buUHyyvWUSu6cX62i8HYo8PsWqgs9DHbwhpSpV5SVUnCqyLcpxcuGanH68eXgzZTGq"
|
||||
},
|
||||
{
|
||||
"second",
|
||||
"Cras fringilla, eros et imperdiet tincidunt",
|
||||
"5yAgp6rBagDHQZ3GacZSeaEPF2jfuwVHM21aNfXETJgn3EkArxc5UWSq1RM"
|
||||
},
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
|
||||
SUBCASE(it->name) {
|
||||
CHECK( libantelope::base58_encode(it->in) == it->expected );
|
||||
}
|
||||
}
|
||||
}
|
||||
52
tests/base58/is_base58.cpp
Normal file
52
tests/base58/is_base58.cpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#include <libantelope/base58.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("base58::is_base58 [string]") {
|
||||
|
||||
struct testcase{
|
||||
const char *name;
|
||||
std::string input;
|
||||
size_t expected;
|
||||
};
|
||||
|
||||
std::vector<struct testcase> tests = {
|
||||
{"empty", "", std::string::npos},
|
||||
{"zero", "2SdasxuGGdVU5VVyrXiko4jKASeS57E0P9uokzUphZt7tZxt24bzsEwvre", 31},
|
||||
{"O", "2RTAsaYN2fpxVEDzaQht8ZnAUmwRpJz9C18VXrAWypxQSijRb9295kw13MA8krpRzK5cj2N5p84qQh3OGJrucW8hkLNy3aaEd2rTVhYkekhFiQoQ41JiNScD5KjmpDDxy", 79},
|
||||
{"I", "5hWrCBA55zLmKpIhZd3RS1DHsJ7SnZpnyBfmibqGpDCJ7QCJGkogvhqPvGuwMgwNHzuZFyR", 14},
|
||||
{"l", "lHxVA2fQKawLAK9MCJSr2xaWyDpoquQxVP6MMchdhzY49TjTfti8LDR6YL", 0},
|
||||
{"all_valid", "2BCoJ2BqNWorSoQcSWCQNanB8teoKFaqjojWGEXPBCPPdoGyVN8dgmKRdw", std::string::npos},
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
|
||||
SUBCASE(it->name) {
|
||||
CHECK(libantelope::is_base58(it->input) == it->expected);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
TEST_CASE("base58::is_base58 [char]") {
|
||||
std::string valid_alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
std::string invalid_alphabet = "0OIl";
|
||||
|
||||
|
||||
SUBCASE("valid") {
|
||||
|
||||
for(std::size_t i = 0; i < valid_alphabet.length(); i++) {
|
||||
char ch = valid_alphabet[i];
|
||||
|
||||
CHECK(libantelope::is_base58(ch));
|
||||
}
|
||||
}
|
||||
|
||||
SUBCASE("invalid") {
|
||||
for(std::size_t i = 0; i < invalid_alphabet.length(); i++) {
|
||||
char ch = invalid_alphabet[i];
|
||||
|
||||
CHECK_FALSE(libantelope::is_base58(ch));
|
||||
}
|
||||
}
|
||||
}
|
||||
3
tests/benchmark/CMakeLists.txt
Normal file
3
tests/benchmark/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
add_executable(bench_ec ec.cpp)
|
||||
target_link_libraries(bench_ec PRIVATE ${LIB_NAME})
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2019-2020 EOS Sw/eden
|
||||
* Copyright (c) 2019-2023 EOS Sw/eden
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -21,35 +21,40 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef LIBEOSIO_TYPES_H
|
||||
#define LIBEOSIO_TYPES_H
|
||||
#include <chrono>
|
||||
#include <libantelope/ec.hpp>
|
||||
#include <libantelope/WIF.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace libeosio {
|
||||
std::chrono::duration<float> _run(size_t num_keys) {
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
for(size_t i = 0; i < num_keys; i++) {
|
||||
struct libantelope::ec_keypair k;
|
||||
libantelope::ec_generate_key(&k);
|
||||
}
|
||||
return std::chrono::steady_clock::now() - start;
|
||||
}
|
||||
|
||||
#define EC_PRIVKEY_SIZE 32
|
||||
void test(size_t num_keys) {
|
||||
float t, kps;
|
||||
|
||||
/*
|
||||
* Compressed format!
|
||||
* z||x, where byte z specifies which (of the 2) solutions of the quadratic equation y is.
|
||||
* Each cordinate is 32 bytes.
|
||||
*/
|
||||
#define EC_PUBKEY_SIZE (32 + 1)
|
||||
|
||||
typedef std::array<unsigned char, EC_PRIVKEY_SIZE> ec_privkey_t;
|
||||
typedef std::array<unsigned char, EC_PUBKEY_SIZE> ec_pubkey_t;
|
||||
std::cout << "Running benchmark for " << num_keys << " keys" << std::endl;
|
||||
t = _run(num_keys).count();
|
||||
kps = static_cast<float>(num_keys) / t;
|
||||
|
||||
struct ec_keypair {
|
||||
ec_privkey_t secret;
|
||||
ec_pubkey_t pub;
|
||||
};
|
||||
std::cout << "Time: " << t << std::endl
|
||||
<< "KPS: " << kps << std::endl;
|
||||
}
|
||||
|
||||
// Hashes.
|
||||
int main() {
|
||||
libantelope::ec_init();
|
||||
|
||||
typedef struct { unsigned char data[20]; } ripemd160_t;
|
||||
typedef struct { unsigned char data[32]; } sha256_t;
|
||||
test(1000);
|
||||
test(10000);
|
||||
test(100000);
|
||||
|
||||
} // namespace libeosio
|
||||
libantelope::ec_shutdown();
|
||||
|
||||
#endif /* LIBEOSIO_TYPES_H */
|
||||
return 0;
|
||||
}
|
||||
189
tests/cmake/doctest.cmake
Normal file
189
tests/cmake/doctest.cmake
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
doctest
|
||||
-----
|
||||
|
||||
This module defines a function to help use the doctest test framework.
|
||||
|
||||
The :command:`doctest_discover_tests` discovers tests by asking the compiled test
|
||||
executable to enumerate its tests. This does not require CMake to be re-run
|
||||
when tests change. However, it may not work in a cross-compiling environment,
|
||||
and setting test properties is less convenient.
|
||||
|
||||
This command is intended to replace use of :command:`add_test` to register
|
||||
tests, and will create a separate CTest test for each doctest test case. Note
|
||||
that this is in some cases less efficient, as common set-up and tear-down logic
|
||||
cannot be shared by multiple test cases executing in the same instance.
|
||||
However, it provides more fine-grained pass/fail information to CTest, which is
|
||||
usually considered as more beneficial. By default, the CTest test name is the
|
||||
same as the doctest name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
||||
|
||||
.. command:: doctest_discover_tests
|
||||
|
||||
Automatically add tests with CTest by querying the compiled test executable
|
||||
for available tests::
|
||||
|
||||
doctest_discover_tests(target
|
||||
[TEST_SPEC arg1...]
|
||||
[EXTRA_ARGS arg1...]
|
||||
[WORKING_DIRECTORY dir]
|
||||
[TEST_PREFIX prefix]
|
||||
[TEST_SUFFIX suffix]
|
||||
[PROPERTIES name1 value1...]
|
||||
[ADD_LABELS value]
|
||||
[TEST_LIST var]
|
||||
[JUNIT_OUTPUT_DIR dir]
|
||||
)
|
||||
|
||||
``doctest_discover_tests`` sets up a post-build command on the test executable
|
||||
that generates the list of tests by parsing the output from running the test
|
||||
with the ``--list-test-cases`` argument. This ensures that the full
|
||||
list of tests is obtained. Since test discovery occurs at build time, it is
|
||||
not necessary to re-run CMake when the list of tests changes.
|
||||
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
|
||||
in order to function in a cross-compiling environment.
|
||||
|
||||
Additionally, setting properties on tests is somewhat less convenient, since
|
||||
the tests are not available at CMake time. Additional test properties may be
|
||||
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
|
||||
more fine-grained test control is needed, custom content may be provided
|
||||
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
|
||||
directory property. The set of discovered tests is made accessible to such a
|
||||
script via the ``<target>_TESTS`` variable.
|
||||
|
||||
The options are:
|
||||
|
||||
``target``
|
||||
Specifies the doctest executable, which must be a known CMake executable
|
||||
target. CMake will substitute the location of the built executable when
|
||||
running the test.
|
||||
|
||||
``TEST_SPEC arg1...``
|
||||
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
||||
pass to the doctest executable with the ``--list-test-cases`` argument.
|
||||
|
||||
``EXTRA_ARGS arg1...``
|
||||
Any extra arguments to pass on the command line to each test case.
|
||||
|
||||
``WORKING_DIRECTORY dir``
|
||||
Specifies the directory in which to run the discovered test cases. If this
|
||||
option is not provided, the current binary directory is used.
|
||||
|
||||
``TEST_PREFIX prefix``
|
||||
Specifies a ``prefix`` to be prepended to the name of each discovered test
|
||||
case. This can be useful when the same test executable is being used in
|
||||
multiple calls to ``doctest_discover_tests()`` but with different
|
||||
``TEST_SPEC`` or ``EXTRA_ARGS``.
|
||||
|
||||
``TEST_SUFFIX suffix``
|
||||
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
|
||||
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
|
||||
be specified.
|
||||
|
||||
``PROPERTIES name1 value1...``
|
||||
Specifies additional properties to be set on all tests discovered by this
|
||||
invocation of ``doctest_discover_tests``.
|
||||
|
||||
``ADD_LABELS value``
|
||||
Specifies if the test labels should be set automatically.
|
||||
|
||||
``TEST_LIST var``
|
||||
Make the list of tests available in the variable ``var``, rather than the
|
||||
default ``<target>_TESTS``. This can be useful when the same test
|
||||
executable is being used in multiple calls to ``doctest_discover_tests()``.
|
||||
Note that this variable is only available in CTest.
|
||||
|
||||
``JUNIT_OUTPUT_DIR dir``
|
||||
If specified, the parameter is passed along with ``--reporters=junit``
|
||||
and ``--out=`` to the test executable. The actual file name is the same
|
||||
as the test target, including prefix and suffix. This should be used
|
||||
instead of EXTRA_ARGS to avoid race conditions writing the XML result
|
||||
output when using parallel test execution.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
function(doctest_discover_tests TARGET)
|
||||
cmake_parse_arguments(
|
||||
""
|
||||
""
|
||||
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;JUNIT_OUTPUT_DIR"
|
||||
"TEST_SPEC;EXTRA_ARGS;PROPERTIES;ADD_LABELS"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
if(NOT _WORKING_DIRECTORY)
|
||||
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
if(NOT _TEST_LIST)
|
||||
set(_TEST_LIST ${TARGET}_TESTS)
|
||||
endif()
|
||||
|
||||
## Generate a unique name based on the extra arguments
|
||||
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
|
||||
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
||||
|
||||
# Define rule to generate test list for aforementioned test executable
|
||||
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
|
||||
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
|
||||
get_property(crosscompiling_emulator
|
||||
TARGET ${TARGET}
|
||||
PROPERTY CROSSCOMPILING_EMULATOR
|
||||
)
|
||||
add_custom_command(
|
||||
TARGET ${TARGET} POST_BUILD
|
||||
BYPRODUCTS "${ctest_tests_file}"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-D "TEST_TARGET=${TARGET}"
|
||||
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
|
||||
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
|
||||
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
|
||||
-D "TEST_SPEC=${_TEST_SPEC}"
|
||||
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
|
||||
-D "TEST_PROPERTIES=${_PROPERTIES}"
|
||||
-D "TEST_ADD_LABELS=${_ADD_LABELS}"
|
||||
-D "TEST_PREFIX=${_TEST_PREFIX}"
|
||||
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
|
||||
-D "TEST_LIST=${_TEST_LIST}"
|
||||
-D "TEST_JUNIT_OUTPUT_DIR=${_JUNIT_OUTPUT_DIR}"
|
||||
-D "CTEST_FILE=${ctest_tests_file}"
|
||||
-P "${_DOCTEST_DISCOVER_TESTS_SCRIPT}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
file(WRITE "${ctest_include_file}"
|
||||
"if(EXISTS \"${ctest_tests_file}\")\n"
|
||||
" include(\"${ctest_tests_file}\")\n"
|
||||
"else()\n"
|
||||
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
||||
"endif()\n"
|
||||
)
|
||||
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.10)
|
||||
# Add discovered tests to directory TEST_INCLUDE_FILES
|
||||
set_property(DIRECTORY
|
||||
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
|
||||
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
|
||||
if(NOT ${test_include_file_set})
|
||||
set_property(DIRECTORY
|
||||
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Cannot set more than one TEST_INCLUDE_FILE"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
###############################################################################
|
||||
|
||||
set(_DOCTEST_DISCOVER_TESTS_SCRIPT
|
||||
${CMAKE_CURRENT_LIST_DIR}/doctestAddTests.cmake
|
||||
)
|
||||
120
tests/cmake/doctestAddTests.cmake
Normal file
120
tests/cmake/doctestAddTests.cmake
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
set(prefix "${TEST_PREFIX}")
|
||||
set(suffix "${TEST_SUFFIX}")
|
||||
set(spec ${TEST_SPEC})
|
||||
set(extra_args ${TEST_EXTRA_ARGS})
|
||||
set(properties ${TEST_PROPERTIES})
|
||||
set(add_labels ${TEST_ADD_LABELS})
|
||||
set(junit_output_dir "${TEST_JUNIT_OUTPUT_DIR}")
|
||||
set(script)
|
||||
set(suite)
|
||||
set(tests)
|
||||
|
||||
function(add_command NAME)
|
||||
set(_args "")
|
||||
foreach(_arg ${ARGN})
|
||||
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
||||
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
||||
else()
|
||||
set(_args "${_args} ${_arg}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Run test executable to get list of available tests
|
||||
if(NOT EXISTS "${TEST_EXECUTABLE}")
|
||||
message(FATAL_ERROR
|
||||
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
|
||||
)
|
||||
endif()
|
||||
|
||||
if("${spec}" MATCHES .)
|
||||
set(spec "--test-case=${spec}")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-cases
|
||||
OUTPUT_VARIABLE output
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||
)
|
||||
if(NOT ${result} EQUAL 0)
|
||||
message(FATAL_ERROR
|
||||
"Error running test executable '${TEST_EXECUTABLE}':\n"
|
||||
" Result: ${result}\n"
|
||||
" Output: ${output}\n"
|
||||
)
|
||||
endif()
|
||||
|
||||
string(REPLACE "\n" ";" output "${output}")
|
||||
|
||||
# Parse output
|
||||
foreach(line ${output})
|
||||
if("${line}" STREQUAL "===============================================================================" OR "${line}" MATCHES [==[^\[doctest\] ]==])
|
||||
continue()
|
||||
endif()
|
||||
set(test ${line})
|
||||
set(labels "")
|
||||
if(${add_labels})
|
||||
# get test suite that test belongs to
|
||||
execute_process(
|
||||
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" --test-case=${test} --list-test-suites
|
||||
OUTPUT_VARIABLE labeloutput
|
||||
RESULT_VARIABLE labelresult
|
||||
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||
)
|
||||
if(NOT ${labelresult} EQUAL 0)
|
||||
message(FATAL_ERROR
|
||||
"Error running test executable '${TEST_EXECUTABLE}':\n"
|
||||
" Result: ${labelresult}\n"
|
||||
" Output: ${labeloutput}\n"
|
||||
)
|
||||
endif()
|
||||
|
||||
string(REPLACE "\n" ";" labeloutput "${labeloutput}")
|
||||
foreach(labelline ${labeloutput})
|
||||
if("${labelline}" STREQUAL "===============================================================================" OR "${labelline}" MATCHES [==[^\[doctest\] ]==])
|
||||
continue()
|
||||
endif()
|
||||
list(APPEND labels ${labelline})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(NOT "${junit_output_dir}" STREQUAL "")
|
||||
# turn testname into a valid filename by replacing all special characters with "-"
|
||||
string(REGEX REPLACE "[/\\:\"|<>]" "-" test_filename "${test}")
|
||||
set(TEST_JUNIT_OUTPUT_PARAM "--reporters=junit" "--out=${junit_output_dir}/${prefix}${test_filename}${suffix}.xml")
|
||||
else()
|
||||
unset(TEST_JUNIT_OUTPUT_PARAM)
|
||||
endif()
|
||||
# use escape commas to handle properly test cases with commas inside the name
|
||||
string(REPLACE "," "\\," test_name ${test})
|
||||
# ...and add to script
|
||||
add_command(add_test
|
||||
"${prefix}${test}${suffix}"
|
||||
${TEST_EXECUTOR}
|
||||
"${TEST_EXECUTABLE}"
|
||||
"--test-case=${test_name}"
|
||||
"${TEST_JUNIT_OUTPUT_PARAM}"
|
||||
${extra_args}
|
||||
)
|
||||
add_command(set_tests_properties
|
||||
"${prefix}${test}${suffix}"
|
||||
PROPERTIES
|
||||
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||
${properties}
|
||||
LABELS ${labels}
|
||||
)
|
||||
unset(labels)
|
||||
list(APPEND tests "${prefix}${test}${suffix}")
|
||||
endforeach()
|
||||
|
||||
# Create a list of all discovered tests, which users may use to e.g. set
|
||||
# properties on the tests
|
||||
add_command(set ${TEST_LIST} ${tests})
|
||||
|
||||
# Write CTest script
|
||||
file(WRITE "${CTEST_FILE}" "${script}")
|
||||
103
tests/ec/ecdsa_recover.cpp
Normal file
103
tests/ec/ecdsa_recover.cpp
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#include <libantelope/ec.hpp>
|
||||
#include <vector>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("ec::ecdsa_recover") {
|
||||
|
||||
struct testcase {
|
||||
const char *name;
|
||||
libantelope::sha256_t dgst;
|
||||
libantelope::ec_signature_t sig;
|
||||
libantelope::ec_pubkey_t expected;
|
||||
int expectedRet;
|
||||
};
|
||||
|
||||
std::vector<testcase> tests = {
|
||||
{
|
||||
"valid #1",
|
||||
{
|
||||
0xab, 0x53, 0x0a, 0x13, 0xe4, 0x59, 0x14, 0x98,
|
||||
0x2b, 0x79, 0xf9, 0xb7, 0xe3, 0xfb, 0xa9, 0x94,
|
||||
0xcf, 0xd1, 0xf3, 0xfb, 0x22, 0xf7, 0x1c, 0xea,
|
||||
0x1a, 0xfb, 0xf0, 0x2b, 0x46, 0x0c, 0x6d, 0x1d
|
||||
},
|
||||
// SIG_K1_KdgBih1poWj8DYZXwLxMdjaHMzYhuAVp7XshR9ZjrZSubZwsgSpiyUKXu44NmCtKgRFswmqKaioWLTuGZrXwYPsSNCSyyr
|
||||
{
|
||||
0x20, 0x44, 0x3f, 0x72, 0x22, 0xfd, 0x7a, 0x1f, 0x56, 0x2d, 0xef, 0x01, 0x55, 0x40, 0xcf, 0x50, 0x6f, 0x5f, 0xdd, 0xfe, 0x71, 0xd7, 0x18, 0xc9, 0xa8, 0xc8, 0xbe, 0x00, 0x96, 0xf8, 0x7c, 0xc7,
|
||||
0x1f, 0x2d, 0xd0, 0xd1, 0xfc, 0x4a, 0x22, 0x6a, 0x25, 0xc4, 0x7c, 0x99, 0xf9, 0xd8, 0x30, 0xfa, 0x8b, 0x5c, 0x33, 0x36, 0x61, 0xd7, 0xcf, 0x6d, 0x04, 0x97, 0x61, 0x76, 0x47, 0x65, 0x30, 0x7b,
|
||||
0x66
|
||||
},
|
||||
// Public Key: EOS6zjfj9Xjk9CYoucZDptdDZ6317eZd622pVvaYtv5q6gwEs9icD
|
||||
{ 0x03, 0x15, 0x93, 0x8a, 0x8e, 0x1d, 0x57, 0x84, 0x9f, 0xab, 0x07, 0x18, 0x67, 0xb5, 0x0c, 0xda, 0xb0, 0x77, 0x62, 0x29, 0xb6, 0x43, 0xb8, 0x67, 0x56, 0xc7, 0xb3, 0xe8, 0x7f, 0xe6, 0x08, 0xf8, 0x4b },
|
||||
0
|
||||
},
|
||||
{
|
||||
"valid #2",
|
||||
{
|
||||
0x19, 0xd3, 0xe0, 0x8b, 0xbb, 0xad, 0x5f, 0x02,
|
||||
0x35, 0xa8, 0xa8, 0xf8, 0x1a, 0x7f, 0xa1, 0xe0,
|
||||
0xf8, 0x50, 0xdd, 0x39, 0x12, 0xe3, 0xc6, 0x55,
|
||||
0xb4, 0x35, 0xd4, 0x78, 0x6b, 0x93, 0x64, 0xa6
|
||||
},
|
||||
// SIG_K1_K4XXx6oSYBzcwzscMstvSxruxdkTCinyN9dnRo4DuBkCCpQbCJQcJmbE7aAmNueBYCccHyyDK5JDfMpvewRF2rGUFtSE2y
|
||||
{
|
||||
0x1f, 0x46, 0xde, 0x7a, 0x7e, 0x87, 0xa7, 0xb0, 0x42, 0xce, 0xdc, 0x57, 0xc9, 0x0d, 0x64, 0x4c, 0xc7, 0x4d, 0xe6, 0x19, 0x5d, 0x34, 0x4e, 0xba, 0xfb, 0xdf, 0x26, 0x79, 0xa1, 0xc6, 0x99, 0x98,
|
||||
0xa7, 0x1f, 0x65, 0xcd, 0xab, 0x2d, 0x19, 0x75, 0x27, 0xdc, 0xb2, 0xc5, 0x46, 0x87, 0x5d, 0xbe, 0xc5, 0x8d, 0xb2, 0xb8, 0x7f, 0x15, 0x47, 0xd7, 0xc7, 0x94, 0x0a, 0xd5, 0x52, 0xd9, 0xe3, 0x93,
|
||||
0xd7
|
||||
},
|
||||
// Public Key: EOS6tVtKhTpM6yU7kkiRz1AecDJPcBQo2w4x4oytJbJi5PMV2Rcw2
|
||||
{ 0x03, 0x07, 0x69, 0xbb, 0xa5, 0x2c, 0xd2, 0xe1, 0x3b, 0x3e, 0x0a, 0x40, 0xb3, 0xa2, 0x44, 0xad, 0x71, 0x6e, 0x32, 0x64, 0x9c, 0x3a, 0x64, 0x27, 0x4f, 0x31, 0x86, 0x8a, 0x4c, 0x69, 0x58, 0x86, 0x49 },
|
||||
0
|
||||
},
|
||||
{
|
||||
"valid #3",
|
||||
{
|
||||
0x1b, 0x01, 0x0b, 0xe5, 0xce, 0x6a, 0x49, 0xc7,
|
||||
0xcd, 0x04, 0x86, 0x0d, 0xef, 0x63, 0x1c, 0x6a,
|
||||
0xcc, 0xd5, 0x17, 0x47, 0x2e, 0x74, 0x5b, 0xa6,
|
||||
0xc8, 0xaf, 0x26, 0x1b, 0x15, 0x7e, 0x11, 0xec
|
||||
},
|
||||
// SIG_K1_K54CVeQjFREm9Z92jutWESZWb9WQfCRZ2KfMtisfsnxedppeSMxTrZ9fYDLiJTfE79zvLCHb5NysAEcNdh7HiBvtU4Ahhh
|
||||
{
|
||||
0x1f, 0x4a, 0xe9, 0x04, 0x20, 0xfa, 0x7b, 0x9d, 0x56, 0xc6, 0x00, 0x5c, 0x83, 0x70, 0xa9, 0x26, 0x41, 0x7d, 0xe8, 0xeb, 0xe7, 0x75, 0xea, 0x6f, 0x75, 0xa7, 0x7c, 0x98, 0x10, 0x27, 0xbf, 0xce,
|
||||
0x48, 0x41, 0x74, 0xb0, 0xe3, 0xb1, 0x4b, 0x06, 0x2c, 0x53, 0x93, 0xbc, 0x35, 0xea, 0xac, 0xd7, 0x9e, 0x07, 0xa7, 0xa1, 0x2e, 0xac, 0xa0, 0x81, 0x45, 0xdb, 0xd4, 0x53, 0x68, 0xda, 0xaa, 0xc6,
|
||||
0xfc
|
||||
},
|
||||
// Public Key: EOS7Xtaa4y44gYapth4MH5bdtCvdtQvVLdsW7a8thVAuvNAkj8X7i
|
||||
{ 0x03, 0x5c, 0x50, 0x81, 0xef, 0xa6, 0x46, 0x00, 0x5a, 0xb9, 0xd8, 0x2b, 0xfe, 0xd8, 0xe1, 0x6d, 0x15, 0x42, 0x9e, 0x9a, 0xcb, 0xc9, 0xd6, 0xb3, 0x2e, 0x5a, 0xe3, 0xed, 0xa5, 0x8d, 0x6a, 0x42, 0x6c },
|
||||
0
|
||||
},
|
||||
{
|
||||
"not valid #1 (non valid signature)",
|
||||
{
|
||||
0xde, 0x01, 0x64, 0x03, 0x39, 0x01, 0x66, 0x8b,
|
||||
0xa0, 0x39, 0xef, 0x31, 0x61, 0xc7, 0xc8, 0x9d,
|
||||
0x15, 0x4b, 0xc6, 0x7b, 0x99, 0x5c, 0xba, 0x9b,
|
||||
0x23, 0x8a, 0x76, 0x4b, 0x81, 0xf2, 0xff, 0xeb
|
||||
},
|
||||
{
|
||||
0x1f, 0x4b, 0xe9, 0x04, 0x20, 0xfa, 0x7b, 0x9d, 0x56, 0xc6, 0x00, 0x5c, 0x83, 0x70, 0xa9, 0x26, 0x41, 0x7d, 0xe8, 0xeb, 0xe7, 0x75, 0xea, 0x6f, 0x75, 0xa7, 0x7c, 0x98, 0x10, 0x27, 0xbf, 0xce,
|
||||
0x48, 0x41, 0x74, 0xb0, 0xe3, 0xb1, 0x4b, 0x06, 0x2c, 0x53, 0x93, 0xbc, 0x35, 0xea, 0xac, 0xd7, 0x9e, 0x07, 0xa7, 0xa1, 0x2e, 0xac, 0xa0, 0x81, 0x45, 0xdb, 0xd4, 0x53, 0x68, 0xda, 0xaa, 0xc6,
|
||||
0xfe
|
||||
},
|
||||
{ },
|
||||
-1
|
||||
},
|
||||
};
|
||||
|
||||
libantelope::ec_init();
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
SUBCASE(it->name) {
|
||||
libantelope::ec_pubkey_t result;
|
||||
|
||||
CHECK( libantelope::ecdsa_recover(&it->dgst, it->sig, result) == it->expectedRet );
|
||||
|
||||
if (it->expectedRet == 0) {
|
||||
CHECK( result == it->expected );
|
||||
}
|
||||
}
|
||||
}
|
||||
libantelope::ec_shutdown();
|
||||
}
|
||||
|
||||
115
tests/ec/ecdsa_sign.cpp
Normal file
115
tests/ec/ecdsa_sign.cpp
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
#include <libantelope/ec.hpp>
|
||||
#include <vector>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("ec::ecdsa_sign") {
|
||||
|
||||
struct testcase {
|
||||
const char *name;
|
||||
libantelope::ec_privkey_t key;
|
||||
libantelope::ec_pubkey_t pub;
|
||||
libantelope::sha256_t dgst;
|
||||
};
|
||||
|
||||
std::vector<testcase> tests = {
|
||||
{
|
||||
"valid #1",
|
||||
// Private Key: 5Ke4YqL2TCtiUTTA1CVMXSrrEHuK9HzbUSWX791yC2UaX2dWRDw
|
||||
{ 0xf0, 0x2d, 0x00, 0x72, 0x8a, 0x7a, 0x93, 0x86, 0xaf, 0xbe, 0x19, 0xab, 0x79, 0x8c, 0xa1, 0x61, 0xab, 0x96, 0x74, 0x7f, 0xe5, 0x97, 0x19, 0x07, 0xb1, 0xc8, 0x65, 0x63, 0xc8, 0x11, 0xe6, 0x74 },
|
||||
// Public key: EOS6zjfj9Xjk9CYoucZDptdDZ6317eZd622pVvaYtv5q6gwEs9icD
|
||||
{ 0x03, 0x15, 0x93, 0x8a, 0x8e, 0x1d, 0x57, 0x84, 0x9f, 0xab, 0x07, 0x18, 0x67, 0xb5, 0x0c, 0xda, 0xb0, 0x77, 0x62, 0x29, 0xb6, 0x43, 0xb8, 0x67, 0x56, 0xc7, 0xb3, 0xe8, 0x7f, 0xe6, 0x08, 0xf8, 0x4b },
|
||||
{
|
||||
0xab, 0x53, 0x0a, 0x13, 0xe4, 0x59, 0x14, 0x98,
|
||||
0x2b, 0x79, 0xf9, 0xb7, 0xe3, 0xfb, 0xa9, 0x94,
|
||||
0xcf, 0xd1, 0xf3, 0xfb, 0x22, 0xf7, 0x1c, 0xea,
|
||||
0x1a, 0xfb, 0xf0, 0x2b, 0x46, 0x0c, 0x6d, 0x1d
|
||||
},
|
||||
},
|
||||
{
|
||||
"valid #2",
|
||||
// Private Key: 5J1VLF3TtdM3FiaUZNjeUXTUmVmRRULSdxrGf3XwQkRAZLcN64b
|
||||
{ 0x19, 0x6f, 0xd7, 0xa5, 0x3f, 0xab, 0x59, 0x8e, 0xa5, 0xef, 0xec, 0x79, 0xdd, 0xbc, 0x49, 0xae, 0xef, 0xff, 0x41, 0x3c, 0x5f, 0xfe, 0x50, 0x3a, 0x66, 0xbc, 0xff, 0xf1, 0x32, 0x1b, 0x8c, 0x2f },
|
||||
// Public key: EOS6tVtKhTpM6yU7kkiRz1AecDJPcBQo2w4x4oytJbJi5PMV2Rcw2
|
||||
{ 0x03, 0x07, 0x69, 0xbb, 0xa5, 0x2c, 0xd2, 0xe1, 0x3b, 0x3e, 0x0a, 0x40, 0xb3, 0xa2, 0x44, 0xad, 0x71, 0x6e, 0x32, 0x64, 0x9c, 0x3a, 0x64, 0x27, 0x4f, 0x31, 0x86, 0x8a, 0x4c, 0x69, 0x58, 0x86, 0x49 },
|
||||
{
|
||||
0x19, 0xd3, 0xe0, 0x8b, 0xbb, 0xad, 0x5f, 0x02,
|
||||
0x35, 0xa8, 0xa8, 0xf8, 0x1a, 0x7f, 0xa1, 0xe0,
|
||||
0xf8, 0x50, 0xdd, 0x39, 0x12, 0xe3, 0xc6, 0x55,
|
||||
0xb4, 0x35, 0xd4, 0x78, 0x6b, 0x93, 0x64, 0xa6
|
||||
},
|
||||
},
|
||||
{
|
||||
"valid #3",
|
||||
// Private Key: 5Hz2iVzC9jDcBUGo2EUSPdcvL1s8jxJ6pY95gQX59mHoHx6zi6W
|
||||
{ 0x16, 0x1f, 0xd0, 0x41, 0x21, 0x50, 0x04, 0x13, 0x90, 0x61, 0xb3, 0xbd, 0xc8, 0x83, 0x09, 0xf0, 0x80, 0x3c, 0x90, 0x45, 0x8e, 0x9a, 0x8c, 0xb2, 0xfb, 0x6a, 0x3c, 0x27, 0x51, 0xcf, 0xd9, 0xca },
|
||||
// Public key: EOS7Xtaa4y44gYapth4MH5bdtCvdtQvVLdsW7a8thVAuvNAkj8X7i
|
||||
{ 0x03, 0x5c, 0x50, 0x81, 0xef, 0xa6, 0x46, 0x00, 0x5a, 0xb9, 0xd8, 0x2b, 0xfe, 0xd8, 0xe1, 0x6d, 0x15, 0x42, 0x9e, 0x9a, 0xcb, 0xc9, 0xd6, 0xb3, 0x2e, 0x5a, 0xe3, 0xed, 0xa5, 0x8d, 0x6a, 0x42, 0x6c },
|
||||
{
|
||||
0x1b, 0x01, 0x0b, 0xe5, 0xce, 0x6a, 0x49, 0xc7,
|
||||
0xcd, 0x04, 0x86, 0x0d, 0xef, 0x63, 0x1c, 0x6a,
|
||||
0xcc, 0xd5, 0x17, 0x47, 0x2e, 0x74, 0x5b, 0xa6,
|
||||
0xc8, 0xaf, 0x26, 0x1b, 0x15, 0x7e, 0x11, 0xec
|
||||
},
|
||||
},
|
||||
{
|
||||
"valid #4",
|
||||
// Private Key: 5KbH8qYyg6f93gHuAdbDmwCVMoarXHqEn5CdbW2VtHTyMsLShwM
|
||||
{ 0xe9, 0xdb, 0x4d, 0xdc, 0x8e, 0x08, 0xd2, 0x04, 0x75, 0xc2, 0xb6, 0xf7, 0x14, 0x9e, 0xa2, 0x16, 0xd7, 0x2b, 0x34, 0x3b, 0xba, 0xb4, 0x7d, 0xe6, 0xd3, 0x96, 0xc1, 0x63, 0x82, 0xdf, 0x2d, 0x13 },
|
||||
// Public key: EOS6E12fqQqWLYJS32ffB6LaQYxyDXUQSPfMTMnj6tc5bgntZKcBy
|
||||
{ 0x02, 0xaf, 0xff, 0xeb, 0xef, 0x47, 0x70, 0x58, 0x2f, 0x9b, 0x66, 0x6c, 0xe0, 0xea, 0x84, 0x32, 0x41, 0xa0, 0x94, 0x36, 0x30, 0x9b, 0xfc, 0xdb, 0x9a, 0x58, 0xdd, 0x0e, 0xe6, 0x3e, 0xd4, 0x5a, 0xcd },
|
||||
{
|
||||
0xbc, 0x83, 0xbe, 0xe1, 0x73, 0x82, 0xfb, 0x02,
|
||||
0x71, 0x25, 0x3b, 0xf5, 0x39, 0x32, 0x55, 0x4e,
|
||||
0x01, 0x28, 0x5d, 0xf4, 0x02, 0xe8, 0xa2, 0x92,
|
||||
0x04, 0xf2, 0x95, 0xbc, 0xfa, 0xed, 0x8f, 0xaa
|
||||
},
|
||||
},
|
||||
{
|
||||
"valid #5",
|
||||
// Private Key: 5KUb7Y5UqoVggesYJzuNcEmjGtQMpfMiVaEDr9E5K1vNgZqvHok
|
||||
{ 0xda, 0xaa, 0x85, 0x66, 0xf5, 0xc9, 0x4c, 0xfa, 0x1f, 0x72, 0x30, 0x8e, 0xb8, 0xed, 0x8c, 0xd7, 0x2b, 0x08, 0x80, 0xc8, 0x2b, 0x9d, 0xe9, 0x0a, 0x81, 0xec, 0x8f, 0x3e, 0xe7, 0x75, 0xf0, 0x3c },
|
||||
// Public key: EOS6uqJC6F7eEMq7SHREhTzRoAT7uumrmHDDYC595CJKeBgPvPojd
|
||||
{ 0x03, 0x0a, 0x71, 0x8e, 0x48, 0x1a, 0x7a, 0x55, 0x84, 0xb9, 0xaf, 0x24, 0xca, 0x8f, 0x85, 0xcd, 0x0f, 0x55, 0x5c, 0xcf, 0xb3, 0x7b, 0x39, 0x5b, 0xa5, 0xfc, 0xb9, 0xaf, 0x26, 0xc7, 0xc7, 0x88, 0x7b },
|
||||
{
|
||||
0xfc, 0xb2, 0x0d, 0xa1, 0x22, 0x6c, 0xcc, 0x59,
|
||||
0x26, 0x66, 0xba, 0x57, 0xeb, 0x4a, 0xfa, 0x20,
|
||||
0xff, 0x40, 0x7b, 0xc7, 0x3c, 0x35, 0xb8, 0xaa,
|
||||
0x72, 0x3e, 0x94, 0xcc, 0x05, 0xe1, 0x51, 0xc7
|
||||
},
|
||||
},
|
||||
{
|
||||
"valid #6",
|
||||
// Private Key: 5K4ErsLWnMv53tfFhtp5JF9CYKwmr89Pt2BEpoak1bfdgvHK2fj
|
||||
{ 0xa3, 0x60, 0xd7, 0x80, 0xdc, 0xe8, 0x3c, 0x5d, 0xc8, 0x61, 0xa1, 0x24, 0x6f, 0x65, 0x9e, 0x16, 0x79, 0x40, 0x10, 0x27, 0xfc, 0x9a, 0x40, 0x3f, 0x2b, 0x40, 0x7a, 0xfd, 0x1e, 0x42, 0xde, 0x84 },
|
||||
// Public key: EOS5YiBwqnFXqeb5hCmwV9bLHp6Jg5hVnRjzYVApf2DXyRGr7B7kZ
|
||||
{ 0x02, 0x56, 0xc9, 0x41, 0x90, 0x44, 0x8a, 0xcc, 0x89, 0x91, 0x79, 0xaf, 0x4e, 0x3a, 0x72, 0xa7, 0x24, 0x86, 0x7f, 0xd8, 0x03, 0x07, 0x04, 0x30, 0xd3, 0xf3, 0x6b, 0x20, 0x94, 0x85, 0x78, 0xfc, 0x38 },
|
||||
{
|
||||
0xd2, 0xfa, 0xa6, 0x97, 0x12, 0xd7, 0x04, 0x05,
|
||||
0xe8, 0x60, 0x7e, 0x86, 0x73, 0x69, 0x05, 0x90,
|
||||
0x97, 0xa2, 0x57, 0xee, 0x12, 0x4b, 0x80, 0x13,
|
||||
0x04, 0xfa, 0x7d, 0x70, 0xe7, 0xdc, 0x86, 0xb2
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
libantelope::ec_init();
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
SUBCASE(it->name) {
|
||||
libantelope::ec_signature_t result;
|
||||
|
||||
CHECK( libantelope::ecdsa_sign(it->key, &it->dgst, result) == 0 );
|
||||
|
||||
// Need to use verify here as different implemententations produces different signatures.
|
||||
// (i have tested eosjs, eos-go and ofc libantelope)
|
||||
// However, the signatures are correct and can be validated by all implementations.
|
||||
//
|
||||
// Now, how do we know that ecdsa_verify is correct?
|
||||
// well, in escdsa_verify.cpp there are tests that checks hardcoded signatures generated by different implementations and should be fine.
|
||||
|
||||
CHECK( libantelope::ecdsa_verify(&it->dgst, result, it->pub) == 0);
|
||||
}
|
||||
}
|
||||
libantelope::ec_shutdown();
|
||||
}
|
||||
|
||||
189
tests/ec/ecdsa_verify.cpp
Normal file
189
tests/ec/ecdsa_verify.cpp
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
#include <libantelope/ec.hpp>
|
||||
#include <vector>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("ec::ecdsa_verify") {
|
||||
|
||||
struct testcase {
|
||||
const char *name;
|
||||
libantelope::sha256_t dgst;
|
||||
libantelope::ec_pubkey_t pubkey;
|
||||
libantelope::ec_signature_t sig;
|
||||
int expected;
|
||||
};
|
||||
|
||||
std::vector<testcase> tests = {
|
||||
{
|
||||
"valid #1",
|
||||
{
|
||||
0xab, 0x53, 0x0a, 0x13, 0xe4, 0x59, 0x14, 0x98,
|
||||
0x2b, 0x79, 0xf9, 0xb7, 0xe3, 0xfb, 0xa9, 0x94,
|
||||
0xcf, 0xd1, 0xf3, 0xfb, 0x22, 0xf7, 0x1c, 0xea,
|
||||
0x1a, 0xfb, 0xf0, 0x2b, 0x46, 0x0c, 0x6d, 0x1d
|
||||
},
|
||||
// Public Key: EOS6zjfj9Xjk9CYoucZDptdDZ6317eZd622pVvaYtv5q6gwEs9icD
|
||||
{ 0x03, 0x15, 0x93, 0x8a, 0x8e, 0x1d, 0x57, 0x84, 0x9f, 0xab, 0x07, 0x18, 0x67, 0xb5, 0x0c, 0xda, 0xb0, 0x77, 0x62, 0x29, 0xb6, 0x43, 0xb8, 0x67, 0x56, 0xc7, 0xb3, 0xe8, 0x7f, 0xe6, 0x08, 0xf8, 0x4b },
|
||||
// SIG_K1_KdgBih1poWj8DYZXwLxMdjaHMzYhuAVp7XshR9ZjrZSubZwsgSpiyUKXu44NmCtKgRFswmqKaioWLTuGZrXwYPsSNCSyyr
|
||||
{
|
||||
0x20, 0x44, 0x3f, 0x72, 0x22, 0xfd, 0x7a, 0x1f, 0x56, 0x2d, 0xef, 0x01, 0x55, 0x40, 0xcf, 0x50, 0x6f, 0x5f, 0xdd, 0xfe, 0x71, 0xd7, 0x18, 0xc9, 0xa8, 0xc8, 0xbe, 0x00, 0x96, 0xf8, 0x7c, 0xc7,
|
||||
0x1f, 0x2d, 0xd0, 0xd1, 0xfc, 0x4a, 0x22, 0x6a, 0x25, 0xc4, 0x7c, 0x99, 0xf9, 0xd8, 0x30, 0xfa, 0x8b, 0x5c, 0x33, 0x36, 0x61, 0xd7, 0xcf, 0x6d, 0x04, 0x97, 0x61, 0x76, 0x47, 0x65, 0x30, 0x7b,
|
||||
0x66
|
||||
},
|
||||
0
|
||||
},
|
||||
{
|
||||
"valid #2 (generated by openssl)",
|
||||
{
|
||||
0xab, 0x53, 0x0a, 0x13, 0xe4, 0x59, 0x14, 0x98,
|
||||
0x2b, 0x79, 0xf9, 0xb7, 0xe3, 0xfb, 0xa9, 0x94,
|
||||
0xcf, 0xd1, 0xf3, 0xfb, 0x22, 0xf7, 0x1c, 0xea,
|
||||
0x1a, 0xfb, 0xf0, 0x2b, 0x46, 0x0c, 0x6d, 0x1d
|
||||
},
|
||||
// Public Key: EOS6zjfj9Xjk9CYoucZDptdDZ6317eZd622pVvaYtv5q6gwEs9icD
|
||||
{ 0x03, 0x15, 0x93, 0x8a, 0x8e, 0x1d, 0x57, 0x84, 0x9f, 0xab, 0x07, 0x18, 0x67, 0xb5, 0x0c, 0xda, 0xb0, 0x77, 0x62, 0x29, 0xb6, 0x43, 0xb8, 0x67, 0x56, 0xc7, 0xb3, 0xe8, 0x7f, 0xe6, 0x08, 0xf8, 0x4b },
|
||||
// SIG_K1_KWRk7botFjDfjNrfk63ud9qEwZbuJ7un8vpEKNzHJ6aSj6eMSVNXmbiXUZV4fsP7PE1kVjYEqtayghNTh1w7ea5ajq4Nrn
|
||||
{
|
||||
0x20, 0x0c, 0xd6, 0xe7, 0xfe, 0x3f, 0xfa, 0x01, 0x93, 0xd2, 0x3b, 0xaa, 0xdd, 0xae, 0x5d, 0x91, 0x76, 0x3a, 0x41, 0xb0, 0x14, 0xdc, 0x29, 0xfc, 0x1b, 0x25, 0x77, 0x40, 0x4a, 0x0c, 0x59, 0xc6,
|
||||
0x77, 0x49, 0x4d, 0xf5, 0x07, 0xc9, 0xfd, 0xf5, 0x11, 0xb5, 0x09, 0xe0, 0xf1, 0x72, 0x4c, 0x08, 0x75, 0xda, 0x47, 0x78, 0x65, 0x12, 0x16, 0x39, 0x1f, 0x6c, 0x9b, 0x22, 0x6c, 0xfa, 0xdd, 0x08,
|
||||
0xb9
|
||||
},
|
||||
0
|
||||
},
|
||||
{
|
||||
"valid #3 (generated by eos-go)",
|
||||
{
|
||||
0xab, 0x53, 0x0a, 0x13, 0xe4, 0x59, 0x14, 0x98,
|
||||
0x2b, 0x79, 0xf9, 0xb7, 0xe3, 0xfb, 0xa9, 0x94,
|
||||
0xcf, 0xd1, 0xf3, 0xfb, 0x22, 0xf7, 0x1c, 0xea,
|
||||
0x1a, 0xfb, 0xf0, 0x2b, 0x46, 0x0c, 0x6d, 0x1d
|
||||
},
|
||||
// Public Key: EOS6zjfj9Xjk9CYoucZDptdDZ6317eZd622pVvaYtv5q6gwEs9icD
|
||||
{ 0x03, 0x15, 0x93, 0x8a, 0x8e, 0x1d, 0x57, 0x84, 0x9f, 0xab, 0x07, 0x18, 0x67, 0xb5, 0x0c, 0xda, 0xb0, 0x77, 0x62, 0x29, 0xb6, 0x43, 0xb8, 0x67, 0x56, 0xc7, 0xb3, 0xe8, 0x7f, 0xe6, 0x08, 0xf8, 0x4b },
|
||||
// SIG_K1_KbRFLvuUdpSwpEYuDQ7EmB3ByGF9i6HdpXS8rxkLeLaKdxFoELh1RVewVyZg2x9ZwstSrJfaLuEgDa8R9RQwkntJFAvQc2
|
||||
{
|
||||
0x20, 0x32, 0xfd, 0xf9, 0x6d, 0x2d, 0xa5, 0xda, 0xf1, 0x4d, 0x75, 0x2e, 0xcf, 0x91, 0x06, 0x9d, 0xbb, 0x6a, 0x24, 0x79, 0xd1, 0x70, 0x8d, 0xc7, 0xa2, 0xc2, 0xc0, 0xb4, 0xf6, 0xb7, 0x2b, 0x06,
|
||||
0xbe, 0x37, 0xc7, 0xbb, 0x3b, 0xe6, 0x47, 0x4c, 0xff, 0x6d, 0x90, 0x02, 0xd4, 0x73, 0x0d, 0x5d, 0xb3, 0x76, 0xc6, 0x52, 0xae, 0xca, 0x90, 0x31, 0xf3, 0xf1, 0x76, 0x5a, 0xbb, 0xad, 0xa5, 0xbc,
|
||||
0x5f
|
||||
},
|
||||
0
|
||||
},
|
||||
{
|
||||
"valid #4 (generated by eosjs)",
|
||||
{
|
||||
0xab, 0x53, 0x0a, 0x13, 0xe4, 0x59, 0x14, 0x98,
|
||||
0x2b, 0x79, 0xf9, 0xb7, 0xe3, 0xfb, 0xa9, 0x94,
|
||||
0xcf, 0xd1, 0xf3, 0xfb, 0x22, 0xf7, 0x1c, 0xea,
|
||||
0x1a, 0xfb, 0xf0, 0x2b, 0x46, 0x0c, 0x6d, 0x1d
|
||||
},
|
||||
// Public Key: EOS6zjfj9Xjk9CYoucZDptdDZ6317eZd622pVvaYtv5q6gwEs9icD
|
||||
{ 0x03, 0x15, 0x93, 0x8a, 0x8e, 0x1d, 0x57, 0x84, 0x9f, 0xab, 0x07, 0x18, 0x67, 0xb5, 0x0c, 0xda, 0xb0, 0x77, 0x62, 0x29, 0xb6, 0x43, 0xb8, 0x67, 0x56, 0xc7, 0xb3, 0xe8, 0x7f, 0xe6, 0x08, 0xf8, 0x4b },
|
||||
// SIG_K1_JzpX9nSsAiQkNLLZ1vSfmDrFQd7228zFhVopCH7S1TnbQ844mDbJeXBF1qifFAcWKBL2mxX7oqj9tgBEPwtu8KY8cWLMim
|
||||
{
|
||||
0x1f, 0x2a, 0x88, 0x81, 0x3c, 0xce, 0x11, 0xbf, 0x5a, 0x59, 0x77, 0x8c, 0x32, 0x5b, 0x3b, 0xe8, 0x78, 0x8f, 0x7f, 0x7d, 0x18, 0x1a, 0x6d, 0xb3, 0x7b, 0x36, 0x18, 0x3f, 0xc2, 0xba, 0xb5, 0xab, 0x61, 0x69, 0x89, 0x9c, 0xb9, 0x44, 0x2c, 0x19, 0x2a, 0xa3, 0xb8, 0x3d, 0x2d, 0x09, 0xd0, 0xc4, 0x1a, 0x67, 0xc7, 0xa6, 0x5d, 0xf5, 0x10, 0xb4, 0x75, 0x05, 0x69, 0x4e, 0x4e, 0xc0, 0x5f, 0x34, 0x9e
|
||||
},
|
||||
0
|
||||
},
|
||||
|
||||
{
|
||||
"valid #4",
|
||||
{
|
||||
0x19, 0xd3, 0xe0, 0x8b, 0xbb, 0xad, 0x5f, 0x02,
|
||||
0x35, 0xa8, 0xa8, 0xf8, 0x1a, 0x7f, 0xa1, 0xe0,
|
||||
0xf8, 0x50, 0xdd, 0x39, 0x12, 0xe3, 0xc6, 0x55,
|
||||
0xb4, 0x35, 0xd4, 0x78, 0x6b, 0x93, 0x64, 0xa6
|
||||
},
|
||||
// Public Key: EOS6tVtKhTpM6yU7kkiRz1AecDJPcBQo2w4x4oytJbJi5PMV2Rcw2
|
||||
{ 0x03, 0x07, 0x69, 0xbb, 0xa5, 0x2c, 0xd2, 0xe1, 0x3b, 0x3e, 0x0a, 0x40, 0xb3, 0xa2, 0x44, 0xad, 0x71, 0x6e, 0x32, 0x64, 0x9c, 0x3a, 0x64, 0x27, 0x4f, 0x31, 0x86, 0x8a, 0x4c, 0x69, 0x58, 0x86, 0x49 },
|
||||
// SIG_K1_K4XXx6oSYBzcwzscMstvSxruxdkTCinyN9dnRo4DuBkCCpQbCJQcJmbE7aAmNueBYCccHyyDK5JDfMpvewRF2rGUFtSE2y
|
||||
{
|
||||
0x1f, 0x46, 0xde, 0x7a, 0x7e, 0x87, 0xa7, 0xb0, 0x42, 0xce, 0xdc, 0x57, 0xc9, 0x0d, 0x64, 0x4c, 0xc7, 0x4d, 0xe6, 0x19, 0x5d, 0x34, 0x4e, 0xba, 0xfb, 0xdf, 0x26, 0x79, 0xa1, 0xc6, 0x99, 0x98,
|
||||
0xa7, 0x1f, 0x65, 0xcd, 0xab, 0x2d, 0x19, 0x75, 0x27, 0xdc, 0xb2, 0xc5, 0x46, 0x87, 0x5d, 0xbe, 0xc5, 0x8d, 0xb2, 0xb8, 0x7f, 0x15, 0x47, 0xd7, 0xc7, 0x94, 0x0a, 0xd5, 0x52, 0xd9, 0xe3, 0x93,
|
||||
0xd7
|
||||
},
|
||||
0
|
||||
},
|
||||
{
|
||||
"valid #5",
|
||||
{
|
||||
0x1b, 0x01, 0x0b, 0xe5, 0xce, 0x6a, 0x49, 0xc7,
|
||||
0xcd, 0x04, 0x86, 0x0d, 0xef, 0x63, 0x1c, 0x6a,
|
||||
0xcc, 0xd5, 0x17, 0x47, 0x2e, 0x74, 0x5b, 0xa6,
|
||||
0xc8, 0xaf, 0x26, 0x1b, 0x15, 0x7e, 0x11, 0xec
|
||||
},
|
||||
// Public Key: EOS7Xtaa4y44gYapth4MH5bdtCvdtQvVLdsW7a8thVAuvNAkj8X7i
|
||||
{ 0x03, 0x5c, 0x50, 0x81, 0xef, 0xa6, 0x46, 0x00, 0x5a, 0xb9, 0xd8, 0x2b, 0xfe, 0xd8, 0xe1, 0x6d, 0x15, 0x42, 0x9e, 0x9a, 0xcb, 0xc9, 0xd6, 0xb3, 0x2e, 0x5a, 0xe3, 0xed, 0xa5, 0x8d, 0x6a, 0x42, 0x6c },
|
||||
// SIG_K1_K54CVeQjFREm9Z92jutWESZWb9WQfCRZ2KfMtisfsnxedppeSMxTrZ9fYDLiJTfE79zvLCHb5NysAEcNdh7HiBvtU4Ahhh
|
||||
{
|
||||
0x1f, 0x4a, 0xe9, 0x04, 0x20, 0xfa, 0x7b, 0x9d, 0x56, 0xc6, 0x00, 0x5c, 0x83, 0x70, 0xa9, 0x26, 0x41, 0x7d, 0xe8, 0xeb, 0xe7, 0x75, 0xea, 0x6f, 0x75, 0xa7, 0x7c, 0x98, 0x10, 0x27, 0xbf, 0xce,
|
||||
0x48, 0x41, 0x74, 0xb0, 0xe3, 0xb1, 0x4b, 0x06, 0x2c, 0x53, 0x93, 0xbc, 0x35, 0xea, 0xac, 0xd7, 0x9e, 0x07, 0xa7, 0xa1, 0x2e, 0xac, 0xa0, 0x81, 0x45, 0xdb, 0xd4, 0x53, 0x68, 0xda, 0xaa, 0xc6,
|
||||
0xfc
|
||||
},
|
||||
0
|
||||
},
|
||||
{
|
||||
"not valid #1",
|
||||
{
|
||||
0xde, 0x01, 0x64, 0x03, 0x39, 0x01, 0x66, 0x8b,
|
||||
0xa0, 0x39, 0xef, 0x31, 0x61, 0xc7, 0xc8, 0x9d,
|
||||
0x15, 0x4b, 0xc6, 0x7b, 0x99, 0x5c, 0xba, 0x9b,
|
||||
0x23, 0x8a, 0x76, 0x4b, 0x81, 0xf2, 0xff, 0xeb
|
||||
},
|
||||
// Public Key: EOS7Xtaa4y44gYapth4MH5bdtCvdtQvVLdsW7a8thVAuvNAkj8X7i
|
||||
{ 0x03, 0x5c, 0x50, 0x81, 0xef, 0xa6, 0x46, 0x00, 0x5a, 0xb9, 0xd8, 0x2b, 0xfe, 0xd8, 0xe1, 0x6d, 0x15, 0x42, 0x9e, 0x9a, 0xcb, 0xc9, 0xd6, 0xb3, 0x2e, 0x5a, 0xe3, 0xed, 0xa5, 0x8d, 0x6a, 0x42, 0x6c },
|
||||
// SIG_K1_K54CVeQjFREm9Z92jutWESZWb9WQfCRZ2KfMtisfsnxedppeSMxTrZ9fYDLiJTfE79zvLCHb5NysAEcNdh7HiBvtU4Ahhh
|
||||
{
|
||||
0x1f, 0x4a, 0xe9, 0x04, 0x20, 0xfa, 0x7b, 0x9d, 0x56, 0xc6, 0x00, 0x5c, 0x83, 0x70, 0xa9, 0x26, 0x41, 0x7d, 0xe8, 0xeb, 0xe7, 0x75, 0xea, 0x6f, 0x75, 0xa7, 0x7c, 0x98, 0x10, 0x27, 0xbf, 0xce,
|
||||
0x48, 0x41, 0x74, 0xb0, 0xe3, 0xb1, 0x4b, 0x06, 0x2c, 0x53, 0x93, 0xbc, 0x35, 0xea, 0xac, 0xd7, 0x9e, 0x07, 0xa7, 0xa1, 0x2e, 0xac, 0xa0, 0x81, 0x45, 0xdb, 0xd4, 0x53, 0x68, 0xda, 0xaa, 0xc6,
|
||||
0xfc
|
||||
},
|
||||
-1
|
||||
},
|
||||
{
|
||||
"not valid #2",
|
||||
{
|
||||
0xa7, 0xf7, 0x89, 0x36, 0xea, 0xb7, 0x95, 0xa7,
|
||||
0x71, 0xaa, 0x73, 0xb5, 0xf6, 0xb8, 0xa0, 0x40,
|
||||
0xe5, 0x4f, 0xb3, 0x87, 0xff, 0xd9, 0xb6, 0x4e,
|
||||
0x30, 0x4c, 0xa3, 0x78, 0xab, 0x68, 0x86, 0x24
|
||||
},
|
||||
// EOS5AxTzvLZ7mRPvo1Ju9nCdB31PruYHE9uar8pF6D3CvZQGWcHq8
|
||||
{ 0x02, 0x25, 0x64, 0x31, 0x9d, 0x41, 0x46, 0x82, 0xeb, 0x60, 0xed, 0x17, 0xe9, 0x8a, 0xd1, 0x21, 0x60, 0xc4, 0x65, 0xe7, 0x7e, 0x73, 0x2e, 0x45, 0xf0, 0x78, 0x8b, 0x7f, 0x43, 0x30, 0x71, 0xbc, 0x34 },
|
||||
// SIG_K1_K4QgBwbwAP879cjV66LjPmEBoVA3FXesYp6KxRbbshVeQRSJmgreFkBYx3eBTHNdJx2dxZatx9sRJvwh1JY2F2U6APmHKE
|
||||
{
|
||||
0x1f, 0x45, 0xf7, 0x1c, 0x26, 0x39, 0x8a, 0x32, 0x5c, 0xfe, 0xb4, 0xc3, 0x46, 0x51, 0x22, 0x88, 0xef, 0x3b, 0xad, 0xb2, 0x5f, 0x29, 0x23, 0xab, 0x26, 0xbd, 0x3a, 0x1f, 0xbf, 0x24, 0x12, 0x36,
|
||||
0x3f, 0x73, 0xfe, 0x26, 0xfc, 0x3b, 0xd0, 0xca, 0xf1, 0xdd, 0x9d, 0x80, 0x68, 0xb9, 0x66, 0x1d, 0xc4, 0xf9, 0x6f, 0x07, 0x9e, 0xe9, 0xf2, 0x4d, 0x4e, 0xff, 0xc1, 0xd1, 0xe1, 0xf1, 0xbc, 0x6f,
|
||||
0x72
|
||||
},
|
||||
-1
|
||||
},
|
||||
{
|
||||
"not valid #3",
|
||||
{
|
||||
0x48, 0xd7, 0xd3, 0x83,0x9c, 0xa2, 0x82, 0xde,
|
||||
0xb6, 0x9a, 0xb8, 0x34,0x36, 0xb0, 0x9f, 0x19,
|
||||
0xbb, 0xdf, 0x2b, 0xb5,0x39, 0x42, 0x92, 0x32,
|
||||
0x33, 0x34, 0x84, 0xdd,0xba, 0xbd, 0x95, 0x43
|
||||
},
|
||||
// EOS5vhJWLeBjQAiTZxWdnFkttUDWANurEka69La2nu8fp2gSi5eQk
|
||||
{ 0x02, 0x88, 0xb4, 0x83, 0x3a, 0x86, 0x18, 0xd3, 0xb2, 0x2b, 0xbe, 0xe6, 0x59, 0x3d, 0xf2, 0x41, 0xf6, 0xed, 0x86, 0x40, 0xe6, 0x19, 0xc8, 0x45, 0x03, 0x78, 0x57, 0xde, 0xcb, 0x2a, 0xd7, 0xc2, 0xf0 },
|
||||
// SIG_K1_K2XJBWCnx98kr8N3fe25BFDpsc8M4nERkzYSWpVAMoXBv9Nw83xDTTSErstUnh25scMGDHn9TsAqNirNruWRM3jzdKGe7m
|
||||
{
|
||||
0x1f, 0x37, 0x8c, 0xf2, 0xbe, 0xb1, 0x18, 0xb7, 0x80, 0x60, 0xd5, 0x60, 0x9f, 0xee, 0x7b, 0x36, 0xcc, 0x42, 0x9c, 0x12, 0xb8, 0xd1, 0x5f, 0x62, 0xad, 0x88, 0x4f, 0x6c, 0x65, 0xa1, 0x70, 0x03,
|
||||
0x30, 0x1b, 0x65, 0x80, 0xc9, 0xe9, 0xba, 0xfe, 0xcf, 0xcc, 0xdb, 0x2d, 0xf0, 0x37, 0x1b, 0x00, 0x39, 0xb5, 0x16, 0x7c, 0xde, 0xec, 0x4b, 0xec, 0xc1, 0xf4, 0xf2, 0x6f, 0x1b, 0xfa, 0x80, 0x9d,
|
||||
0x81
|
||||
},
|
||||
-1
|
||||
},
|
||||
};
|
||||
|
||||
libantelope::ec_init();
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
SUBCASE(it->name) {
|
||||
CHECK( libantelope::ecdsa_verify(&it->dgst, it->sig, it->pubkey) == it->expected );
|
||||
}
|
||||
}
|
||||
|
||||
libantelope::ec_shutdown();
|
||||
}
|
||||
|
||||
18
tests/ec/generate.cpp
Normal file
18
tests/ec/generate.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#include <libantelope/ec.hpp>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("ec::generate") {
|
||||
|
||||
libantelope::ec_init();
|
||||
|
||||
libantelope::ec_pubkey_t result;
|
||||
libantelope::ec_keypair pair;
|
||||
CHECK(libantelope::ec_generate_key(&pair) == 0);
|
||||
|
||||
// Can't test much because... well the private key should be random :)
|
||||
// But alteast verify that the public key belongs to the private key.
|
||||
CHECK(libantelope::ec_get_publickey(&pair.secret, &result) == 0);
|
||||
CHECK( result == pair.pub );
|
||||
|
||||
libantelope::ec_shutdown();
|
||||
}
|
||||
140
tests/ec/pubkey.cpp
Normal file
140
tests/ec/pubkey.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
#include <libantelope/ec.hpp>
|
||||
#include <libantelope/WIF.hpp>
|
||||
#include <vector>
|
||||
#include <doctest.h>
|
||||
|
||||
TEST_CASE("ec::pubkey") {
|
||||
|
||||
|
||||
struct testcase {
|
||||
std::string name;
|
||||
libantelope::ec_privkey_t priv;
|
||||
libantelope::ec_pubkey_t expected;
|
||||
};
|
||||
|
||||
std::vector<struct testcase> tests {
|
||||
{
|
||||
"valid #1",
|
||||
// 5KWCD8zm3nHbYSZhq4rfnX3VxXGnKzcorwnqi9QoYvkyj6kSVYr
|
||||
{
|
||||
0xde, 0x4f, 0x8a, 0x59, 0x12, 0x2d, 0xee, 0x24,
|
||||
0xf3, 0x75, 0x39, 0x00, 0xa5, 0x2c, 0x64, 0x58,
|
||||
0x31, 0x5a, 0x1e, 0xea, 0x14, 0x30, 0x1b, 0x4d,
|
||||
0x61, 0x6d, 0x2e, 0xab, 0x48, 0x48, 0xf3, 0xe1
|
||||
},
|
||||
// EOS6bmyyDPYt3ZXZF1VGKnKN4pbMuZPnFBoK7xkvXmyYUnXmBTSYq
|
||||
{
|
||||
0x02, 0xe1, 0x71, 0x50, 0x31, 0x19, 0x5b, 0xe8,
|
||||
0xe0, 0x92, 0xec, 0x61, 0xfc, 0x93, 0xa8, 0x81,
|
||||
0x2a, 0x1e, 0x83, 0x74, 0xc3, 0x5f, 0x5b, 0xe0,
|
||||
0xfd, 0xb7, 0xd4, 0x32, 0xa6, 0xb9, 0x87, 0x61,
|
||||
0x1b
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid #2",
|
||||
// 5KCjzBFK5jiUdwjwFzqymHbVoUEjhbK86CGiDKtuwXrP2xyDZLY
|
||||
{
|
||||
0xb6, 0xae, 0xfa, 0x9a, 0xc2, 0x1e, 0x56, 0xb8,
|
||||
0x70, 0xa1, 0x14, 0x4e, 0x7f, 0xaa, 0x70, 0x30,
|
||||
0x5b, 0x6d, 0xc4, 0x94, 0xd5, 0x05, 0xba, 0xf7,
|
||||
0x77, 0x82, 0x93, 0xf2, 0x91, 0x15, 0x9b, 0x00
|
||||
},
|
||||
// EOS75mzwjLQAKaVdtGKe5MjfjQY9UJRZqa1iGcpkvZQ6jLE8ptE2j
|
||||
{
|
||||
0x03, 0x21, 0x05, 0x4d, 0x71, 0x0d, 0x08, 0x32,
|
||||
0x67, 0xf9, 0xca, 0xa4, 0x16, 0x9e, 0x42, 0xca,
|
||||
0xa6, 0xa2, 0x90, 0xe4, 0xbf, 0xe4, 0xc6, 0x79,
|
||||
0x30, 0x69, 0x3d, 0xe7, 0x00, 0x76, 0x40, 0xea,
|
||||
0x11
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid #3",
|
||||
// 5KfQfL9BKMsW1eNBYqFRJ7SgDAFzJcNH8UsXd1RWHdFUzUxJEKf
|
||||
{
|
||||
0xf3, 0x3b, 0xd8, 0x45, 0xaf, 0x53, 0x1e, 0x51,
|
||||
0x88, 0x62, 0x03, 0x46, 0xa9, 0x13, 0x54, 0x5b,
|
||||
0xf9, 0x6c, 0x95, 0x23, 0x9b, 0xbb, 0xbe, 0xd9,
|
||||
0xff, 0x91, 0xde, 0x0d, 0x5a, 0x38, 0x9e, 0x8f
|
||||
},
|
||||
// EOS6DqV9RU4D5bN8TMg6G4Gcby56UxxBMfk21XotQ2TDuzDyA3QjN
|
||||
{
|
||||
0x02, 0xaf, 0xa0, 0x46, 0xa0, 0x36, 0x8a, 0xf4,
|
||||
0x55, 0xd1, 0x60, 0x8d, 0xf8, 0x6d, 0x2f, 0x73,
|
||||
0x24, 0xe4, 0x6e, 0xa9, 0xf2, 0x37, 0x47, 0x83,
|
||||
0x6b, 0x74, 0x3a, 0x0e, 0xb6, 0x8f, 0x6b, 0xed,
|
||||
0x51
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid #4",
|
||||
// 5KfdPV9x9BNqrDQoB4XfX8PyGyA6Nhwi6DtAG9KmEpyRNomNFoP
|
||||
{
|
||||
0xf3, 0xbb, 0x64, 0xc9, 0xc8, 0x8c, 0xb1, 0x8c,
|
||||
0xc2, 0xbc, 0xd7, 0x03, 0x5c, 0x53, 0xa0, 0xd6,
|
||||
0xeb, 0x53, 0xea, 0xb5, 0x20, 0x45, 0x92, 0xb1,
|
||||
0xed, 0x9b, 0x1e, 0x6a, 0x01, 0xe9, 0x1a, 0xdd
|
||||
|
||||
},
|
||||
// EOS7B1MBLsYbo7dppCwPG6L25AaS1wTGeaVtjLFKo8ue1Yo317G65
|
||||
{
|
||||
0x03, 0x2c, 0xe5, 0x7b, 0x76, 0x3d, 0xb6, 0x33,
|
||||
0x10, 0xb2, 0x0b, 0x04, 0xb5, 0x32, 0xeb, 0xad,
|
||||
0x0f, 0x27, 0x18, 0x77, 0xe8, 0x5a, 0x32, 0xc3,
|
||||
0x76, 0x12, 0x1a, 0x85, 0xf3, 0x61, 0x3b, 0x5d,
|
||||
0x4b
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid #5",
|
||||
// 5KRrtvA13uHmKVy6ofjEQQvcciGKeC2NTGYeoAGMYrNp56dn98y
|
||||
{
|
||||
0xd4, 0x78, 0xdb, 0x03, 0x2d, 0xf3, 0xfa, 0xad,
|
||||
0x21, 0xa0, 0xdd, 0x36, 0xb1, 0xf5, 0xf5, 0x13,
|
||||
0xc4, 0x8a, 0xe1, 0xa8, 0x37, 0xfa, 0x2e, 0x1b,
|
||||
0xaa, 0x69, 0x2c, 0xf8, 0xf9, 0x5e, 0xb1, 0x87
|
||||
|
||||
},
|
||||
// EOS54o7UHWAPXxHtrWS3uoZDJ6npud84R9w8XVMPYZNKhKiQgkQ1k
|
||||
{
|
||||
0x02, 0x17, 0x66, 0xc5, 0xb1, 0x59, 0xd7, 0xbe,
|
||||
0x10, 0x82, 0xc5, 0x7f, 0xa3, 0xd2, 0xc8, 0x21,
|
||||
0xd8, 0x48, 0x09, 0x34, 0xdf, 0x66, 0x61, 0x23,
|
||||
0x6d, 0xb0, 0x85, 0x73, 0x77, 0xe7, 0xd8, 0xe8,
|
||||
0x3b
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid #6",
|
||||
// 5JXVrPTX5WvZ524wEVYoThGFUJZkpkemQPLDa5MCrRo3MoGatyC
|
||||
{
|
||||
0x5d, 0x93, 0x6e, 0x47, 0x44, 0x35, 0x85, 0x33,
|
||||
0xbc, 0xde, 0xff, 0xa7, 0x88, 0xe7, 0x9c, 0x6f,
|
||||
0x53, 0xbc, 0x8e, 0xbf, 0x5e, 0x8e, 0xdb, 0x7e,
|
||||
0x36, 0x2b, 0xdf, 0x11, 0xff, 0x77, 0x59, 0x98
|
||||
},
|
||||
// EOS7d5Nq7w2xscT6V6qZkDCJy2EnMFE8TGuQ9u2LyBE1fSZFiitrp
|
||||
{
|
||||
0x03, 0x68, 0x17, 0x1e, 0x3b, 0x22, 0x0a, 0x6b,
|
||||
0x6b, 0xb6, 0xfa, 0x1b, 0x32, 0xdd, 0xce, 0xf6,
|
||||
0x34, 0x7a, 0x34, 0x62, 0xb7, 0xf9, 0xea, 0x1c,
|
||||
0xa2, 0xf9, 0xf0, 0x2c, 0x50, 0x3e, 0xff, 0xf3,
|
||||
0xfa
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
libantelope::ec_init();
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
|
||||
SUBCASE(it->name.c_str()) {
|
||||
libantelope::ec_pubkey_t result;
|
||||
CHECK( libantelope::ec_get_publickey(&it->priv, &result) == 0 );
|
||||
CHECK( result == it->expected );
|
||||
}
|
||||
}
|
||||
|
||||
libantelope::ec_shutdown();
|
||||
}
|
||||
118
tests/hash/ripemd160.cpp
Normal file
118
tests/hash/ripemd160.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#include <libantelope/hash/ripemd160.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <testing.h>
|
||||
|
||||
TEST_CASE("hash::ripemd160::ripemd160") {
|
||||
|
||||
struct testcase {
|
||||
const char *name;
|
||||
std::string input;
|
||||
libantelope::ripemd160_t expected;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
std::vector<testcase> tests = {
|
||||
{
|
||||
"valid #1",
|
||||
"Morbi at egestas risus. Praesent blandit pharetra urna, nec porttitor risus sodales eu. Cras et volutpat elit, porta dapibus ipsum. Donec facilisis, eros nec imperdiet tristique, purus eros malesuada neque, quis interdum nisl risus nec leo.",
|
||||
{
|
||||
0xd9, 0x6a, 0x48, 0xf8, 0x2b, 0x39, 0xa9, 0x9f,
|
||||
0x22, 0xba, 0x3e, 0x01, 0x58, 0x5b, 0x15, 0xc7,
|
||||
0x7b, 0x0e, 0x5f, 0x50,
|
||||
},
|
||||
true
|
||||
},
|
||||
{
|
||||
"valid #2",
|
||||
"Donec eget mattis velit, vel vulputate sem. Suspendisse vulputate dolor vel est facilisis congue. Nulla non leo nulla. Proin lorem elit, sagittis eget congue in, pellentesque sed nisi. In pulvinar tortor fermentum suscipit varius.",
|
||||
{
|
||||
0x87, 0x1b, 0x87, 0xde, 0x2e, 0xb6, 0x8b, 0xb6,
|
||||
0xdc, 0x29, 0xe7, 0x40, 0xc3, 0xd1, 0x99, 0x42,
|
||||
0xad, 0x1a, 0xe3, 0x57
|
||||
},
|
||||
true
|
||||
}
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
SUBCASE(it->name) {
|
||||
libantelope::ripemd160_t dgst;
|
||||
|
||||
CHECK( libantelope::ripemd160((const unsigned char*) it->input.c_str(), it->input.size(), &dgst) == &dgst );
|
||||
|
||||
CHECK_PRED(doctest::toString(dgst), doctest::toString(it->expected), it->valid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("hash::ripemd160::init/update/final") {
|
||||
|
||||
struct testcase {
|
||||
const char *name;
|
||||
std::vector<std::string> inputs;
|
||||
libantelope::ripemd160_t expected;
|
||||
#ifdef _MSC_VER
|
||||
char _; // ripemd160_t can't be last, wierd compiler bug on MSVC
|
||||
#endif
|
||||
};
|
||||
|
||||
std::vector<testcase> tests = {
|
||||
{
|
||||
"valid #1",
|
||||
{
|
||||
"tortor in congue luctus, tortor sapien condimentum quam, ac congue enim lacus vitae erat. Mauris dapibus eros bibendum",
|
||||
"Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae",
|
||||
},
|
||||
{
|
||||
0x30, 0x77, 0xaf, 0x6b, 0x43, 0x0b, 0x94, 0x8d,
|
||||
0x59, 0x4e, 0xc7, 0xbb, 0x1a, 0x2b, 0xc3, 0x08,
|
||||
0xaa, 0xf0, 0x75, 0x3a
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid #2",
|
||||
{
|
||||
"Cras suscipit, mi sit amet pretium blandit, massa felis aliquet eros",
|
||||
"Aenean efficitur nibh quis enim mollis blandit",
|
||||
"Vestibulum posuere tempus mi nec cursus"
|
||||
},
|
||||
{
|
||||
0xf1, 0xcf, 0xea, 0xf7, 0xef, 0x3a, 0x0f, 0x80,
|
||||
0x26, 0x75, 0x40, 0x75, 0xe0, 0x9d, 0x89, 0x05,
|
||||
0xd1, 0x29, 0xe5, 0xf6
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid #3",
|
||||
{
|
||||
"Donec nec blandit dui. Nulla et tempus odio, id fermentum neque. Nam vitae nunc leo. Aliquam dictum velit nec neque dignissim maximus nec at tellus",
|
||||
"Proin elementum porttitor odio, ut ullamcorper justo rutrum in. Proin dignissim nec diam a eleifend. Duis consequat ultrices purus sed finibus",
|
||||
"Donec eget ante dictum, scelerisque metus eget, mollis velit. Curabitur elementum fermentum lorem, a fringilla velit ultrices non"
|
||||
},
|
||||
{
|
||||
0xbb, 0x25, 0x58, 0xa9, 0xd0, 0xc1, 0x23, 0xef,
|
||||
0x55, 0xac, 0x2d, 0x8c, 0xd5, 0xd6, 0xe1, 0x49,
|
||||
0x00, 0x5d, 0x86, 0xe8
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
SUBCASE(it->name) {
|
||||
libantelope::ripemd160_ctx_t ctx;
|
||||
libantelope::ripemd160_t dgst;
|
||||
|
||||
CHECK_EQ(libantelope::ripemd160_init(&ctx), 1);
|
||||
|
||||
for (auto in_it = it->inputs.begin(); in_it != it->inputs.end(); in_it++ ) {
|
||||
CHECK_EQ(libantelope::ripemd160_update(&ctx, (const unsigned char*) in_it->c_str(), in_it->size()), 1);
|
||||
}
|
||||
|
||||
CHECK_EQ(libantelope::ripemd160_final(&ctx, &dgst), 1);
|
||||
|
||||
CHECK( doctest::toString(dgst) == doctest::toString(it->expected) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
180
tests/hash/sha256.cpp
Normal file
180
tests/hash/sha256.cpp
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
#include <libantelope/hash/sha256.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <testing.h>
|
||||
|
||||
TEST_CASE("hash::sha256::sha256") {
|
||||
|
||||
struct testcase {
|
||||
const char *name;
|
||||
std::string input;
|
||||
libantelope::sha256_t expected;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
std::vector<testcase> tests = {
|
||||
{
|
||||
"valid #1",
|
||||
"Suspendisse ut tincidunt quam. Praesent scelerisque risus vitae est consectetur, sed facilisis sem luctus. Praesent aliquet eros quis leo sodales, eget blandit diam scelerisque.",
|
||||
{
|
||||
0x1e, 0x54, 0x96, 0x86, 0x2f, 0x39, 0x44, 0xea,
|
||||
0x42, 0xa9, 0x0f, 0xad, 0x56, 0x79, 0x4b, 0x77,
|
||||
0x8f, 0xcc, 0x54, 0xf7, 0x7a, 0x32, 0x60, 0x37,
|
||||
0x4b, 0xac, 0xd5, 0x65, 0x74, 0xf7, 0xcf, 0x6c
|
||||
},
|
||||
true
|
||||
},
|
||||
{
|
||||
"valid #2",
|
||||
"Phasellus consectetur augue vitae massa vulputate placerat. Pellentesque nec eros a velit bibendum venenatis sit amet et augue. Morbi malesuada facilisis consequat.",
|
||||
{
|
||||
0x7c, 0x79, 0x4a, 0xf4, 0x9b, 0x5b, 0xb4, 0x0c,
|
||||
0xef, 0x4f, 0xaa, 0x65, 0xa4, 0x7c, 0x5f, 0xc5,
|
||||
0x95, 0x69, 0x49, 0x99, 0x6b, 0x08, 0x9b, 0xc0,
|
||||
0x40, 0x2d, 0x57, 0x8a, 0x90, 0x02, 0x42, 0x32,
|
||||
},
|
||||
true
|
||||
}
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
SUBCASE(it->name) {
|
||||
libantelope::sha256_t dgst;
|
||||
|
||||
CHECK( libantelope::sha256((const unsigned char*) it->input.c_str(), it->input.size(), &dgst) == &dgst );
|
||||
|
||||
CHECK_PRED(doctest::toString(dgst), doctest::toString(it->expected), it->valid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("hash::sha256::sha256d") {
|
||||
|
||||
struct testcase {
|
||||
const char *name;
|
||||
std::string input;
|
||||
libantelope::sha256_t expected;
|
||||
#ifdef _MSC_VER
|
||||
char _; // sha256_t can't be last, wierd compiler bug on MSVC
|
||||
#endif
|
||||
};
|
||||
|
||||
std::vector<testcase> tests = {
|
||||
{
|
||||
"valid #1",
|
||||
"Suspendisse ut tincidunt quam. Praesent scelerisque risus vitae est consectetur, sed facilisis sem luctus. Praesent aliquet eros quis leo sodales, eget blandit diam scelerisque.",
|
||||
{
|
||||
0x4b, 0x6f, 0xa1, 0xf6, 0x30, 0x1e, 0xbe, 0x4a,
|
||||
0xc7, 0xef, 0x1e, 0x55, 0x3e, 0xdb, 0xc1, 0x31,
|
||||
0x1f, 0x6b, 0xf5, 0xc8, 0x04, 0xe9, 0x0e, 0xe3,
|
||||
0xbe, 0x66, 0x01, 0xbf, 0x70, 0x9f, 0x8e, 0x80,
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid #2",
|
||||
"Vivamus ut elementum justo. Vestibulum lobortis rutrum libero sollicitudin aliquet. Nullam tempor urna non odio iaculis, sed pretium quam porttitor. Pellentesque pretium, justo vitae tristique porttitor, diam massa pulvinar neque, sed lacinia mi nulla sed nisi.",
|
||||
{
|
||||
0x1f, 0x3f, 0x1c, 0x48, 0xf6, 0xee, 0x24, 0x1f,
|
||||
0x6c, 0x41, 0x86, 0x69, 0xe3, 0x2f, 0x5e, 0x4d,
|
||||
0xa5, 0x51, 0x04, 0x8b, 0x11, 0x35, 0x47, 0xad,
|
||||
0x7e, 0xd9, 0xfb, 0x2e, 0x59, 0xee, 0x66, 0x21,
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid #3",
|
||||
"Praesent ultrices consequat risus luctus faucibus.",
|
||||
{
|
||||
0xd5, 0x5f, 0x9c, 0xda, 0x2d, 0x93, 0x32, 0xc2,
|
||||
0x9b, 0xb1, 0xbb, 0x14, 0x55, 0x80, 0x72, 0xb7,
|
||||
0xba, 0x13, 0xa8, 0xc6, 0xa6, 0xbc, 0x65, 0xfc,
|
||||
0x49, 0xe0, 0x3b, 0x23, 0x04, 0x2a, 0x92, 0x8d,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
SUBCASE(it->name) {
|
||||
libantelope::sha256_t dgst;
|
||||
|
||||
CHECK( libantelope::sha256d((const unsigned char*) it->input.c_str(), it->input.size(), &dgst) == &dgst );
|
||||
|
||||
CHECK( doctest::toString(dgst) == doctest::toString(it->expected) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("hash::sha256::init/update/final") {
|
||||
|
||||
struct testcase {
|
||||
const char *name;
|
||||
std::vector<std::string> inputs;
|
||||
libantelope::sha256_t expected;
|
||||
#ifdef _MSC_VER
|
||||
char _; // sha256_t can't be last, wierd compiler bug on MSVC
|
||||
#endif
|
||||
};
|
||||
|
||||
std::vector<testcase> tests = {
|
||||
{
|
||||
"valid #1",
|
||||
{
|
||||
"Donec vestibulum enim commodo, faucibus nisi non, mattis quam.",
|
||||
"Nam sed nunc dapibus, auctor risus placerat, aliquet dolor",
|
||||
},
|
||||
{
|
||||
0x48, 0xc2, 0x34, 0x93, 0x3d, 0xae, 0x0d, 0xd0,
|
||||
0x28, 0xff, 0x5c, 0xa0, 0xca, 0xb1, 0x0a, 0xa3,
|
||||
0xe2, 0xa0, 0xa4, 0x7e, 0xb2, 0x71, 0xa5, 0x28,
|
||||
0x41, 0x03, 0x72, 0x20, 0xb5, 0x23, 0xc3, 0x67,
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid #2",
|
||||
{
|
||||
"In tempus, lectus ac molestie venenatis, enim purus suscipit tortor",
|
||||
"sed sodales massa condimentum a",
|
||||
"Integer sit amet pretium magna",
|
||||
"Aenean non accumsan eros. Donec imperdiet justo tempor magna tincidunt malesuada",
|
||||
"Duis eu tortor ac massa sagittis elementum"
|
||||
},
|
||||
{
|
||||
0xfb, 0x12, 0x31, 0x9c, 0x2c, 0xe4, 0x94, 0x29,
|
||||
0xc9, 0xd3, 0xc7, 0x84, 0x0c, 0x58, 0x3d, 0x4c,
|
||||
0xde, 0xb5, 0x36, 0x59, 0x46, 0x69, 0xe1, 0x63,
|
||||
0xc5, 0x75, 0xb6, 0x94, 0x41, 0x5a, 0xd4, 0x62,
|
||||
}
|
||||
},
|
||||
{
|
||||
"valid #3",
|
||||
{
|
||||
"Donec tempus pellentesque lobortis. Integer pellentesque feugiat enim ac suscipit. Curabitur urna quam, condimentum sed bibendum eu",
|
||||
"Nullam lacinia ligula at ex gravida fermentum. Integer scelerisque accumsan iaculis. Suspendisse quis eros ut orci sollicitudin dignissim",
|
||||
"Nulla ligula tortor, tristique eget feugiat non, vehicula sit amet velit. Proin fermentum sagittis tincidunt. Nullam condimentum dapibus magna",
|
||||
},
|
||||
{
|
||||
0x19, 0xfb, 0x71, 0xb1, 0x47, 0x01, 0x7f, 0xf5,
|
||||
0xeb, 0xda, 0xc2, 0xd8, 0xe7, 0xab, 0xc9, 0xcb,
|
||||
0xea, 0x7d, 0x13, 0xa0, 0x2e, 0xe8, 0x48, 0x94,
|
||||
0x67, 0xc5, 0x14, 0xbf, 0x7d, 0x6f, 0x96, 0x83,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
for(auto it = tests.begin(); it != tests.end(); it++) {
|
||||
SUBCASE(it->name) {
|
||||
libantelope::sha256_ctx_t ctx;
|
||||
libantelope::sha256_t dgst;
|
||||
|
||||
CHECK_EQ(libantelope::sha256_init(&ctx), 1);
|
||||
|
||||
for (auto in_it = it->inputs.begin(); in_it != it->inputs.end(); in_it++ ) {
|
||||
CHECK_EQ(libantelope::sha256_update(&ctx, (const unsigned char*) in_it->c_str(), in_it->size()), 1);
|
||||
}
|
||||
|
||||
CHECK_EQ(libantelope::sha256_final(&ctx, &dgst), 1);
|
||||
|
||||
CHECK( doctest::toString(dgst) == doctest::toString(it->expected) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
7091
tests/include/doctest.h
Normal file
7091
tests/include/doctest.h
Normal file
File diff suppressed because it is too large
Load diff
8
tests/include/testing.h
Normal file
8
tests/include/testing.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef LIBANTELOPE_TESTING_H
|
||||
#define LIBANTELOPE_TESTING_H
|
||||
|
||||
#include <doctest.h>
|
||||
|
||||
#define CHECK_PRED(a,b,pred) if (pred) { CHECK_EQ((a), (b)); } else { CHECK_NE((a), (b)); }
|
||||
|
||||
#endif /* LIBANTELOPE_TESTING_H */
|
||||
11
tests/main.cpp
Normal file
11
tests/main.cpp
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
#define DOCTEST_CONFIG_IMPLEMENT
|
||||
#include <doctest.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
doctest::Context context;
|
||||
|
||||
context.applyCommandLine(argc, argv);
|
||||
|
||||
return context.run();
|
||||
}
|
||||
16
vendor/secp256k1/CMakeLists.txt
vendored
Normal file
16
vendor/secp256k1/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
set(TARGET secp256k1)
|
||||
|
||||
add_library(${TARGET} OBJECT
|
||||
repo/src/secp256k1.c
|
||||
repo/src/precomputed_ecmult.c
|
||||
repo/src/precomputed_ecmult_gen.c
|
||||
)
|
||||
|
||||
target_compile_definitions(${TARGET}
|
||||
PRIVATE ENABLE_MODULE_RECOVERY
|
||||
)
|
||||
|
||||
target_include_directories(${TARGET}
|
||||
PUBLIC ${CMAKE_CURRENT_LIST_DIR}/repo/include
|
||||
)
|
||||
409
vendor/secp256k1/repo/.cirrus.yml
vendored
Normal file
409
vendor/secp256k1/repo/.cirrus.yml
vendored
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
env:
|
||||
### cirrus config
|
||||
CIRRUS_CLONE_DEPTH: 1
|
||||
### compiler options
|
||||
HOST:
|
||||
WRAPPER_CMD:
|
||||
# Specific warnings can be disabled with -Wno-error=foo.
|
||||
# -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual.
|
||||
WERROR_CFLAGS: -Werror -pedantic-errors
|
||||
MAKEFLAGS: -j4
|
||||
BUILD: check
|
||||
### secp256k1 config
|
||||
ECMULTWINDOW: auto
|
||||
ECMULTGENPRECISION: auto
|
||||
ASM: no
|
||||
WIDEMUL: auto
|
||||
WITH_VALGRIND: yes
|
||||
EXTRAFLAGS:
|
||||
### secp256k1 modules
|
||||
EXPERIMENTAL: no
|
||||
ECDH: no
|
||||
RECOVERY: no
|
||||
SCHNORRSIG: no
|
||||
### test options
|
||||
SECP256K1_TEST_ITERS:
|
||||
BENCH: yes
|
||||
SECP256K1_BENCH_ITERS: 2
|
||||
CTIMETESTS: yes
|
||||
# Compile and run the tests
|
||||
EXAMPLES: yes
|
||||
|
||||
# https://cirrus-ci.org/pricing/#compute-credits
|
||||
credits_snippet: &CREDITS
|
||||
# Don't use any credits for now.
|
||||
use_compute_credits: false
|
||||
|
||||
cat_logs_snippet: &CAT_LOGS
|
||||
always:
|
||||
cat_tests_log_script:
|
||||
- cat tests.log || true
|
||||
cat_noverify_tests_log_script:
|
||||
- cat noverify_tests.log || true
|
||||
cat_exhaustive_tests_log_script:
|
||||
- cat exhaustive_tests.log || true
|
||||
cat_ctime_tests_log_script:
|
||||
- cat ctime_tests.log || true
|
||||
cat_bench_log_script:
|
||||
- cat bench.log || true
|
||||
cat_config_log_script:
|
||||
- cat config.log || true
|
||||
cat_test_env_script:
|
||||
- cat test_env.log || true
|
||||
cat_ci_env_script:
|
||||
- env
|
||||
|
||||
merge_base_script_snippet: &MERGE_BASE
|
||||
merge_base_script:
|
||||
- if [ "$CIRRUS_PR" = "" ]; then exit 0; fi
|
||||
- git fetch --depth=1 $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge"
|
||||
- git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts
|
||||
|
||||
linux_container_snippet: &LINUX_CONTAINER
|
||||
container:
|
||||
dockerfile: ci/linux-debian.Dockerfile
|
||||
# Reduce number of CPUs to be able to do more builds in parallel.
|
||||
cpu: 1
|
||||
# Gives us more CPUs for free if they're available.
|
||||
greedy: true
|
||||
# More than enough for our scripts.
|
||||
memory: 1G
|
||||
|
||||
task:
|
||||
name: "x86_64: Linux (Debian stable)"
|
||||
<< : *LINUX_CONTAINER
|
||||
matrix: &ENV_MATRIX
|
||||
- env: {WIDEMUL: int64, RECOVERY: yes}
|
||||
- env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes}
|
||||
- env: {WIDEMUL: int128}
|
||||
- env: {WIDEMUL: int128_struct}
|
||||
- env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
|
||||
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes}
|
||||
- env: {WIDEMUL: int128, ASM: x86_64}
|
||||
- env: { RECOVERY: yes, SCHNORRSIG: yes}
|
||||
- env: {CTIMETESTS: no, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, CPPFLAGS: -DVERIFY}
|
||||
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETESTS: no, BENCH: no}
|
||||
- env: {CPPFLAGS: -DDETERMINISTIC}
|
||||
- env: {CFLAGS: -O0, CTIMETESTS: no}
|
||||
- env: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
|
||||
- env: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 }
|
||||
matrix:
|
||||
- env:
|
||||
CC: gcc
|
||||
- env:
|
||||
CC: clang
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "i686: Linux (Debian stable)"
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
HOST: i686-linux-gnu
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
matrix:
|
||||
- env:
|
||||
CC: i686-linux-gnu-gcc
|
||||
- env:
|
||||
CC: clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "arm64: macOS Ventura"
|
||||
macos_instance:
|
||||
image: ghcr.io/cirruslabs/macos-ventura-base:latest
|
||||
env:
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
||||
# Cirrus gives us a fixed number of 4 virtual CPUs. Not that we even have that many jobs at the moment...
|
||||
MAKEFLAGS: -j5
|
||||
matrix:
|
||||
<< : *ENV_MATRIX
|
||||
env:
|
||||
ASM: no
|
||||
WITH_VALGRIND: no
|
||||
CTIMETESTS: no
|
||||
matrix:
|
||||
- env:
|
||||
CC: gcc
|
||||
- env:
|
||||
CC: clang
|
||||
brew_script:
|
||||
- brew install automake libtool gcc
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
<< : *CREDITS
|
||||
|
||||
task:
|
||||
name: "s390x (big-endian): Linux (Debian stable, QEMU)"
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
WRAPPER_CMD: qemu-s390x
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
HOST: s390x-linux-gnu
|
||||
WITH_VALGRIND: no
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
# https://sourceware.org/bugzilla/show_bug.cgi?id=27008
|
||||
- rm /etc/ld.so.cache
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "ARM32: Linux (Debian stable, QEMU)"
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
WRAPPER_CMD: qemu-arm
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
HOST: arm-linux-gnueabihf
|
||||
WITH_VALGRIND: no
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
matrix:
|
||||
- env: {}
|
||||
- env: {EXPERIMENTAL: yes, ASM: arm}
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "ARM64: Linux (Debian stable, QEMU)"
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
WRAPPER_CMD: qemu-aarch64
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
HOST: aarch64-linux-gnu
|
||||
WITH_VALGRIND: no
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "ppc64le: Linux (Debian stable, QEMU)"
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
WRAPPER_CMD: qemu-ppc64le
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
HOST: powerpc64le-linux-gnu
|
||||
WITH_VALGRIND: no
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
WRAPPER_CMD: wine
|
||||
WITH_VALGRIND: no
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
matrix:
|
||||
- name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
|
||||
env:
|
||||
HOST: x86_64-w64-mingw32
|
||||
- name: "i686 (mingw32-w64): Windows (Debian stable, Wine)"
|
||||
env:
|
||||
HOST: i686-w64-mingw32
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
WRAPPER_CMD: wine
|
||||
WERROR_CFLAGS: -WX
|
||||
WITH_VALGRIND: no
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
EXPERIMENTAL: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
# Use a MinGW-w64 host to tell ./configure we're building for Windows.
|
||||
# This will detect some MinGW-w64 tools but then make will need only
|
||||
# the MSVC tools CC, AR and NM as specified below.
|
||||
HOST: x86_64-w64-mingw32
|
||||
CC: /opt/msvc/bin/x64/cl
|
||||
AR: /opt/msvc/bin/x64/lib
|
||||
NM: /opt/msvc/bin/x64/dumpbin -symbols -headers
|
||||
# Set non-essential options that affect the CLI messages here.
|
||||
# (They depend on the user's taste, so we don't want to set them automatically in configure.ac.)
|
||||
CFLAGS: -nologo -diagnostics:caret
|
||||
LDFLAGS: -Xlinker -Xlinker -Xlinker -nologo
|
||||
matrix:
|
||||
- name: "x86_64 (MSVC): Windows (Debian stable, Wine)"
|
||||
- name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct)"
|
||||
env:
|
||||
WIDEMUL: int128_struct
|
||||
- name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct with __(u)mulh)"
|
||||
env:
|
||||
WIDEMUL: int128_struct
|
||||
CPPFLAGS: -DSECP256K1_MSVC_MULH_TEST_OVERRIDE
|
||||
- name: "i686 (MSVC): Windows (Debian stable, Wine)"
|
||||
env:
|
||||
HOST: i686-w64-mingw32
|
||||
CC: /opt/msvc/bin/x86/cl
|
||||
AR: /opt/msvc/bin/x86/lib
|
||||
NM: /opt/msvc/bin/x86/dumpbin -symbols -headers
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
# Sanitizers
|
||||
task:
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
matrix:
|
||||
- name: "Valgrind (memcheck)"
|
||||
container:
|
||||
cpu: 2
|
||||
env:
|
||||
# The `--error-exitcode` is required to make the test fail if valgrind found errors, otherwise it'll return 0 (https://www.valgrind.org/docs/manual/manual-core.html)
|
||||
WRAPPER_CMD: "valgrind --error-exitcode=42"
|
||||
SECP256K1_TEST_ITERS: 2
|
||||
- name: "UBSan, ASan, LSan"
|
||||
container:
|
||||
memory: 2G
|
||||
env:
|
||||
CFLAGS: "-fsanitize=undefined,address -g"
|
||||
UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1"
|
||||
ASAN_OPTIONS: "strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1"
|
||||
LSAN_OPTIONS: "use_unaligned=1"
|
||||
SECP256K1_TEST_ITERS: 32
|
||||
# Try to cover many configurations with just a tiny matrix.
|
||||
matrix:
|
||||
- env:
|
||||
ASM: auto
|
||||
- env:
|
||||
ASM: no
|
||||
ECMULTGENPRECISION: 2
|
||||
ECMULTWINDOW: 2
|
||||
matrix:
|
||||
- env:
|
||||
CC: clang
|
||||
- env:
|
||||
HOST: i686-linux-gnu
|
||||
CC: i686-linux-gnu-gcc
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
# Memory sanitizers
|
||||
task:
|
||||
<< : *LINUX_CONTAINER
|
||||
name: "MSan"
|
||||
env:
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: yes
|
||||
CC: clang
|
||||
SECP256K1_TEST_ITERS: 32
|
||||
ASM: no
|
||||
WITH_VALGRIND: no
|
||||
container:
|
||||
memory: 2G
|
||||
matrix:
|
||||
- env:
|
||||
CFLAGS: "-fsanitize=memory -g"
|
||||
- env:
|
||||
ECMULTGENPRECISION: 2
|
||||
ECMULTWINDOW: 2
|
||||
CFLAGS: "-fsanitize=memory -g -O3"
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "C++ -fpermissive (entire project)"
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
CC: g++
|
||||
CFLAGS: -fpermissive -g
|
||||
CPPFLAGS: -DSECP256K1_CPLUSPLUS_TEST_OVERRIDE
|
||||
WERROR_CFLAGS:
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "C++ (public headers)"
|
||||
<< : *LINUX_CONTAINER
|
||||
test_script:
|
||||
- g++ -Werror include/*.h
|
||||
- clang -Werror -x c++-header include/*.h
|
||||
- /opt/msvc/bin/x64/cl.exe -c -WX -TP include/*.h
|
||||
|
||||
task:
|
||||
name: "sage prover"
|
||||
<< : *LINUX_CONTAINER
|
||||
test_script:
|
||||
- cd sage
|
||||
- sage prove_group_implementations.sage
|
||||
|
||||
task:
|
||||
name: "x86_64: Windows (VS 2022)"
|
||||
windows_container:
|
||||
image: cirrusci/windowsservercore:visualstudio2022
|
||||
cpu: 4
|
||||
memory: 3840MB
|
||||
env:
|
||||
PATH: '%CIRRUS_WORKING_DIR%\build\src\RelWithDebInfo;%PATH%'
|
||||
x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"'
|
||||
# Ignore MSBuild warning MSB8029.
|
||||
# See: https://learn.microsoft.com/en-us/visualstudio/msbuild/errors/msb8029?view=vs-2022
|
||||
IgnoreWarnIntDirInTempDetected: 'true'
|
||||
merge_script:
|
||||
- PowerShell -NoLogo -Command if ($env:CIRRUS_PR -ne $null) { git fetch $env:CIRRUS_REPO_CLONE_URL pull/$env:CIRRUS_PR/merge; git reset --hard FETCH_HEAD; }
|
||||
configure_script:
|
||||
- '%x64_NATIVE_TOOLS%'
|
||||
- cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON
|
||||
build_script:
|
||||
- '%x64_NATIVE_TOOLS%'
|
||||
- cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5
|
||||
check_script:
|
||||
- '%x64_NATIVE_TOOLS%'
|
||||
- ctest --test-dir build -j 5
|
||||
- build\src\RelWithDebInfo\bench_ecmult.exe
|
||||
- build\src\RelWithDebInfo\bench_internal.exe
|
||||
- build\src\RelWithDebInfo\bench.exe
|
||||
2
vendor/secp256k1/repo/.gitattributes
vendored
Normal file
2
vendor/secp256k1/repo/.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
src/precomputed_ecmult.c linguist-generated
|
||||
src/precomputed_ecmult_gen.c linguist-generated
|
||||
63
vendor/secp256k1/repo/.gitignore
vendored
Normal file
63
vendor/secp256k1/repo/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
bench
|
||||
bench_ecmult
|
||||
bench_internal
|
||||
noverify_tests
|
||||
tests
|
||||
exhaustive_tests
|
||||
precompute_ecmult_gen
|
||||
precompute_ecmult
|
||||
ctime_tests
|
||||
ecdh_example
|
||||
ecdsa_example
|
||||
schnorr_example
|
||||
*.exe
|
||||
*.so
|
||||
*.a
|
||||
*.csv
|
||||
*.log
|
||||
*.trs
|
||||
*.sage.py
|
||||
|
||||
Makefile
|
||||
configure
|
||||
.libs/
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
config.log
|
||||
config.status
|
||||
conftest*
|
||||
*.tar.gz
|
||||
*.la
|
||||
libtool
|
||||
.deps/
|
||||
.dirstamp
|
||||
*.lo
|
||||
*.o
|
||||
*~
|
||||
|
||||
coverage/
|
||||
coverage.html
|
||||
coverage.*.html
|
||||
*.gcda
|
||||
*.gcno
|
||||
*.gcov
|
||||
|
||||
build-aux/ar-lib
|
||||
build-aux/config.guess
|
||||
build-aux/config.sub
|
||||
build-aux/depcomp
|
||||
build-aux/install-sh
|
||||
build-aux/ltmain.sh
|
||||
build-aux/m4/libtool.m4
|
||||
build-aux/m4/lt~obsolete.m4
|
||||
build-aux/m4/ltoptions.m4
|
||||
build-aux/m4/ltsugar.m4
|
||||
build-aux/m4/ltversion.m4
|
||||
build-aux/missing
|
||||
build-aux/compile
|
||||
build-aux/test-driver
|
||||
libsecp256k1.pc
|
||||
|
||||
# Default CMake build directory.
|
||||
/build
|
||||
61
vendor/secp256k1/repo/CHANGELOG.md
vendored
Normal file
61
vendor/secp256k1/repo/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.3.0] - 2023-03-08
|
||||
|
||||
#### Added
|
||||
- Added experimental support for CMake builds. Traditional GNU Autotools builds (`./configure` and `make`) remain fully supported.
|
||||
- Usage examples: Added a recommended method for securely clearing sensitive data, e.g., secret keys, from memory.
|
||||
- Tests: Added a new test binary `noverify_tests`. This binary runs the tests without some additional checks present in the ordinary `tests` binary and is thereby closer to production binaries. The `noverify_tests` binary is automatically run as part of the `make check` target.
|
||||
|
||||
#### Fixed
|
||||
- Fixed declarations of API variables for MSVC (`__declspec(dllimport)`). This fixes MSVC builds of programs which link against a libsecp256k1 DLL dynamically and use API variables (and not only API functions). Unfortunately, the MSVC linker now will emit warning `LNK4217` when trying to link against libsecp256k1 statically. Pass `/ignore:4217` to the linker to suppress this warning.
|
||||
|
||||
#### Changed
|
||||
- Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.)
|
||||
- Forbade randomizing (copies of) `secp256k1_context_static`. Randomizing a copy of `secp256k1_context_static` did not have any effect and did not provide defense-in-depth protection against side-channel attacks. Create a new context if you want to benefit from randomization.
|
||||
|
||||
#### Removed
|
||||
- Removed the configuration header `src/libsecp256k1-config.h`. We recommend passing flags to `./configure` or `cmake` to set configuration options (see `./configure --help` or `cmake -LH`). If you cannot or do not want to use one of the supported build systems, pass configuration flags such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG` manually to the compiler (see the file `configure.ac` for supported flags).
|
||||
|
||||
#### ABI Compatibility
|
||||
|
||||
Due to changes in the API regarding `secp256k1_context_static` described above, the ABI is *not* compatible with previous versions.
|
||||
|
||||
## [0.2.0] - 2022-12-12
|
||||
|
||||
#### Added
|
||||
- Added usage examples for common use cases in a new `examples/` directory.
|
||||
- Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`.
|
||||
- Added support for 128-bit wide multiplication on MSVC for x86_64 and arm64, giving roughly a 20% speedup on those platforms.
|
||||
|
||||
#### Changed
|
||||
- Enabled modules `schnorrsig`, `extrakeys` and `ecdh` by default in `./configure`.
|
||||
- The `secp256k1_nonce_function_rfc6979` nonce function, used by default by `secp256k1_ecdsa_sign`, now reduces the message hash modulo the group order to match the specification. This only affects improper use of ECDSA signing API.
|
||||
|
||||
#### Deprecated
|
||||
- Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead.
|
||||
- Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`.
|
||||
- Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`.
|
||||
|
||||
#### ABI Compatibility
|
||||
|
||||
Since this is the first release, we do not compare application binary interfaces.
|
||||
However, there are earlier unreleased versions of libsecp256k1 that are *not* ABI compatible with this version.
|
||||
|
||||
## [0.1.0] - 2013-03-05 to 2021-12-25
|
||||
|
||||
This version was in fact never released.
|
||||
The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6).
|
||||
Therefore, this version number does not uniquely identify a set of source files.
|
||||
|
||||
[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...HEAD
|
||||
[0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0
|
||||
[0.2.0]: https://github.com/bitcoin-core/secp256k1/compare/423b6d19d373f1224fd671a982584d7e7900bc93..v0.2.0
|
||||
[0.1.0]: https://github.com/bitcoin-core/secp256k1/commit/423b6d19d373f1224fd671a982584d7e7900bc93
|
||||
302
vendor/secp256k1/repo/CMakeLists.txt
vendored
Normal file
302
vendor/secp256k1/repo/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER 3.14)
|
||||
# MSVC runtime library flags are selected by the CMAKE_MSVC_RUNTIME_LIBRARY abstraction.
|
||||
cmake_policy(SET CMP0091 NEW)
|
||||
# MSVC warning flags are not in CMAKE_<LANG>_FLAGS by default.
|
||||
cmake_policy(SET CMP0092 NEW)
|
||||
endif()
|
||||
|
||||
# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of
|
||||
# the API. All changes in experimental modules are treated as
|
||||
# backwards-compatible and therefore at most increase the minor version.
|
||||
project(libsecp256k1 VERSION 0.3.0 LANGUAGES C)
|
||||
|
||||
# The library version is based on libtool versioning of the ABI. The set of
|
||||
# rules for updating the version can be found here:
|
||||
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
# All changes in experimental modules are treated as if they don't affect the
|
||||
# interface and therefore only increase the revision.
|
||||
set(${PROJECT_NAME}_LIB_VERSION_CURRENT 2)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_REVISION 0)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_AGE 0)
|
||||
|
||||
set(CMAKE_C_STANDARD 90)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
|
||||
# We do not use CMake's BUILD_SHARED_LIBS option.
|
||||
option(SECP256K1_BUILD_SHARED "Build shared library." ON)
|
||||
option(SECP256K1_BUILD_STATIC "Build static library." ON)
|
||||
if(NOT SECP256K1_BUILD_SHARED AND NOT SECP256K1_BUILD_STATIC)
|
||||
message(FATAL_ERROR "At least one of SECP256K1_BUILD_SHARED and SECP256K1_BUILD_STATIC must be enabled.")
|
||||
endif()
|
||||
|
||||
option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON)
|
||||
if(SECP256K1_ENABLE_MODULE_ECDH)
|
||||
add_definitions(-DENABLE_MODULE_ECDH=1)
|
||||
endif()
|
||||
|
||||
option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF)
|
||||
if(SECP256K1_ENABLE_MODULE_RECOVERY)
|
||||
add_definitions(-DENABLE_MODULE_RECOVERY=1)
|
||||
endif()
|
||||
|
||||
option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
|
||||
option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON)
|
||||
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON)
|
||||
add_definitions(-DENABLE_MODULE_SCHNORRSIG=1)
|
||||
endif()
|
||||
if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
|
||||
add_definitions(-DENABLE_MODULE_EXTRAKEYS=1)
|
||||
endif()
|
||||
|
||||
option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF)
|
||||
if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS)
|
||||
add_definitions(-DUSE_EXTERNAL_DEFAULT_CALLBACKS=1)
|
||||
endif()
|
||||
|
||||
set(SECP256K1_ECMULT_WINDOW_SIZE "AUTO" CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. \"AUTO\" is a reasonable setting for desktop machines (currently 15). [default=AUTO]")
|
||||
set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS "AUTO" 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24)
|
||||
include(CheckStringOptionValue)
|
||||
check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE)
|
||||
if(SECP256K1_ECMULT_WINDOW_SIZE STREQUAL "AUTO")
|
||||
set(SECP256K1_ECMULT_WINDOW_SIZE 15)
|
||||
endif()
|
||||
add_definitions(-DECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE})
|
||||
|
||||
set(SECP256K1_ECMULT_GEN_PREC_BITS "AUTO" CACHE STRING "Precision bits to tune the precomputed table size for signing, specified as integer 2, 4 or 8. \"AUTO\" is a reasonable setting for desktop machines (currently 4). [default=AUTO]")
|
||||
set_property(CACHE SECP256K1_ECMULT_GEN_PREC_BITS PROPERTY STRINGS "AUTO" 2 4 8)
|
||||
check_string_option_value(SECP256K1_ECMULT_GEN_PREC_BITS)
|
||||
if(SECP256K1_ECMULT_GEN_PREC_BITS STREQUAL "AUTO")
|
||||
set(SECP256K1_ECMULT_GEN_PREC_BITS 4)
|
||||
endif()
|
||||
add_definitions(-DECMULT_GEN_PREC_BITS=${SECP256K1_ECMULT_GEN_PREC_BITS})
|
||||
|
||||
set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "OFF" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting. Legal values are: \"OFF\", \"int128_struct\", \"int128\" or \"int64\". [default=OFF]")
|
||||
set_property(CACHE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY PROPERTY STRINGS "OFF" "int128_struct" "int128" "int64")
|
||||
check_string_option_value(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
|
||||
if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
|
||||
string(TOUPPER "${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" widemul_upper_value)
|
||||
add_definitions(-DUSE_FORCE_WIDEMUL_${widemul_upper_value}=1)
|
||||
endif()
|
||||
mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
|
||||
|
||||
set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm\" (experimental). [default=AUTO]")
|
||||
set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm")
|
||||
check_string_option_value(SECP256K1_ASM)
|
||||
if(SECP256K1_ASM STREQUAL "arm")
|
||||
enable_language(ASM)
|
||||
add_definitions(-DUSE_EXTERNAL_ASM=1)
|
||||
elseif(SECP256K1_ASM)
|
||||
include(Check64bitAssembly)
|
||||
check_64bit_assembly()
|
||||
if(HAS_64BIT_ASM)
|
||||
set(SECP256K1_ASM "x86_64")
|
||||
add_definitions(-DUSE_ASM_X86_64=1)
|
||||
elseif(SECP256K1_ASM STREQUAL "AUTO")
|
||||
set(SECP256K1_ASM "OFF")
|
||||
else()
|
||||
message(FATAL_ERROR "x86_64 assembly optimization requested but not available.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF)
|
||||
if(NOT SECP256K1_EXPERIMENTAL)
|
||||
if(SECP256K1_ASM STREQUAL "arm")
|
||||
message(FATAL_ERROR "ARM assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(SECP256K1_VALGRIND "AUTO" CACHE STRING "Build with extra checks for running inside Valgrind. [default=AUTO]")
|
||||
set_property(CACHE SECP256K1_VALGRIND PROPERTY STRINGS "AUTO" "OFF" "ON")
|
||||
check_string_option_value(SECP256K1_VALGRIND)
|
||||
if(SECP256K1_VALGRIND)
|
||||
find_package(Valgrind MODULE)
|
||||
if(Valgrind_FOUND)
|
||||
set(SECP256K1_VALGRIND ON)
|
||||
include_directories(${Valgrind_INCLUDE_DIR})
|
||||
add_definitions(-DVALGRIND)
|
||||
elseif(SECP256K1_VALGRIND STREQUAL "AUTO")
|
||||
set(SECP256K1_VALGRIND OFF)
|
||||
else()
|
||||
message(FATAL_ERROR "Valgrind support requested but valgrind/memcheck.h header not available.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." ON)
|
||||
option(SECP256K1_BUILD_TESTS "Build tests." ON)
|
||||
option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." ON)
|
||||
option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." ${SECP256K1_VALGRIND})
|
||||
option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF)
|
||||
|
||||
# Redefine configuration flags.
|
||||
# We leave assertions on, because they are only used in the examples, and we want them always on there.
|
||||
if(MSVC)
|
||||
string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
|
||||
string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
|
||||
else()
|
||||
string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
|
||||
string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
|
||||
# Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.)
|
||||
string(REGEX REPLACE "-O3[ \t\r\n]*" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
|
||||
endif()
|
||||
|
||||
# Define custom "Coverage" build type.
|
||||
set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O0 -DCOVERAGE=1 --coverage -Wno-unused-parameter" CACHE STRING
|
||||
"Flags used by the C compiler during \"Coverage\" builds."
|
||||
FORCE
|
||||
)
|
||||
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING
|
||||
"Flags used for linking binaries during \"Coverage\" builds."
|
||||
FORCE
|
||||
)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING
|
||||
"Flags used by the shared libraries linker during \"Coverage\" builds."
|
||||
FORCE
|
||||
)
|
||||
mark_as_advanced(
|
||||
CMAKE_C_FLAGS_COVERAGE
|
||||
CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||
CMAKE_SHARED_LINKER_FLAGS_COVERAGE
|
||||
)
|
||||
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage")
|
||||
endif()
|
||||
|
||||
get_property(cached_cmake_build_type CACHE CMAKE_BUILD_TYPE PROPERTY TYPE)
|
||||
if(cached_cmake_build_type)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
|
||||
STRINGS "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(default_build_type "RelWithDebInfo")
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "Setting build type to \"${default_build_type}\" as none was specified")
|
||||
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
|
||||
endif()
|
||||
|
||||
include(TryAddCompileOption)
|
||||
if(MSVC)
|
||||
try_add_compile_option(/W2)
|
||||
try_add_compile_option(/wd4146)
|
||||
else()
|
||||
try_add_compile_option(-pedantic)
|
||||
try_add_compile_option(-Wall)
|
||||
try_add_compile_option(-Wcast-align)
|
||||
try_add_compile_option(-Wcast-align=strict)
|
||||
try_add_compile_option(-Wconditional-uninitialized)
|
||||
try_add_compile_option(-Wextra)
|
||||
try_add_compile_option(-Wnested-externs)
|
||||
try_add_compile_option(-Wno-long-long)
|
||||
try_add_compile_option(-Wno-overlength-strings)
|
||||
try_add_compile_option(-Wno-unused-function)
|
||||
try_add_compile_option(-Wreserved-identifier)
|
||||
try_add_compile_option(-Wshadow)
|
||||
try_add_compile_option(-Wstrict-prototypes)
|
||||
try_add_compile_option(-Wundef)
|
||||
endif()
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER 3.2)
|
||||
# Honor visibility properties for all target types.
|
||||
# See: https://cmake.org/cmake/help/latest/policy/CMP0063.html
|
||||
cmake_policy(SET CMP0063 NEW)
|
||||
endif()
|
||||
set(CMAKE_C_VISIBILITY_PRESET hidden)
|
||||
|
||||
# Ask CTest to create a "check" target (e.g., make check) as alias for the "test" target.
|
||||
# CTEST_TEST_TARGET_ALIAS is not documented but supposed to be user-facing.
|
||||
# See: https://gitlab.kitware.com/cmake/cmake/-/commit/816c9d1aa1f2b42d40c81a991b68c96eb12b6d2
|
||||
set(CTEST_TEST_TARGET_ALIAS check)
|
||||
include(CTest)
|
||||
# We do not use CTest's BUILD_TESTING because a single toggle for all tests is too coarse for our needs.
|
||||
mark_as_advanced(BUILD_TESTING)
|
||||
if(SECP256K1_BUILD_BENCHMARK OR SECP256K1_BUILD_TESTS OR SECP256K1_BUILD_EXHAUSTIVE_TESTS OR SECP256K1_BUILD_CTIME_TESTS OR SECP256K1_BUILD_EXAMPLES)
|
||||
enable_testing()
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
if(SECP256K1_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
message("\n")
|
||||
message("secp256k1 configure summary")
|
||||
message("===========================")
|
||||
message("Build artifacts:")
|
||||
message(" shared library ...................... ${SECP256K1_BUILD_SHARED}")
|
||||
message(" static library ...................... ${SECP256K1_BUILD_STATIC}")
|
||||
message("Optional modules:")
|
||||
message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}")
|
||||
message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}")
|
||||
message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}")
|
||||
message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}")
|
||||
message("Parameters:")
|
||||
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
|
||||
message(" ecmult gen precision bits ........... ${SECP256K1_ECMULT_GEN_PREC_BITS}")
|
||||
message("Optional features:")
|
||||
message(" assembly optimization ............... ${SECP256K1_ASM}")
|
||||
message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}")
|
||||
if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
|
||||
message(" wide multiplication (test-only) ..... ${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}")
|
||||
endif()
|
||||
message("Optional binaries:")
|
||||
message(" benchmark ........................... ${SECP256K1_BUILD_BENCHMARK}")
|
||||
message(" noverify_tests ...................... ${SECP256K1_BUILD_TESTS}")
|
||||
set(tests_status "${SECP256K1_BUILD_TESTS}")
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
|
||||
set(tests_status OFF)
|
||||
endif()
|
||||
message(" tests ............................... ${tests_status}")
|
||||
message(" exhaustive tests .................... ${SECP256K1_BUILD_EXHAUSTIVE_TESTS}")
|
||||
message(" ctime_tests ......................... ${SECP256K1_BUILD_CTIME_TESTS}")
|
||||
message(" examples ............................ ${SECP256K1_BUILD_EXAMPLES}")
|
||||
message("")
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
else()
|
||||
set(cross_status "FALSE")
|
||||
endif()
|
||||
message("Cross compiling ....................... ${cross_status}")
|
||||
message("Valgrind .............................. ${SECP256K1_VALGRIND}")
|
||||
get_directory_property(definitions COMPILE_DEFINITIONS)
|
||||
string(REPLACE ";" " " definitions "${definitions}")
|
||||
message("Preprocessor defined macros ........... ${definitions}")
|
||||
message("C compiler ............................ ${CMAKE_C_COMPILER}")
|
||||
message("CFLAGS ................................ ${CMAKE_C_FLAGS}")
|
||||
get_directory_property(compile_options COMPILE_OPTIONS)
|
||||
string(REPLACE ";" " " compile_options "${compile_options}")
|
||||
message("Compile options ....................... " ${compile_options})
|
||||
if(DEFINED CMAKE_BUILD_TYPE)
|
||||
message("Build type:")
|
||||
message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}")
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type)
|
||||
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${build_type}}")
|
||||
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}")
|
||||
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}")
|
||||
else()
|
||||
message("Available configurations .............. ${CMAKE_CONFIGURATION_TYPES}")
|
||||
message("RelWithDebInfo configuration:")
|
||||
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
|
||||
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")
|
||||
message("Debug configuration:")
|
||||
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_DEBUG}")
|
||||
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}")
|
||||
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}")
|
||||
endif()
|
||||
message("\n")
|
||||
if(SECP256K1_EXPERIMENTAL)
|
||||
message(
|
||||
" ******\n"
|
||||
" WARNING: experimental build\n"
|
||||
" Experimental features do not have stable APIs or properties, and may not be safe for production use.\n"
|
||||
" ******\n"
|
||||
)
|
||||
endif()
|
||||
19
vendor/secp256k1/repo/COPYING
vendored
Normal file
19
vendor/secp256k1/repo/COPYING
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2013 Pieter Wuille
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
249
vendor/secp256k1/repo/Makefile.am
vendored
Normal file
249
vendor/secp256k1/repo/Makefile.am
vendored
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
.PHONY: clean-precomp precomp
|
||||
|
||||
ACLOCAL_AMFLAGS = -I build-aux/m4
|
||||
|
||||
# AM_CFLAGS will be automatically prepended to CFLAGS by Automake when compiling some foo
|
||||
# which does not have an explicit foo_CFLAGS variable set.
|
||||
AM_CFLAGS = $(SECP_CFLAGS)
|
||||
|
||||
lib_LTLIBRARIES = libsecp256k1.la
|
||||
include_HEADERS = include/secp256k1.h
|
||||
include_HEADERS += include/secp256k1_preallocated.h
|
||||
noinst_HEADERS =
|
||||
noinst_HEADERS += src/scalar.h
|
||||
noinst_HEADERS += src/scalar_4x64.h
|
||||
noinst_HEADERS += src/scalar_8x32.h
|
||||
noinst_HEADERS += src/scalar_low.h
|
||||
noinst_HEADERS += src/scalar_impl.h
|
||||
noinst_HEADERS += src/scalar_4x64_impl.h
|
||||
noinst_HEADERS += src/scalar_8x32_impl.h
|
||||
noinst_HEADERS += src/scalar_low_impl.h
|
||||
noinst_HEADERS += src/group.h
|
||||
noinst_HEADERS += src/group_impl.h
|
||||
noinst_HEADERS += src/ecdsa.h
|
||||
noinst_HEADERS += src/ecdsa_impl.h
|
||||
noinst_HEADERS += src/eckey.h
|
||||
noinst_HEADERS += src/eckey_impl.h
|
||||
noinst_HEADERS += src/ecmult.h
|
||||
noinst_HEADERS += src/ecmult_impl.h
|
||||
noinst_HEADERS += src/ecmult_compute_table.h
|
||||
noinst_HEADERS += src/ecmult_compute_table_impl.h
|
||||
noinst_HEADERS += src/ecmult_const.h
|
||||
noinst_HEADERS += src/ecmult_const_impl.h
|
||||
noinst_HEADERS += src/ecmult_gen.h
|
||||
noinst_HEADERS += src/ecmult_gen_impl.h
|
||||
noinst_HEADERS += src/ecmult_gen_compute_table.h
|
||||
noinst_HEADERS += src/ecmult_gen_compute_table_impl.h
|
||||
noinst_HEADERS += src/field_10x26.h
|
||||
noinst_HEADERS += src/field_10x26_impl.h
|
||||
noinst_HEADERS += src/field_5x52.h
|
||||
noinst_HEADERS += src/field_5x52_impl.h
|
||||
noinst_HEADERS += src/field_5x52_int128_impl.h
|
||||
noinst_HEADERS += src/field_5x52_asm_impl.h
|
||||
noinst_HEADERS += src/modinv32.h
|
||||
noinst_HEADERS += src/modinv32_impl.h
|
||||
noinst_HEADERS += src/modinv64.h
|
||||
noinst_HEADERS += src/modinv64_impl.h
|
||||
noinst_HEADERS += src/precomputed_ecmult.h
|
||||
noinst_HEADERS += src/precomputed_ecmult_gen.h
|
||||
noinst_HEADERS += src/assumptions.h
|
||||
noinst_HEADERS += src/checkmem.h
|
||||
noinst_HEADERS += src/util.h
|
||||
noinst_HEADERS += src/int128.h
|
||||
noinst_HEADERS += src/int128_impl.h
|
||||
noinst_HEADERS += src/int128_native.h
|
||||
noinst_HEADERS += src/int128_native_impl.h
|
||||
noinst_HEADERS += src/int128_struct.h
|
||||
noinst_HEADERS += src/int128_struct_impl.h
|
||||
noinst_HEADERS += src/scratch.h
|
||||
noinst_HEADERS += src/scratch_impl.h
|
||||
noinst_HEADERS += src/selftest.h
|
||||
noinst_HEADERS += src/testrand.h
|
||||
noinst_HEADERS += src/testrand_impl.h
|
||||
noinst_HEADERS += src/hash.h
|
||||
noinst_HEADERS += src/hash_impl.h
|
||||
noinst_HEADERS += src/field.h
|
||||
noinst_HEADERS += src/field_impl.h
|
||||
noinst_HEADERS += src/bench.h
|
||||
noinst_HEADERS += contrib/lax_der_parsing.h
|
||||
noinst_HEADERS += contrib/lax_der_parsing.c
|
||||
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
|
||||
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
|
||||
noinst_HEADERS += examples/examples_util.h
|
||||
|
||||
PRECOMPUTED_LIB = libsecp256k1_precomputed.la
|
||||
noinst_LTLIBRARIES = $(PRECOMPUTED_LIB)
|
||||
libsecp256k1_precomputed_la_SOURCES = src/precomputed_ecmult.c src/precomputed_ecmult_gen.c
|
||||
# We need `-I$(top_srcdir)/src` in VPATH builds if libsecp256k1_precomputed_la_SOURCES have been recreated in the build tree.
|
||||
# This helps users and packagers who insist on recreating the precomputed files (e.g., Gentoo).
|
||||
libsecp256k1_precomputed_la_CPPFLAGS = -I$(top_srcdir)/src $(SECP_CONFIG_DEFINES)
|
||||
|
||||
if USE_EXTERNAL_ASM
|
||||
COMMON_LIB = libsecp256k1_common.la
|
||||
else
|
||||
COMMON_LIB =
|
||||
endif
|
||||
noinst_LTLIBRARIES += $(COMMON_LIB)
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libsecp256k1.pc
|
||||
|
||||
if USE_EXTERNAL_ASM
|
||||
if USE_ASM_ARM
|
||||
libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s
|
||||
endif
|
||||
endif
|
||||
|
||||
libsecp256k1_la_SOURCES = src/secp256k1.c
|
||||
libsecp256k1_la_CPPFLAGS = $(SECP_CONFIG_DEFINES)
|
||||
libsecp256k1_la_LIBADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
|
||||
libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE)
|
||||
|
||||
noinst_PROGRAMS =
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench bench_internal bench_ecmult
|
||||
bench_SOURCES = src/bench.c
|
||||
bench_LDADD = libsecp256k1.la
|
||||
bench_CPPFLAGS = $(SECP_CONFIG_DEFINES)
|
||||
bench_internal_SOURCES = src/bench_internal.c
|
||||
bench_internal_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
|
||||
bench_internal_CPPFLAGS = $(SECP_CONFIG_DEFINES)
|
||||
bench_ecmult_SOURCES = src/bench_ecmult.c
|
||||
bench_ecmult_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
|
||||
bench_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES)
|
||||
endif
|
||||
|
||||
TESTS =
|
||||
if USE_TESTS
|
||||
TESTS += noverify_tests
|
||||
noinst_PROGRAMS += noverify_tests
|
||||
noverify_tests_SOURCES = src/tests.c
|
||||
noverify_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES)
|
||||
noverify_tests_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
|
||||
noverify_tests_LDFLAGS = -static
|
||||
if !ENABLE_COVERAGE
|
||||
TESTS += tests
|
||||
noinst_PROGRAMS += tests
|
||||
tests_SOURCES = $(noverify_tests_SOURCES)
|
||||
tests_CPPFLAGS = $(noverify_tests_CPPFLAGS) -DVERIFY
|
||||
tests_LDADD = $(noverify_tests_LDADD)
|
||||
tests_LDFLAGS = $(noverify_tests_LDFLAGS)
|
||||
endif
|
||||
endif
|
||||
|
||||
if USE_CTIME_TESTS
|
||||
noinst_PROGRAMS += ctime_tests
|
||||
ctime_tests_SOURCES = src/ctime_tests.c
|
||||
ctime_tests_LDADD = libsecp256k1.la
|
||||
ctime_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES)
|
||||
endif
|
||||
|
||||
if USE_EXHAUSTIVE_TESTS
|
||||
noinst_PROGRAMS += exhaustive_tests
|
||||
exhaustive_tests_SOURCES = src/tests_exhaustive.c
|
||||
exhaustive_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES)
|
||||
if !ENABLE_COVERAGE
|
||||
exhaustive_tests_CPPFLAGS += -DVERIFY
|
||||
endif
|
||||
# Note: do not include $(PRECOMPUTED_LIB) in exhaustive_tests (it uses runtime-generated tables).
|
||||
exhaustive_tests_LDADD = $(COMMON_LIB)
|
||||
exhaustive_tests_LDFLAGS = -static
|
||||
TESTS += exhaustive_tests
|
||||
endif
|
||||
|
||||
if USE_EXAMPLES
|
||||
noinst_PROGRAMS += ecdsa_example
|
||||
ecdsa_example_SOURCES = examples/ecdsa.c
|
||||
ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include
|
||||
ecdsa_example_LDADD = libsecp256k1.la
|
||||
ecdsa_example_LDFLAGS = -static
|
||||
if BUILD_WINDOWS
|
||||
ecdsa_example_LDFLAGS += -lbcrypt
|
||||
endif
|
||||
TESTS += ecdsa_example
|
||||
if ENABLE_MODULE_ECDH
|
||||
noinst_PROGRAMS += ecdh_example
|
||||
ecdh_example_SOURCES = examples/ecdh.c
|
||||
ecdh_example_CPPFLAGS = -I$(top_srcdir)/include
|
||||
ecdh_example_LDADD = libsecp256k1.la
|
||||
ecdh_example_LDFLAGS = -static
|
||||
if BUILD_WINDOWS
|
||||
ecdh_example_LDFLAGS += -lbcrypt
|
||||
endif
|
||||
TESTS += ecdh_example
|
||||
endif
|
||||
if ENABLE_MODULE_SCHNORRSIG
|
||||
noinst_PROGRAMS += schnorr_example
|
||||
schnorr_example_SOURCES = examples/schnorr.c
|
||||
schnorr_example_CPPFLAGS = -I$(top_srcdir)/include
|
||||
schnorr_example_LDADD = libsecp256k1.la
|
||||
schnorr_example_LDFLAGS = -static
|
||||
if BUILD_WINDOWS
|
||||
schnorr_example_LDFLAGS += -lbcrypt
|
||||
endif
|
||||
TESTS += schnorr_example
|
||||
endif
|
||||
endif
|
||||
|
||||
### Precomputed tables
|
||||
EXTRA_PROGRAMS = precompute_ecmult precompute_ecmult_gen
|
||||
CLEANFILES = $(EXTRA_PROGRAMS)
|
||||
|
||||
precompute_ecmult_SOURCES = src/precompute_ecmult.c
|
||||
precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES)
|
||||
precompute_ecmult_LDADD = $(COMMON_LIB)
|
||||
|
||||
precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c
|
||||
precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES)
|
||||
precompute_ecmult_gen_LDADD = $(COMMON_LIB)
|
||||
|
||||
# See Automake manual, Section "Errors with distclean".
|
||||
# We don't list any dependencies for the prebuilt files here because
|
||||
# otherwise make's decision whether to rebuild them (even in the first
|
||||
# build by a normal user) depends on mtimes, and thus is very fragile.
|
||||
# This means that rebuilds of the prebuilt files always need to be
|
||||
# forced by deleting them, e.g., by invoking `make clean-precomp`.
|
||||
src/precomputed_ecmult.c:
|
||||
$(MAKE) $(AM_MAKEFLAGS) precompute_ecmult$(EXEEXT)
|
||||
./precompute_ecmult$(EXEEXT)
|
||||
src/precomputed_ecmult_gen.c:
|
||||
$(MAKE) $(AM_MAKEFLAGS) precompute_ecmult_gen$(EXEEXT)
|
||||
./precompute_ecmult_gen$(EXEEXT)
|
||||
|
||||
PRECOMP = src/precomputed_ecmult_gen.c src/precomputed_ecmult.c
|
||||
precomp: $(PRECOMP)
|
||||
|
||||
# Ensure the prebuilt files will be build first (only if they don't exist,
|
||||
# e.g., after `make maintainer-clean`).
|
||||
BUILT_SOURCES = $(PRECOMP)
|
||||
|
||||
maintainer-clean-local: clean-precomp
|
||||
|
||||
clean-precomp:
|
||||
rm -f $(PRECOMP)
|
||||
|
||||
EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md
|
||||
EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.md
|
||||
EXTRA_DIST += examples/EXAMPLES_COPYING
|
||||
EXTRA_DIST += sage/gen_exhaustive_groups.sage
|
||||
EXTRA_DIST += sage/gen_split_lambda_constants.sage
|
||||
EXTRA_DIST += sage/group_prover.sage
|
||||
EXTRA_DIST += sage/prove_group_implementations.sage
|
||||
EXTRA_DIST += sage/secp256k1_params.sage
|
||||
EXTRA_DIST += sage/weierstrass_prover.sage
|
||||
|
||||
if ENABLE_MODULE_ECDH
|
||||
include src/modules/ecdh/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_RECOVERY
|
||||
include src/modules/recovery/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_EXTRAKEYS
|
||||
include src/modules/extrakeys/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_SCHNORRSIG
|
||||
include src/modules/schnorrsig/Makefile.am.include
|
||||
endif
|
||||
157
vendor/secp256k1/repo/README.md
vendored
Normal file
157
vendor/secp256k1/repo/README.md
vendored
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
libsecp256k1
|
||||
============
|
||||
|
||||
[](https://cirrus-ci.com/github/bitcoin-core/secp256k1)
|
||||

|
||||
[](https://web.libera.chat/#secp256k1)
|
||||
|
||||
Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1.
|
||||
|
||||
This library is intended to be the highest quality publicly available library for cryptography on the secp256k1 curve. However, the primary focus of its development has been for usage in the Bitcoin system and usage unlike Bitcoin's may be less well tested, verified, or suffer from a less well thought out interface. Correct usage requires some care and consideration that the library is fit for your application's purpose.
|
||||
|
||||
Features:
|
||||
* secp256k1 ECDSA signing/verification and key generation.
|
||||
* Additive and multiplicative tweaking of secret/public keys.
|
||||
* Serialization/parsing of secret keys, public keys, signatures.
|
||||
* Constant time, constant memory access signing and public key generation.
|
||||
* Derandomized ECDSA (via RFC6979 or with a caller provided function.)
|
||||
* Very efficient implementation.
|
||||
* Suitable for embedded systems.
|
||||
* No runtime dependencies.
|
||||
* Optional module for public key recovery.
|
||||
* Optional module for ECDH key exchange.
|
||||
* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
||||
|
||||
Implementation details
|
||||
----------------------
|
||||
|
||||
* General
|
||||
* No runtime heap allocation.
|
||||
* Extensive testing infrastructure.
|
||||
* Structured to facilitate review and analysis.
|
||||
* Intended to be portable to any system with a C89 compiler and uint64_t support.
|
||||
* No use of floating types.
|
||||
* Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.")
|
||||
* Field operations
|
||||
* Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
|
||||
* Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys).
|
||||
* Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan).
|
||||
* This is an experimental feature that has not received enough scrutiny to satisfy the standard of quality of this library but is made available for testing and review by the community.
|
||||
* Scalar operations
|
||||
* Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
|
||||
* Using 4 64-bit limbs (relying on __int128 support in the compiler).
|
||||
* Using 8 32-bit limbs.
|
||||
* Modular inverses (both field elements and scalars) based on [safegcd](https://gcd.cr.yp.to/index.html) with some modifications, and a variable-time variant (by Peter Dettman).
|
||||
* Group operations
|
||||
* Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7).
|
||||
* Use addition between points in Jacobian and affine coordinates where possible.
|
||||
* Use a unified addition/doubling formula where necessary to avoid data-dependent branches.
|
||||
* Point/x comparison without a field inversion by comparison in the Jacobian coordinate space.
|
||||
* Point multiplication for verification (a*P + b*G).
|
||||
* Use wNAF notation for point multiplicands.
|
||||
* Use a much larger window for multiples of G, using precomputed multiples.
|
||||
* Use Shamir's trick to do the multiplication with the public key and the generator simultaneously.
|
||||
* Use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.
|
||||
* Point multiplication for signing
|
||||
* Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions.
|
||||
* Intended to be completely free of timing sidechannels for secret-key operations (on reasonable hardware/toolchains)
|
||||
* Access the table with branch-free conditional moves so memory access is uniform.
|
||||
* No data-dependent branches
|
||||
* Optional runtime blinding which attempts to frustrate differential power analysis.
|
||||
* The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally.
|
||||
|
||||
Building with Autotools
|
||||
-----------------------
|
||||
|
||||
$ ./autogen.sh
|
||||
$ ./configure
|
||||
$ make
|
||||
$ make check # run the test suite
|
||||
$ sudo make install # optional
|
||||
|
||||
To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags.
|
||||
|
||||
Building with CMake (experimental)
|
||||
----------------------------------
|
||||
|
||||
To maintain a pristine source tree, CMake encourages to perform an out-of-source build by using a separate dedicated build tree.
|
||||
|
||||
### Building on POSIX systems
|
||||
|
||||
$ mkdir build && cd build
|
||||
$ cmake ..
|
||||
$ make
|
||||
$ make check # run the test suite
|
||||
$ sudo make install # optional
|
||||
|
||||
To compile optional modules (such as Schnorr signatures), you need to run `cmake` with additional flags (such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG=ON`). Run `cmake .. -LH` to see the full list of available flags.
|
||||
|
||||
### Cross compiling
|
||||
|
||||
To alleviate issues with cross compiling, preconfigured toolchain files are available in the `cmake` directory.
|
||||
For example, to cross compile for Windows:
|
||||
|
||||
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-w64-mingw32.toolchain.cmake
|
||||
|
||||
To cross compile for Android with [NDK](https://developer.android.com/ndk/guides/cmake) (using NDK's toolchain file, and assuming the `ANDROID_NDK_ROOT` environment variable has been set):
|
||||
|
||||
$ cmake .. -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=28
|
||||
|
||||
### Building on Windows
|
||||
|
||||
To build on Windows with Visual Studio, a proper [generator](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators) must be specified for a new build tree.
|
||||
|
||||
The following example assumes using of Visual Studio 2022 and CMake v3.21+.
|
||||
|
||||
In "Developer Command Prompt for VS 2022":
|
||||
|
||||
>cmake -G "Visual Studio 17 2022" -A x64 -S . -B build
|
||||
>cmake --build build --config RelWithDebInfo
|
||||
|
||||
Usage examples
|
||||
-----------
|
||||
Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
|
||||
* [ECDSA example](examples/ecdsa.c)
|
||||
* [Schnorr signatures example](examples/schnorr.c)
|
||||
* [Deriving a shared secret (ECDH) example](examples/ecdh.c)
|
||||
|
||||
To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
|
||||
|
||||
Test coverage
|
||||
-----------
|
||||
|
||||
This library aims to have full coverage of the reachable lines and branches.
|
||||
|
||||
To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary):
|
||||
|
||||
$ ./configure --enable-coverage
|
||||
|
||||
Run the tests:
|
||||
|
||||
$ make check
|
||||
|
||||
To create a report, `gcovr` is recommended, as it includes branch coverage reporting:
|
||||
|
||||
$ gcovr --exclude 'src/bench*' --print-summary
|
||||
|
||||
To create a HTML report with coloured and annotated source code:
|
||||
|
||||
$ mkdir -p coverage
|
||||
$ gcovr --exclude 'src/bench*' --html --html-details -o coverage/coverage.html
|
||||
|
||||
Benchmark
|
||||
------------
|
||||
If configured with `--enable-benchmark` (which is the default), binaries for benchmarking the libsecp256k1 functions will be present in the root directory after the build.
|
||||
|
||||
To print the benchmark result to the command line:
|
||||
|
||||
$ ./bench_name
|
||||
|
||||
To create a CSV file for the benchmark result :
|
||||
|
||||
$ ./bench_name | sed '2d;s/ \{1,\}//g' > bench_name.csv
|
||||
|
||||
Reporting a vulnerability
|
||||
------------
|
||||
|
||||
See [SECURITY.md](SECURITY.md)
|
||||
15
vendor/secp256k1/repo/SECURITY.md
vendored
Normal file
15
vendor/secp256k1/repo/SECURITY.md
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
To report security issues send an email to secp256k1-security@bitcoincore.org (not for support).
|
||||
|
||||
The following keys may be used to communicate sensitive information to developers:
|
||||
|
||||
| Name | Fingerprint |
|
||||
|------|-------------|
|
||||
| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 |
|
||||
| Jonas Nick | 36C7 1A37 C9D9 88BD E825 08D9 B1A7 0E4F 8DCD 0366 |
|
||||
| Tim Ruffing | 09E0 3F87 1092 E40E 106E 902B 33BC 86AB 80FF 5516 |
|
||||
|
||||
You can import a key by running the following command with that individual’s fingerprint: `gpg --keyserver hkps://keys.openpgp.org --recv-keys "<fingerprint>"` Ensure that you put quotes around fingerprints containing spaces.
|
||||
3
vendor/secp256k1/repo/autogen.sh
vendored
Executable file
3
vendor/secp256k1/repo/autogen.sh
vendored
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
autoreconf -if --warnings=all
|
||||
55
vendor/secp256k1/repo/build-aux/m4/bitcoin_secp.m4
vendored
Normal file
55
vendor/secp256k1/repo/build-aux/m4/bitcoin_secp.m4
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
|
||||
AC_DEFUN([SECP_64BIT_ASM_CHECK],[
|
||||
AC_MSG_CHECKING(for x86_64 assembly availability)
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <stdint.h>]],[[
|
||||
uint64_t a = 11, tmp;
|
||||
__asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
|
||||
]])],[has_64bit_asm=yes],[has_64bit_asm=no])
|
||||
AC_MSG_RESULT([$has_64bit_asm])
|
||||
])
|
||||
|
||||
AC_DEFUN([SECP_VALGRIND_CHECK],[
|
||||
AC_MSG_CHECKING([for valgrind support])
|
||||
if test x"$has_valgrind" != x"yes"; then
|
||||
CPPFLAGS_TEMP="$CPPFLAGS"
|
||||
CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <valgrind/memcheck.h>
|
||||
]], [[
|
||||
#if defined(NVALGRIND)
|
||||
# error "Valgrind does not support this platform."
|
||||
#endif
|
||||
]])], [has_valgrind=yes])
|
||||
fi
|
||||
AC_MSG_RESULT($has_valgrind)
|
||||
])
|
||||
|
||||
dnl SECP_TRY_APPEND_CFLAGS(flags, VAR)
|
||||
dnl Append flags to VAR if CC accepts them.
|
||||
AC_DEFUN([SECP_TRY_APPEND_CFLAGS], [
|
||||
AC_MSG_CHECKING([if ${CC} supports $1])
|
||||
SECP_TRY_APPEND_CFLAGS_saved_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$1 $CFLAGS"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], [flag_works=yes], [flag_works=no])
|
||||
AC_MSG_RESULT($flag_works)
|
||||
CFLAGS="$SECP_TRY_APPEND_CFLAGS_saved_CFLAGS"
|
||||
if test x"$flag_works" = x"yes"; then
|
||||
$2="$$2 $1"
|
||||
fi
|
||||
unset flag_works
|
||||
AC_SUBST($2)
|
||||
])
|
||||
|
||||
dnl SECP_SET_DEFAULT(VAR, default, default-dev-mode)
|
||||
dnl Set VAR to default or default-dev-mode, depending on whether dev mode is enabled
|
||||
AC_DEFUN([SECP_SET_DEFAULT], [
|
||||
if test "${enable_dev_mode+set}" != set; then
|
||||
AC_MSG_ERROR([[Set enable_dev_mode before calling SECP_SET_DEFAULT]])
|
||||
fi
|
||||
if test x"$enable_dev_mode" = x"yes"; then
|
||||
$1="$3"
|
||||
else
|
||||
$1="$2"
|
||||
fi
|
||||
])
|
||||
118
vendor/secp256k1/repo/ci/cirrus.sh
vendored
Executable file
118
vendor/secp256k1/repo/ci/cirrus.sh
vendored
Executable file
|
|
@ -0,0 +1,118 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
# Print relevant CI environment to allow reproducing the job outside of CI.
|
||||
print_environment() {
|
||||
# Turn off -x because it messes up the output
|
||||
set +x
|
||||
# There are many ways to print variable names and their content. This one
|
||||
# does not rely on bash.
|
||||
for var in WERROR_CFLAGS MAKEFLAGS BUILD \
|
||||
ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
|
||||
EXPERIMENTAL ECDH RECOVERY SCHNORRSIG \
|
||||
SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
|
||||
EXAMPLES \
|
||||
HOST WRAPPER_CMD \
|
||||
CC CFLAGS CPPFLAGS AR NM
|
||||
do
|
||||
eval "isset=\${$var+x}"
|
||||
if [ -n "$isset" ]; then
|
||||
eval "val=\${$var}"
|
||||
# shellcheck disable=SC2154
|
||||
printf '%s="%s" ' "$var" "$val"
|
||||
fi
|
||||
done
|
||||
echo "$0"
|
||||
set -x
|
||||
}
|
||||
print_environment
|
||||
|
||||
# Start persistent wineserver if necessary.
|
||||
# This speeds up jobs with many invocations of wine (e.g., ./configure with MSVC) tremendously.
|
||||
case "$WRAPPER_CMD" in
|
||||
*wine*)
|
||||
# Make sure to shutdown wineserver whenever we exit.
|
||||
trap "wineserver -k || true" EXIT INT HUP
|
||||
# This is apparently only reliable when we run a dummy command such as "hh.exe" afterwards.
|
||||
wineserver -p && wine hh.exe
|
||||
;;
|
||||
esac
|
||||
|
||||
env >> test_env.log
|
||||
|
||||
if [ -n "${CC+x}" ]; then
|
||||
# The MSVC compiler "cl" doesn't understand "-v"
|
||||
$CC -v || true
|
||||
fi
|
||||
if [ "$WITH_VALGRIND" = "yes" ]; then
|
||||
valgrind --version
|
||||
fi
|
||||
if [ -n "$WRAPPER_CMD" ]; then
|
||||
$WRAPPER_CMD --version
|
||||
fi
|
||||
|
||||
./autogen.sh
|
||||
|
||||
./configure \
|
||||
--enable-experimental="$EXPERIMENTAL" \
|
||||
--with-test-override-wide-multiply="$WIDEMUL" --with-asm="$ASM" \
|
||||
--with-ecmult-window="$ECMULTWINDOW" \
|
||||
--with-ecmult-gen-precision="$ECMULTGENPRECISION" \
|
||||
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
|
||||
--enable-module-schnorrsig="$SCHNORRSIG" \
|
||||
--enable-examples="$EXAMPLES" \
|
||||
--enable-ctime-tests="$CTIMETESTS" \
|
||||
--with-valgrind="$WITH_VALGRIND" \
|
||||
--host="$HOST" $EXTRAFLAGS
|
||||
|
||||
# We have set "-j<n>" in MAKEFLAGS.
|
||||
make
|
||||
|
||||
# Print information about binaries so that we can see that the architecture is correct
|
||||
file *tests* || true
|
||||
file bench* || true
|
||||
file .libs/* || true
|
||||
|
||||
# This tells `make check` to wrap test invocations.
|
||||
export LOG_COMPILER="$WRAPPER_CMD"
|
||||
|
||||
make "$BUILD"
|
||||
|
||||
# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool
|
||||
EXEC='./libtool --mode=execute'
|
||||
if [ -n "$WRAPPER_CMD" ]
|
||||
then
|
||||
EXEC="$EXEC $WRAPPER_CMD"
|
||||
fi
|
||||
|
||||
if [ "$BENCH" = "yes" ]
|
||||
then
|
||||
{
|
||||
$EXEC ./bench_ecmult
|
||||
$EXEC ./bench_internal
|
||||
$EXEC ./bench
|
||||
} >> bench.log 2>&1
|
||||
fi
|
||||
|
||||
if [ "$CTIMETESTS" = "yes" ]
|
||||
then
|
||||
if [ "$WITH_VALGRIND" = "yes" ]; then
|
||||
./libtool --mode=execute valgrind --error-exitcode=42 ./ctime_tests > ctime_tests.log 2>&1
|
||||
else
|
||||
$EXEC ./ctime_tests > ctime_tests.log 2>&1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Rebuild precomputed files (if not cross-compiling).
|
||||
if [ -z "$HOST" ]
|
||||
then
|
||||
make clean-precomp
|
||||
make precomp
|
||||
fi
|
||||
|
||||
# Check that no repo files have been modified by the build.
|
||||
# (This fails for example if the precomp files need to be updated in the repo.)
|
||||
git diff --exit-code
|
||||
37
vendor/secp256k1/repo/ci/linux-debian.Dockerfile
vendored
Normal file
37
vendor/secp256k1/repo/ci/linux-debian.Dockerfile
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
FROM debian:stable
|
||||
|
||||
RUN dpkg --add-architecture i386 && \
|
||||
dpkg --add-architecture s390x && \
|
||||
dpkg --add-architecture armhf && \
|
||||
dpkg --add-architecture arm64 && \
|
||||
dpkg --add-architecture ppc64el
|
||||
|
||||
# dkpg-dev: to make pkg-config work in cross-builds
|
||||
# llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
git ca-certificates \
|
||||
make automake libtool pkg-config dpkg-dev valgrind qemu-user \
|
||||
gcc clang llvm libc6-dbg \
|
||||
g++ \
|
||||
gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan6:i386 \
|
||||
gcc-s390x-linux-gnu libc6-dev-s390x-cross libc6-dbg:s390x \
|
||||
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \
|
||||
gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \
|
||||
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \
|
||||
gcc-mingw-w64-x86-64-win32 wine64 wine \
|
||||
gcc-mingw-w64-i686-win32 wine32 \
|
||||
sagemath
|
||||
|
||||
WORKDIR /root
|
||||
# The "wine" package provides a convience wrapper that we need
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
git ca-certificates wine64 wine python3-simplejson python3-six msitools winbind procps && \
|
||||
git clone https://github.com/mstorsjo/msvc-wine && \
|
||||
mkdir /opt/msvc && \
|
||||
python3 msvc-wine/vsdownload.py --accept-license --dest /opt/msvc Microsoft.VisualStudio.Workload.VCTools && \
|
||||
msvc-wine/install.sh /opt/msvc
|
||||
|
||||
# Initialize the wine environment. Wait until the wineserver process has
|
||||
# exited before closing the session, to avoid corrupting the wine prefix.
|
||||
RUN wine64 wineboot --init && \
|
||||
while (ps -A | grep wineserver) > /dev/null; do sleep 1; done
|
||||
14
vendor/secp256k1/repo/cmake/Check64bitAssembly.cmake
vendored
Normal file
14
vendor/secp256k1/repo/cmake/Check64bitAssembly.cmake
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
include(CheckCSourceCompiles)
|
||||
|
||||
function(check_64bit_assembly)
|
||||
check_c_source_compiles("
|
||||
#include <stdint.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
uint64_t a = 11, tmp;
|
||||
__asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\");
|
||||
}
|
||||
" HAS_64BIT_ASM)
|
||||
set(HAS_64BIT_ASM ${HAS_64BIT_ASM} PARENT_SCOPE)
|
||||
endfunction()
|
||||
12
vendor/secp256k1/repo/cmake/CheckStringOptionValue.cmake
vendored
Normal file
12
vendor/secp256k1/repo/cmake/CheckStringOptionValue.cmake
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
function(check_string_option_value option)
|
||||
get_property(expected_values CACHE ${option} PROPERTY STRINGS)
|
||||
if(expected_values)
|
||||
foreach(value IN LISTS expected_values)
|
||||
if(value STREQUAL "${${option}}")
|
||||
return()
|
||||
endif()
|
||||
endforeach()
|
||||
message(FATAL_ERROR "${option} value is \"${${option}}\", but must be one of ${expected_values}.")
|
||||
endif()
|
||||
message(AUTHOR_WARNING "The STRINGS property must be set before invoking `check_string_option_value' function.")
|
||||
endfunction()
|
||||
41
vendor/secp256k1/repo/cmake/FindValgrind.cmake
vendored
Normal file
41
vendor/secp256k1/repo/cmake/FindValgrind.cmake
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
|
||||
find_program(BREW_COMMAND brew)
|
||||
execute_process(
|
||||
COMMAND ${BREW_COMMAND} --prefix valgrind
|
||||
OUTPUT_VARIABLE valgrind_brew_prefix
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
endif()
|
||||
|
||||
set(hints_paths)
|
||||
if(valgrind_brew_prefix)
|
||||
set(hints_paths ${valgrind_brew_prefix}/include)
|
||||
endif()
|
||||
|
||||
find_path(Valgrind_INCLUDE_DIR
|
||||
NAMES valgrind/memcheck.h
|
||||
HINTS ${hints_paths}
|
||||
)
|
||||
|
||||
if(Valgrind_INCLUDE_DIR)
|
||||
include(CheckCSourceCompiles)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${Valgrind_INCLUDE_DIR})
|
||||
check_c_source_compiles("
|
||||
#include <valgrind/memcheck.h>
|
||||
#if defined(NVALGRIND)
|
||||
# error \"Valgrind does not support this platform.\"
|
||||
#endif
|
||||
|
||||
int main() {}
|
||||
" Valgrind_WORKS)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Valgrind
|
||||
REQUIRED_VARS Valgrind_INCLUDE_DIR Valgrind_WORKS
|
||||
)
|
||||
|
||||
mark_as_advanced(
|
||||
Valgrind_INCLUDE_DIR
|
||||
)
|
||||
23
vendor/secp256k1/repo/cmake/TryAddCompileOption.cmake
vendored
Normal file
23
vendor/secp256k1/repo/cmake/TryAddCompileOption.cmake
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
include(CheckCCompilerFlag)
|
||||
|
||||
function(try_add_compile_option option)
|
||||
string(MAKE_C_IDENTIFIER ${option} result)
|
||||
string(TOUPPER ${result} result)
|
||||
set(result "C_SUPPORTS${result}")
|
||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_REQUIRED_FLAGS "-Werror")
|
||||
endif()
|
||||
check_c_compiler_flag(${option} ${result})
|
||||
if(${result})
|
||||
get_property(compile_options
|
||||
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
PROPERTY COMPILE_OPTIONS
|
||||
)
|
||||
list(APPEND compile_options "${option}")
|
||||
set_property(
|
||||
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
PROPERTY COMPILE_OPTIONS "${compile_options}"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
3
vendor/secp256k1/repo/cmake/arm-linux-gnueabihf.toolchain.cmake
vendored
Normal file
3
vendor/secp256k1/repo/cmake/arm-linux-gnueabihf.toolchain.cmake
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
|
||||
5
vendor/secp256k1/repo/cmake/config.cmake.in
vendored
Normal file
5
vendor/secp256k1/repo/cmake/config.cmake.in
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
|
||||
|
||||
check_required_components(@PROJECT_NAME@)
|
||||
3
vendor/secp256k1/repo/cmake/x86_64-w64-mingw32.toolchain.cmake
vendored
Normal file
3
vendor/secp256k1/repo/cmake/x86_64-w64-mingw32.toolchain.cmake
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
|
||||
460
vendor/secp256k1/repo/configure.ac
vendored
Normal file
460
vendor/secp256k1/repo/configure.ac
vendored
Normal file
|
|
@ -0,0 +1,460 @@
|
|||
AC_PREREQ([2.60])
|
||||
|
||||
# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of
|
||||
# the API. All changes in experimental modules are treated as
|
||||
# backwards-compatible and therefore at most increase the minor version.
|
||||
define(_PKG_VERSION_MAJOR, 0)
|
||||
define(_PKG_VERSION_MINOR, 3)
|
||||
define(_PKG_VERSION_PATCH, 0)
|
||||
define(_PKG_VERSION_IS_RELEASE, true)
|
||||
|
||||
# The library version is based on libtool versioning of the ABI. The set of
|
||||
# rules for updating the version can be found here:
|
||||
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
# All changes in experimental modules are treated as if they don't affect the
|
||||
# interface and therefore only increase the revision.
|
||||
define(_LIB_VERSION_CURRENT, 2)
|
||||
define(_LIB_VERSION_REVISION, 0)
|
||||
define(_LIB_VERSION_AGE, 0)
|
||||
|
||||
AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1])
|
||||
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_MACRO_DIR([build-aux/m4])
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
# Require Automake 1.11.2 for AM_PROG_AR
|
||||
AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
|
||||
|
||||
# Make the compilation flags quiet unless V=1 is used.
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
AC_PROG_CC
|
||||
AM_PROG_AS
|
||||
AM_PROG_AR
|
||||
|
||||
# Clear some cache variables as a workaround for a bug that appears due to a bad
|
||||
# interaction between AM_PROG_AR and LT_INIT when combining MSVC's archiver lib.exe.
|
||||
# https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54421
|
||||
AS_UNSET(ac_cv_prog_AR)
|
||||
AS_UNSET(ac_cv_prog_ac_ct_AR)
|
||||
LT_INIT([win32-dll])
|
||||
|
||||
build_windows=no
|
||||
|
||||
case $host_os in
|
||||
*darwin*)
|
||||
if test x$cross_compiling != xyes; then
|
||||
AC_CHECK_PROG([BREW], brew, brew)
|
||||
if test x$BREW = xbrew; then
|
||||
# These Homebrew packages may be keg-only, meaning that they won't be found
|
||||
# in expected paths because they may conflict with system files. Ask
|
||||
# Homebrew where each one is located, then adjust paths accordingly.
|
||||
if $BREW list --versions valgrind >/dev/null; then
|
||||
valgrind_prefix=$($BREW --prefix valgrind 2>/dev/null)
|
||||
VALGRIND_CPPFLAGS="-I$valgrind_prefix/include"
|
||||
fi
|
||||
else
|
||||
AC_CHECK_PROG([PORT], port, port)
|
||||
# If homebrew isn't installed and macports is, add the macports default paths
|
||||
# as a last resort.
|
||||
if test x$PORT = xport; then
|
||||
CPPFLAGS="$CPPFLAGS -isystem /opt/local/include"
|
||||
LDFLAGS="$LDFLAGS -L/opt/local/lib"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
cygwin*|mingw*)
|
||||
build_windows=yes
|
||||
;;
|
||||
esac
|
||||
|
||||
# Try if some desirable compiler flags are supported and append them to SECP_CFLAGS.
|
||||
#
|
||||
# These are our own flags, so we append them to our own SECP_CFLAGS variable (instead of CFLAGS) as
|
||||
# recommended in the automake manual (Section "Flag Variables Ordering"). CFLAGS belongs to the user
|
||||
# and we are not supposed to touch it. In the Makefile, we will need to ensure that SECP_CFLAGS
|
||||
# is prepended to CFLAGS when invoking the compiler so that the user always has the last word (flag).
|
||||
#
|
||||
# Another advantage of not touching CFLAGS is that the contents of CFLAGS will be picked up by
|
||||
# libtool for compiling helper executables. For example, when compiling for Windows, libtool will
|
||||
# generate entire wrapper executables (instead of simple wrapper scripts as on Unix) to ensure
|
||||
# proper operation of uninstalled programs linked by libtool against the uninstalled shared library.
|
||||
# These executables are compiled from C source file for which our flags may not be appropriate,
|
||||
# e.g., -std=c89 flag has lead to undesirable warnings in the past.
|
||||
#
|
||||
# TODO We should analogously not touch CPPFLAGS and LDFLAGS but currently there are no issues.
|
||||
AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
|
||||
# GCC and compatible (incl. clang)
|
||||
if test "x$GCC" = "xyes"; then
|
||||
# Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will
|
||||
# not error out if it gets unknown warning flags and the checks here will always succeed
|
||||
# no matter if clang knows the flag or not.
|
||||
SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS"
|
||||
SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS)
|
||||
|
||||
SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
|
||||
SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
|
||||
SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers
|
||||
SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall.
|
||||
SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
|
||||
SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95
|
||||
SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0
|
||||
SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only
|
||||
SECP_TRY_APPEND_CFLAGS([-Wreserved-identifier], $1) # Clang >= 13.0 only
|
||||
SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0
|
||||
|
||||
CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
|
||||
fi
|
||||
|
||||
# MSVC
|
||||
# Assume MSVC if we're building for Windows but not with GCC or compatible;
|
||||
# libtool makes the same assumption internally.
|
||||
# Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path.
|
||||
if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then
|
||||
SECP_TRY_APPEND_CFLAGS([-W2 -wd4146], $1) # Moderate warning level, disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned"
|
||||
SECP_TRY_APPEND_CFLAGS([-external:anglebrackets -external:W0], $1) # Suppress warnings from #include <...> files
|
||||
# We pass -ignore:4217 to the MSVC linker to suppress warning 4217 when
|
||||
# importing variables from a statically linked secp256k1.
|
||||
# (See the libtool manual, section "Windows DLLs" for background.)
|
||||
# Unfortunately, libtool tries to be too clever and strips "-Xlinker arg"
|
||||
# into "arg", so this will be " -Xlinker -ignore:4217" after stripping.
|
||||
LDFLAGS="-Xlinker -Xlinker -Xlinker -ignore:4217 $LDFLAGS"
|
||||
fi
|
||||
])
|
||||
SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS)
|
||||
|
||||
###
|
||||
### Define config arguments
|
||||
###
|
||||
|
||||
# In dev mode, we enable all binaries and modules by default but individual options can still be overridden explicitly.
|
||||
# Check for dev mode first because SECP_SET_DEFAULT needs enable_dev_mode set.
|
||||
AC_ARG_ENABLE(dev_mode, [], [],
|
||||
[enable_dev_mode=no])
|
||||
|
||||
AC_ARG_ENABLE(benchmark,
|
||||
AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]), [],
|
||||
[SECP_SET_DEFAULT([enable_benchmark], [yes], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(coverage,
|
||||
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), [],
|
||||
[SECP_SET_DEFAULT([enable_coverage], [no], [no])])
|
||||
|
||||
AC_ARG_ENABLE(tests,
|
||||
AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [],
|
||||
[SECP_SET_DEFAULT([enable_tests], [yes], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(ctime_tests,
|
||||
AS_HELP_STRING([--enable-ctime-tests],[compile constant-time tests [default=yes if valgrind enabled]]), [],
|
||||
[SECP_SET_DEFAULT([enable_ctime_tests], [auto], [auto])])
|
||||
|
||||
AC_ARG_ENABLE(experimental,
|
||||
AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [],
|
||||
[SECP_SET_DEFAULT([enable_experimental], [no], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(exhaustive_tests,
|
||||
AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]), [],
|
||||
[SECP_SET_DEFAULT([enable_exhaustive_tests], [yes], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(examples,
|
||||
AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [],
|
||||
[SECP_SET_DEFAULT([enable_examples], [no], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(module_ecdh,
|
||||
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=yes]]), [],
|
||||
[SECP_SET_DEFAULT([enable_module_ecdh], [yes], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(module_recovery,
|
||||
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [],
|
||||
[SECP_SET_DEFAULT([enable_module_recovery], [no], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(module_extrakeys,
|
||||
AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=yes]]), [],
|
||||
[SECP_SET_DEFAULT([enable_module_extrakeys], [yes], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(module_schnorrsig,
|
||||
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [],
|
||||
[SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(external_default_callbacks,
|
||||
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
|
||||
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
|
||||
|
||||
# Test-only override of the (autodetected by the C code) "widemul" setting.
|
||||
# Legal values are:
|
||||
# * int64 (for [u]int64_t),
|
||||
# * int128 (for [unsigned] __int128),
|
||||
# * int128_struct (for int128 implemented as a structure),
|
||||
# * and auto (the default).
|
||||
AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
|
||||
|
||||
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto],
|
||||
[assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto])
|
||||
|
||||
AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto],
|
||||
[window size for ecmult precomputation for verification, specified as integer in range [2..24].]
|
||||
[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.]
|
||||
[The table will store 2^(SIZE-1) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.]
|
||||
[A window size larger than 15 will require you delete the prebuilt precomputed_ecmult.c file so that it can be rebuilt.]
|
||||
[For very large window sizes, use "make -j 1" to reduce memory use during compilation.]
|
||||
["auto" is a reasonable setting for desktop machines (currently 15). [default=auto]]
|
||||
)],
|
||||
[req_ecmult_window=$withval], [req_ecmult_window=auto])
|
||||
|
||||
AC_ARG_WITH([ecmult-gen-precision], [AS_HELP_STRING([--with-ecmult-gen-precision=2|4|8|auto],
|
||||
[Precision bits to tune the precomputed table size for signing.]
|
||||
[The size of the table is 32kB for 2 bits, 64kB for 4 bits, 512kB for 8 bits of precision.]
|
||||
[A larger table size usually results in possible faster signing.]
|
||||
["auto" is a reasonable setting for desktop machines (currently 4). [default=auto]]
|
||||
)],
|
||||
[req_ecmult_gen_precision=$withval], [req_ecmult_gen_precision=auto])
|
||||
|
||||
AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind=yes|no|auto],
|
||||
[Build with extra checks for running inside Valgrind [default=auto]]
|
||||
)],
|
||||
[req_valgrind=$withval], [req_valgrind=auto])
|
||||
|
||||
###
|
||||
### Handle config options (except for modules)
|
||||
###
|
||||
|
||||
if test x"$req_valgrind" = x"no"; then
|
||||
enable_valgrind=no
|
||||
else
|
||||
SECP_VALGRIND_CHECK
|
||||
if test x"$has_valgrind" != x"yes"; then
|
||||
if test x"$req_valgrind" = x"yes"; then
|
||||
AC_MSG_ERROR([Valgrind support explicitly requested but valgrind/memcheck.h header not available])
|
||||
fi
|
||||
enable_valgrind=no
|
||||
else
|
||||
enable_valgrind=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$enable_ctime_tests" = x"auto"; then
|
||||
enable_ctime_tests=$enable_valgrind
|
||||
fi
|
||||
|
||||
if test x"$enable_coverage" = x"yes"; then
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOVERAGE=1"
|
||||
SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS"
|
||||
LDFLAGS="--coverage $LDFLAGS"
|
||||
else
|
||||
# Most likely the CFLAGS already contain -O2 because that is autoconf's default.
|
||||
# We still add it here because passing it twice is not an issue, and handling
|
||||
# this case would just add unnecessary complexity (see #896).
|
||||
SECP_CFLAGS="-O2 $SECP_CFLAGS"
|
||||
fi
|
||||
|
||||
if test x"$req_asm" = x"auto"; then
|
||||
SECP_64BIT_ASM_CHECK
|
||||
if test x"$has_64bit_asm" = x"yes"; then
|
||||
set_asm=x86_64
|
||||
fi
|
||||
if test x"$set_asm" = x; then
|
||||
set_asm=no
|
||||
fi
|
||||
else
|
||||
set_asm=$req_asm
|
||||
case $set_asm in
|
||||
x86_64)
|
||||
SECP_64BIT_ASM_CHECK
|
||||
if test x"$has_64bit_asm" != x"yes"; then
|
||||
AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
|
||||
fi
|
||||
;;
|
||||
arm)
|
||||
;;
|
||||
no)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([invalid assembly optimization selection])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Select assembly optimization
|
||||
enable_external_asm=no
|
||||
|
||||
case $set_asm in
|
||||
x86_64)
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_ASM_X86_64=1"
|
||||
;;
|
||||
arm)
|
||||
enable_external_asm=yes
|
||||
;;
|
||||
no)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([invalid assembly optimizations])
|
||||
;;
|
||||
esac
|
||||
|
||||
if test x"$enable_external_asm" = x"yes"; then
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_ASM=1"
|
||||
fi
|
||||
|
||||
|
||||
# Select wide multiplication implementation
|
||||
case $set_widemul in
|
||||
int128_struct)
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128_STRUCT=1"
|
||||
;;
|
||||
int128)
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128=1"
|
||||
;;
|
||||
int64)
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT64=1"
|
||||
;;
|
||||
auto)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([invalid wide multiplication implementation])
|
||||
;;
|
||||
esac
|
||||
|
||||
# Set ecmult window size
|
||||
if test x"$req_ecmult_window" = x"auto"; then
|
||||
set_ecmult_window=15
|
||||
else
|
||||
set_ecmult_window=$req_ecmult_window
|
||||
fi
|
||||
|
||||
error_window_size=['window size for ecmult precomputation not an integer in range [2..24] or "auto"']
|
||||
case $set_ecmult_window in
|
||||
''|*[[!0-9]]*)
|
||||
# no valid integer
|
||||
AC_MSG_ERROR($error_window_size)
|
||||
;;
|
||||
*)
|
||||
if test "$set_ecmult_window" -lt 2 -o "$set_ecmult_window" -gt 24 ; then
|
||||
# not in range
|
||||
AC_MSG_ERROR($error_window_size)
|
||||
fi
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DECMULT_WINDOW_SIZE=$set_ecmult_window"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Set ecmult gen precision
|
||||
if test x"$req_ecmult_gen_precision" = x"auto"; then
|
||||
set_ecmult_gen_precision=4
|
||||
else
|
||||
set_ecmult_gen_precision=$req_ecmult_gen_precision
|
||||
fi
|
||||
|
||||
case $set_ecmult_gen_precision in
|
||||
2|4|8)
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DECMULT_GEN_PREC_BITS=$set_ecmult_gen_precision"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR(['ecmult gen precision not 2, 4, 8 or "auto"'])
|
||||
;;
|
||||
esac
|
||||
|
||||
if test x"$enable_valgrind" = x"yes"; then
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES $VALGRIND_CPPFLAGS -DVALGRIND"
|
||||
fi
|
||||
|
||||
# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI).
|
||||
# We don't want to set the user variable CFLAGS in CI because this would disable
|
||||
# autoconf's logic for setting default CFLAGS, which we would like to test in CI.
|
||||
SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"
|
||||
|
||||
###
|
||||
### Handle module options
|
||||
###
|
||||
|
||||
if test x"$enable_module_ecdh" = x"yes"; then
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1"
|
||||
fi
|
||||
|
||||
if test x"$enable_module_recovery" = x"yes"; then
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RECOVERY=1"
|
||||
fi
|
||||
|
||||
if test x"$enable_module_schnorrsig" = x"yes"; then
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG=1"
|
||||
enable_module_extrakeys=yes
|
||||
fi
|
||||
|
||||
# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
|
||||
# module to set enable_module_extrakeys=yes
|
||||
if test x"$enable_module_extrakeys" = x"yes"; then
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_EXTRAKEYS=1"
|
||||
fi
|
||||
|
||||
if test x"$enable_external_default_callbacks" = x"yes"; then
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_DEFAULT_CALLBACKS=1"
|
||||
fi
|
||||
|
||||
###
|
||||
### Check for --enable-experimental if necessary
|
||||
###
|
||||
|
||||
if test x"$enable_experimental" = x"yes"; then
|
||||
AC_MSG_NOTICE([******])
|
||||
AC_MSG_NOTICE([WARNING: experimental build])
|
||||
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
|
||||
AC_MSG_NOTICE([******])
|
||||
else
|
||||
if test x"$set_asm" = x"arm"; then
|
||||
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
fi
|
||||
|
||||
###
|
||||
### Generate output
|
||||
###
|
||||
|
||||
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
|
||||
AC_SUBST(SECP_CFLAGS)
|
||||
AC_SUBST(SECP_CONFIG_DEFINES)
|
||||
AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"])
|
||||
AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"])
|
||||
AM_CONDITIONAL([USE_CTIME_TESTS], [test x"$enable_ctime_tests" = x"yes"])
|
||||
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"])
|
||||
AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"])
|
||||
AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
|
||||
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
|
||||
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
|
||||
AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"])
|
||||
AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT)
|
||||
AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION)
|
||||
AC_SUBST(LIB_VERSION_AGE, _LIB_VERSION_AGE)
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
echo
|
||||
echo "Build Options:"
|
||||
echo " with external callbacks = $enable_external_default_callbacks"
|
||||
echo " with benchmarks = $enable_benchmark"
|
||||
echo " with tests = $enable_tests"
|
||||
echo " with ctime tests = $enable_ctime_tests"
|
||||
echo " with coverage = $enable_coverage"
|
||||
echo " with examples = $enable_examples"
|
||||
echo " module ecdh = $enable_module_ecdh"
|
||||
echo " module recovery = $enable_module_recovery"
|
||||
echo " module extrakeys = $enable_module_extrakeys"
|
||||
echo " module schnorrsig = $enable_module_schnorrsig"
|
||||
echo
|
||||
echo " asm = $set_asm"
|
||||
echo " ecmult window size = $set_ecmult_window"
|
||||
echo " ecmult gen prec. bits = $set_ecmult_gen_precision"
|
||||
# Hide test-only options unless they're used.
|
||||
if test x"$set_widemul" != xauto; then
|
||||
echo " wide multiplication = $set_widemul"
|
||||
fi
|
||||
echo
|
||||
echo " valgrind = $enable_valgrind"
|
||||
echo " CC = $CC"
|
||||
echo " CPPFLAGS = $CPPFLAGS"
|
||||
echo " SECP_CFLAGS = $SECP_CFLAGS"
|
||||
echo " CFLAGS = $CFLAGS"
|
||||
echo " LDFLAGS = $LDFLAGS"
|
||||
148
vendor/secp256k1/repo/contrib/lax_der_parsing.c
vendored
Normal file
148
vendor/secp256k1/repo/contrib/lax_der_parsing.c
vendored
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/***********************************************************************
|
||||
* Copyright (c) 2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "lax_der_parsing.h"
|
||||
|
||||
int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
|
||||
size_t rpos, rlen, spos, slen;
|
||||
size_t pos = 0;
|
||||
size_t lenbyte;
|
||||
unsigned char tmpsig[64] = {0};
|
||||
int overflow = 0;
|
||||
|
||||
/* Hack to initialize sig with a correctly-parsed but invalid signature. */
|
||||
secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
|
||||
|
||||
/* Sequence tag byte */
|
||||
if (pos == inputlen || input[pos] != 0x30) {
|
||||
return 0;
|
||||
}
|
||||
pos++;
|
||||
|
||||
/* Sequence length bytes */
|
||||
if (pos == inputlen) {
|
||||
return 0;
|
||||
}
|
||||
lenbyte = input[pos++];
|
||||
if (lenbyte & 0x80) {
|
||||
lenbyte -= 0x80;
|
||||
if (lenbyte > inputlen - pos) {
|
||||
return 0;
|
||||
}
|
||||
pos += lenbyte;
|
||||
}
|
||||
|
||||
/* Integer tag byte for R */
|
||||
if (pos == inputlen || input[pos] != 0x02) {
|
||||
return 0;
|
||||
}
|
||||
pos++;
|
||||
|
||||
/* Integer length for R */
|
||||
if (pos == inputlen) {
|
||||
return 0;
|
||||
}
|
||||
lenbyte = input[pos++];
|
||||
if (lenbyte & 0x80) {
|
||||
lenbyte -= 0x80;
|
||||
if (lenbyte > inputlen - pos) {
|
||||
return 0;
|
||||
}
|
||||
while (lenbyte > 0 && input[pos] == 0) {
|
||||
pos++;
|
||||
lenbyte--;
|
||||
}
|
||||
if (lenbyte >= sizeof(size_t)) {
|
||||
return 0;
|
||||
}
|
||||
rlen = 0;
|
||||
while (lenbyte > 0) {
|
||||
rlen = (rlen << 8) + input[pos];
|
||||
pos++;
|
||||
lenbyte--;
|
||||
}
|
||||
} else {
|
||||
rlen = lenbyte;
|
||||
}
|
||||
if (rlen > inputlen - pos) {
|
||||
return 0;
|
||||
}
|
||||
rpos = pos;
|
||||
pos += rlen;
|
||||
|
||||
/* Integer tag byte for S */
|
||||
if (pos == inputlen || input[pos] != 0x02) {
|
||||
return 0;
|
||||
}
|
||||
pos++;
|
||||
|
||||
/* Integer length for S */
|
||||
if (pos == inputlen) {
|
||||
return 0;
|
||||
}
|
||||
lenbyte = input[pos++];
|
||||
if (lenbyte & 0x80) {
|
||||
lenbyte -= 0x80;
|
||||
if (lenbyte > inputlen - pos) {
|
||||
return 0;
|
||||
}
|
||||
while (lenbyte > 0 && input[pos] == 0) {
|
||||
pos++;
|
||||
lenbyte--;
|
||||
}
|
||||
if (lenbyte >= sizeof(size_t)) {
|
||||
return 0;
|
||||
}
|
||||
slen = 0;
|
||||
while (lenbyte > 0) {
|
||||
slen = (slen << 8) + input[pos];
|
||||
pos++;
|
||||
lenbyte--;
|
||||
}
|
||||
} else {
|
||||
slen = lenbyte;
|
||||
}
|
||||
if (slen > inputlen - pos) {
|
||||
return 0;
|
||||
}
|
||||
spos = pos;
|
||||
|
||||
/* Ignore leading zeroes in R */
|
||||
while (rlen > 0 && input[rpos] == 0) {
|
||||
rlen--;
|
||||
rpos++;
|
||||
}
|
||||
/* Copy R value */
|
||||
if (rlen > 32) {
|
||||
overflow = 1;
|
||||
} else if (rlen) {
|
||||
memcpy(tmpsig + 32 - rlen, input + rpos, rlen);
|
||||
}
|
||||
|
||||
/* Ignore leading zeroes in S */
|
||||
while (slen > 0 && input[spos] == 0) {
|
||||
slen--;
|
||||
spos++;
|
||||
}
|
||||
/* Copy S value */
|
||||
if (slen > 32) {
|
||||
overflow = 1;
|
||||
} else if (slen) {
|
||||
memcpy(tmpsig + 64 - slen, input + spos, slen);
|
||||
}
|
||||
|
||||
if (!overflow) {
|
||||
overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
|
||||
}
|
||||
if (overflow) {
|
||||
memset(tmpsig, 0, 64);
|
||||
secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
97
vendor/secp256k1/repo/contrib/lax_der_parsing.h
vendored
Normal file
97
vendor/secp256k1/repo/contrib/lax_der_parsing.h
vendored
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/***********************************************************************
|
||||
* Copyright (c) 2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
/****
|
||||
* Please do not link this file directly. It is not part of the libsecp256k1
|
||||
* project and does not promise any stability in its API, functionality or
|
||||
* presence. Projects which use this code should instead copy this header
|
||||
* and its accompanying .c file directly into their codebase.
|
||||
****/
|
||||
|
||||
/* This file defines a function that parses DER with various errors and
|
||||
* violations. This is not a part of the library itself, because the allowed
|
||||
* violations are chosen arbitrarily and do not follow or establish any
|
||||
* standard.
|
||||
*
|
||||
* In many places it matters that different implementations do not only accept
|
||||
* the same set of valid signatures, but also reject the same set of signatures.
|
||||
* The only means to accomplish that is by strictly obeying a standard, and not
|
||||
* accepting anything else.
|
||||
*
|
||||
* Nonetheless, sometimes there is a need for compatibility with systems that
|
||||
* use signatures which do not strictly obey DER. The snippet below shows how
|
||||
* certain violations are easily supported. You may need to adapt it.
|
||||
*
|
||||
* Do not use this for new systems. Use well-defined DER or compact signatures
|
||||
* instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and
|
||||
* secp256k1_ecdsa_signature_parse_compact).
|
||||
*
|
||||
* The supported violations are:
|
||||
* - All numbers are parsed as nonnegative integers, even though X.609-0207
|
||||
* section 8.3.3 specifies that integers are always encoded as two's
|
||||
* complement.
|
||||
* - Integers can have length 0, even though section 8.3.1 says they can't.
|
||||
* - Integers with overly long padding are accepted, violation section
|
||||
* 8.3.2.
|
||||
* - 127-byte long length descriptors are accepted, even though section
|
||||
* 8.1.3.5.c says that they are not.
|
||||
* - Trailing garbage data inside or after the signature is ignored.
|
||||
* - The length descriptor of the sequence is ignored.
|
||||
*
|
||||
* Compared to for example OpenSSL, many violations are NOT supported:
|
||||
* - Using overly long tag descriptors for the sequence or integers inside,
|
||||
* violating section 8.1.2.2.
|
||||
* - Encoding primitive integers as constructed values, violating section
|
||||
* 8.3.1.
|
||||
*/
|
||||
|
||||
#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H
|
||||
#define SECP256K1_CONTRIB_LAX_DER_PARSING_H
|
||||
|
||||
/* #include secp256k1.h only when it hasn't been included yet.
|
||||
This enables this file to be #included directly in other project
|
||||
files (such as tests.c) without the need to set an explicit -I flag,
|
||||
which would be necessary to locate secp256k1.h. */
|
||||
#ifndef SECP256K1_H
|
||||
#include <secp256k1.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Parse a signature in "lax DER" format
|
||||
*
|
||||
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: sig: a pointer to a signature object
|
||||
* In: input: a pointer to the signature to be parsed
|
||||
* inputlen: the length of the array pointed to be input
|
||||
*
|
||||
* This function will accept any valid DER encoded signature, even if the
|
||||
* encoded numbers are out of range. In addition, it will accept signatures
|
||||
* which violate the DER spec in various ways. Its purpose is to allow
|
||||
* validation of the Bitcoin blockchain, which includes non-DER signatures
|
||||
* from before the network rules were updated to enforce DER. Note that
|
||||
* the set of supported violations is a strict subset of what OpenSSL will
|
||||
* accept.
|
||||
*
|
||||
* After the call, sig will always be initialized. If parsing failed or the
|
||||
* encoded numbers are out of range, signature validation with it is
|
||||
* guaranteed to fail for every message and public key.
|
||||
*/
|
||||
int ecdsa_signature_parse_der_lax(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_ecdsa_signature* sig,
|
||||
const unsigned char *input,
|
||||
size_t inputlen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_CONTRIB_LAX_DER_PARSING_H */
|
||||
112
vendor/secp256k1/repo/contrib/lax_der_privatekey_parsing.c
vendored
Normal file
112
vendor/secp256k1/repo/contrib/lax_der_privatekey_parsing.c
vendored
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/***********************************************************************
|
||||
* Copyright (c) 2014, 2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "lax_der_privatekey_parsing.h"
|
||||
|
||||
int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) {
|
||||
const unsigned char *end = privkey + privkeylen;
|
||||
int lenb = 0;
|
||||
int len = 0;
|
||||
memset(out32, 0, 32);
|
||||
/* sequence header */
|
||||
if (end < privkey+1 || *privkey != 0x30) {
|
||||
return 0;
|
||||
}
|
||||
privkey++;
|
||||
/* sequence length constructor */
|
||||
if (end < privkey+1 || !(*privkey & 0x80)) {
|
||||
return 0;
|
||||
}
|
||||
lenb = *privkey & ~0x80; privkey++;
|
||||
if (lenb < 1 || lenb > 2) {
|
||||
return 0;
|
||||
}
|
||||
if (end < privkey+lenb) {
|
||||
return 0;
|
||||
}
|
||||
/* sequence length */
|
||||
len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0);
|
||||
privkey += lenb;
|
||||
if (end < privkey+len) {
|
||||
return 0;
|
||||
}
|
||||
/* sequence element 0: version number (=1) */
|
||||
if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) {
|
||||
return 0;
|
||||
}
|
||||
privkey += 3;
|
||||
/* sequence element 1: octet string, up to 32 bytes */
|
||||
if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) {
|
||||
return 0;
|
||||
}
|
||||
if (privkey[1]) memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]);
|
||||
if (!secp256k1_ec_seckey_verify(ctx, out32)) {
|
||||
memset(out32, 0, 32);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) {
|
||||
secp256k1_pubkey pubkey;
|
||||
size_t pubkeylen = 0;
|
||||
if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) {
|
||||
*privkeylen = 0;
|
||||
return 0;
|
||||
}
|
||||
if (compressed) {
|
||||
static const unsigned char begin[] = {
|
||||
0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20
|
||||
};
|
||||
static const unsigned char middle[] = {
|
||||
0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
|
||||
0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
|
||||
0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
|
||||
0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
|
||||
0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
|
||||
0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00
|
||||
};
|
||||
unsigned char *ptr = privkey;
|
||||
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
|
||||
memcpy(ptr, key32, 32); ptr += 32;
|
||||
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
|
||||
pubkeylen = 33;
|
||||
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED);
|
||||
ptr += pubkeylen;
|
||||
*privkeylen = ptr - privkey;
|
||||
} else {
|
||||
static const unsigned char begin[] = {
|
||||
0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
|
||||
};
|
||||
static const unsigned char middle[] = {
|
||||
0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48,
|
||||
0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04,
|
||||
0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87,
|
||||
0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8,
|
||||
0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11,
|
||||
0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10,
|
||||
0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
|
||||
0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00
|
||||
};
|
||||
unsigned char *ptr = privkey;
|
||||
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
|
||||
memcpy(ptr, key32, 32); ptr += 32;
|
||||
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
|
||||
pubkeylen = 65;
|
||||
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
|
||||
ptr += pubkeylen;
|
||||
*privkeylen = ptr - privkey;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
95
vendor/secp256k1/repo/contrib/lax_der_privatekey_parsing.h
vendored
Normal file
95
vendor/secp256k1/repo/contrib/lax_der_privatekey_parsing.h
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/***********************************************************************
|
||||
* Copyright (c) 2014, 2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
/****
|
||||
* Please do not link this file directly. It is not part of the libsecp256k1
|
||||
* project and does not promise any stability in its API, functionality or
|
||||
* presence. Projects which use this code should instead copy this header
|
||||
* and its accompanying .c file directly into their codebase.
|
||||
****/
|
||||
|
||||
/* This file contains code snippets that parse DER private keys with
|
||||
* various errors and violations. This is not a part of the library
|
||||
* itself, because the allowed violations are chosen arbitrarily and
|
||||
* do not follow or establish any standard.
|
||||
*
|
||||
* It also contains code to serialize private keys in a compatible
|
||||
* manner.
|
||||
*
|
||||
* These functions are meant for compatibility with applications
|
||||
* that require BER encoded keys. When working with secp256k1-specific
|
||||
* code, the simple 32-byte private keys normally used by the
|
||||
* library are sufficient.
|
||||
*/
|
||||
|
||||
#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H
|
||||
#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H
|
||||
|
||||
/* #include secp256k1.h only when it hasn't been included yet.
|
||||
This enables this file to be #included directly in other project
|
||||
files (such as tests.c) without the need to set an explicit -I flag,
|
||||
which would be necessary to locate secp256k1.h. */
|
||||
#ifndef SECP256K1_H
|
||||
#include <secp256k1.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Export a private key in DER format.
|
||||
*
|
||||
* Returns: 1 if the private key was valid.
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* Out: privkey: pointer to an array for storing the private key in BER.
|
||||
* Should have space for 279 bytes, and cannot be NULL.
|
||||
* privkeylen: Pointer to an int where the length of the private key in
|
||||
* privkey will be stored.
|
||||
* In: seckey: pointer to a 32-byte secret key to export.
|
||||
* compressed: 1 if the key should be exported in
|
||||
* compressed format, 0 otherwise
|
||||
*
|
||||
* This function is purely meant for compatibility with applications that
|
||||
* require BER encoded keys. When working with secp256k1-specific code, the
|
||||
* simple 32-byte private keys are sufficient.
|
||||
*
|
||||
* Note that this function does not guarantee correct DER output. It is
|
||||
* guaranteed to be parsable by secp256k1_ec_privkey_import_der
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *privkey,
|
||||
size_t *privkeylen,
|
||||
const unsigned char *seckey,
|
||||
int compressed
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Import a private key in DER format.
|
||||
* Returns: 1 if a private key was extracted.
|
||||
* Args: ctx: pointer to a context object (cannot be NULL).
|
||||
* Out: seckey: pointer to a 32-byte array for storing the private key.
|
||||
* (cannot be NULL).
|
||||
* In: privkey: pointer to a private key in DER format (cannot be NULL).
|
||||
* privkeylen: length of the DER private key pointed to be privkey.
|
||||
*
|
||||
* This function will accept more than just strict DER, and even allow some BER
|
||||
* violations. The public key stored inside the DER-encoded private key is not
|
||||
* verified for correctness, nor are the curve parameters. Use this function
|
||||
* only if you know in advance it is supposed to contain a secp256k1 private
|
||||
* key.
|
||||
*/
|
||||
SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey,
|
||||
const unsigned char *privkey,
|
||||
size_t privkeylen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_CONTRIB_BER_PRIVATEKEY_H */
|
||||
52
vendor/secp256k1/repo/doc/release-process.md
vendored
Normal file
52
vendor/secp256k1/repo/doc/release-process.md
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Release Process
|
||||
|
||||
This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`.
|
||||
|
||||
We distinguish between two types of releases: *regular* and *maintenance* releases.
|
||||
Regular releases are releases of a new major or minor version as well as patches of the most recent release.
|
||||
Maintenance releases, on the other hand, are required for patches of older releases.
|
||||
|
||||
You should coordinate with the other maintainers on the release date, if possible.
|
||||
This date will be part of the release entry in [CHANGELOG.md](../CHANGELOG.md) and it should match the dates of the remaining steps in the release process (including the date of the tag and the GitHub release).
|
||||
It is best if the maintainers are present during the release, so they can help ensure that the process is followed correctly and, in the case of a regular release, they are aware that they should not modify the master branch between merging the PR in step 1 and the PR in step 3.
|
||||
|
||||
This process also assumes that there will be no minor releases for old major releases.
|
||||
|
||||
## Regular release
|
||||
|
||||
1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that
|
||||
* finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) (make sure to include an entry for `### ABI Compatibility`) and
|
||||
* updates `_PKG_VERSION_*`, `_LIB_VERSION_*`, and sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`.
|
||||
2. After the PR is merged, tag the commit and push it:
|
||||
```
|
||||
RELEASE_COMMIT=<merge commit of step 1>
|
||||
git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT
|
||||
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
|
||||
```
|
||||
3. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that sets `_PKG_VERSION_IS_RELEASE` to `false` and `_PKG_VERSION_PATCH` to `$PATCH + 1` and increases `_LIB_VERSION_REVISION`. If other maintainers are not present to approve the PR, it can be merged without ACKs.
|
||||
4. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
|
||||
|
||||
## Maintenance release
|
||||
|
||||
Note that bugfixes only need to be backported to releases for which no compatible release without the bug exists.
|
||||
|
||||
1. If `$PATCH = 1`, create maintenance branch `$MAJOR.$MINOR`:
|
||||
```
|
||||
git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.0
|
||||
git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR
|
||||
```
|
||||
2. Open a pull request to the `$MAJOR.$MINOR` branch that
|
||||
* includes the bugfixes,
|
||||
* finalizes the release notes,
|
||||
* bumps `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac` (with commit message `"release: update PKG_ and LIB_VERSION for $MAJOR.$MINOR.$PATCH"`, for example).
|
||||
3. After the PRs are merged, update the release branch and tag the commit:
|
||||
```
|
||||
git checkout $MAJOR.$MINOR && git pull
|
||||
git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH"
|
||||
```
|
||||
4. Push tag:
|
||||
```
|
||||
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
|
||||
```
|
||||
5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
|
||||
6. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md).
|
||||
819
vendor/secp256k1/repo/doc/safegcd_implementation.md
vendored
Normal file
819
vendor/secp256k1/repo/doc/safegcd_implementation.md
vendored
Normal file
|
|
@ -0,0 +1,819 @@
|
|||
# The safegcd implementation in libsecp256k1 explained
|
||||
|
||||
This document explains the modular inverse and Jacobi symbol implementations in the `src/modinv*.h` files.
|
||||
It is based on the paper
|
||||
["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd)
|
||||
by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version.
|
||||
|
||||
The actual implementation is in C of course, but for demonstration purposes Python3 is used here.
|
||||
Most implementation aspects and optimizations are explained, except those that depend on the specific
|
||||
number representation used in the C code.
|
||||
|
||||
## 1. Computing the Greatest Common Divisor (GCD) using divsteps
|
||||
|
||||
The algorithm from the paper (section 11), at a very high level, is this:
|
||||
|
||||
```python
|
||||
def gcd(f, g):
|
||||
"""Compute the GCD of an odd integer f and another integer g."""
|
||||
assert f & 1 # require f to be odd
|
||||
delta = 1 # additional state variable
|
||||
while g != 0:
|
||||
assert f & 1 # f will be odd in every iteration
|
||||
if delta > 0 and g & 1:
|
||||
delta, f, g = 1 - delta, g, (g - f) // 2
|
||||
elif g & 1:
|
||||
delta, f, g = 1 + delta, f, (g + f) // 2
|
||||
else:
|
||||
delta, f, g = 1 + delta, f, (g ) // 2
|
||||
return abs(f)
|
||||
```
|
||||
|
||||
It computes the greatest common divisor of an odd integer *f* and any integer *g*. Its inner loop
|
||||
keeps rewriting the variables *f* and *g* alongside a state variable *δ* that starts at *1*, until
|
||||
*g=0* is reached. At that point, *|f|* gives the GCD. Each of the transitions in the loop is called a
|
||||
"division step" (referred to as divstep in what follows).
|
||||
|
||||
For example, *gcd(21, 14)* would be computed as:
|
||||
- Start with *δ=1 f=21 g=14*
|
||||
- Take the third branch: *δ=2 f=21 g=7*
|
||||
- Take the first branch: *δ=-1 f=7 g=-7*
|
||||
- Take the second branch: *δ=0 f=7 g=0*
|
||||
- The answer *|f| = 7*.
|
||||
|
||||
Why it works:
|
||||
- Divsteps can be decomposed into two steps (see paragraph 8.2 in the paper):
|
||||
- (a) If *g* is odd, replace *(f,g)* with *(g,g-f)* or (f,g+f), resulting in an even *g*.
|
||||
- (b) Replace *(f,g)* with *(f,g/2)* (where *g* is guaranteed to be even).
|
||||
- Neither of those two operations change the GCD:
|
||||
- For (a), assume *gcd(f,g)=c*, then it must be the case that *f=a c* and *g=b c* for some integers *a*
|
||||
and *b*. As *(g,g-f)=(b c,(b-a)c)* and *(f,f+g)=(a c,(a+b)c)*, the result clearly still has
|
||||
common factor *c*. Reasoning in the other direction shows that no common factor can be added by
|
||||
doing so either.
|
||||
- For (b), we know that *f* is odd, so *gcd(f,g)* clearly has no factor *2*, and we can remove
|
||||
it from *g*.
|
||||
- The algorithm will eventually converge to *g=0*. This is proven in the paper (see theorem G.3).
|
||||
- It follows that eventually we find a final value *f'* for which *gcd(f,g) = gcd(f',0)*. As the
|
||||
gcd of *f'* and *0* is *|f'|* by definition, that is our answer.
|
||||
|
||||
Compared to more [traditional GCD algorithms](https://en.wikipedia.org/wiki/Euclidean_algorithm), this one has the property of only ever looking at
|
||||
the low-order bits of the variables to decide the next steps, and being easy to make
|
||||
constant-time (in more low-level languages than Python). The *δ* parameter is necessary to
|
||||
guide the algorithm towards shrinking the numbers' magnitudes without explicitly needing to look
|
||||
at high order bits.
|
||||
|
||||
Properties that will become important later:
|
||||
- Performing more divsteps than needed is not a problem, as *f* does not change anymore after *g=0*.
|
||||
- Only even numbers are divided by *2*. This means that when reasoning about it algebraically we
|
||||
do not need to worry about rounding.
|
||||
- At every point during the algorithm's execution the next *N* steps only depend on the bottom *N*
|
||||
bits of *f* and *g*, and on *δ*.
|
||||
|
||||
|
||||
## 2. From GCDs to modular inverses
|
||||
|
||||
We want an algorithm to compute the inverse *a* of *x* modulo *M*, i.e. the number a such that *a x=1
|
||||
mod M*. This inverse only exists if the GCD of *x* and *M* is *1*, but that is always the case if *M* is
|
||||
prime and *0 < x < M*. In what follows, assume that the modular inverse exists.
|
||||
It turns out this inverse can be computed as a side effect of computing the GCD by keeping track
|
||||
of how the internal variables can be written as linear combinations of the inputs at every step
|
||||
(see the [extended Euclidean algorithm](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm)).
|
||||
Since the GCD is *1*, such an algorithm will compute numbers *a* and *b* such that a x + b M = 1*.
|
||||
Taking that expression *mod M* gives *a x mod M = 1*, and we see that *a* is the modular inverse of *x
|
||||
mod M*.
|
||||
|
||||
A similar approach can be used to calculate modular inverses using the divsteps-based GCD
|
||||
algorithm shown above, if the modulus *M* is odd. To do so, compute *gcd(f=M,g=x)*, while keeping
|
||||
track of extra variables *d* and *e*, for which at every step *d = f/x (mod M)* and *e = g/x (mod M)*.
|
||||
*f/x* here means the number which multiplied with *x* gives *f mod M*. As *f* and *g* are initialized to *M*
|
||||
and *x* respectively, *d* and *e* just start off being *0* (*M/x mod M = 0/x mod M = 0*) and *1* (*x/x mod M
|
||||
= 1*).
|
||||
|
||||
```python
|
||||
def div2(M, x):
|
||||
"""Helper routine to compute x/2 mod M (where M is odd)."""
|
||||
assert M & 1
|
||||
if x & 1: # If x is odd, make it even by adding M.
|
||||
x += M
|
||||
# x must be even now, so a clean division by 2 is possible.
|
||||
return x // 2
|
||||
|
||||
def modinv(M, x):
|
||||
"""Compute the inverse of x mod M (given that it exists, and M is odd)."""
|
||||
assert M & 1
|
||||
delta, f, g, d, e = 1, M, x, 0, 1
|
||||
while g != 0:
|
||||
# Note that while division by two for f and g is only ever done on even inputs, this is
|
||||
# not true for d and e, so we need the div2 helper function.
|
||||
if delta > 0 and g & 1:
|
||||
delta, f, g, d, e = 1 - delta, g, (g - f) // 2, e, div2(M, e - d)
|
||||
elif g & 1:
|
||||
delta, f, g, d, e = 1 + delta, f, (g + f) // 2, d, div2(M, e + d)
|
||||
else:
|
||||
delta, f, g, d, e = 1 + delta, f, (g ) // 2, d, div2(M, e )
|
||||
# Verify that the invariants d=f/x mod M, e=g/x mod M are maintained.
|
||||
assert f % M == (d * x) % M
|
||||
assert g % M == (e * x) % M
|
||||
assert f == 1 or f == -1 # |f| is the GCD, it must be 1
|
||||
# Because of invariant d = f/x (mod M), 1/x = d/f (mod M). As |f|=1, d/f = d*f.
|
||||
return (d * f) % M
|
||||
```
|
||||
|
||||
Also note that this approach to track *d* and *e* throughout the computation to determine the inverse
|
||||
is different from the paper. There (see paragraph 12.1 in the paper) a transition matrix for the
|
||||
entire computation is determined (see section 3 below) and the inverse is computed from that.
|
||||
The approach here avoids the need for 2x2 matrix multiplications of various sizes, and appears to
|
||||
be faster at the level of optimization we're able to do in C.
|
||||
|
||||
|
||||
## 3. Batching multiple divsteps
|
||||
|
||||
Every divstep can be expressed as a matrix multiplication, applying a transition matrix *(1/2 t)*
|
||||
to both vectors *[f, g]* and *[d, e]* (see paragraph 8.1 in the paper):
|
||||
|
||||
```
|
||||
t = [ u, v ]
|
||||
[ q, r ]
|
||||
|
||||
[ out_f ] = (1/2 * t) * [ in_f ]
|
||||
[ out_g ] = [ in_g ]
|
||||
|
||||
[ out_d ] = (1/2 * t) * [ in_d ] (mod M)
|
||||
[ out_e ] [ in_e ]
|
||||
```
|
||||
|
||||
where *(u, v, q, r)* is *(0, 2, -1, 1)*, *(2, 0, 1, 1)*, or *(2, 0, 0, 1)*, depending on which branch is
|
||||
taken. As above, the resulting *f* and *g* are always integers.
|
||||
|
||||
Performing multiple divsteps corresponds to a multiplication with the product of all the
|
||||
individual divsteps' transition matrices. As each transition matrix consists of integers
|
||||
divided by *2*, the product of these matrices will consist of integers divided by *2<sup>N</sup>* (see also
|
||||
theorem 9.2 in the paper). These divisions are expensive when updating *d* and *e*, so we delay
|
||||
them: we compute the integer coefficients of the combined transition matrix scaled by *2<sup>N</sup>*, and
|
||||
do one division by *2<sup>N</sup>* as a final step:
|
||||
|
||||
```python
|
||||
def divsteps_n_matrix(delta, f, g):
|
||||
"""Compute delta and transition matrix t after N divsteps (multiplied by 2^N)."""
|
||||
u, v, q, r = 1, 0, 0, 1 # start with identity matrix
|
||||
for _ in range(N):
|
||||
if delta > 0 and g & 1:
|
||||
delta, f, g, u, v, q, r = 1 - delta, g, (g - f) // 2, 2*q, 2*r, q-u, r-v
|
||||
elif g & 1:
|
||||
delta, f, g, u, v, q, r = 1 + delta, f, (g + f) // 2, 2*u, 2*v, q+u, r+v
|
||||
else:
|
||||
delta, f, g, u, v, q, r = 1 + delta, f, (g ) // 2, 2*u, 2*v, q , r
|
||||
return delta, (u, v, q, r)
|
||||
```
|
||||
|
||||
As the branches in the divsteps are completely determined by the bottom *N* bits of *f* and *g*, this
|
||||
function to compute the transition matrix only needs to see those bottom bits. Furthermore all
|
||||
intermediate results and outputs fit in *(N+1)*-bit numbers (unsigned for *f* and *g*; signed for *u*, *v*,
|
||||
*q*, and *r*) (see also paragraph 8.3 in the paper). This means that an implementation using 64-bit
|
||||
integers could set *N=62* and compute the full transition matrix for 62 steps at once without any
|
||||
big integer arithmetic at all. This is the reason why this algorithm is efficient: it only needs
|
||||
to update the full-size *f*, *g*, *d*, and *e* numbers once every *N* steps.
|
||||
|
||||
We still need functions to compute:
|
||||
|
||||
```
|
||||
[ out_f ] = (1/2^N * [ u, v ]) * [ in_f ]
|
||||
[ out_g ] ( [ q, r ]) [ in_g ]
|
||||
|
||||
[ out_d ] = (1/2^N * [ u, v ]) * [ in_d ] (mod M)
|
||||
[ out_e ] ( [ q, r ]) [ in_e ]
|
||||
```
|
||||
|
||||
Because the divsteps transformation only ever divides even numbers by two, the result of *t [f,g]* is always even. When *t* is a composition of *N* divsteps, it follows that the resulting *f*
|
||||
and *g* will be multiple of *2<sup>N</sup>*, and division by *2<sup>N</sup>* is simply shifting them down:
|
||||
|
||||
```python
|
||||
def update_fg(f, g, t):
|
||||
"""Multiply matrix t/2^N with [f, g]."""
|
||||
u, v, q, r = t
|
||||
cf, cg = u*f + v*g, q*f + r*g
|
||||
# (t / 2^N) should cleanly apply to [f,g] so the result of t*[f,g] should have N zero
|
||||
# bottom bits.
|
||||
assert cf % 2**N == 0
|
||||
assert cg % 2**N == 0
|
||||
return cf >> N, cg >> N
|
||||
```
|
||||
|
||||
The same is not true for *d* and *e*, and we need an equivalent of the `div2` function for division by *2<sup>N</sup> mod M*.
|
||||
This is easy if we have precomputed *1/M mod 2<sup>N</sup>* (which always exists for odd *M*):
|
||||
|
||||
```python
|
||||
def div2n(M, Mi, x):
|
||||
"""Compute x/2^N mod M, given Mi = 1/M mod 2^N."""
|
||||
assert (M * Mi) % 2**N == 1
|
||||
# Find a factor m such that m*M has the same bottom N bits as x. We want:
|
||||
# (m * M) mod 2^N = x mod 2^N
|
||||
# <=> m mod 2^N = (x / M) mod 2^N
|
||||
# <=> m mod 2^N = (x * Mi) mod 2^N
|
||||
m = (Mi * x) % 2**N
|
||||
# Subtract that multiple from x, cancelling its bottom N bits.
|
||||
x -= m * M
|
||||
# Now a clean division by 2^N is possible.
|
||||
assert x % 2**N == 0
|
||||
return (x >> N) % M
|
||||
|
||||
def update_de(d, e, t, M, Mi):
|
||||
"""Multiply matrix t/2^N with [d, e], modulo M."""
|
||||
u, v, q, r = t
|
||||
cd, ce = u*d + v*e, q*d + r*e
|
||||
return div2n(M, Mi, cd), div2n(M, Mi, ce)
|
||||
```
|
||||
|
||||
With all of those, we can write a version of `modinv` that performs *N* divsteps at once:
|
||||
|
||||
```python3
|
||||
def modinv(M, Mi, x):
|
||||
"""Compute the modular inverse of x mod M, given Mi=1/M mod 2^N."""
|
||||
assert M & 1
|
||||
delta, f, g, d, e = 1, M, x, 0, 1
|
||||
while g != 0:
|
||||
# Compute the delta and transition matrix t for the next N divsteps (this only needs
|
||||
# (N+1)-bit signed integer arithmetic).
|
||||
delta, t = divsteps_n_matrix(delta, f % 2**N, g % 2**N)
|
||||
# Apply the transition matrix t to [f, g]:
|
||||
f, g = update_fg(f, g, t)
|
||||
# Apply the transition matrix t to [d, e]:
|
||||
d, e = update_de(d, e, t, M, Mi)
|
||||
return (d * f) % M
|
||||
```
|
||||
|
||||
This means that in practice we'll always perform a multiple of *N* divsteps. This is not a problem
|
||||
because once *g=0*, further divsteps do not affect *f*, *g*, *d*, or *e* anymore (only *δ* keeps
|
||||
increasing). For variable time code such excess iterations will be mostly optimized away in later
|
||||
sections.
|
||||
|
||||
|
||||
## 4. Avoiding modulus operations
|
||||
|
||||
So far, there are two places where we compute a remainder of big numbers modulo *M*: at the end of
|
||||
`div2n` in every `update_de`, and at the very end of `modinv` after potentially negating *d* due to the
|
||||
sign of *f*. These are relatively expensive operations when done generically.
|
||||
|
||||
To deal with the modulus operation in `div2n`, we simply stop requiring *d* and *e* to be in range
|
||||
*[0,M)* all the time. Let's start by inlining `div2n` into `update_de`, and dropping the modulus
|
||||
operation at the end:
|
||||
|
||||
```python
|
||||
def update_de(d, e, t, M, Mi):
|
||||
"""Multiply matrix t/2^N with [d, e] mod M, given Mi=1/M mod 2^N."""
|
||||
u, v, q, r = t
|
||||
cd, ce = u*d + v*e, q*d + r*e
|
||||
# Cancel out bottom N bits of cd and ce.
|
||||
md = -((Mi * cd) % 2**N)
|
||||
me = -((Mi * ce) % 2**N)
|
||||
cd += md * M
|
||||
ce += me * M
|
||||
# And cleanly divide by 2**N.
|
||||
return cd >> N, ce >> N
|
||||
```
|
||||
|
||||
Let's look at bounds on the ranges of these numbers. It can be shown that *|u|+|v|* and *|q|+|r|*
|
||||
never exceed *2<sup>N</sup>* (see paragraph 8.3 in the paper), and thus a multiplication with *t* will have
|
||||
outputs whose absolute values are at most *2<sup>N</sup>* times the maximum absolute input value. In case the
|
||||
inputs *d* and *e* are in *(-M,M)*, which is certainly true for the initial values *d=0* and *e=1* assuming
|
||||
*M > 1*, the multiplication results in numbers in range *(-2<sup>N</sup>M,2<sup>N</sup>M)*. Subtracting less than *2<sup>N</sup>*
|
||||
times *M* to cancel out *N* bits brings that up to *(-2<sup>N+1</sup>M,2<sup>N</sup>M)*, and
|
||||
dividing by *2<sup>N</sup>* at the end takes it to *(-2M,M)*. Another application of `update_de` would take that
|
||||
to *(-3M,2M)*, and so forth. This progressive expansion of the variables' ranges can be
|
||||
counteracted by incrementing *d* and *e* by *M* whenever they're negative:
|
||||
|
||||
```python
|
||||
...
|
||||
if d < 0:
|
||||
d += M
|
||||
if e < 0:
|
||||
e += M
|
||||
cd, ce = u*d + v*e, q*d + r*e
|
||||
# Cancel out bottom N bits of cd and ce.
|
||||
...
|
||||
```
|
||||
|
||||
With inputs in *(-2M,M)*, they will first be shifted into range *(-M,M)*, which means that the
|
||||
output will again be in *(-2M,M)*, and this remains the case regardless of how many `update_de`
|
||||
invocations there are. In what follows, we will try to make this more efficient.
|
||||
|
||||
Note that increasing *d* by *M* is equal to incrementing *cd* by *u M* and *ce* by *q M*. Similarly,
|
||||
increasing *e* by *M* is equal to incrementing *cd* by *v M* and *ce* by *r M*. So we could instead write:
|
||||
|
||||
```python
|
||||
...
|
||||
cd, ce = u*d + v*e, q*d + r*e
|
||||
# Perform the equivalent of incrementing d, e by M when they're negative.
|
||||
if d < 0:
|
||||
cd += u*M
|
||||
ce += q*M
|
||||
if e < 0:
|
||||
cd += v*M
|
||||
ce += r*M
|
||||
# Cancel out bottom N bits of cd and ce.
|
||||
md = -((Mi * cd) % 2**N)
|
||||
me = -((Mi * ce) % 2**N)
|
||||
cd += md * M
|
||||
ce += me * M
|
||||
...
|
||||
```
|
||||
|
||||
Now note that we have two steps of corrections to *cd* and *ce* that add multiples of *M*: this
|
||||
increment, and the decrement that cancels out bottom bits. The second one depends on the first
|
||||
one, but they can still be efficiently combined by only computing the bottom bits of *cd* and *ce*
|
||||
at first, and using that to compute the final *md*, *me* values:
|
||||
|
||||
```python
|
||||
def update_de(d, e, t, M, Mi):
|
||||
"""Multiply matrix t/2^N with [d, e], modulo M."""
|
||||
u, v, q, r = t
|
||||
md, me = 0, 0
|
||||
# Compute what multiples of M to add to cd and ce.
|
||||
if d < 0:
|
||||
md += u
|
||||
me += q
|
||||
if e < 0:
|
||||
md += v
|
||||
me += r
|
||||
# Compute bottom N bits of t*[d,e] + M*[md,me].
|
||||
cd, ce = (u*d + v*e + md*M) % 2**N, (q*d + r*e + me*M) % 2**N
|
||||
# Correct md and me such that the bottom N bits of t*[d,e] + M*[md,me] are zero.
|
||||
md -= (Mi * cd) % 2**N
|
||||
me -= (Mi * ce) % 2**N
|
||||
# Do the full computation.
|
||||
cd, ce = u*d + v*e + md*M, q*d + r*e + me*M
|
||||
# And cleanly divide by 2**N.
|
||||
return cd >> N, ce >> N
|
||||
```
|
||||
|
||||
One last optimization: we can avoid the *md M* and *me M* multiplications in the bottom bits of *cd*
|
||||
and *ce* by moving them to the *md* and *me* correction:
|
||||
|
||||
```python
|
||||
...
|
||||
# Compute bottom N bits of t*[d,e].
|
||||
cd, ce = (u*d + v*e) % 2**N, (q*d + r*e) % 2**N
|
||||
# Correct md and me such that the bottom N bits of t*[d,e]+M*[md,me] are zero.
|
||||
# Note that this is not the same as {md = (-Mi * cd) % 2**N} etc. That would also result in N
|
||||
# zero bottom bits, but isn't guaranteed to be a reduction of [0,2^N) compared to the
|
||||
# previous md and me values, and thus would violate our bounds analysis.
|
||||
md -= (Mi*cd + md) % 2**N
|
||||
me -= (Mi*ce + me) % 2**N
|
||||
...
|
||||
```
|
||||
|
||||
The resulting function takes *d* and *e* in range *(-2M,M)* as inputs, and outputs values in the same
|
||||
range. That also means that the *d* value at the end of `modinv` will be in that range, while we want
|
||||
a result in *[0,M)*. To do that, we need a normalization function. It's easy to integrate the
|
||||
conditional negation of *d* (based on the sign of *f*) into it as well:
|
||||
|
||||
```python
|
||||
def normalize(sign, v, M):
|
||||
"""Compute sign*v mod M, where v is in range (-2*M,M); output in [0,M)."""
|
||||
assert sign == 1 or sign == -1
|
||||
# v in (-2*M,M)
|
||||
if v < 0:
|
||||
v += M
|
||||
# v in (-M,M). Now multiply v with sign (which can only be 1 or -1).
|
||||
if sign == -1:
|
||||
v = -v
|
||||
# v in (-M,M)
|
||||
if v < 0:
|
||||
v += M
|
||||
# v in [0,M)
|
||||
return v
|
||||
```
|
||||
|
||||
And calling it in `modinv` is simply:
|
||||
|
||||
```python
|
||||
...
|
||||
return normalize(f, d, M)
|
||||
```
|
||||
|
||||
|
||||
## 5. Constant-time operation
|
||||
|
||||
The primary selling point of the algorithm is fast constant-time operation. What code flow still
|
||||
depends on the input data so far?
|
||||
|
||||
- the number of iterations of the while *g ≠ 0* loop in `modinv`
|
||||
- the branches inside `divsteps_n_matrix`
|
||||
- the sign checks in `update_de`
|
||||
- the sign checks in `normalize`
|
||||
|
||||
To make the while loop in `modinv` constant time it can be replaced with a constant number of
|
||||
iterations. The paper proves (Theorem 11.2) that *741* divsteps are sufficient for any *256*-bit
|
||||
inputs, and [safegcd-bounds](https://github.com/sipa/safegcd-bounds) shows that the slightly better bound *724* is
|
||||
sufficient even. Given that every loop iteration performs *N* divsteps, it will run a total of
|
||||
*⌈724/N⌉* times.
|
||||
|
||||
To deal with the branches in `divsteps_n_matrix` we will replace them with constant-time bitwise
|
||||
operations (and hope the C compiler isn't smart enough to turn them back into branches; see
|
||||
`ctime_tests.c` for automated tests that this isn't the case). To do so, observe that a
|
||||
divstep can be written instead as (compare to the inner loop of `gcd` in section 1).
|
||||
|
||||
```python
|
||||
x = -f if delta > 0 else f # set x equal to (input) -f or f
|
||||
if g & 1:
|
||||
g += x # set g to (input) g-f or g+f
|
||||
if delta > 0:
|
||||
delta = -delta
|
||||
f += g # set f to (input) g (note that g was set to g-f before)
|
||||
delta += 1
|
||||
g >>= 1
|
||||
```
|
||||
|
||||
To convert the above to bitwise operations, we rely on a trick to negate conditionally: per the
|
||||
definition of negative numbers in two's complement, (*-v == ~v + 1*) holds for every number *v*. As
|
||||
*-1* in two's complement is all *1* bits, bitflipping can be expressed as xor with *-1*. It follows
|
||||
that *-v == (v ^ -1) - (-1)*. Thus, if we have a variable *c* that takes on values *0* or *-1*, then
|
||||
*(v ^ c) - c* is *v* if *c=0* and *-v* if *c=-1*.
|
||||
|
||||
Using this we can write:
|
||||
|
||||
```python
|
||||
x = -f if delta > 0 else f
|
||||
```
|
||||
|
||||
in constant-time form as:
|
||||
|
||||
```python
|
||||
c1 = (-delta) >> 63
|
||||
# Conditionally negate f based on c1:
|
||||
x = (f ^ c1) - c1
|
||||
```
|
||||
|
||||
To use that trick, we need a helper mask variable *c1* that resolves the condition *δ>0* to *-1*
|
||||
(if true) or *0* (if false). We compute *c1* using right shifting, which is equivalent to dividing by
|
||||
the specified power of *2* and rounding down (in Python, and also in C under the assumption of a typical two's complement system; see
|
||||
`assumptions.h` for tests that this is the case). Right shifting by *63* thus maps all
|
||||
numbers in range *[-2<sup>63</sup>,0)* to *-1*, and numbers in range *[0,2<sup>63</sup>)* to *0*.
|
||||
|
||||
Using the facts that *x&0=0* and *x&(-1)=x* (on two's complement systems again), we can write:
|
||||
|
||||
```python
|
||||
if g & 1:
|
||||
g += x
|
||||
```
|
||||
|
||||
as:
|
||||
|
||||
```python
|
||||
# Compute c2=0 if g is even and c2=-1 if g is odd.
|
||||
c2 = -(g & 1)
|
||||
# This masks out x if g is even, and leaves x be if g is odd.
|
||||
g += x & c2
|
||||
```
|
||||
|
||||
Using the conditional negation trick again we can write:
|
||||
|
||||
```python
|
||||
if g & 1:
|
||||
if delta > 0:
|
||||
delta = -delta
|
||||
```
|
||||
|
||||
as:
|
||||
|
||||
```python
|
||||
# Compute c3=-1 if g is odd and delta>0, and 0 otherwise.
|
||||
c3 = c1 & c2
|
||||
# Conditionally negate delta based on c3:
|
||||
delta = (delta ^ c3) - c3
|
||||
```
|
||||
|
||||
Finally:
|
||||
|
||||
```python
|
||||
if g & 1:
|
||||
if delta > 0:
|
||||
f += g
|
||||
```
|
||||
|
||||
becomes:
|
||||
|
||||
```python
|
||||
f += g & c3
|
||||
```
|
||||
|
||||
It turns out that this can be implemented more efficiently by applying the substitution
|
||||
*η=-δ*. In this representation, negating *δ* corresponds to negating *η*, and incrementing
|
||||
*δ* corresponds to decrementing *η*. This allows us to remove the negation in the *c1*
|
||||
computation:
|
||||
|
||||
```python
|
||||
# Compute a mask c1 for eta < 0, and compute the conditional negation x of f:
|
||||
c1 = eta >> 63
|
||||
x = (f ^ c1) - c1
|
||||
# Compute a mask c2 for odd g, and conditionally add x to g:
|
||||
c2 = -(g & 1)
|
||||
g += x & c2
|
||||
# Compute a mask c for (eta < 0) and odd (input) g, and use it to conditionally negate eta,
|
||||
# and add g to f:
|
||||
c3 = c1 & c2
|
||||
eta = (eta ^ c3) - c3
|
||||
f += g & c3
|
||||
# Incrementing delta corresponds to decrementing eta.
|
||||
eta -= 1
|
||||
g >>= 1
|
||||
```
|
||||
|
||||
A variant of divsteps with better worst-case performance can be used instead: starting *δ* at
|
||||
*1/2* instead of *1*. This reduces the worst case number of iterations to *590* for *256*-bit inputs
|
||||
(which can be shown using convex hull analysis). In this case, the substitution *ζ=-(δ+1/2)*
|
||||
is used instead to keep the variable integral. Incrementing *δ* by *1* still translates to
|
||||
decrementing *ζ* by *1*, but negating *δ* now corresponds to going from *ζ* to *-(ζ+1)*, or
|
||||
*~ζ*. Doing that conditionally based on *c3* is simply:
|
||||
|
||||
```python
|
||||
...
|
||||
c3 = c1 & c2
|
||||
zeta ^= c3
|
||||
...
|
||||
```
|
||||
|
||||
By replacing the loop in `divsteps_n_matrix` with a variant of the divstep code above (extended to
|
||||
also apply all *f* operations to *u*, *v* and all *g* operations to *q*, *r*), a constant-time version of
|
||||
`divsteps_n_matrix` is obtained. The full code will be in section 7.
|
||||
|
||||
These bit fiddling tricks can also be used to make the conditional negations and additions in
|
||||
`update_de` and `normalize` constant-time.
|
||||
|
||||
|
||||
## 6. Variable-time optimizations
|
||||
|
||||
In section 5, we modified the `divsteps_n_matrix` function (and a few others) to be constant time.
|
||||
Constant time operations are only necessary when computing modular inverses of secret data. In
|
||||
other cases, it slows down calculations unnecessarily. In this section, we will construct a
|
||||
faster non-constant time `divsteps_n_matrix` function.
|
||||
|
||||
To do so, first consider yet another way of writing the inner loop of divstep operations in
|
||||
`gcd` from section 1. This decomposition is also explained in the paper in section 8.2. We use
|
||||
the original version with initial *δ=1* and *η=-δ* here.
|
||||
|
||||
```python
|
||||
for _ in range(N):
|
||||
if g & 1 and eta < 0:
|
||||
eta, f, g = -eta, g, -f
|
||||
if g & 1:
|
||||
g += f
|
||||
eta -= 1
|
||||
g >>= 1
|
||||
```
|
||||
|
||||
Whenever *g* is even, the loop only shifts *g* down and decreases *η*. When *g* ends in multiple zero
|
||||
bits, these iterations can be consolidated into one step. This requires counting the bottom zero
|
||||
bits efficiently, which is possible on most platforms; it is abstracted here as the function
|
||||
`count_trailing_zeros`.
|
||||
|
||||
```python
|
||||
def count_trailing_zeros(v):
|
||||
"""
|
||||
When v is zero, consider all N zero bits as "trailing".
|
||||
For a non-zero value v, find z such that v=(d<<z) for some odd d.
|
||||
"""
|
||||
if v == 0:
|
||||
return N
|
||||
else:
|
||||
return (v & -v).bit_length() - 1
|
||||
|
||||
i = N # divsteps left to do
|
||||
while True:
|
||||
# Get rid of all bottom zeros at once. In the first iteration, g may be odd and the following
|
||||
# lines have no effect (until "if eta < 0").
|
||||
zeros = min(i, count_trailing_zeros(g))
|
||||
eta -= zeros
|
||||
g >>= zeros
|
||||
i -= zeros
|
||||
if i == 0:
|
||||
break
|
||||
# We know g is odd now
|
||||
if eta < 0:
|
||||
eta, f, g = -eta, g, -f
|
||||
g += f
|
||||
# g is even now, and the eta decrement and g shift will happen in the next loop.
|
||||
```
|
||||
|
||||
We can now remove multiple bottom *0* bits from *g* at once, but still need a full iteration whenever
|
||||
there is a bottom *1* bit. In what follows, we will get rid of multiple *1* bits simultaneously as
|
||||
well.
|
||||
|
||||
Observe that as long as *η ≥ 0*, the loop does not modify *f*. Instead, it cancels out bottom
|
||||
bits of *g* and shifts them out, and decreases *η* and *i* accordingly - interrupting only when *η*
|
||||
becomes negative, or when *i* reaches *0*. Combined, this is equivalent to adding a multiple of *f* to
|
||||
*g* to cancel out multiple bottom bits, and then shifting them out.
|
||||
|
||||
It is easy to find what that multiple is: we want a number *w* such that *g+w f* has a few bottom
|
||||
zero bits. If that number of bits is *L*, we want *g+w f mod 2<sup>L</sup> = 0*, or *w = -g/f mod 2<sup>L</sup>*. Since *f*
|
||||
is odd, such a *w* exists for any *L*. *L* cannot be more than *i* steps (as we'd finish the loop before
|
||||
doing more) or more than *η+1* steps (as we'd run `eta, f, g = -eta, g, -f` at that point), but
|
||||
apart from that, we're only limited by the complexity of computing *w*.
|
||||
|
||||
This code demonstrates how to cancel up to 4 bits per step:
|
||||
|
||||
```python
|
||||
NEGINV16 = [15, 5, 3, 9, 7, 13, 11, 1] # NEGINV16[n//2] = (-n)^-1 mod 16, for odd n
|
||||
i = N
|
||||
while True:
|
||||
zeros = min(i, count_trailing_zeros(g))
|
||||
eta -= zeros
|
||||
g >>= zeros
|
||||
i -= zeros
|
||||
if i == 0:
|
||||
break
|
||||
# We know g is odd now
|
||||
if eta < 0:
|
||||
eta, f, g = -eta, g, -f
|
||||
# Compute limit on number of bits to cancel
|
||||
limit = min(min(eta + 1, i), 4)
|
||||
# Compute w = -g/f mod 2**limit, using the table value for -1/f mod 2**4. Note that f is
|
||||
# always odd, so its inverse modulo a power of two always exists.
|
||||
w = (g * NEGINV16[(f & 15) // 2]) % (2**limit)
|
||||
# As w = -g/f mod (2**limit), g+w*f mod 2**limit = 0 mod 2**limit.
|
||||
g += w * f
|
||||
assert g % (2**limit) == 0
|
||||
# The next iteration will now shift out at least limit bottom zero bits from g.
|
||||
```
|
||||
|
||||
By using a bigger table more bits can be cancelled at once. The table can also be implemented
|
||||
as a formula. Several formulas are known for computing modular inverses modulo powers of two;
|
||||
some can be found in Hacker's Delight second edition by Henry S. Warren, Jr. pages 245-247.
|
||||
Here we need the negated modular inverse, which is a simple transformation of those:
|
||||
|
||||
- Instead of a 3-bit table:
|
||||
- *-f* or *f ^ 6*
|
||||
- Instead of a 4-bit table:
|
||||
- *1 - f(f + 1)*
|
||||
- *-(f + (((f + 1) & 4) << 1))*
|
||||
- For larger tables the following technique can be used: if *w=-1/f mod 2<sup>L</sup>*, then *w(w f+2)* is
|
||||
*-1/f mod 2<sup>2L</sup>*. This allows extending the previous formulas (or tables). In particular we
|
||||
have this 6-bit function (based on the 3-bit function above):
|
||||
- *f(f<sup>2</sup> - 2)*
|
||||
|
||||
This loop, again extended to also handle *u*, *v*, *q*, and *r* alongside *f* and *g*, placed in
|
||||
`divsteps_n_matrix`, gives a significantly faster, but non-constant time version.
|
||||
|
||||
|
||||
## 7. Final Python version
|
||||
|
||||
All together we need the following functions:
|
||||
|
||||
- A way to compute the transition matrix in constant time, using the `divsteps_n_matrix` function
|
||||
from section 2, but with its loop replaced by a variant of the constant-time divstep from
|
||||
section 5, extended to handle *u*, *v*, *q*, *r*:
|
||||
|
||||
```python
|
||||
def divsteps_n_matrix(zeta, f, g):
|
||||
"""Compute zeta and transition matrix t after N divsteps (multiplied by 2^N)."""
|
||||
u, v, q, r = 1, 0, 0, 1 # start with identity matrix
|
||||
for _ in range(N):
|
||||
c1 = zeta >> 63
|
||||
# Compute x, y, z as conditionally-negated versions of f, u, v.
|
||||
x, y, z = (f ^ c1) - c1, (u ^ c1) - c1, (v ^ c1) - c1
|
||||
c2 = -(g & 1)
|
||||
# Conditionally add x, y, z to g, q, r.
|
||||
g, q, r = g + (x & c2), q + (y & c2), r + (z & c2)
|
||||
c1 &= c2 # reusing c1 here for the earlier c3 variable
|
||||
zeta = (zeta ^ c1) - 1 # inlining the unconditional zeta decrement here
|
||||
# Conditionally add g, q, r to f, u, v.
|
||||
f, u, v = f + (g & c1), u + (q & c1), v + (r & c1)
|
||||
# When shifting g down, don't shift q, r, as we construct a transition matrix multiplied
|
||||
# by 2^N. Instead, shift f's coefficients u and v up.
|
||||
g, u, v = g >> 1, u << 1, v << 1
|
||||
return zeta, (u, v, q, r)
|
||||
```
|
||||
|
||||
- The functions to update *f* and *g*, and *d* and *e*, from section 2 and section 4, with the constant-time
|
||||
changes to `update_de` from section 5:
|
||||
|
||||
```python
|
||||
def update_fg(f, g, t):
|
||||
"""Multiply matrix t/2^N with [f, g]."""
|
||||
u, v, q, r = t
|
||||
cf, cg = u*f + v*g, q*f + r*g
|
||||
return cf >> N, cg >> N
|
||||
|
||||
def update_de(d, e, t, M, Mi):
|
||||
"""Multiply matrix t/2^N with [d, e], modulo M."""
|
||||
u, v, q, r = t
|
||||
d_sign, e_sign = d >> 257, e >> 257
|
||||
md, me = (u & d_sign) + (v & e_sign), (q & d_sign) + (r & e_sign)
|
||||
cd, ce = (u*d + v*e) % 2**N, (q*d + r*e) % 2**N
|
||||
md -= (Mi*cd + md) % 2**N
|
||||
me -= (Mi*ce + me) % 2**N
|
||||
cd, ce = u*d + v*e + M*md, q*d + r*e + M*me
|
||||
return cd >> N, ce >> N
|
||||
```
|
||||
|
||||
- The `normalize` function from section 4, made constant time as well:
|
||||
|
||||
```python
|
||||
def normalize(sign, v, M):
|
||||
"""Compute sign*v mod M, where v in (-2*M,M); output in [0,M)."""
|
||||
v_sign = v >> 257
|
||||
# Conditionally add M to v.
|
||||
v += M & v_sign
|
||||
c = (sign - 1) >> 1
|
||||
# Conditionally negate v.
|
||||
v = (v ^ c) - c
|
||||
v_sign = v >> 257
|
||||
# Conditionally add M to v again.
|
||||
v += M & v_sign
|
||||
return v
|
||||
```
|
||||
|
||||
- And finally the `modinv` function too, adapted to use *ζ* instead of *δ*, and using the fixed
|
||||
iteration count from section 5:
|
||||
|
||||
```python
|
||||
def modinv(M, Mi, x):
|
||||
"""Compute the modular inverse of x mod M, given Mi=1/M mod 2^N."""
|
||||
zeta, f, g, d, e = -1, M, x, 0, 1
|
||||
for _ in range((590 + N - 1) // N):
|
||||
zeta, t = divsteps_n_matrix(zeta, f % 2**N, g % 2**N)
|
||||
f, g = update_fg(f, g, t)
|
||||
d, e = update_de(d, e, t, M, Mi)
|
||||
return normalize(f, d, M)
|
||||
```
|
||||
|
||||
- To get a variable time version, replace the `divsteps_n_matrix` function with one that uses the
|
||||
divsteps loop from section 5, and a `modinv` version that calls it without the fixed iteration
|
||||
count:
|
||||
|
||||
```python
|
||||
NEGINV16 = [15, 5, 3, 9, 7, 13, 11, 1] # NEGINV16[n//2] = (-n)^-1 mod 16, for odd n
|
||||
def divsteps_n_matrix_var(eta, f, g):
|
||||
"""Compute eta and transition matrix t after N divsteps (multiplied by 2^N)."""
|
||||
u, v, q, r = 1, 0, 0, 1
|
||||
i = N
|
||||
while True:
|
||||
zeros = min(i, count_trailing_zeros(g))
|
||||
eta, i = eta - zeros, i - zeros
|
||||
g, u, v = g >> zeros, u << zeros, v << zeros
|
||||
if i == 0:
|
||||
break
|
||||
if eta < 0:
|
||||
eta, f, u, v, g, q, r = -eta, g, q, r, -f, -u, -v
|
||||
limit = min(min(eta + 1, i), 4)
|
||||
w = (g * NEGINV16[(f & 15) // 2]) % (2**limit)
|
||||
g, q, r = g + w*f, q + w*u, r + w*v
|
||||
return eta, (u, v, q, r)
|
||||
|
||||
def modinv_var(M, Mi, x):
|
||||
"""Compute the modular inverse of x mod M, given Mi = 1/M mod 2^N."""
|
||||
eta, f, g, d, e = -1, M, x, 0, 1
|
||||
while g != 0:
|
||||
eta, t = divsteps_n_matrix_var(eta, f % 2**N, g % 2**N)
|
||||
f, g = update_fg(f, g, t)
|
||||
d, e = update_de(d, e, t, M, Mi)
|
||||
return normalize(f, d, Mi)
|
||||
```
|
||||
|
||||
## 8. From GCDs to Jacobi symbol
|
||||
|
||||
We can also use a similar approach to calculate Jacobi symbol *(x | M)* by keeping track of an
|
||||
extra variable *j*, for which at every step *(x | M) = j (g | f)*. As we update *f* and *g*, we
|
||||
make corresponding updates to *j* using
|
||||
[properties of the Jacobi symbol](https://en.wikipedia.org/wiki/Jacobi_symbol#Properties):
|
||||
* *((g/2) | f)* is either *(g | f)* or *-(g | f)*, depending on the value of *f mod 8* (negating if it's *3* or *5*).
|
||||
* *(f | g)* is either *(g | f)* or *-(g | f)*, depending on *f mod 4* and *g mod 4* (negating if both are *3*).
|
||||
|
||||
These updates depend only on the values of *f* and *g* modulo *4* or *8*, and can thus be applied
|
||||
very quickly, as long as we keep track of a few additional bits of *f* and *g*. Overall, this
|
||||
calculation is slightly simpler than the one for the modular inverse because we no longer need to
|
||||
keep track of *d* and *e*.
|
||||
|
||||
However, one difficulty of this approach is that the Jacobi symbol *(a | n)* is only defined for
|
||||
positive odd integers *n*, whereas in the original safegcd algorithm, *f, g* can take negative
|
||||
values. We resolve this by using the following modified steps:
|
||||
|
||||
```python
|
||||
# Before
|
||||
if delta > 0 and g & 1:
|
||||
delta, f, g = 1 - delta, g, (g - f) // 2
|
||||
|
||||
# After
|
||||
if delta > 0 and g & 1:
|
||||
delta, f, g = 1 - delta, g, (g + f) // 2
|
||||
```
|
||||
|
||||
The algorithm is still correct, since the changed divstep, called a "posdivstep" (see section 8.4
|
||||
and E.5 in the paper) preserves *gcd(f, g)*. However, there's no proof that the modified algorithm
|
||||
will converge. The justification for posdivsteps is completely empirical: in practice, it appears
|
||||
that the vast majority of nonzero inputs converge to *f=g=gcd(f<sub>0</sub>, g<sub>0</sub>)* in a
|
||||
number of steps proportional to their logarithm.
|
||||
|
||||
Note that:
|
||||
- We require inputs to satisfy *gcd(x, M) = 1*, as otherwise *f=1* is not reached.
|
||||
- We require inputs *x &neq; 0*, because applying posdivstep with *g=0* has no effect.
|
||||
- We need to update the termination condition from *g=0* to *f=1*.
|
||||
|
||||
We account for the possibility of nonconvergence by only performing a bounded number of
|
||||
posdivsteps, and then falling back to square-root based Jacobi calculation if a solution has not
|
||||
yet been found.
|
||||
|
||||
The optimizations in sections 3-7 above are described in the context of the original divsteps, but
|
||||
in the C implementation we also adapt most of them (not including "avoiding modulus operations",
|
||||
since it's not necessary to track *d, e*, and "constant-time operation", since we never calculate
|
||||
Jacobi symbols for secret data) to the posdivsteps version.
|
||||
34
vendor/secp256k1/repo/examples/CMakeLists.txt
vendored
Normal file
34
vendor/secp256k1/repo/examples/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
add_library(example INTERFACE)
|
||||
target_include_directories(example INTERFACE
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
)
|
||||
target_compile_options(example INTERFACE
|
||||
$<$<C_COMPILER_ID:MSVC>:/wd4005>
|
||||
)
|
||||
target_link_libraries(example INTERFACE
|
||||
$<$<PLATFORM_ID:Windows>:bcrypt>
|
||||
)
|
||||
if(SECP256K1_BUILD_SHARED)
|
||||
target_link_libraries(example INTERFACE secp256k1)
|
||||
elseif(SECP256K1_BUILD_STATIC)
|
||||
target_link_libraries(example INTERFACE secp256k1_static)
|
||||
if(MSVC)
|
||||
target_link_options(example INTERFACE /IGNORE:4217)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_executable(ecdsa_example ecdsa.c)
|
||||
target_link_libraries(ecdsa_example example)
|
||||
add_test(ecdsa_example ecdsa_example)
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_ECDH)
|
||||
add_executable(ecdh_example ecdh.c)
|
||||
target_link_libraries(ecdh_example example)
|
||||
add_test(ecdh_example ecdh_example)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
add_executable(schnorr_example schnorr.c)
|
||||
target_link_libraries(schnorr_example example)
|
||||
add_test(schnorr_example schnorr_example)
|
||||
endif()
|
||||
121
vendor/secp256k1/repo/examples/EXAMPLES_COPYING
vendored
Normal file
121
vendor/secp256k1/repo/examples/EXAMPLES_COPYING
vendored
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
Creative Commons Legal Code
|
||||
|
||||
CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
||||
122
vendor/secp256k1/repo/examples/ecdh.c
vendored
Normal file
122
vendor/secp256k1/repo/examples/ecdh.c
vendored
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*************************************************************************
|
||||
* Written in 2020-2022 by Elichai Turkel *
|
||||
* To the extent possible under law, the author(s) have dedicated all *
|
||||
* copyright and related and neighboring rights to the software in this *
|
||||
* file to the public domain worldwide. This software is distributed *
|
||||
* without any warranty. For the CC0 Public Domain Dedication, see *
|
||||
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
|
||||
*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_ecdh.h>
|
||||
|
||||
#include "examples_util.h"
|
||||
|
||||
int main(void) {
|
||||
unsigned char seckey1[32];
|
||||
unsigned char seckey2[32];
|
||||
unsigned char compressed_pubkey1[33];
|
||||
unsigned char compressed_pubkey2[33];
|
||||
unsigned char shared_secret1[32];
|
||||
unsigned char shared_secret2[32];
|
||||
unsigned char randomize[32];
|
||||
int return_val;
|
||||
size_t len;
|
||||
secp256k1_pubkey pubkey1;
|
||||
secp256k1_pubkey pubkey2;
|
||||
|
||||
/* Before we can call actual API functions, we need to create a "context". */
|
||||
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
if (!fill_random(randomize, sizeof(randomize))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* Randomizing the context is recommended to protect against side-channel
|
||||
* leakage See `secp256k1_context_randomize` in secp256k1.h for more
|
||||
* information about it. This should never fail. */
|
||||
return_val = secp256k1_context_randomize(ctx, randomize);
|
||||
assert(return_val);
|
||||
|
||||
/*** Key Generation ***/
|
||||
|
||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
||||
* order), we try to sample a new key. Note that the probability of this
|
||||
* happening is negligible. */
|
||||
while (1) {
|
||||
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Public key creation using a valid context with a verified secret key should never fail */
|
||||
return_val = secp256k1_ec_pubkey_create(ctx, &pubkey1, seckey1);
|
||||
assert(return_val);
|
||||
return_val = secp256k1_ec_pubkey_create(ctx, &pubkey2, seckey2);
|
||||
assert(return_val);
|
||||
|
||||
/* Serialize pubkey1 in a compressed form (33 bytes), should always return 1 */
|
||||
len = sizeof(compressed_pubkey1);
|
||||
return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey1, &len, &pubkey1, SECP256K1_EC_COMPRESSED);
|
||||
assert(return_val);
|
||||
/* Should be the same size as the size of the output, because we passed a 33 byte array. */
|
||||
assert(len == sizeof(compressed_pubkey1));
|
||||
|
||||
/* Serialize pubkey2 in a compressed form (33 bytes) */
|
||||
len = sizeof(compressed_pubkey2);
|
||||
return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey2, &len, &pubkey2, SECP256K1_EC_COMPRESSED);
|
||||
assert(return_val);
|
||||
/* Should be the same size as the size of the output, because we passed a 33 byte array. */
|
||||
assert(len == sizeof(compressed_pubkey2));
|
||||
|
||||
/*** Creating the shared secret ***/
|
||||
|
||||
/* Perform ECDH with seckey1 and pubkey2. Should never fail with a verified
|
||||
* seckey and valid pubkey */
|
||||
return_val = secp256k1_ecdh(ctx, shared_secret1, &pubkey2, seckey1, NULL, NULL);
|
||||
assert(return_val);
|
||||
|
||||
/* Perform ECDH with seckey2 and pubkey1. Should never fail with a verified
|
||||
* seckey and valid pubkey */
|
||||
return_val = secp256k1_ecdh(ctx, shared_secret2, &pubkey1, seckey2, NULL, NULL);
|
||||
assert(return_val);
|
||||
|
||||
/* Both parties should end up with the same shared secret */
|
||||
return_val = memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1));
|
||||
assert(return_val == 0);
|
||||
|
||||
printf("Secret Key1: ");
|
||||
print_hex(seckey1, sizeof(seckey1));
|
||||
printf("Compressed Pubkey1: ");
|
||||
print_hex(compressed_pubkey1, sizeof(compressed_pubkey1));
|
||||
printf("\nSecret Key2: ");
|
||||
print_hex(seckey2, sizeof(seckey2));
|
||||
printf("Compressed Pubkey2: ");
|
||||
print_hex(compressed_pubkey2, sizeof(compressed_pubkey2));
|
||||
printf("\nShared Secret: ");
|
||||
print_hex(shared_secret1, sizeof(shared_secret1));
|
||||
|
||||
/* This will clear everything from the context and free the memory */
|
||||
secp256k1_context_destroy(ctx);
|
||||
|
||||
/* It's best practice to try to clear secrets from memory after using them.
|
||||
* This is done because some bugs can allow an attacker to leak memory, for
|
||||
* example through "out of bounds" array access (see Heartbleed), Or the OS
|
||||
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
|
||||
*
|
||||
* Here we are preventing these writes from being optimized out, as any good compiler
|
||||
* will remove any writes that aren't used. */
|
||||
secure_erase(seckey1, sizeof(seckey1));
|
||||
secure_erase(seckey2, sizeof(seckey2));
|
||||
secure_erase(shared_secret1, sizeof(shared_secret1));
|
||||
secure_erase(shared_secret2, sizeof(shared_secret2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
139
vendor/secp256k1/repo/examples/ecdsa.c
vendored
Normal file
139
vendor/secp256k1/repo/examples/ecdsa.c
vendored
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*************************************************************************
|
||||
* Written in 2020-2022 by Elichai Turkel *
|
||||
* To the extent possible under law, the author(s) have dedicated all *
|
||||
* copyright and related and neighboring rights to the software in this *
|
||||
* file to the public domain worldwide. This software is distributed *
|
||||
* without any warranty. For the CC0 Public Domain Dedication, see *
|
||||
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
|
||||
*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <secp256k1.h>
|
||||
|
||||
#include "examples_util.h"
|
||||
|
||||
int main(void) {
|
||||
/* Instead of signing the message directly, we must sign a 32-byte hash.
|
||||
* Here the message is "Hello, world!" and the hash function was SHA-256.
|
||||
* An actual implementation should just call SHA-256, but this example
|
||||
* hardcodes the output to avoid depending on an additional library.
|
||||
* See https://bitcoin.stackexchange.com/questions/81115/if-someone-wanted-to-pretend-to-be-satoshi-by-posting-a-fake-signature-to-defrau/81116#81116 */
|
||||
unsigned char msg_hash[32] = {
|
||||
0x31, 0x5F, 0x5B, 0xDB, 0x76, 0xD0, 0x78, 0xC4,
|
||||
0x3B, 0x8A, 0xC0, 0x06, 0x4E, 0x4A, 0x01, 0x64,
|
||||
0x61, 0x2B, 0x1F, 0xCE, 0x77, 0xC8, 0x69, 0x34,
|
||||
0x5B, 0xFC, 0x94, 0xC7, 0x58, 0x94, 0xED, 0xD3,
|
||||
};
|
||||
unsigned char seckey[32];
|
||||
unsigned char randomize[32];
|
||||
unsigned char compressed_pubkey[33];
|
||||
unsigned char serialized_signature[64];
|
||||
size_t len;
|
||||
int is_signature_valid, is_signature_valid2;
|
||||
int return_val;
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
/* Before we can call actual API functions, we need to create a "context". */
|
||||
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
if (!fill_random(randomize, sizeof(randomize))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* Randomizing the context is recommended to protect against side-channel
|
||||
* leakage See `secp256k1_context_randomize` in secp256k1.h for more
|
||||
* information about it. This should never fail. */
|
||||
return_val = secp256k1_context_randomize(ctx, randomize);
|
||||
assert(return_val);
|
||||
|
||||
/*** Key Generation ***/
|
||||
|
||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
||||
* order), we try to sample a new key. Note that the probability of this
|
||||
* happening is negligible. */
|
||||
while (1) {
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
if (secp256k1_ec_seckey_verify(ctx, seckey)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Public key creation using a valid context with a verified secret key should never fail */
|
||||
return_val = secp256k1_ec_pubkey_create(ctx, &pubkey, seckey);
|
||||
assert(return_val);
|
||||
|
||||
/* Serialize the pubkey in a compressed form(33 bytes). Should always return 1. */
|
||||
len = sizeof(compressed_pubkey);
|
||||
return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey, &len, &pubkey, SECP256K1_EC_COMPRESSED);
|
||||
assert(return_val);
|
||||
/* Should be the same size as the size of the output, because we passed a 33 byte array. */
|
||||
assert(len == sizeof(compressed_pubkey));
|
||||
|
||||
/*** Signing ***/
|
||||
|
||||
/* Generate an ECDSA signature `noncefp` and `ndata` allows you to pass a
|
||||
* custom nonce function, passing `NULL` will use the RFC-6979 safe default.
|
||||
* Signing with a valid context, verified secret key
|
||||
* and the default nonce function should never fail. */
|
||||
return_val = secp256k1_ecdsa_sign(ctx, &sig, msg_hash, seckey, NULL, NULL);
|
||||
assert(return_val);
|
||||
|
||||
/* Serialize the signature in a compact form. Should always return 1
|
||||
* according to the documentation in secp256k1.h. */
|
||||
return_val = secp256k1_ecdsa_signature_serialize_compact(ctx, serialized_signature, &sig);
|
||||
assert(return_val);
|
||||
|
||||
|
||||
/*** Verification ***/
|
||||
|
||||
/* Deserialize the signature. This will return 0 if the signature can't be parsed correctly. */
|
||||
if (!secp256k1_ecdsa_signature_parse_compact(ctx, &sig, serialized_signature)) {
|
||||
printf("Failed parsing the signature\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */
|
||||
if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))) {
|
||||
printf("Failed parsing the public key\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Verify a signature. This will return 1 if it's valid and 0 if it's not. */
|
||||
is_signature_valid = secp256k1_ecdsa_verify(ctx, &sig, msg_hash, &pubkey);
|
||||
|
||||
printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false");
|
||||
printf("Secret Key: ");
|
||||
print_hex(seckey, sizeof(seckey));
|
||||
printf("Public Key: ");
|
||||
print_hex(compressed_pubkey, sizeof(compressed_pubkey));
|
||||
printf("Signature: ");
|
||||
print_hex(serialized_signature, sizeof(serialized_signature));
|
||||
|
||||
/* This will clear everything from the context and free the memory */
|
||||
secp256k1_context_destroy(ctx);
|
||||
|
||||
/* Bonus example: if all we need is signature verification (and no key
|
||||
generation or signing), we don't need to use a context created via
|
||||
secp256k1_context_create(). We can simply use the static (i.e., global)
|
||||
context secp256k1_context_static. See its description in
|
||||
include/secp256k1.h for details. */
|
||||
is_signature_valid2 = secp256k1_ecdsa_verify(secp256k1_context_static,
|
||||
&sig, msg_hash, &pubkey);
|
||||
assert(is_signature_valid2 == is_signature_valid);
|
||||
|
||||
/* It's best practice to try to clear secrets from memory after using them.
|
||||
* This is done because some bugs can allow an attacker to leak memory, for
|
||||
* example through "out of bounds" array access (see Heartbleed), Or the OS
|
||||
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
|
||||
*
|
||||
* Here we are preventing these writes from being optimized out, as any good compiler
|
||||
* will remove any writes that aren't used. */
|
||||
secure_erase(seckey, sizeof(seckey));
|
||||
|
||||
return 0;
|
||||
}
|
||||
102
vendor/secp256k1/repo/examples/examples_util.h
vendored
Normal file
102
vendor/secp256k1/repo/examples/examples_util.h
vendored
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*************************************************************************
|
||||
* Copyright (c) 2020-2021 Elichai Turkel *
|
||||
* Distributed under the CC0 software license, see the accompanying file *
|
||||
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
|
||||
*************************************************************************/
|
||||
|
||||
/*
|
||||
* This file is an attempt at collecting best practice methods for obtaining randomness with different operating systems.
|
||||
* It may be out-of-date. Consult the documentation of the operating system before considering to use the methods below.
|
||||
*
|
||||
* Platform randomness sources:
|
||||
* Linux -> `getrandom(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. http://man7.org/linux/man-pages/man2/getrandom.2.html, https://linux.die.net/man/4/urandom
|
||||
* macOS -> `getentropy(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. https://www.unix.com/man-page/mojave/2/getentropy, https://opensource.apple.com/source/xnu/xnu-517.12.7/bsd/man/man4/random.4.auto.html
|
||||
* FreeBSD -> `getrandom(2)`(`sys/random.h`), if not available `kern.arandom` should be used. https://www.freebsd.org/cgi/man.cgi?query=getrandom, https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
|
||||
* OpenBSD -> `getentropy(2)`(`unistd.h`), if not available `/dev/urandom` should be used. https://man.openbsd.org/getentropy, https://man.openbsd.org/urandom
|
||||
* Windows -> `BCryptGenRandom`(`bcrypt.h`). https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
|
||||
*/
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <ntstatus.h>
|
||||
#include <bcrypt.h>
|
||||
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <sys/random.h>
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#error "Couldn't identify the OS"
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
/* Returns 1 on success, and 0 on failure. */
|
||||
static int fill_random(unsigned char* data, size_t size) {
|
||||
#if defined(_WIN32)
|
||||
NTSTATUS res = BCryptGenRandom(NULL, data, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||
if (res != STATUS_SUCCESS || size > ULONG_MAX) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
#elif defined(__linux__) || defined(__FreeBSD__)
|
||||
/* If `getrandom(2)` is not available you should fallback to /dev/urandom */
|
||||
ssize_t res = getrandom(data, size, 0);
|
||||
if (res < 0 || (size_t)res != size ) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
#elif defined(__APPLE__) || defined(__OpenBSD__)
|
||||
/* If `getentropy(2)` is not available you should fallback to either
|
||||
* `SecRandomCopyBytes` or /dev/urandom */
|
||||
int res = getentropy(data, size);
|
||||
if (res == 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_hex(unsigned char* data, size_t size) {
|
||||
size_t i;
|
||||
printf("0x");
|
||||
for (i = 0; i < size; i++) {
|
||||
printf("%02x", data[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// For SecureZeroMemory
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */
|
||||
static SECP256K1_INLINE void secure_erase(void *ptr, size_t len) {
|
||||
#if defined(_MSC_VER)
|
||||
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
|
||||
SecureZeroMemory(ptr, len);
|
||||
#elif defined(__GNUC__)
|
||||
/* We use a memory barrier that scares the compiler away from optimizing out the memset.
|
||||
*
|
||||
* Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f
|
||||
* in BoringSSL (ISC License):
|
||||
* As best as we can tell, this is sufficient to break any optimisations that
|
||||
* might try to eliminate "superfluous" memsets.
|
||||
* This method used in memzero_explicit() the Linux kernel, too. Its advantage is that it is
|
||||
* pretty efficient, because the compiler can still implement the memset() efficently,
|
||||
* just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
|
||||
* Yang et al. (USENIX Security 2017) for more background.
|
||||
*/
|
||||
memset(ptr, 0, len);
|
||||
__asm__ __volatile__("" : : "r"(ptr) : "memory");
|
||||
#else
|
||||
void *(*volatile const volatile_memset)(void *, int, size_t) = memset;
|
||||
volatile_memset(ptr, 0, len);
|
||||
#endif
|
||||
}
|
||||
156
vendor/secp256k1/repo/examples/schnorr.c
vendored
Normal file
156
vendor/secp256k1/repo/examples/schnorr.c
vendored
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/*************************************************************************
|
||||
* Written in 2020-2022 by Elichai Turkel *
|
||||
* To the extent possible under law, the author(s) have dedicated all *
|
||||
* copyright and related and neighboring rights to the software in this *
|
||||
* file to the public domain worldwide. This software is distributed *
|
||||
* without any warranty. For the CC0 Public Domain Dedication, see *
|
||||
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
|
||||
*************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_extrakeys.h>
|
||||
#include <secp256k1_schnorrsig.h>
|
||||
|
||||
#include "examples_util.h"
|
||||
|
||||
int main(void) {
|
||||
unsigned char msg[12] = "Hello World!";
|
||||
unsigned char msg_hash[32];
|
||||
unsigned char tag[17] = "my_fancy_protocol";
|
||||
unsigned char seckey[32];
|
||||
unsigned char randomize[32];
|
||||
unsigned char auxiliary_rand[32];
|
||||
unsigned char serialized_pubkey[32];
|
||||
unsigned char signature[64];
|
||||
int is_signature_valid, is_signature_valid2;
|
||||
int return_val;
|
||||
secp256k1_xonly_pubkey pubkey;
|
||||
secp256k1_keypair keypair;
|
||||
/* Before we can call actual API functions, we need to create a "context". */
|
||||
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
if (!fill_random(randomize, sizeof(randomize))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* Randomizing the context is recommended to protect against side-channel
|
||||
* leakage See `secp256k1_context_randomize` in secp256k1.h for more
|
||||
* information about it. This should never fail. */
|
||||
return_val = secp256k1_context_randomize(ctx, randomize);
|
||||
assert(return_val);
|
||||
|
||||
/*** Key Generation ***/
|
||||
|
||||
/* If the secret key is zero or out of range (bigger than secp256k1's
|
||||
* order), we try to sample a new key. Note that the probability of this
|
||||
* happening is negligible. */
|
||||
while (1) {
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* Try to create a keypair with a valid context, it should only fail if
|
||||
* the secret key is zero or out of range. */
|
||||
if (secp256k1_keypair_create(ctx, &keypair, seckey)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract the X-only public key from the keypair. We pass NULL for
|
||||
* `pk_parity` as the parity isn't needed for signing or verification.
|
||||
* `secp256k1_keypair_xonly_pub` supports returning the parity for
|
||||
* other use cases such as tests or verifying Taproot tweaks.
|
||||
* This should never fail with a valid context and public key. */
|
||||
return_val = secp256k1_keypair_xonly_pub(ctx, &pubkey, NULL, &keypair);
|
||||
assert(return_val);
|
||||
|
||||
/* Serialize the public key. Should always return 1 for a valid public key. */
|
||||
return_val = secp256k1_xonly_pubkey_serialize(ctx, serialized_pubkey, &pubkey);
|
||||
assert(return_val);
|
||||
|
||||
/*** Signing ***/
|
||||
|
||||
/* Instead of signing (possibly very long) messages directly, we sign a
|
||||
* 32-byte hash of the message in this example.
|
||||
*
|
||||
* We use secp256k1_tagged_sha256 to create this hash. This function expects
|
||||
* a context-specific "tag", which restricts the context in which the signed
|
||||
* messages should be considered valid. For example, if protocol A mandates
|
||||
* to use the tag "my_fancy_protocol" and protocol B mandates to use the tag
|
||||
* "my_boring_protocol", then signed messages from protocol A will never be
|
||||
* valid in protocol B (and vice versa), even if keys are reused across
|
||||
* protocols. This implements "domain separation", which is considered good
|
||||
* practice. It avoids attacks in which users are tricked into signing a
|
||||
* message that has intended consequences in the intended context (e.g.,
|
||||
* protocol A) but would have unintended consequences if it were valid in
|
||||
* some other context (e.g., protocol B). */
|
||||
return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg));
|
||||
assert(return_val);
|
||||
|
||||
/* Generate 32 bytes of randomness to use with BIP-340 schnorr signing. */
|
||||
if (!fill_random(auxiliary_rand, sizeof(auxiliary_rand))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generate a Schnorr signature.
|
||||
*
|
||||
* We use the secp256k1_schnorrsig_sign32 function that provides a simple
|
||||
* interface for signing 32-byte messages (which in our case is a hash of
|
||||
* the actual message). BIP-340 recommends passing 32 bytes of randomness
|
||||
* to the signing function to improve security against side-channel attacks.
|
||||
* Signing with a valid context, a 32-byte message, a verified keypair, and
|
||||
* any 32 bytes of auxiliary random data should never fail. */
|
||||
return_val = secp256k1_schnorrsig_sign32(ctx, signature, msg_hash, &keypair, auxiliary_rand);
|
||||
assert(return_val);
|
||||
|
||||
/*** Verification ***/
|
||||
|
||||
/* Deserialize the public key. This will return 0 if the public key can't
|
||||
* be parsed correctly */
|
||||
if (!secp256k1_xonly_pubkey_parse(ctx, &pubkey, serialized_pubkey)) {
|
||||
printf("Failed parsing the public key\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compute the tagged hash on the received messages using the same tag as the signer. */
|
||||
return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg));
|
||||
assert(return_val);
|
||||
|
||||
/* Verify a signature. This will return 1 if it's valid and 0 if it's not. */
|
||||
is_signature_valid = secp256k1_schnorrsig_verify(ctx, signature, msg_hash, 32, &pubkey);
|
||||
|
||||
|
||||
printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false");
|
||||
printf("Secret Key: ");
|
||||
print_hex(seckey, sizeof(seckey));
|
||||
printf("Public Key: ");
|
||||
print_hex(serialized_pubkey, sizeof(serialized_pubkey));
|
||||
printf("Signature: ");
|
||||
print_hex(signature, sizeof(signature));
|
||||
|
||||
/* This will clear everything from the context and free the memory */
|
||||
secp256k1_context_destroy(ctx);
|
||||
|
||||
/* Bonus example: if all we need is signature verification (and no key
|
||||
generation or signing), we don't need to use a context created via
|
||||
secp256k1_context_create(). We can simply use the static (i.e., global)
|
||||
context secp256k1_context_static. See its description in
|
||||
include/secp256k1.h for details. */
|
||||
is_signature_valid2 = secp256k1_schnorrsig_verify(secp256k1_context_static,
|
||||
signature, msg_hash, 32, &pubkey);
|
||||
assert(is_signature_valid2 == is_signature_valid);
|
||||
|
||||
/* It's best practice to try to clear secrets from memory after using them.
|
||||
* This is done because some bugs can allow an attacker to leak memory, for
|
||||
* example through "out of bounds" array access (see Heartbleed), Or the OS
|
||||
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
|
||||
*
|
||||
* Here we are preventing these writes from being optimized out, as any good compiler
|
||||
* will remove any writes that aren't used. */
|
||||
secure_erase(seckey, sizeof(seckey));
|
||||
return 0;
|
||||
}
|
||||
914
vendor/secp256k1/repo/include/secp256k1.h
vendored
Normal file
914
vendor/secp256k1/repo/include/secp256k1.h
vendored
Normal file
|
|
@ -0,0 +1,914 @@
|
|||
#ifndef SECP256K1_H
|
||||
#define SECP256K1_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/** Unless explicitly stated all pointer arguments must not be NULL.
|
||||
*
|
||||
* The following rules specify the order of arguments in API calls:
|
||||
*
|
||||
* 1. Context pointers go first, followed by output arguments, combined
|
||||
* output/input arguments, and finally input-only arguments.
|
||||
* 2. Array lengths always immediately follow the argument whose length
|
||||
* they describe, even if this violates rule 1.
|
||||
* 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated
|
||||
* later go first. This means: signatures, public nonces, secret nonces,
|
||||
* messages, public keys, secret keys, tweaks.
|
||||
* 4. Arguments that are not data pointers go last, from more complex to less
|
||||
* complex: function pointers, algorithm names, messages, void pointers,
|
||||
* counts, flags, booleans.
|
||||
* 5. Opaque data pointers follow the function pointer they are to be passed to.
|
||||
*/
|
||||
|
||||
/** Opaque data structure that holds context information
|
||||
*
|
||||
* The primary purpose of context objects is to store randomization data for
|
||||
* enhanced protection against side-channel leakage. This protection is only
|
||||
* effective if the context is randomized after its creation. See
|
||||
* secp256k1_context_create for creation of contexts and
|
||||
* secp256k1_context_randomize for randomization.
|
||||
*
|
||||
* A secondary purpose of context objects is to store pointers to callback
|
||||
* functions that the library will call when certain error states arise. See
|
||||
* secp256k1_context_set_error_callback as well as
|
||||
* secp256k1_context_set_illegal_callback for details. Future library versions
|
||||
* may use context objects for additional purposes.
|
||||
*
|
||||
* A constructed context can safely be used from multiple threads
|
||||
* simultaneously, but API calls that take a non-const pointer to a context
|
||||
* need exclusive access to it. In particular this is the case for
|
||||
* secp256k1_context_destroy, secp256k1_context_preallocated_destroy,
|
||||
* and secp256k1_context_randomize.
|
||||
*
|
||||
* Regarding randomization, either do it once at creation time (in which case
|
||||
* you do not need any locking for the other calls), or use a read-write lock.
|
||||
*/
|
||||
typedef struct secp256k1_context_struct secp256k1_context;
|
||||
|
||||
/** Opaque data structure that holds rewritable "scratch space"
|
||||
*
|
||||
* The purpose of this structure is to replace dynamic memory allocations,
|
||||
* because we target architectures where this may not be available. It is
|
||||
* essentially a resizable (within specified parameters) block of bytes,
|
||||
* which is initially created either by memory allocation or TODO as a pointer
|
||||
* into some fixed rewritable space.
|
||||
*
|
||||
* Unlike the context object, this cannot safely be shared between threads
|
||||
* without additional synchronization logic.
|
||||
*/
|
||||
typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space;
|
||||
|
||||
/** Opaque data structure that holds a parsed and valid public key.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage or transmission,
|
||||
* use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. To
|
||||
* compare keys, use secp256k1_ec_pubkey_cmp.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
} secp256k1_pubkey;
|
||||
|
||||
/** Opaque data structured that holds a parsed ECDSA signature.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage, transmission, or
|
||||
* comparison, use the secp256k1_ecdsa_signature_serialize_* and
|
||||
* secp256k1_ecdsa_signature_parse_* functions.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
} secp256k1_ecdsa_signature;
|
||||
|
||||
/** A pointer to a function to deterministically generate a nonce.
|
||||
*
|
||||
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail.
|
||||
* Out: nonce32: pointer to a 32-byte array to be filled by the function.
|
||||
* In: msg32: the 32-byte message hash being verified (will not be NULL)
|
||||
* key32: pointer to a 32-byte secret key (will not be NULL)
|
||||
* algo16: pointer to a 16-byte array describing the signature
|
||||
* algorithm (will be NULL for ECDSA for compatibility).
|
||||
* data: Arbitrary data pointer that is passed through.
|
||||
* attempt: how many iterations we have tried to find a nonce.
|
||||
* This will almost always be 0, but different attempt values
|
||||
* are required to result in a different nonce.
|
||||
*
|
||||
* Except for test cases, this function should compute some cryptographic hash of
|
||||
* the message, the algorithm, the key and the attempt.
|
||||
*/
|
||||
typedef int (*secp256k1_nonce_function)(
|
||||
unsigned char *nonce32,
|
||||
const unsigned char *msg32,
|
||||
const unsigned char *key32,
|
||||
const unsigned char *algo16,
|
||||
void *data,
|
||||
unsigned int attempt
|
||||
);
|
||||
|
||||
# if !defined(SECP256K1_GNUC_PREREQ)
|
||||
# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
|
||||
# define SECP256K1_GNUC_PREREQ(_maj,_min) \
|
||||
((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
|
||||
# else
|
||||
# define SECP256K1_GNUC_PREREQ(_maj,_min) 0
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
|
||||
# if SECP256K1_GNUC_PREREQ(2,7)
|
||||
# define SECP256K1_INLINE __inline__
|
||||
# elif (defined(_MSC_VER))
|
||||
# define SECP256K1_INLINE __inline
|
||||
# else
|
||||
# define SECP256K1_INLINE
|
||||
# endif
|
||||
# else
|
||||
# define SECP256K1_INLINE inline
|
||||
# endif
|
||||
|
||||
/* When this header is used at build-time the SECP256K1_BUILD define needs to be set
|
||||
* to correctly setup export attributes and nullness checks. This is normally done
|
||||
* by secp256k1.c but to guard against this header being included before secp256k1.c
|
||||
* has had a chance to set the define (e.g. via test harnesses that just includes
|
||||
* secp256k1.c) we set SECP256K1_NO_BUILD when this header is processed without the
|
||||
* BUILD define so this condition can be caught.
|
||||
*/
|
||||
#ifndef SECP256K1_BUILD
|
||||
# define SECP256K1_NO_BUILD
|
||||
#endif
|
||||
|
||||
/* Symbol visibility. See libtool manual, section "Windows DLLs". */
|
||||
#if defined(_WIN32) && !defined(__GNUC__)
|
||||
# ifdef SECP256K1_BUILD
|
||||
# ifdef DLL_EXPORT
|
||||
# define SECP256K1_API __declspec (dllexport)
|
||||
# define SECP256K1_API_VAR extern __declspec (dllexport)
|
||||
# endif
|
||||
# elif defined _MSC_VER
|
||||
# define SECP256K1_API
|
||||
# define SECP256K1_API_VAR extern __declspec (dllimport)
|
||||
# elif defined DLL_EXPORT
|
||||
# define SECP256K1_API __declspec (dllimport)
|
||||
# define SECP256K1_API_VAR extern __declspec (dllimport)
|
||||
# endif
|
||||
#endif
|
||||
#ifndef SECP256K1_API
|
||||
# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
|
||||
# define SECP256K1_API __attribute__ ((visibility ("default")))
|
||||
# define SECP256K1_API_VAR extern __attribute__ ((visibility ("default")))
|
||||
# else
|
||||
# define SECP256K1_API
|
||||
# define SECP256K1_API_VAR extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Warning attributes
|
||||
* NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out
|
||||
* some paranoid null checks. */
|
||||
# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)
|
||||
# define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
|
||||
# else
|
||||
# define SECP256K1_WARN_UNUSED_RESULT
|
||||
# endif
|
||||
# if !defined(SECP256K1_BUILD) && defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)
|
||||
# define SECP256K1_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x)))
|
||||
# else
|
||||
# define SECP256K1_ARG_NONNULL(_x)
|
||||
# endif
|
||||
|
||||
/* Attribute for marking functions, types, and variables as deprecated */
|
||||
#if !defined(SECP256K1_BUILD) && defined(__has_attribute)
|
||||
# if __has_attribute(__deprecated__)
|
||||
# define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg)))
|
||||
# else
|
||||
# define SECP256K1_DEPRECATED(_msg)
|
||||
# endif
|
||||
#else
|
||||
# define SECP256K1_DEPRECATED(_msg)
|
||||
#endif
|
||||
|
||||
/* All flags' lower 8 bits indicate what they're for. Do not use directly. */
|
||||
#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)
|
||||
#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)
|
||||
#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1)
|
||||
/* The higher bits contain the actual data. Do not use directly. */
|
||||
#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8)
|
||||
#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)
|
||||
#define SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY (1 << 10)
|
||||
#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)
|
||||
|
||||
/** Context flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and
|
||||
* secp256k1_context_preallocated_create. */
|
||||
#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
|
||||
|
||||
/** Deprecated context flags. These flags are treated equivalent to SECP256K1_CONTEXT_NONE. */
|
||||
#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
|
||||
#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
|
||||
|
||||
/* Testing flag. Do not use. */
|
||||
#define SECP256K1_CONTEXT_DECLASSIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY)
|
||||
|
||||
/** Flag to pass to secp256k1_ec_pubkey_serialize. */
|
||||
#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
|
||||
#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION)
|
||||
|
||||
/** Prefix byte used to tag various encoded curvepoints for specific purposes */
|
||||
#define SECP256K1_TAG_PUBKEY_EVEN 0x02
|
||||
#define SECP256K1_TAG_PUBKEY_ODD 0x03
|
||||
#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04
|
||||
#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06
|
||||
#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07
|
||||
|
||||
/** A built-in constant secp256k1 context object with static storage duration, to be
|
||||
* used in conjunction with secp256k1_selftest.
|
||||
*
|
||||
* This context object offers *only limited functionality* , i.e., it cannot be used
|
||||
* for API functions that perform computations involving secret keys, e.g., signing
|
||||
* and public key generation. If this restriction applies to a specific API function,
|
||||
* it is mentioned in its documentation. See secp256k1_context_create if you need a
|
||||
* full context object that supports all functionality offered by the library.
|
||||
*
|
||||
* It is highly recommended to call secp256k1_selftest before using this context.
|
||||
*/
|
||||
SECP256K1_API_VAR const secp256k1_context *secp256k1_context_static;
|
||||
|
||||
/** Deprecated alias for secp256k1_context_static. */
|
||||
SECP256K1_API_VAR const secp256k1_context *secp256k1_context_no_precomp
|
||||
SECP256K1_DEPRECATED("Use secp256k1_context_static instead");
|
||||
|
||||
/** Perform basic self tests (to be used in conjunction with secp256k1_context_static)
|
||||
*
|
||||
* This function performs self tests that detect some serious usage errors and
|
||||
* similar conditions, e.g., when the library is compiled for the wrong endianness.
|
||||
* This is a last resort measure to be used in production. The performed tests are
|
||||
* very rudimentary and are not intended as a replacement for running the test
|
||||
* binaries.
|
||||
*
|
||||
* It is highly recommended to call this before using secp256k1_context_static.
|
||||
* It is not necessary to call this function before using a context created with
|
||||
* secp256k1_context_create (or secp256k1_context_preallocated_create), which will
|
||||
* take care of performing the self tests.
|
||||
*
|
||||
* If the tests fail, this function will call the default error handler to abort the
|
||||
* program (see secp256k1_context_set_error_callback).
|
||||
*/
|
||||
SECP256K1_API void secp256k1_selftest(void);
|
||||
|
||||
|
||||
/** Create a secp256k1 context object (in dynamically allocated memory).
|
||||
*
|
||||
* This function uses malloc to allocate memory. It is guaranteed that malloc is
|
||||
* called at most once for every call of this function. If you need to avoid dynamic
|
||||
* memory allocation entirely, see secp256k1_context_static and the functions in
|
||||
* secp256k1_preallocated.h.
|
||||
*
|
||||
* Returns: a newly created context object.
|
||||
* In: flags: Always set to SECP256K1_CONTEXT_NONE (see below).
|
||||
*
|
||||
* The only valid non-deprecated flag in recent library versions is
|
||||
* SECP256K1_CONTEXT_NONE, which will create a context sufficient for all functionality
|
||||
* offered by the library. All other (deprecated) flags will be treated as equivalent
|
||||
* to the SECP256K1_CONTEXT_NONE flag. Though the flags parameter primarily exists for
|
||||
* historical reasons, future versions of the library may introduce new flags.
|
||||
*
|
||||
* If the context is intended to be used for API functions that perform computations
|
||||
* involving secret keys, e.g., signing and public key generation, then it is highly
|
||||
* recommended to call secp256k1_context_randomize on the context before calling
|
||||
* those API functions. This will provide enhanced protection against side-channel
|
||||
* leakage, see secp256k1_context_randomize for details.
|
||||
*
|
||||
* Do not create a new context object for each operation, as construction and
|
||||
* randomization can take non-negligible time.
|
||||
*/
|
||||
SECP256K1_API secp256k1_context* secp256k1_context_create(
|
||||
unsigned int flags
|
||||
) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Copy a secp256k1 context object (into dynamically allocated memory).
|
||||
*
|
||||
* This function uses malloc to allocate memory. It is guaranteed that malloc is
|
||||
* called at most once for every call of this function. If you need to avoid dynamic
|
||||
* memory allocation entirely, see the functions in secp256k1_preallocated.h.
|
||||
*
|
||||
* Cloning secp256k1_context_static is not possible, and should not be emulated by
|
||||
* the caller (e.g., using memcpy). Create a new context instead.
|
||||
*
|
||||
* Returns: a newly created context object.
|
||||
* Args: ctx: an existing context to copy (not secp256k1_context_static)
|
||||
*/
|
||||
SECP256K1_API secp256k1_context* secp256k1_context_clone(
|
||||
const secp256k1_context* ctx
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Destroy a secp256k1 context object (created in dynamically allocated memory).
|
||||
*
|
||||
* The context pointer may not be used afterwards.
|
||||
*
|
||||
* The context to destroy must have been created using secp256k1_context_create
|
||||
* or secp256k1_context_clone. If the context has instead been created using
|
||||
* secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone, the
|
||||
* behaviour is undefined. In that case, secp256k1_context_preallocated_destroy must
|
||||
* be used instead.
|
||||
*
|
||||
* Args: ctx: an existing context to destroy, constructed using
|
||||
* secp256k1_context_create or secp256k1_context_clone
|
||||
* (i.e., not secp256k1_context_static).
|
||||
*/
|
||||
SECP256K1_API void secp256k1_context_destroy(
|
||||
secp256k1_context* ctx
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Set a callback function to be called when an illegal argument is passed to
|
||||
* an API call. It will only trigger for violations that are mentioned
|
||||
* explicitly in the header.
|
||||
*
|
||||
* The philosophy is that these shouldn't be dealt with through a
|
||||
* specific return value, as calling code should not have branches to deal with
|
||||
* the case that this code itself is broken.
|
||||
*
|
||||
* On the other hand, during debug stage, one would want to be informed about
|
||||
* such mistakes, and the default (crashing) may be inadvisable.
|
||||
* When this callback is triggered, the API function called is guaranteed not
|
||||
* to cause a crash, though its return value and output arguments are
|
||||
* undefined.
|
||||
*
|
||||
* When this function has not been called (or called with fn==NULL), then the
|
||||
* default handler will be used. The library provides a default handler which
|
||||
* writes the message to stderr and calls abort. This default handler can be
|
||||
* replaced at link time if the preprocessor macro
|
||||
* USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build
|
||||
* has been configured with --enable-external-default-callbacks. Then the
|
||||
* following two symbols must be provided to link against:
|
||||
* - void secp256k1_default_illegal_callback_fn(const char* message, void* data);
|
||||
* - void secp256k1_default_error_callback_fn(const char* message, void* data);
|
||||
* The library can call these default handlers even before a proper callback data
|
||||
* pointer could have been set using secp256k1_context_set_illegal_callback or
|
||||
* secp256k1_context_set_error_callback, e.g., when the creation of a context
|
||||
* fails. In this case, the corresponding default handler will be called with
|
||||
* the data pointer argument set to NULL.
|
||||
*
|
||||
* Args: ctx: an existing context object.
|
||||
* In: fun: a pointer to a function to call when an illegal argument is
|
||||
* passed to the API, taking a message and an opaque pointer.
|
||||
* (NULL restores the default handler.)
|
||||
* data: the opaque pointer to pass to fun above, must be NULL for the default handler.
|
||||
*
|
||||
* See also secp256k1_context_set_error_callback.
|
||||
*/
|
||||
SECP256K1_API void secp256k1_context_set_illegal_callback(
|
||||
secp256k1_context* ctx,
|
||||
void (*fun)(const char* message, void* data),
|
||||
const void* data
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Set a callback function to be called when an internal consistency check
|
||||
* fails.
|
||||
*
|
||||
* The default callback writes an error message to stderr and calls abort
|
||||
* to abort the program.
|
||||
*
|
||||
* This can only trigger in case of a hardware failure, miscompilation,
|
||||
* memory corruption, serious bug in the library, or other error would can
|
||||
* otherwise result in undefined behaviour. It will not trigger due to mere
|
||||
* incorrect usage of the API (see secp256k1_context_set_illegal_callback
|
||||
* for that). After this callback returns, anything may happen, including
|
||||
* crashing.
|
||||
*
|
||||
* Args: ctx: an existing context object.
|
||||
* In: fun: a pointer to a function to call when an internal error occurs,
|
||||
* taking a message and an opaque pointer (NULL restores the
|
||||
* default handler, see secp256k1_context_set_illegal_callback
|
||||
* for details).
|
||||
* data: the opaque pointer to pass to fun above, must be NULL for the default handler.
|
||||
*
|
||||
* See also secp256k1_context_set_illegal_callback.
|
||||
*/
|
||||
SECP256K1_API void secp256k1_context_set_error_callback(
|
||||
secp256k1_context* ctx,
|
||||
void (*fun)(const char* message, void* data),
|
||||
const void* data
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Create a secp256k1 scratch space object.
|
||||
*
|
||||
* Returns: a newly created scratch space.
|
||||
* Args: ctx: an existing context object.
|
||||
* In: size: amount of memory to be available as scratch space. Some extra
|
||||
* (<100 bytes) will be allocated for extra accounting.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space* secp256k1_scratch_space_create(
|
||||
const secp256k1_context* ctx,
|
||||
size_t size
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Destroy a secp256k1 scratch space.
|
||||
*
|
||||
* The pointer may not be used afterwards.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* scratch: space to destroy
|
||||
*/
|
||||
SECP256K1_API void secp256k1_scratch_space_destroy(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_scratch_space* scratch
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Parse a variable-length public key into the pubkey object.
|
||||
*
|
||||
* Returns: 1 if the public key was fully valid.
|
||||
* 0 if the public key could not be parsed or is invalid.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
|
||||
* parsed version of input. If not, its value is undefined.
|
||||
* In: input: pointer to a serialized public key
|
||||
* inputlen: length of the array pointed to by input
|
||||
*
|
||||
* This function supports parsing compressed (33 bytes, header byte 0x02 or
|
||||
* 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header
|
||||
* byte 0x06 or 0x07) format public keys.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey* pubkey,
|
||||
const unsigned char *input,
|
||||
size_t inputlen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a pubkey object into a serialized byte sequence.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if
|
||||
* compressed==1) byte array to place the serialized key
|
||||
* in.
|
||||
* In/Out: outputlen: a pointer to an integer which is initially set to the
|
||||
* size of output, and is overwritten with the written
|
||||
* size.
|
||||
* In: pubkey: a pointer to a secp256k1_pubkey containing an
|
||||
* initialized public key.
|
||||
* flags: SECP256K1_EC_COMPRESSED if serialization should be in
|
||||
* compressed format, otherwise SECP256K1_EC_UNCOMPRESSED.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ec_pubkey_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
size_t *outputlen,
|
||||
const secp256k1_pubkey* pubkey,
|
||||
unsigned int flags
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Compare two public keys using lexicographic (of compressed serialization) order
|
||||
*
|
||||
* Returns: <0 if the first public key is less than the second
|
||||
* >0 if the first public key is greater than the second
|
||||
* 0 if the two public keys are equal
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* In: pubkey1: first public key to compare
|
||||
* pubkey2: second public key to compare
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_pubkey* pubkey1,
|
||||
const secp256k1_pubkey* pubkey2
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Parse an ECDSA signature in compact (64 bytes) format.
|
||||
*
|
||||
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: sig: a pointer to a signature object
|
||||
* In: input64: a pointer to the 64-byte array to parse
|
||||
*
|
||||
* The signature must consist of a 32-byte big endian R value, followed by a
|
||||
* 32-byte big endian S value. If R or S fall outside of [0..order-1], the
|
||||
* encoding is invalid. R and S with value 0 are allowed in the encoding.
|
||||
*
|
||||
* After the call, sig will always be initialized. If parsing failed or R or
|
||||
* S are zero, the resulting sig value is guaranteed to fail verification for
|
||||
* any message and public key.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_ecdsa_signature* sig,
|
||||
const unsigned char *input64
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Parse a DER ECDSA signature.
|
||||
*
|
||||
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: sig: a pointer to a signature object
|
||||
* In: input: a pointer to the signature to be parsed
|
||||
* inputlen: the length of the array pointed to be input
|
||||
*
|
||||
* This function will accept any valid DER encoded signature, even if the
|
||||
* encoded numbers are out of range.
|
||||
*
|
||||
* After the call, sig will always be initialized. If parsing failed or the
|
||||
* encoded numbers are out of range, signature verification with it is
|
||||
* guaranteed to fail for every message and public key.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_signature_parse_der(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_ecdsa_signature* sig,
|
||||
const unsigned char *input,
|
||||
size_t inputlen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize an ECDSA signature in DER format.
|
||||
*
|
||||
* Returns: 1 if enough space was available to serialize, 0 otherwise
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: output: a pointer to an array to store the DER serialization
|
||||
* In/Out: outputlen: a pointer to a length integer. Initially, this integer
|
||||
* should be set to the length of output. After the call
|
||||
* it will be set to the length of the serialization (even
|
||||
* if 0 was returned).
|
||||
* In: sig: a pointer to an initialized signature object
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_signature_serialize_der(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
size_t *outputlen,
|
||||
const secp256k1_ecdsa_signature* sig
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Serialize an ECDSA signature in compact (64 byte) format.
|
||||
*
|
||||
* Returns: 1
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: output64: a pointer to a 64-byte array to store the compact serialization
|
||||
* In: sig: a pointer to an initialized signature object
|
||||
*
|
||||
* See secp256k1_ecdsa_signature_parse_compact for details about the encoding.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output64,
|
||||
const secp256k1_ecdsa_signature* sig
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Verify an ECDSA signature.
|
||||
*
|
||||
* Returns: 1: correct signature
|
||||
* 0: incorrect or unparseable signature
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* In: sig: the signature being verified.
|
||||
* msghash32: the 32-byte message hash being verified.
|
||||
* The verifier must make sure to apply a cryptographic
|
||||
* hash function to the message by itself and not accept an
|
||||
* msghash32 value directly. Otherwise, it would be easy to
|
||||
* create a "valid" signature without knowledge of the
|
||||
* secret key. See also
|
||||
* https://bitcoin.stackexchange.com/a/81116/35586 for more
|
||||
* background on this topic.
|
||||
* pubkey: pointer to an initialized public key to verify with.
|
||||
*
|
||||
* To avoid accepting malleable signatures, only ECDSA signatures in lower-S
|
||||
* form are accepted.
|
||||
*
|
||||
* If you need to accept ECDSA signatures from sources that do not obey this
|
||||
* rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to
|
||||
* verification, but be aware that doing so results in malleable signatures.
|
||||
*
|
||||
* For details, see the comments for that function.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_ecdsa_signature *sig,
|
||||
const unsigned char *msghash32,
|
||||
const secp256k1_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Convert a signature to a normalized lower-S form.
|
||||
*
|
||||
* Returns: 1 if sigin was not normalized, 0 if it already was.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: sigout: a pointer to a signature to fill with the normalized form,
|
||||
* or copy if the input was already normalized. (can be NULL if
|
||||
* you're only interested in whether the input was already
|
||||
* normalized).
|
||||
* In: sigin: a pointer to a signature to check/normalize (can be identical to sigout)
|
||||
*
|
||||
* With ECDSA a third-party can forge a second distinct signature of the same
|
||||
* message, given a single initial signature, but without knowing the key. This
|
||||
* is done by negating the S value modulo the order of the curve, 'flipping'
|
||||
* the sign of the random point R which is not included in the signature.
|
||||
*
|
||||
* Forgery of the same message isn't universally problematic, but in systems
|
||||
* where message malleability or uniqueness of signatures is important this can
|
||||
* cause issues. This forgery can be blocked by all verifiers forcing signers
|
||||
* to use a normalized form.
|
||||
*
|
||||
* The lower-S form reduces the size of signatures slightly on average when
|
||||
* variable length encodings (such as DER) are used and is cheap to verify,
|
||||
* making it a good choice. Security of always using lower-S is assured because
|
||||
* anyone can trivially modify a signature after the fact to enforce this
|
||||
* property anyway.
|
||||
*
|
||||
* The lower S value is always between 0x1 and
|
||||
* 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
|
||||
* inclusive.
|
||||
*
|
||||
* No other forms of ECDSA malleability are known and none seem likely, but
|
||||
* there is no formal proof that ECDSA, even with this additional restriction,
|
||||
* is free of other malleability. Commonly used serialization schemes will also
|
||||
* accept various non-unique encodings, so care should be taken when this
|
||||
* property is required for an application.
|
||||
*
|
||||
* The secp256k1_ecdsa_sign function will by default create signatures in the
|
||||
* lower-S form, and secp256k1_ecdsa_verify will not accept others. In case
|
||||
* signatures come from a system that cannot enforce this property,
|
||||
* secp256k1_ecdsa_signature_normalize must be called before verification.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_signature_normalize(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_ecdsa_signature *sigout,
|
||||
const secp256k1_ecdsa_signature *sigin
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function.
|
||||
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
|
||||
* extra entropy.
|
||||
*/
|
||||
SECP256K1_API_VAR const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
|
||||
|
||||
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
|
||||
SECP256K1_API_VAR const secp256k1_nonce_function secp256k1_nonce_function_default;
|
||||
|
||||
/** Create an ECDSA signature.
|
||||
*
|
||||
* Returns: 1: signature created
|
||||
* 0: the nonce generation function failed, or the secret key was invalid.
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* Out: sig: pointer to an array where the signature will be placed.
|
||||
* In: msghash32: the 32-byte message hash being signed.
|
||||
* seckey: pointer to a 32-byte secret key.
|
||||
* noncefp: pointer to a nonce generation function. If NULL,
|
||||
* secp256k1_nonce_function_default is used.
|
||||
* ndata: pointer to arbitrary data used by the nonce generation function
|
||||
* (can be NULL). If it is non-NULL and
|
||||
* secp256k1_nonce_function_default is used, then ndata must be a
|
||||
* pointer to 32-bytes of additional data.
|
||||
*
|
||||
* The created signature is always in lower-S form. See
|
||||
* secp256k1_ecdsa_signature_normalize for more details.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_sign(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_ecdsa_signature *sig,
|
||||
const unsigned char *msghash32,
|
||||
const unsigned char *seckey,
|
||||
secp256k1_nonce_function noncefp,
|
||||
const void *ndata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Verify an ECDSA secret key.
|
||||
*
|
||||
* A secret key is valid if it is not 0 and less than the secp256k1 curve order
|
||||
* when interpreted as an integer (most significant byte first). The
|
||||
* probability of choosing a 32-byte string uniformly at random which is an
|
||||
* invalid secret key is negligible.
|
||||
*
|
||||
* Returns: 1: secret key is valid
|
||||
* 0: secret key is invalid
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In: seckey: pointer to a 32-byte secret key.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
|
||||
const secp256k1_context* ctx,
|
||||
const unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Compute the public key for a secret key.
|
||||
*
|
||||
* Returns: 1: secret was valid, public key stores.
|
||||
* 0: secret was invalid, try again.
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* Out: pubkey: pointer to the created public key.
|
||||
* In: seckey: pointer to a 32-byte secret key.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Negates a secret key in place.
|
||||
*
|
||||
* Returns: 0 if the given secret key is invalid according to
|
||||
* secp256k1_ec_seckey_verify. 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* In/Out: seckey: pointer to the 32-byte secret key to be negated. If the
|
||||
* secret key is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0 and
|
||||
* seckey will be set to some unspecified value.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Same as secp256k1_ec_seckey_negate, but DEPRECATED. Will be removed in
|
||||
* future versions. */
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2)
|
||||
SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_negate instead");
|
||||
|
||||
/** Negates a public key in place.
|
||||
*
|
||||
* Returns: 1 always
|
||||
* Args: ctx: pointer to a context object
|
||||
* In/Out: pubkey: pointer to the public key to be negated.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Tweak a secret key by adding tweak to it.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting secret key would be
|
||||
* invalid (only when the tweak is the negation of the secret key). 1
|
||||
* otherwise.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In/Out: seckey: pointer to a 32-byte secret key. If the secret key is
|
||||
* invalid according to secp256k1_ec_seckey_verify, this
|
||||
* function returns 0. seckey will be set to some unspecified
|
||||
* value if this function returns 0.
|
||||
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Same as secp256k1_ec_seckey_tweak_add, but DEPRECATED. Will be removed in
|
||||
* future versions. */
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
|
||||
SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_add instead");
|
||||
|
||||
/** Tweak a public key by adding tweak times the generator to it.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting public key would be
|
||||
* invalid (only when the tweak is the negation of the corresponding
|
||||
* secret key). 1 otherwise.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
|
||||
* invalid value if this function returns 0.
|
||||
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Tweak a secret key by multiplying it by a tweak.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In/Out: seckey: pointer to a 32-byte secret key. If the secret key is
|
||||
* invalid according to secp256k1_ec_seckey_verify, this
|
||||
* function returns 0. seckey will be set to some unspecified
|
||||
* value if this function returns 0.
|
||||
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Same as secp256k1_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in
|
||||
* future versions. */
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
|
||||
SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_mul instead");
|
||||
|
||||
/** Tweak a public key by multiplying it by a tweak value.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
|
||||
* invalid value if this function returns 0.
|
||||
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Randomizes the context to provide enhanced protection against side-channel leakage.
|
||||
*
|
||||
* Returns: 1: randomization successful
|
||||
* 0: error
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state).
|
||||
*
|
||||
* While secp256k1 code is written and tested to be constant-time no matter what
|
||||
* secret values are, it is possible that a compiler may output code which is not,
|
||||
* and also that the CPU may not emit the same radio frequencies or draw the same
|
||||
* amount of power for all values. Randomization of the context shields against
|
||||
* side-channel observations which aim to exploit secret-dependent behaviour in
|
||||
* certain computations which involve secret keys.
|
||||
*
|
||||
* It is highly recommended to call this function on contexts returned from
|
||||
* secp256k1_context_create or secp256k1_context_clone (or from the corresponding
|
||||
* functions in secp256k1_preallocated.h) before using these contexts to call API
|
||||
* functions that perform computations involving secret keys, e.g., signing and
|
||||
* public key generation. It is possible to call this function more than once on
|
||||
* the same context, and doing so before every few computations involving secret
|
||||
* keys is recommended as a defense-in-depth measure. Randomization of the static
|
||||
* context secp256k1_context_static is not supported.
|
||||
*
|
||||
* Currently, the random seed is mainly used for blinding multiplications of a
|
||||
* secret scalar with the elliptic curve base point. Multiplications of this
|
||||
* kind are performed by exactly those API functions which are documented to
|
||||
* require a context that is not secp256k1_context_static. As a rule of thumb,
|
||||
* these are all functions which take a secret key (or a keypair) as an input.
|
||||
* A notable exception to that rule is the ECDH module, which relies on a different
|
||||
* kind of elliptic curve point multiplication and thus does not benefit from
|
||||
* enhanced protection against side-channel leakage currently.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
|
||||
secp256k1_context* ctx,
|
||||
const unsigned char *seed32
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Add a number of public keys together.
|
||||
*
|
||||
* Returns: 1: the sum of the public keys is valid.
|
||||
* 0: the sum of the public keys is not valid.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: out: pointer to a public key object for placing the resulting public key.
|
||||
* In: ins: pointer to array of pointers to public keys.
|
||||
* n: the number of public keys to add together (must be at least 1).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *out,
|
||||
const secp256k1_pubkey * const * ins,
|
||||
size_t n
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Compute a tagged hash as defined in BIP-340.
|
||||
*
|
||||
* This is useful for creating a message hash and achieving domain separation
|
||||
* through an application-specific tag. This function returns
|
||||
* SHA256(SHA256(tag)||SHA256(tag)||msg). Therefore, tagged hash
|
||||
* implementations optimized for a specific tag can precompute the SHA256 state
|
||||
* after hashing the tag hashes.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: hash32: pointer to a 32-byte array to store the resulting hash
|
||||
* In: tag: pointer to an array containing the tag
|
||||
* taglen: length of the tag array
|
||||
* msg: pointer to an array containing the message
|
||||
* msglen: length of the message array
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_tagged_sha256(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *hash32,
|
||||
const unsigned char *tag,
|
||||
size_t taglen,
|
||||
const unsigned char *msg,
|
||||
size_t msglen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_H */
|
||||
63
vendor/secp256k1/repo/include/secp256k1_ecdh.h
vendored
Normal file
63
vendor/secp256k1/repo/include/secp256k1_ecdh.h
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef SECP256K1_ECDH_H
|
||||
#define SECP256K1_ECDH_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** A pointer to a function that hashes an EC point to obtain an ECDH secret
|
||||
*
|
||||
* Returns: 1 if the point was successfully hashed.
|
||||
* 0 will cause secp256k1_ecdh to fail and return 0.
|
||||
* Other return values are not allowed, and the behaviour of
|
||||
* secp256k1_ecdh is undefined for other return values.
|
||||
* Out: output: pointer to an array to be filled by the function
|
||||
* In: x32: pointer to a 32-byte x coordinate
|
||||
* y32: pointer to a 32-byte y coordinate
|
||||
* data: arbitrary data pointer that is passed through
|
||||
*/
|
||||
typedef int (*secp256k1_ecdh_hash_function)(
|
||||
unsigned char *output,
|
||||
const unsigned char *x32,
|
||||
const unsigned char *y32,
|
||||
void *data
|
||||
);
|
||||
|
||||
/** An implementation of SHA256 hash function that applies to compressed public key.
|
||||
* Populates the output parameter with 32 bytes. */
|
||||
SECP256K1_API_VAR const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
|
||||
|
||||
/** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256).
|
||||
* Populates the output parameter with 32 bytes. */
|
||||
SECP256K1_API_VAR const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
|
||||
|
||||
/** Compute an EC Diffie-Hellman secret in constant time
|
||||
*
|
||||
* Returns: 1: exponentiation was successful
|
||||
* 0: scalar was invalid (zero or overflow) or hashfp returned 0
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: output: pointer to an array to be filled by hashfp.
|
||||
* In: pubkey: a pointer to a secp256k1_pubkey containing an initialized public key.
|
||||
* seckey: a 32-byte scalar with which to multiply the point.
|
||||
* hashfp: pointer to a hash function. If NULL,
|
||||
* secp256k1_ecdh_hash_function_sha256 is used
|
||||
* (in which case, 32 bytes will be written to output).
|
||||
* data: arbitrary data pointer that is passed through to hashfp
|
||||
* (can be NULL for secp256k1_ecdh_hash_function_sha256).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
const unsigned char *seckey,
|
||||
secp256k1_ecdh_hash_function hashfp,
|
||||
void *data
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_ECDH_H */
|
||||
249
vendor/secp256k1/repo/include/secp256k1_extrakeys.h
vendored
Normal file
249
vendor/secp256k1/repo/include/secp256k1_extrakeys.h
vendored
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
#ifndef SECP256K1_EXTRAKEYS_H
|
||||
#define SECP256K1_EXTRAKEYS_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Opaque data structure that holds a parsed and valid "x-only" public key.
|
||||
* An x-only pubkey encodes a point whose Y coordinate is even. It is
|
||||
* serialized using only its X coordinate (32 bytes). See BIP-340 for more
|
||||
* information about x-only pubkeys.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage, transmission, use
|
||||
* use secp256k1_xonly_pubkey_serialize and secp256k1_xonly_pubkey_parse. To
|
||||
* compare keys, use secp256k1_xonly_pubkey_cmp.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
} secp256k1_xonly_pubkey;
|
||||
|
||||
/** Opaque data structure that holds a keypair consisting of a secret and a
|
||||
* public key.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 96 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[96];
|
||||
} secp256k1_keypair;
|
||||
|
||||
/** Parse a 32-byte sequence into a xonly_pubkey object.
|
||||
*
|
||||
* Returns: 1 if the public key was fully valid.
|
||||
* 0 if the public key could not be parsed or is invalid.
|
||||
*
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
|
||||
* parsed version of input. If not, it's set to an invalid value.
|
||||
* In: input32: pointer to a serialized xonly_pubkey.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_xonly_pubkey* pubkey,
|
||||
const unsigned char *input32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize an xonly_pubkey object into a 32-byte sequence.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
*
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: output32: a pointer to a 32-byte array to place the serialized key in.
|
||||
* In: pubkey: a pointer to a secp256k1_xonly_pubkey containing an initialized public key.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_xonly_pubkey_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output32,
|
||||
const secp256k1_xonly_pubkey* pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Compare two x-only public keys using lexicographic order
|
||||
*
|
||||
* Returns: <0 if the first public key is less than the second
|
||||
* >0 if the first public key is greater than the second
|
||||
* 0 if the two public keys are equal
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* In: pubkey1: first public key to compare
|
||||
* pubkey2: second public key to compare
|
||||
*/
|
||||
SECP256K1_API int secp256k1_xonly_pubkey_cmp(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_xonly_pubkey* pk1,
|
||||
const secp256k1_xonly_pubkey* pk2
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
*
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: xonly_pubkey: pointer to an x-only public key object for placing the converted public key.
|
||||
* pk_parity: Ignored if NULL. Otherwise, pointer to an integer that
|
||||
* will be set to 1 if the point encoded by xonly_pubkey is
|
||||
* the negation of the pubkey and set to 0 otherwise.
|
||||
* In: pubkey: pointer to a public key that is converted.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_xonly_pubkey *xonly_pubkey,
|
||||
int *pk_parity,
|
||||
const secp256k1_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Tweak an x-only public key by adding the generator multiplied with tweak32
|
||||
* to it.
|
||||
*
|
||||
* Note that the resulting point can not in general be represented by an x-only
|
||||
* pubkey because it may have an odd Y coordinate. Instead, the output_pubkey
|
||||
* is a normal secp256k1_pubkey.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting public key would be
|
||||
* invalid (only when the tweak is the negation of the corresponding
|
||||
* secret key). 1 otherwise.
|
||||
*
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: output_pubkey: pointer to a public key to store the result. Will be set
|
||||
* to an invalid value if this function returns 0.
|
||||
* In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to.
|
||||
* tweak32: pointer to a 32-byte tweak. If the tweak is invalid
|
||||
* according to secp256k1_ec_seckey_verify, this function
|
||||
* returns 0. For uniformly random 32-byte arrays the
|
||||
* chance of being invalid is negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *output_pubkey,
|
||||
const secp256k1_xonly_pubkey *internal_pubkey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Checks that a tweaked pubkey is the result of calling
|
||||
* secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32.
|
||||
*
|
||||
* The tweaked pubkey is represented by its 32-byte x-only serialization and
|
||||
* its pk_parity, which can both be obtained by converting the result of
|
||||
* tweak_add to a secp256k1_xonly_pubkey.
|
||||
*
|
||||
* Note that this alone does _not_ verify that the tweaked pubkey is a
|
||||
* commitment. If the tweak is not chosen in a specific way, the tweaked pubkey
|
||||
* can easily be the result of a different internal_pubkey and tweak.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the tweaked pubkey is not the
|
||||
* result of tweaking the internal_pubkey with tweak32. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In: tweaked_pubkey32: pointer to a serialized xonly_pubkey.
|
||||
* tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization
|
||||
* is passed in as tweaked_pubkey32). This must match the
|
||||
* pk_parity value that is returned when calling
|
||||
* secp256k1_xonly_pubkey with the tweaked pubkey, or
|
||||
* this function will fail.
|
||||
* internal_pubkey: pointer to an x-only public key object to apply the tweak to.
|
||||
* tweak32: pointer to a 32-byte tweak.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_check(
|
||||
const secp256k1_context* ctx,
|
||||
const unsigned char *tweaked_pubkey32,
|
||||
int tweaked_pk_parity,
|
||||
const secp256k1_xonly_pubkey *internal_pubkey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Compute the keypair for a secret key.
|
||||
*
|
||||
* Returns: 1: secret was valid, keypair is ready to use
|
||||
* 0: secret was invalid, try again with a different secret
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* Out: keypair: pointer to the created keypair.
|
||||
* In: seckey: pointer to a 32-byte secret key.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_keypair *keypair,
|
||||
const unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Get the secret key from a keypair.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: seckey: pointer to a 32-byte buffer for the secret key.
|
||||
* In: keypair: pointer to a keypair.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey,
|
||||
const secp256k1_keypair *keypair
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Get the public key from a keypair.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to
|
||||
* the keypair public key. If not, it's set to an invalid value.
|
||||
* In: keypair: pointer to a keypair.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const secp256k1_keypair *keypair
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Get the x-only public key from a keypair.
|
||||
*
|
||||
* This is the same as calling secp256k1_keypair_pub and then
|
||||
* secp256k1_xonly_pubkey_from_pubkey.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: pubkey: pointer to an xonly_pubkey object. If 1 is returned, it is set
|
||||
* to the keypair public key after converting it to an
|
||||
* xonly_pubkey. If not, it's set to an invalid value.
|
||||
* pk_parity: Ignored if NULL. Otherwise, pointer to an integer that will be set to the
|
||||
* pk_parity argument of secp256k1_xonly_pubkey_from_pubkey.
|
||||
* In: keypair: pointer to a keypair.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_xonly_pubkey *pubkey,
|
||||
int *pk_parity,
|
||||
const secp256k1_keypair *keypair
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Tweak a keypair by adding tweak32 to the secret key and updating the public
|
||||
* key accordingly.
|
||||
*
|
||||
* Calling this function and then secp256k1_keypair_pub results in the same
|
||||
* public key as calling secp256k1_keypair_xonly_pub and then
|
||||
* secp256k1_xonly_pubkey_tweak_add.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting keypair would be
|
||||
* invalid (only when the tweak is the negation of the keypair's
|
||||
* secret key). 1 otherwise.
|
||||
*
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to
|
||||
* an invalid value if this function returns 0.
|
||||
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according
|
||||
* to secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_keypair *keypair,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_EXTRAKEYS_H */
|
||||
134
vendor/secp256k1/repo/include/secp256k1_preallocated.h
vendored
Normal file
134
vendor/secp256k1/repo/include/secp256k1_preallocated.h
vendored
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
#ifndef SECP256K1_PREALLOCATED_H
|
||||
#define SECP256K1_PREALLOCATED_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The module provided by this header file is intended for settings in which it
|
||||
* is not possible or desirable to rely on dynamic memory allocation. It provides
|
||||
* functions for creating, cloning, and destroying secp256k1 context objects in a
|
||||
* contiguous fixed-size block of memory provided by the caller.
|
||||
*
|
||||
* Context objects created by functions in this module can be used like contexts
|
||||
* objects created by functions in secp256k1.h, i.e., they can be passed to any
|
||||
* API function that expects a context object (see secp256k1.h for details). The
|
||||
* only exception is that context objects created by functions in this module
|
||||
* must be destroyed using secp256k1_context_preallocated_destroy (in this
|
||||
* module) instead of secp256k1_context_destroy (in secp256k1.h).
|
||||
*
|
||||
* It is guaranteed that functions in this module will not call malloc or its
|
||||
* friends realloc, calloc, and free.
|
||||
*/
|
||||
|
||||
/** Determine the memory size of a secp256k1 context object to be created in
|
||||
* caller-provided memory.
|
||||
*
|
||||
* The purpose of this function is to determine how much memory must be provided
|
||||
* to secp256k1_context_preallocated_create.
|
||||
*
|
||||
* Returns: the required size of the caller-provided memory block
|
||||
* In: flags: which parts of the context to initialize.
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_context_preallocated_size(
|
||||
unsigned int flags
|
||||
) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Create a secp256k1 context object in caller-provided memory.
|
||||
*
|
||||
* The caller must provide a pointer to a rewritable contiguous block of memory
|
||||
* of size at least secp256k1_context_preallocated_size(flags) bytes, suitably
|
||||
* aligned to hold an object of any type.
|
||||
*
|
||||
* The block of memory is exclusively owned by the created context object during
|
||||
* the lifetime of this context object, which begins with the call to this
|
||||
* function and ends when a call to secp256k1_context_preallocated_destroy
|
||||
* (which destroys the context object again) returns. During the lifetime of the
|
||||
* context object, the caller is obligated not to access this block of memory,
|
||||
* i.e., the caller may not read or write the memory, e.g., by copying the memory
|
||||
* contents to a different location or trying to create a second context object
|
||||
* in the memory. In simpler words, the prealloc pointer (or any pointer derived
|
||||
* from it) should not be used during the lifetime of the context object.
|
||||
*
|
||||
* Returns: a newly created context object.
|
||||
* In: prealloc: a pointer to a rewritable contiguous block of memory of
|
||||
* size at least secp256k1_context_preallocated_size(flags)
|
||||
* bytes, as detailed above.
|
||||
* flags: which parts of the context to initialize.
|
||||
*
|
||||
* See secp256k1_context_create (in secp256k1.h) for further details.
|
||||
*
|
||||
* See also secp256k1_context_randomize (in secp256k1.h)
|
||||
* and secp256k1_context_preallocated_destroy.
|
||||
*/
|
||||
SECP256K1_API secp256k1_context* secp256k1_context_preallocated_create(
|
||||
void* prealloc,
|
||||
unsigned int flags
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Determine the memory size of a secp256k1 context object to be copied into
|
||||
* caller-provided memory.
|
||||
*
|
||||
* Returns: the required size of the caller-provided memory block.
|
||||
* In: ctx: an existing context to copy.
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
|
||||
const secp256k1_context* ctx
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Copy a secp256k1 context object into caller-provided memory.
|
||||
*
|
||||
* The caller must provide a pointer to a rewritable contiguous block of memory
|
||||
* of size at least secp256k1_context_preallocated_size(flags) bytes, suitably
|
||||
* aligned to hold an object of any type.
|
||||
*
|
||||
* The block of memory is exclusively owned by the created context object during
|
||||
* the lifetime of this context object, see the description of
|
||||
* secp256k1_context_preallocated_create for details.
|
||||
*
|
||||
* Cloning secp256k1_context_static is not possible, and should not be emulated by
|
||||
* the caller (e.g., using memcpy). Create a new context instead.
|
||||
*
|
||||
* Returns: a newly created context object.
|
||||
* Args: ctx: an existing context to copy (not secp256k1_context_static).
|
||||
* In: prealloc: a pointer to a rewritable contiguous block of memory of
|
||||
* size at least secp256k1_context_preallocated_size(flags)
|
||||
* bytes, as detailed above.
|
||||
*/
|
||||
SECP256K1_API secp256k1_context* secp256k1_context_preallocated_clone(
|
||||
const secp256k1_context* ctx,
|
||||
void* prealloc
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Destroy a secp256k1 context object that has been created in
|
||||
* caller-provided memory.
|
||||
*
|
||||
* The context pointer may not be used afterwards.
|
||||
*
|
||||
* The context to destroy must have been created using
|
||||
* secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone.
|
||||
* If the context has instead been created using secp256k1_context_create or
|
||||
* secp256k1_context_clone, the behaviour is undefined. In that case,
|
||||
* secp256k1_context_destroy must be used instead.
|
||||
*
|
||||
* If required, it is the responsibility of the caller to deallocate the block
|
||||
* of memory properly after this function returns, e.g., by calling free on the
|
||||
* preallocated pointer given to secp256k1_context_preallocated_create or
|
||||
* secp256k1_context_preallocated_clone.
|
||||
*
|
||||
* Args: ctx: an existing context to destroy, constructed using
|
||||
* secp256k1_context_preallocated_create or
|
||||
* secp256k1_context_preallocated_clone
|
||||
* (i.e., not secp256k1_context_static).
|
||||
*/
|
||||
SECP256K1_API void secp256k1_context_preallocated_destroy(
|
||||
secp256k1_context* ctx
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_PREALLOCATED_H */
|
||||
113
vendor/secp256k1/repo/include/secp256k1_recovery.h
vendored
Normal file
113
vendor/secp256k1/repo/include/secp256k1_recovery.h
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
#ifndef SECP256K1_RECOVERY_H
|
||||
#define SECP256K1_RECOVERY_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Opaque data structured that holds a parsed ECDSA signature,
|
||||
* supporting pubkey recovery.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 65 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage or transmission, use
|
||||
* the secp256k1_ecdsa_signature_serialize_* and
|
||||
* secp256k1_ecdsa_signature_parse_* functions.
|
||||
*
|
||||
* Furthermore, it is guaranteed that identical signatures (including their
|
||||
* recoverability) will have identical representation, so they can be
|
||||
* memcmp'ed.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[65];
|
||||
} secp256k1_ecdsa_recoverable_signature;
|
||||
|
||||
/** Parse a compact ECDSA signature (64 bytes + recovery id).
|
||||
*
|
||||
* Returns: 1 when the signature could be parsed, 0 otherwise
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: sig: a pointer to a signature object
|
||||
* In: input64: a pointer to a 64-byte compact signature
|
||||
* recid: the recovery id (0, 1, 2 or 3)
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_ecdsa_recoverable_signature* sig,
|
||||
const unsigned char *input64,
|
||||
int recid
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Convert a recoverable signature into a normal signature.
|
||||
*
|
||||
* Returns: 1
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: sig: a pointer to a normal signature.
|
||||
* In: sigin: a pointer to a recoverable signature.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_ecdsa_signature* sig,
|
||||
const secp256k1_ecdsa_recoverable_signature* sigin
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize an ECDSA signature in compact format (64 bytes + recovery id).
|
||||
*
|
||||
* Returns: 1
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: output64: a pointer to a 64-byte array of the compact signature.
|
||||
* recid: a pointer to an integer to hold the recovery id.
|
||||
* In: sig: a pointer to an initialized signature object.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output64,
|
||||
int *recid,
|
||||
const secp256k1_ecdsa_recoverable_signature* sig
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Create a recoverable ECDSA signature.
|
||||
*
|
||||
* Returns: 1: signature created
|
||||
* 0: the nonce generation function failed, or the secret key was invalid.
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* Out: sig: pointer to an array where the signature will be placed.
|
||||
* In: msghash32: the 32-byte message hash being signed.
|
||||
* seckey: pointer to a 32-byte secret key.
|
||||
* noncefp: pointer to a nonce generation function. If NULL,
|
||||
* secp256k1_nonce_function_default is used.
|
||||
* ndata: pointer to arbitrary data used by the nonce generation function
|
||||
* (can be NULL for secp256k1_nonce_function_default).
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_ecdsa_recoverable_signature *sig,
|
||||
const unsigned char *msghash32,
|
||||
const unsigned char *seckey,
|
||||
secp256k1_nonce_function noncefp,
|
||||
const void *ndata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Recover an ECDSA public key from a signature.
|
||||
*
|
||||
* Returns: 1: public key successfully recovered (which guarantees a correct signature).
|
||||
* 0: otherwise.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: pubkey: pointer to the recovered public key.
|
||||
* In: sig: pointer to initialized signature that supports pubkey recovery.
|
||||
* msghash32: the 32-byte message hash assumed to be signed.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const secp256k1_ecdsa_recoverable_signature *sig,
|
||||
const unsigned char *msghash32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_RECOVERY_H */
|
||||
182
vendor/secp256k1/repo/include/secp256k1_schnorrsig.h
vendored
Normal file
182
vendor/secp256k1/repo/include/secp256k1_schnorrsig.h
vendored
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
#ifndef SECP256K1_SCHNORRSIG_H
|
||||
#define SECP256K1_SCHNORRSIG_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
#include "secp256k1_extrakeys.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** This module implements a variant of Schnorr signatures compliant with
|
||||
* Bitcoin Improvement Proposal 340 "Schnorr Signatures for secp256k1"
|
||||
* (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
||||
*/
|
||||
|
||||
/** A pointer to a function to deterministically generate a nonce.
|
||||
*
|
||||
* Same as secp256k1_nonce function with the exception of accepting an
|
||||
* additional pubkey argument and not requiring an attempt argument. The pubkey
|
||||
* argument can protect signature schemes with key-prefixed challenge hash
|
||||
* inputs against reusing the nonce when signing with the wrong precomputed
|
||||
* pubkey.
|
||||
*
|
||||
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to
|
||||
* return an error.
|
||||
* Out: nonce32: pointer to a 32-byte array to be filled by the function
|
||||
* In: msg: the message being verified. Is NULL if and only if msglen
|
||||
* is 0.
|
||||
* msglen: the length of the message
|
||||
* key32: pointer to a 32-byte secret key (will not be NULL)
|
||||
* xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32
|
||||
* (will not be NULL)
|
||||
* algo: pointer to an array describing the signature
|
||||
* algorithm (will not be NULL)
|
||||
* algolen: the length of the algo array
|
||||
* data: arbitrary data pointer that is passed through
|
||||
*
|
||||
* Except for test cases, this function should compute some cryptographic hash of
|
||||
* the message, the key, the pubkey, the algorithm description, and data.
|
||||
*/
|
||||
typedef int (*secp256k1_nonce_function_hardened)(
|
||||
unsigned char *nonce32,
|
||||
const unsigned char *msg,
|
||||
size_t msglen,
|
||||
const unsigned char *key32,
|
||||
const unsigned char *xonly_pk32,
|
||||
const unsigned char *algo,
|
||||
size_t algolen,
|
||||
void *data
|
||||
);
|
||||
|
||||
/** An implementation of the nonce generation function as defined in Bitcoin
|
||||
* Improvement Proposal 340 "Schnorr Signatures for secp256k1"
|
||||
* (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
||||
*
|
||||
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
|
||||
* auxiliary random data as defined in BIP-340. If the data pointer is NULL,
|
||||
* the nonce derivation procedure follows BIP-340 by setting the auxiliary
|
||||
* random data to zero. The algo argument must be non-NULL, otherwise the
|
||||
* function will fail and return 0. The hash will be tagged with algo.
|
||||
* Therefore, to create BIP-340 compliant signatures, algo must be set to
|
||||
* "BIP0340/nonce" and algolen to 13.
|
||||
*/
|
||||
SECP256K1_API_VAR const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
|
||||
|
||||
/** Data structure that contains additional arguments for schnorrsig_sign_custom.
|
||||
*
|
||||
* A schnorrsig_extraparams structure object can be initialized correctly by
|
||||
* setting it to SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT.
|
||||
*
|
||||
* Members:
|
||||
* magic: set to SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC at initialization
|
||||
* and has no other function than making sure the object is
|
||||
* initialized.
|
||||
* noncefp: pointer to a nonce generation function. If NULL,
|
||||
* secp256k1_nonce_function_bip340 is used
|
||||
* ndata: pointer to arbitrary data used by the nonce generation function
|
||||
* (can be NULL). If it is non-NULL and
|
||||
* secp256k1_nonce_function_bip340 is used, then ndata must be a
|
||||
* pointer to 32-byte auxiliary randomness as per BIP-340.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char magic[4];
|
||||
secp256k1_nonce_function_hardened noncefp;
|
||||
void* ndata;
|
||||
} secp256k1_schnorrsig_extraparams;
|
||||
|
||||
#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC { 0xda, 0x6f, 0xb3, 0x8c }
|
||||
#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT {\
|
||||
SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC,\
|
||||
NULL,\
|
||||
NULL\
|
||||
}
|
||||
|
||||
/** Create a Schnorr signature.
|
||||
*
|
||||
* Does _not_ strictly follow BIP-340 because it does not verify the resulting
|
||||
* signature. Instead, you can manually use secp256k1_schnorrsig_verify and
|
||||
* abort if it fails.
|
||||
*
|
||||
* This function only signs 32-byte messages. If you have messages of a
|
||||
* different size (or the same size but without a context-specific tag
|
||||
* prefix), it is recommended to create a 32-byte message hash with
|
||||
* secp256k1_tagged_sha256 and then sign the hash. Tagged hashing allows
|
||||
* providing an context-specific tag for domain separation. This prevents
|
||||
* signatures from being valid in multiple contexts by accident.
|
||||
*
|
||||
* Returns 1 on success, 0 on failure.
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* Out: sig64: pointer to a 64-byte array to store the serialized signature.
|
||||
* In: msg32: the 32-byte message being signed.
|
||||
* keypair: pointer to an initialized keypair.
|
||||
* aux_rand32: 32 bytes of fresh randomness. While recommended to provide
|
||||
* this, it is only supplemental to security and can be NULL. A
|
||||
* NULL argument is treated the same as an all-zero one. See
|
||||
* BIP-340 "Default Signing" for a full explanation of this
|
||||
* argument and for guidance if randomness is expensive.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_schnorrsig_sign32(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_keypair *keypair,
|
||||
const unsigned char *aux_rand32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Same as secp256k1_schnorrsig_sign32, but DEPRECATED. Will be removed in
|
||||
* future versions. */
|
||||
SECP256K1_API int secp256k1_schnorrsig_sign(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_keypair *keypair,
|
||||
const unsigned char *aux_rand32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
|
||||
SECP256K1_DEPRECATED("Use secp256k1_schnorrsig_sign32 instead");
|
||||
|
||||
/** Create a Schnorr signature with a more flexible API.
|
||||
*
|
||||
* Same arguments as secp256k1_schnorrsig_sign except that it allows signing
|
||||
* variable length messages and accepts a pointer to an extraparams object that
|
||||
* allows customizing signing by passing additional arguments.
|
||||
*
|
||||
* Creates the same signatures as schnorrsig_sign if msglen is 32 and the
|
||||
* extraparams.ndata is the same as aux_rand32.
|
||||
*
|
||||
* In: msg: the message being signed. Can only be NULL if msglen is 0.
|
||||
* msglen: length of the message
|
||||
* extraparams: pointer to a extraparams object (can be NULL)
|
||||
*/
|
||||
SECP256K1_API int secp256k1_schnorrsig_sign_custom(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *msg,
|
||||
size_t msglen,
|
||||
const secp256k1_keypair *keypair,
|
||||
secp256k1_schnorrsig_extraparams *extraparams
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Verify a Schnorr signature.
|
||||
*
|
||||
* Returns: 1: correct signature
|
||||
* 0: incorrect signature
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* In: sig64: pointer to the 64-byte signature to verify.
|
||||
* msg: the message being verified. Can only be NULL if msglen is 0.
|
||||
* msglen: length of the message
|
||||
* pubkey: pointer to an x-only public key to verify with (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
|
||||
const secp256k1_context* ctx,
|
||||
const unsigned char *sig64,
|
||||
const unsigned char *msg,
|
||||
size_t msglen,
|
||||
const secp256k1_xonly_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_SCHNORRSIG_H */
|
||||
12
vendor/secp256k1/repo/libsecp256k1.pc.in
vendored
Normal file
12
vendor/secp256k1/repo/libsecp256k1.pc.in
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libsecp256k1
|
||||
Description: Optimized C library for EC operations on curve secp256k1
|
||||
URL: https://github.com/bitcoin-core/secp256k1
|
||||
Version: @PACKAGE_VERSION@
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -lsecp256k1
|
||||
|
||||
156
vendor/secp256k1/repo/sage/gen_exhaustive_groups.sage
vendored
Normal file
156
vendor/secp256k1/repo/sage/gen_exhaustive_groups.sage
vendored
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
load("secp256k1_params.sage")
|
||||
|
||||
MAX_ORDER = 1000
|
||||
|
||||
# Set of (curve) orders we have encountered so far.
|
||||
orders_done = set()
|
||||
|
||||
# Map from (subgroup) orders to [b, int(gen.x), int(gen.y), gen, lambda] for those subgroups.
|
||||
solutions = {}
|
||||
|
||||
# Iterate over curves of the form y^2 = x^3 + B.
|
||||
for b in range(1, P):
|
||||
# There are only 6 curves (up to isomorphism) of the form y^2 = x^3 + B. Stop once we have tried all.
|
||||
if len(orders_done) == 6:
|
||||
break
|
||||
|
||||
E = EllipticCurve(F, [0, b])
|
||||
print("Analyzing curve y^2 = x^3 + %i" % b)
|
||||
n = E.order()
|
||||
|
||||
# Skip curves with an order we've already tried
|
||||
if n in orders_done:
|
||||
print("- Isomorphic to earlier curve")
|
||||
print()
|
||||
continue
|
||||
orders_done.add(n)
|
||||
|
||||
# Skip curves isomorphic to the real secp256k1
|
||||
if n.is_pseudoprime():
|
||||
assert E.is_isomorphic(C)
|
||||
print("- Isomorphic to secp256k1")
|
||||
print()
|
||||
continue
|
||||
|
||||
print("- Finding prime subgroups")
|
||||
|
||||
# Map from group_order to a set of independent generators for that order.
|
||||
curve_gens = {}
|
||||
|
||||
for g in E.gens():
|
||||
# Find what prime subgroups of group generated by g exist.
|
||||
g_order = g.order()
|
||||
for f, _ in g.order().factor():
|
||||
# Skip subgroups that have bad size.
|
||||
if f < 4:
|
||||
print(f" - Subgroup of size {f}: too small")
|
||||
continue
|
||||
if f > MAX_ORDER:
|
||||
print(f" - Subgroup of size {f}: too large")
|
||||
continue
|
||||
|
||||
# Construct a generator for that subgroup.
|
||||
gen = g * (g_order // f)
|
||||
assert(gen.order() == f)
|
||||
|
||||
# Add to set the minimal multiple of gen.
|
||||
curve_gens.setdefault(f, set()).add(min([j*gen for j in range(1, f)]))
|
||||
print(f" - Subgroup of size {f}: ok")
|
||||
|
||||
for f in sorted(curve_gens.keys()):
|
||||
print(f"- Constructing group of order {f}")
|
||||
cbrts = sorted([int(c) for c in Integers(f)(1).nth_root(3, all=true) if c != 1])
|
||||
gens = list(curve_gens[f])
|
||||
sol_count = 0
|
||||
no_endo_count = 0
|
||||
|
||||
# Consider all non-zero linear combinations of the independent generators.
|
||||
for j in range(1, f**len(gens)):
|
||||
gen = sum(gens[k] * ((j // f**k) % f) for k in range(len(gens)))
|
||||
assert not gen.is_zero()
|
||||
assert (f*gen).is_zero()
|
||||
|
||||
# Find lambda for endomorphism. Skip if none can be found.
|
||||
lam = None
|
||||
for l in cbrts:
|
||||
if l*gen == E(BETA*gen[0], gen[1]):
|
||||
lam = l
|
||||
break
|
||||
|
||||
if lam is None:
|
||||
no_endo_count += 1
|
||||
else:
|
||||
sol_count += 1
|
||||
solutions.setdefault(f, []).append((b, int(gen[0]), int(gen[1]), gen, lam))
|
||||
|
||||
print(f" - Found {sol_count} generators (plus {no_endo_count} without endomorphism)")
|
||||
|
||||
print()
|
||||
|
||||
def output_generator(g, name):
|
||||
print(f"#define {name} SECP256K1_GE_CONST(\\")
|
||||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
|
||||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
|
||||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
|
||||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
|
||||
print(")")
|
||||
|
||||
def output_b(b):
|
||||
print(f"#define SECP256K1_B {int(b)}")
|
||||
|
||||
print()
|
||||
print("To be put in src/group_impl.h:")
|
||||
print()
|
||||
print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */")
|
||||
for f in sorted(solutions.keys()):
|
||||
# Use as generator/2 the one with lowest b, and lowest (x, y) generator (interpreted as non-negative integers).
|
||||
b, _, _, HALF_G, lam = min(solutions[f])
|
||||
output_generator(2 * HALF_G, f"SECP256K1_G_ORDER_{f}")
|
||||
print("/** Generator for secp256k1, value 'g' defined in")
|
||||
print(" * \"Standards for Efficient Cryptography\" (SEC2) 2.7.1.")
|
||||
print(" */")
|
||||
output_generator(G, "SECP256K1_G")
|
||||
print("/* These exhaustive group test orders and generators are chosen such that:")
|
||||
print(" * - The field size is equal to that of secp256k1, so field code is the same.")
|
||||
print(" * - The curve equation is of the form y^2=x^3+B for some small constant B.")
|
||||
print(" * - The subgroup has a generator 2*P, where P.x is as small as possible.")
|
||||
print(f" * - The subgroup has size less than {MAX_ORDER} to permit exhaustive testing.")
|
||||
print(" * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y).")
|
||||
print(" */")
|
||||
print("#if defined(EXHAUSTIVE_TEST_ORDER)")
|
||||
first = True
|
||||
for f in sorted(solutions.keys()):
|
||||
b, _, _, _, lam = min(solutions[f])
|
||||
print(f"# {'if' if first else 'elif'} EXHAUSTIVE_TEST_ORDER == {f}")
|
||||
first = False
|
||||
print()
|
||||
print(f"static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_{f};")
|
||||
output_b(b)
|
||||
print()
|
||||
print("# else")
|
||||
print("# error No known generator for the specified exhaustive test group order.")
|
||||
print("# endif")
|
||||
print("#else")
|
||||
print()
|
||||
print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;")
|
||||
output_b(7)
|
||||
print()
|
||||
print("#endif")
|
||||
print("/* End of section generated by sage/gen_exhaustive_groups.sage. */")
|
||||
|
||||
|
||||
print()
|
||||
print()
|
||||
print("To be put in src/scalar_impl.h:")
|
||||
print()
|
||||
print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */")
|
||||
first = True
|
||||
for f in sorted(solutions.keys()):
|
||||
_, _, _, _, lam = min(solutions[f])
|
||||
print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f))
|
||||
first = False
|
||||
print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam)
|
||||
print("# else")
|
||||
print("# error No known lambda for the specified exhaustive test group order.")
|
||||
print("# endif")
|
||||
print("/* End of section generated by sage/gen_exhaustive_groups.sage. */")
|
||||
114
vendor/secp256k1/repo/sage/gen_split_lambda_constants.sage
vendored
Normal file
114
vendor/secp256k1/repo/sage/gen_split_lambda_constants.sage
vendored
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
""" Generates the constants used in secp256k1_scalar_split_lambda.
|
||||
|
||||
See the comments for secp256k1_scalar_split_lambda in src/scalar_impl.h for detailed explanations.
|
||||
"""
|
||||
|
||||
load("secp256k1_params.sage")
|
||||
|
||||
def inf_norm(v):
|
||||
"""Returns the infinity norm of a vector."""
|
||||
return max(map(abs, v))
|
||||
|
||||
def gauss_reduction(i1, i2):
|
||||
v1, v2 = i1.copy(), i2.copy()
|
||||
while True:
|
||||
if inf_norm(v2) < inf_norm(v1):
|
||||
v1, v2 = v2, v1
|
||||
# This is essentially
|
||||
# m = round((v1[0]*v2[0] + v1[1]*v2[1]) / (inf_norm(v1)**2))
|
||||
# (rounding to the nearest integer) without relying on floating point arithmetic.
|
||||
m = ((v1[0]*v2[0] + v1[1]*v2[1]) + (inf_norm(v1)**2) // 2) // (inf_norm(v1)**2)
|
||||
if m == 0:
|
||||
return v1, v2
|
||||
v2[0] -= m*v1[0]
|
||||
v2[1] -= m*v1[1]
|
||||
|
||||
def find_split_constants_gauss():
|
||||
"""Find constants for secp256k1_scalar_split_lamdba using gauss reduction."""
|
||||
(v11, v12), (v21, v22) = gauss_reduction([0, N], [1, int(LAMBDA)])
|
||||
|
||||
# We use related vectors in secp256k1_scalar_split_lambda.
|
||||
A1, B1 = -v21, -v11
|
||||
A2, B2 = v22, -v21
|
||||
|
||||
return A1, B1, A2, B2
|
||||
|
||||
def find_split_constants_explicit_tof():
|
||||
"""Find constants for secp256k1_scalar_split_lamdba using the trace of Frobenius.
|
||||
|
||||
See Benjamin Smith: "Easy scalar decompositions for efficient scalar multiplication on
|
||||
elliptic curves and genus 2 Jacobians" (https://eprint.iacr.org/2013/672), Example 2
|
||||
"""
|
||||
assert P % 3 == 1 # The paper says P % 3 == 2 but that appears to be a mistake, see [10].
|
||||
assert C.j_invariant() == 0
|
||||
|
||||
t = C.trace_of_frobenius()
|
||||
|
||||
c = Integer(sqrt((4*P - t**2)/3))
|
||||
A1 = Integer((t - c)/2 - 1)
|
||||
B1 = c
|
||||
|
||||
A2 = Integer((t + c)/2 - 1)
|
||||
B2 = Integer(1 - (t - c)/2)
|
||||
|
||||
# We use a negated b values in secp256k1_scalar_split_lambda.
|
||||
B1, B2 = -B1, -B2
|
||||
|
||||
return A1, B1, A2, B2
|
||||
|
||||
A1, B1, A2, B2 = find_split_constants_explicit_tof()
|
||||
|
||||
# For extra fun, use an independent method to recompute the constants.
|
||||
assert (A1, B1, A2, B2) == find_split_constants_gauss()
|
||||
|
||||
# PHI : Z[l] -> Z_n where phi(a + b*l) == a + b*lambda mod n.
|
||||
def PHI(a,b):
|
||||
return Z(a + LAMBDA*b)
|
||||
|
||||
# Check that (A1, B1) and (A2, B2) are in the kernel of PHI.
|
||||
assert PHI(A1, B1) == Z(0)
|
||||
assert PHI(A2, B2) == Z(0)
|
||||
|
||||
# Check that the parallelogram generated by (A1, A2) and (B1, B2)
|
||||
# is a fundamental domain by containing exactly N points.
|
||||
# Since the LHS is the determinant and N != 0, this also checks that
|
||||
# (A1, A2) and (B1, B2) are linearly independent. By the previous
|
||||
# assertions, (A1, A2) and (B1, B2) are a basis of the kernel.
|
||||
assert A1*B2 - B1*A2 == N
|
||||
|
||||
# Check that their components are short enough.
|
||||
assert (A1 + A2)/2 < sqrt(N)
|
||||
assert B1 < sqrt(N)
|
||||
assert B2 < sqrt(N)
|
||||
|
||||
G1 = round((2**384)*B2/N)
|
||||
G2 = round((2**384)*(-B1)/N)
|
||||
|
||||
def rnddiv2(v):
|
||||
if v & 1:
|
||||
v += 1
|
||||
return v >> 1
|
||||
|
||||
def scalar_lambda_split(k):
|
||||
"""Equivalent to secp256k1_scalar_lambda_split()."""
|
||||
c1 = rnddiv2((k * G1) >> 383)
|
||||
c2 = rnddiv2((k * G2) >> 383)
|
||||
c1 = (c1 * -B1) % N
|
||||
c2 = (c2 * -B2) % N
|
||||
r2 = (c1 + c2) % N
|
||||
r1 = (k + r2 * -LAMBDA) % N
|
||||
return (r1, r2)
|
||||
|
||||
# The result of scalar_lambda_split can depend on the representation of k (mod n).
|
||||
SPECIAL = (2**383) // G2 + 1
|
||||
assert scalar_lambda_split(SPECIAL) != scalar_lambda_split(SPECIAL + N)
|
||||
|
||||
print(' A1 =', hex(A1))
|
||||
print(' -B1 =', hex(-B1))
|
||||
print(' A2 =', hex(A2))
|
||||
print(' -B2 =', hex(-B2))
|
||||
print(' =', hex(Z(-B2)))
|
||||
print(' -LAMBDA =', hex(-LAMBDA))
|
||||
|
||||
print(' G1 =', hex(G1))
|
||||
print(' G2 =', hex(G2))
|
||||
353
vendor/secp256k1/repo/sage/group_prover.sage
vendored
Normal file
353
vendor/secp256k1/repo/sage/group_prover.sage
vendored
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
# This code supports verifying group implementations which have branches
|
||||
# or conditional statements (like cmovs), by allowing each execution path
|
||||
# to independently set assumptions on input or intermediary variables.
|
||||
#
|
||||
# The general approach is:
|
||||
# * A constraint is a tuple of two sets of symbolic expressions:
|
||||
# the first of which are required to evaluate to zero, the second of which
|
||||
# are required to evaluate to nonzero.
|
||||
# - A constraint is said to be conflicting if any of its nonzero expressions
|
||||
# is in the ideal with basis the zero expressions (in other words: when the
|
||||
# zero expressions imply that one of the nonzero expressions are zero).
|
||||
# * There is a list of laws that describe the intended behaviour, including
|
||||
# laws for addition and doubling. Each law is called with the symbolic point
|
||||
# coordinates as arguments, and returns:
|
||||
# - A constraint describing the assumptions under which it is applicable,
|
||||
# called "assumeLaw"
|
||||
# - A constraint describing the requirements of the law, called "require"
|
||||
# * Implementations are transliterated into functions that operate as well on
|
||||
# algebraic input points, and are called once per combination of branches
|
||||
# executed. Each execution returns:
|
||||
# - A constraint describing the assumptions this implementation requires
|
||||
# (such as Z1=1), called "assumeFormula"
|
||||
# - A constraint describing the assumptions this specific branch requires,
|
||||
# but which is by construction guaranteed to cover the entire space by
|
||||
# merging the results from all branches, called "assumeBranch"
|
||||
# - The result of the computation
|
||||
# * All combinations of laws with implementation branches are tried, and:
|
||||
# - If the combination of assumeLaw, assumeFormula, and assumeBranch results
|
||||
# in a conflict, it means this law does not apply to this branch, and it is
|
||||
# skipped.
|
||||
# - For others, we try to prove the require constraints hold, assuming the
|
||||
# information in assumeLaw + assumeFormula + assumeBranch, and if this does
|
||||
# not succeed, we fail.
|
||||
# + To prove an expression is zero, we check whether it belongs to the
|
||||
# ideal with the assumed zero expressions as basis. This test is exact.
|
||||
# + To prove an expression is nonzero, we check whether each of its
|
||||
# factors is contained in the set of nonzero assumptions' factors.
|
||||
# This test is not exact, so various combinations of original and
|
||||
# reduced expressions' factors are tried.
|
||||
# - If we succeed, we print out the assumptions from assumeFormula that
|
||||
# weren't implied by assumeLaw already. Those from assumeBranch are skipped,
|
||||
# as we assume that all constraints in it are complementary with each other.
|
||||
#
|
||||
# Based on the sage verification scripts used in the Explicit-Formulas Database
|
||||
# by Tanja Lange and others, see https://hyperelliptic.org/EFD
|
||||
|
||||
class fastfrac:
|
||||
"""Fractions over rings."""
|
||||
|
||||
def __init__(self,R,top,bot=1):
|
||||
"""Construct a fractional, given a ring, a numerator, and denominator."""
|
||||
self.R = R
|
||||
if parent(top) == ZZ or parent(top) == R:
|
||||
self.top = R(top)
|
||||
self.bot = R(bot)
|
||||
elif top.__class__ == fastfrac:
|
||||
self.top = top.top
|
||||
self.bot = top.bot * bot
|
||||
else:
|
||||
self.top = R(numerator(top))
|
||||
self.bot = R(denominator(top)) * bot
|
||||
|
||||
def iszero(self,I):
|
||||
"""Return whether this fraction is zero given an ideal."""
|
||||
return self.top in I and self.bot not in I
|
||||
|
||||
def reduce(self,assumeZero):
|
||||
zero = self.R.ideal(list(map(numerator, assumeZero)))
|
||||
return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot))
|
||||
|
||||
def __add__(self,other):
|
||||
"""Add two fractions."""
|
||||
if parent(other) == ZZ:
|
||||
return fastfrac(self.R,self.top + self.bot * other,self.bot)
|
||||
if other.__class__ == fastfrac:
|
||||
return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot)
|
||||
return NotImplemented
|
||||
|
||||
def __sub__(self,other):
|
||||
"""Subtract two fractions."""
|
||||
if parent(other) == ZZ:
|
||||
return fastfrac(self.R,self.top - self.bot * other,self.bot)
|
||||
if other.__class__ == fastfrac:
|
||||
return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot)
|
||||
return NotImplemented
|
||||
|
||||
def __neg__(self):
|
||||
"""Return the negation of a fraction."""
|
||||
return fastfrac(self.R,-self.top,self.bot)
|
||||
|
||||
def __mul__(self,other):
|
||||
"""Multiply two fractions."""
|
||||
if parent(other) == ZZ:
|
||||
return fastfrac(self.R,self.top * other,self.bot)
|
||||
if other.__class__ == fastfrac:
|
||||
return fastfrac(self.R,self.top * other.top,self.bot * other.bot)
|
||||
return NotImplemented
|
||||
|
||||
def __rmul__(self,other):
|
||||
"""Multiply something else with a fraction."""
|
||||
return self.__mul__(other)
|
||||
|
||||
def __truediv__(self,other):
|
||||
"""Divide two fractions."""
|
||||
if parent(other) == ZZ:
|
||||
return fastfrac(self.R,self.top,self.bot * other)
|
||||
if other.__class__ == fastfrac:
|
||||
return fastfrac(self.R,self.top * other.bot,self.bot * other.top)
|
||||
return NotImplemented
|
||||
|
||||
# Compatibility wrapper for Sage versions based on Python 2
|
||||
def __div__(self,other):
|
||||
"""Divide two fractions."""
|
||||
return self.__truediv__(other)
|
||||
|
||||
def __pow__(self,other):
|
||||
"""Compute a power of a fraction."""
|
||||
if parent(other) == ZZ:
|
||||
if other < 0:
|
||||
# Negative powers require flipping top and bottom
|
||||
return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other))
|
||||
else:
|
||||
return fastfrac(self.R,self.top ^ other,self.bot ^ other)
|
||||
return NotImplemented
|
||||
|
||||
def __str__(self):
|
||||
return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))"
|
||||
def __repr__(self):
|
||||
return "%s" % self
|
||||
|
||||
def numerator(self):
|
||||
return self.top
|
||||
|
||||
class constraints:
|
||||
"""A set of constraints, consisting of zero and nonzero expressions.
|
||||
|
||||
Constraints can either be used to express knowledge or a requirement.
|
||||
|
||||
Both the fields zero and nonzero are maps from expressions to description
|
||||
strings. The expressions that are the keys in zero are required to be zero,
|
||||
and the expressions that are the keys in nonzero are required to be nonzero.
|
||||
|
||||
Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in
|
||||
nonzero could be multiplied into a single key. This is often much less
|
||||
efficient to work with though, so we keep them separate inside the
|
||||
constraints. This allows higher-level code to do fast checks on the individual
|
||||
nonzero elements, or combine them if needed for stronger checks.
|
||||
|
||||
We can't multiply the different zero elements, as it would suffice for one of
|
||||
the factors to be zero, instead of all of them. Instead, the zero elements are
|
||||
typically combined into an ideal first.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
if 'zero' in kwargs:
|
||||
self.zero = dict(kwargs['zero'])
|
||||
else:
|
||||
self.zero = dict()
|
||||
if 'nonzero' in kwargs:
|
||||
self.nonzero = dict(kwargs['nonzero'])
|
||||
else:
|
||||
self.nonzero = dict()
|
||||
|
||||
def negate(self):
|
||||
return constraints(zero=self.nonzero, nonzero=self.zero)
|
||||
|
||||
def map(self, fun):
|
||||
return constraints(zero={fun(k): v for k, v in self.zero.items()}, nonzero={fun(k): v for k, v in self.nonzero.items()})
|
||||
|
||||
def __add__(self, other):
|
||||
zero = self.zero.copy()
|
||||
zero.update(other.zero)
|
||||
nonzero = self.nonzero.copy()
|
||||
nonzero.update(other.nonzero)
|
||||
return constraints(zero=zero, nonzero=nonzero)
|
||||
|
||||
def __str__(self):
|
||||
return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero)
|
||||
|
||||
def __repr__(self):
|
||||
return "%s" % self
|
||||
|
||||
def normalize_factor(p):
|
||||
"""Normalizes the sign of primitive polynomials (as returned by factor())
|
||||
|
||||
This function ensures that the polynomial has a positive leading coefficient.
|
||||
|
||||
This is necessary because recent sage versions (starting with v9.3 or v9.4,
|
||||
we don't know) are inconsistent about the placement of the minus sign in
|
||||
polynomial factorizations:
|
||||
```
|
||||
sage: R.<ax,bx,ay,by,Az,Bz,Ai,Bi> = PolynomialRing(QQ,8,order='invlex')
|
||||
sage: R((-2 * (bx - ax)) ^ 1).factor()
|
||||
(-2) * (bx - ax)
|
||||
sage: R((-2 * (bx - ax)) ^ 2).factor()
|
||||
(4) * (-bx + ax)^2
|
||||
sage: R((-2 * (bx - ax)) ^ 3).factor()
|
||||
(8) * (-bx + ax)^3
|
||||
```
|
||||
"""
|
||||
# Assert p is not 0 and that its non-zero coeffients are coprime.
|
||||
# (We could just work with the primitive part p/p.content() but we want to be
|
||||
# aware if factor() does not return a primitive part in future sage versions.)
|
||||
assert p.content() == 1
|
||||
# Ensure that the first non-zero coefficient is positive.
|
||||
return p if p.lc() > 0 else -p
|
||||
|
||||
def conflicts(R, con):
|
||||
"""Check whether any of the passed non-zero assumptions is implied by the zero assumptions"""
|
||||
zero = R.ideal(list(map(numerator, con.zero)))
|
||||
if 1 in zero:
|
||||
return True
|
||||
# First a cheap check whether any of the individual nonzero terms conflict on
|
||||
# their own.
|
||||
for nonzero in con.nonzero:
|
||||
if nonzero.iszero(zero):
|
||||
return True
|
||||
# It can be the case that entries in the nonzero set do not individually
|
||||
# conflict with the zero set, but their combination does. For example, knowing
|
||||
# that either x or y is zero is equivalent to having x*y in the zero set.
|
||||
# Having x or y individually in the nonzero set is not a conflict, but both
|
||||
# simultaneously is, so that is the right thing to check for.
|
||||
if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def get_nonzero_set(R, assume):
|
||||
"""Calculate a simple set of nonzero expressions"""
|
||||
zero = R.ideal(list(map(numerator, assume.zero)))
|
||||
nonzero = set()
|
||||
for nz in map(numerator, assume.nonzero):
|
||||
for (f,n) in nz.factor():
|
||||
nonzero.add(normalize_factor(f))
|
||||
rnz = zero.reduce(nz)
|
||||
for (f,n) in rnz.factor():
|
||||
nonzero.add(normalize_factor(f))
|
||||
return nonzero
|
||||
|
||||
|
||||
def prove_nonzero(R, exprs, assume):
|
||||
"""Check whether an expression is provably nonzero, given assumptions"""
|
||||
zero = R.ideal(list(map(numerator, assume.zero)))
|
||||
nonzero = get_nonzero_set(R, assume)
|
||||
expl = set()
|
||||
ok = True
|
||||
for expr in exprs:
|
||||
if numerator(expr) in zero:
|
||||
return (False, [exprs[expr]])
|
||||
allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1)
|
||||
for (f, n) in allexprs.factor():
|
||||
if normalize_factor(f) not in nonzero:
|
||||
ok = False
|
||||
if ok:
|
||||
return (True, None)
|
||||
ok = True
|
||||
for (f, n) in zero.reduce(allexprs).factor():
|
||||
if normalize_factor(f) not in nonzero:
|
||||
ok = False
|
||||
if ok:
|
||||
return (True, None)
|
||||
ok = True
|
||||
for expr in exprs:
|
||||
for (f,n) in numerator(expr).factor():
|
||||
if normalize_factor(f) not in nonzero:
|
||||
ok = False
|
||||
if ok:
|
||||
return (True, None)
|
||||
ok = True
|
||||
for expr in exprs:
|
||||
for (f,n) in zero.reduce(numerator(expr)).factor():
|
||||
if normalize_factor(f) not in nonzero:
|
||||
expl.add(exprs[expr])
|
||||
if expl:
|
||||
return (False, list(expl))
|
||||
else:
|
||||
return (True, None)
|
||||
|
||||
|
||||
def prove_zero(R, exprs, assume):
|
||||
"""Check whether all of the passed expressions are provably zero, given assumptions"""
|
||||
r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume)
|
||||
if not r:
|
||||
return (False, list(map(lambda x: "Possibly zero denominator: %s" % x, e)))
|
||||
zero = R.ideal(list(map(numerator, assume.zero)))
|
||||
nonzero = prod(x for x in assume.nonzero)
|
||||
expl = []
|
||||
for expr in exprs:
|
||||
if not expr.iszero(zero):
|
||||
expl.append(exprs[expr])
|
||||
if not expl:
|
||||
return (True, None)
|
||||
return (False, expl)
|
||||
|
||||
|
||||
def describe_extra(R, assume, assumeExtra):
|
||||
"""Describe what assumptions are added, given existing assumptions"""
|
||||
zerox = assume.zero.copy()
|
||||
zerox.update(assumeExtra.zero)
|
||||
zero = R.ideal(list(map(numerator, assume.zero)))
|
||||
zeroextra = R.ideal(list(map(numerator, zerox)))
|
||||
nonzero = get_nonzero_set(R, assume)
|
||||
ret = set()
|
||||
# Iterate over the extra zero expressions
|
||||
for base in assumeExtra.zero:
|
||||
if base not in zero:
|
||||
add = []
|
||||
for (f, n) in numerator(base).factor():
|
||||
if normalize_factor(f) not in nonzero:
|
||||
add += ["%s" % normalize_factor(f)]
|
||||
if add:
|
||||
ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base])
|
||||
# Iterate over the extra nonzero expressions
|
||||
for nz in assumeExtra.nonzero:
|
||||
nzr = zeroextra.reduce(numerator(nz))
|
||||
if nzr not in zeroextra:
|
||||
for (f,n) in nzr.factor():
|
||||
if normalize_factor(zeroextra.reduce(f)) not in nonzero:
|
||||
ret.add("%s != 0" % normalize_factor(zeroextra.reduce(f)))
|
||||
return ", ".join(x for x in ret)
|
||||
|
||||
|
||||
def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require):
|
||||
"""Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions"""
|
||||
assume = assumeLaw + assumeAssert + assumeBranch
|
||||
|
||||
if conflicts(R, assume):
|
||||
# This formula does not apply
|
||||
return (True, None)
|
||||
|
||||
describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert)
|
||||
if describe != "":
|
||||
describe = " (assuming " + describe + ")"
|
||||
|
||||
ok, msg = prove_zero(R, require.zero, assume)
|
||||
if not ok:
|
||||
return (False, "FAIL, %s fails%s" % (str(msg), describe))
|
||||
|
||||
res, expl = prove_nonzero(R, require.nonzero, assume)
|
||||
if not res:
|
||||
return (False, "FAIL, %s fails%s" % (str(expl), describe))
|
||||
|
||||
return (True, "OK%s" % describe)
|
||||
|
||||
|
||||
def concrete_verify(c):
|
||||
for k in c.zero:
|
||||
if k != 0:
|
||||
return (False, c.zero[k])
|
||||
for k in c.nonzero:
|
||||
if k == 0:
|
||||
return (False, c.nonzero[k])
|
||||
return (True, None)
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue