mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-04 11:15:56 +00:00
Compare commits
58 Commits
415a412d42
...
q73zhao/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2751498cea | ||
|
|
c4d9635f22 | ||
|
|
8f6208eb66 | ||
|
|
efa1255386 | ||
|
|
6e198078a9 | ||
|
|
8d55192f0c | ||
|
|
2de83f36ae | ||
|
|
87ba6ba2d8 | ||
|
|
51f427c4e8 | ||
|
|
6a3c6dd8a3 | ||
|
|
f82b56605e | ||
|
|
aa0aa44cf4 | ||
|
|
4a1ef3d42f | ||
|
|
87b13184b1 | ||
|
|
cdae348a4b | ||
|
|
b7057b5fba | ||
|
|
e96fb0ce55 | ||
|
|
359565b377 | ||
|
|
0376c7af60 | ||
|
|
f5dac74afb | ||
|
|
c92bd4a817 | ||
|
|
6b16569273 | ||
|
|
7fdfbc7b87 | ||
|
|
463e62e64b | ||
|
|
ffc88d703b | ||
|
|
0613024aac | ||
|
|
b991d24070 | ||
|
|
f3d39ec680 | ||
|
|
1d0acf1490 | ||
|
|
a331a172c6 | ||
|
|
1a341cb9cb | ||
|
|
1b043fcc7b | ||
|
|
e742a6f9fc | ||
|
|
4d837884cf | ||
|
|
7f55b38377 | ||
|
|
cf96bd6058 | ||
|
|
1718790820 | ||
|
|
7c8ead9c3c | ||
|
|
6bc78370ba | ||
|
|
afc9a42ff5 | ||
|
|
090393930f | ||
|
|
c36daa7857 | ||
|
|
9069e430ad | ||
|
|
6c66b7448d | ||
|
|
1bb3c9db58 | ||
|
|
63cbd84487 | ||
|
|
f6d74d8c29 | ||
|
|
117306f8ae | ||
|
|
7717f08a05 | ||
|
|
0633844187 | ||
|
|
dc0608825b | ||
|
|
49f35dc4d5 | ||
|
|
8d78701c96 | ||
|
|
a1e3009bff | ||
|
|
8632aa8d3d | ||
|
|
984e489a56 | ||
|
|
adc30e6fff | ||
|
|
6704194941 |
2
.github/actions/build/action.yml
vendored
2
.github/actions/build/action.yml
vendored
@@ -20,6 +20,8 @@ runs:
|
||||
${{ inputs.generator && format('-G "{0}"', inputs.generator) || '' }} \
|
||||
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
|
||||
-DCMAKE_BUILD_TYPE=${{ inputs.configuration }} \
|
||||
-Dassert=TRUE \
|
||||
-Dwerr=TRUE \
|
||||
-Dtests=TRUE \
|
||||
-Dxrpld=TRUE \
|
||||
${{ inputs.cmake-args }} \
|
||||
|
||||
1
.github/actions/dependencies/action.yml
vendored
1
.github/actions/dependencies/action.yml
vendored
@@ -16,6 +16,7 @@ runs:
|
||||
conan export external/snappy snappy/1.1.10@
|
||||
conan export external/rocksdb rocksdb/6.29.5@
|
||||
conan export external/soci soci/4.0.3@
|
||||
conan export external/nudb nudb/2.0.8@
|
||||
- name: add Ripple Conan remote
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
96
.github/workflows/clang-format.yml
vendored
96
.github/workflows/clang-format.yml
vendored
@@ -8,52 +8,52 @@ jobs:
|
||||
env:
|
||||
CLANG_VERSION: 18
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install clang-format
|
||||
run: |
|
||||
codename=$( lsb_release --codename --short )
|
||||
sudo tee /etc/apt/sources.list.d/llvm.list >/dev/null <<EOF
|
||||
deb http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-${CLANG_VERSION} main
|
||||
deb-src http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-${CLANG_VERSION} main
|
||||
EOF
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-format-${CLANG_VERSION}
|
||||
- name: Format first-party sources
|
||||
run: find include src -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-${CLANG_VERSION} -i {} +
|
||||
- name: Check for differences
|
||||
id: assert
|
||||
run: |
|
||||
set -o pipefail
|
||||
git diff --exit-code | tee "clang-format.patch"
|
||||
- name: Upload patch
|
||||
if: failure() && steps.assert.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v3
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: clang-format.patch
|
||||
if-no-files-found: ignore
|
||||
path: clang-format.patch
|
||||
- name: What happened?
|
||||
if: failure() && steps.assert.outcome == 'failure'
|
||||
env:
|
||||
PREAMBLE: |
|
||||
If you are reading this, you are looking at a failed Github Actions
|
||||
job. That means you pushed one or more files that did not conform
|
||||
to the formatting specified in .clang-format. That may be because
|
||||
you neglected to run 'git clang-format' or 'clang-format' before
|
||||
committing, or that your version of clang-format has an
|
||||
incompatibility with the one on this
|
||||
machine, which is:
|
||||
SUGGESTION: |
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install clang-format
|
||||
run: |
|
||||
codename=$( lsb_release --codename --short )
|
||||
sudo tee /etc/apt/sources.list.d/llvm.list >/dev/null <<EOF
|
||||
deb http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-${CLANG_VERSION} main
|
||||
deb-src http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-${CLANG_VERSION} main
|
||||
EOF
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-format-${CLANG_VERSION}
|
||||
- name: Format first-party sources
|
||||
run: find include src -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-${CLANG_VERSION} -i {} +
|
||||
- name: Check for differences
|
||||
id: assert
|
||||
run: |
|
||||
set -o pipefail
|
||||
git diff --exit-code | tee "clang-format.patch"
|
||||
- name: Upload patch
|
||||
if: failure() && steps.assert.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v4
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: clang-format.patch
|
||||
if-no-files-found: ignore
|
||||
path: clang-format.patch
|
||||
- name: What happened?
|
||||
if: failure() && steps.assert.outcome == 'failure'
|
||||
env:
|
||||
PREAMBLE: |
|
||||
If you are reading this, you are looking at a failed Github Actions
|
||||
job. That means you pushed one or more files that did not conform
|
||||
to the formatting specified in .clang-format. That may be because
|
||||
you neglected to run 'git clang-format' or 'clang-format' before
|
||||
committing, or that your version of clang-format has an
|
||||
incompatibility with the one on this
|
||||
machine, which is:
|
||||
SUGGESTION: |
|
||||
|
||||
To fix it, you can do one of two things:
|
||||
1. Download and apply the patch generated as an artifact of this
|
||||
job to your repo, commit, and push.
|
||||
2. Run 'git-clang-format --extensions cpp,h,hpp,ipp develop'
|
||||
in your repo, commit, and push.
|
||||
run: |
|
||||
echo "${PREAMBLE}"
|
||||
clang-format-${CLANG_VERSION} --version
|
||||
echo "${SUGGESTION}"
|
||||
exit 1
|
||||
To fix it, you can do one of two things:
|
||||
1. Download and apply the patch generated as an artifact of this
|
||||
job to your repo, commit, and push.
|
||||
2. Run 'git-clang-format --extensions cpp,h,hpp,ipp develop'
|
||||
in your repo, commit, and push.
|
||||
run: |
|
||||
echo "${PREAMBLE}"
|
||||
clang-format-${CLANG_VERSION} --version
|
||||
echo "${SUGGESTION}"
|
||||
exit 1
|
||||
|
||||
72
.github/workflows/levelization.yml
vendored
72
.github/workflows/levelization.yml
vendored
@@ -8,42 +8,42 @@ jobs:
|
||||
env:
|
||||
CLANG_VERSION: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check levelization
|
||||
run: Builds/levelization/levelization.sh
|
||||
- name: Check for differences
|
||||
id: assert
|
||||
run: |
|
||||
set -o pipefail
|
||||
git diff --exit-code | tee "levelization.patch"
|
||||
- name: Upload patch
|
||||
if: failure() && steps.assert.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v3
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: levelization.patch
|
||||
if-no-files-found: ignore
|
||||
path: levelization.patch
|
||||
- name: What happened?
|
||||
if: failure() && steps.assert.outcome == 'failure'
|
||||
env:
|
||||
MESSAGE: |
|
||||
If you are reading this, you are looking at a failed Github
|
||||
Actions job. That means you changed the dependency relationships
|
||||
between the modules in rippled. That may be an improvement or a
|
||||
regression. This check doesn't judge.
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check levelization
|
||||
run: Builds/levelization/levelization.sh
|
||||
- name: Check for differences
|
||||
id: assert
|
||||
run: |
|
||||
set -o pipefail
|
||||
git diff --exit-code | tee "levelization.patch"
|
||||
- name: Upload patch
|
||||
if: failure() && steps.assert.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v4
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: levelization.patch
|
||||
if-no-files-found: ignore
|
||||
path: levelization.patch
|
||||
- name: What happened?
|
||||
if: failure() && steps.assert.outcome == 'failure'
|
||||
env:
|
||||
MESSAGE: |
|
||||
If you are reading this, you are looking at a failed Github
|
||||
Actions job. That means you changed the dependency relationships
|
||||
between the modules in rippled. That may be an improvement or a
|
||||
regression. This check doesn't judge.
|
||||
|
||||
A rule of thumb, though, is that if your changes caused
|
||||
something to be removed from loops.txt, that's probably an
|
||||
improvement. If something was added, it's probably a regression.
|
||||
A rule of thumb, though, is that if your changes caused
|
||||
something to be removed from loops.txt, that's probably an
|
||||
improvement. If something was added, it's probably a regression.
|
||||
|
||||
To fix it, you can do one of two things:
|
||||
1. Download and apply the patch generated as an artifact of this
|
||||
job to your repo, commit, and push.
|
||||
2. Run './Builds/levelization/levelization.sh' in your repo,
|
||||
commit, and push.
|
||||
To fix it, you can do one of two things:
|
||||
1. Download and apply the patch generated as an artifact of this
|
||||
job to your repo, commit, and push.
|
||||
2. Run './Builds/levelization/levelization.sh' in your repo,
|
||||
commit, and push.
|
||||
|
||||
See Builds/levelization/README.md for more info.
|
||||
run: |
|
||||
echo "${MESSAGE}"
|
||||
exit 1
|
||||
See Builds/levelization/README.md for more info.
|
||||
run: |
|
||||
echo "${MESSAGE}"
|
||||
exit 1
|
||||
|
||||
28
.github/workflows/macos.yml
vendored
28
.github/workflows/macos.yml
vendored
@@ -3,7 +3,7 @@ on:
|
||||
pull_request:
|
||||
push:
|
||||
# If the branches list is ever changed, be sure to change it on all
|
||||
# build/test jobs (nix, macos, windows)
|
||||
# build/test jobs (nix, macos, windows, instrumentation)
|
||||
branches:
|
||||
# Always build the package branches
|
||||
- develop
|
||||
@@ -41,6 +41,24 @@ jobs:
|
||||
- name: install Ninja
|
||||
if: matrix.generator == 'Ninja'
|
||||
run: brew install ninja
|
||||
- name: install python
|
||||
run: |
|
||||
if which python > /dev/null 2>&1; then
|
||||
echo "Python executable exists"
|
||||
else
|
||||
brew install python@3.13
|
||||
ln -s /opt/homebrew/bin/python3 /opt/homebrew/bin/python
|
||||
fi
|
||||
- name: install cmake
|
||||
run: |
|
||||
if which cmake > /dev/null 2>&1; then
|
||||
echo "cmake executable exists"
|
||||
else
|
||||
brew install cmake
|
||||
fi
|
||||
- name: install nproc
|
||||
run: |
|
||||
brew install coreutils
|
||||
- name: check environment
|
||||
run: |
|
||||
env | sort
|
||||
@@ -48,6 +66,9 @@ jobs:
|
||||
python --version
|
||||
conan --version
|
||||
cmake --version
|
||||
nproc --version
|
||||
echo -n "nproc returns: "
|
||||
nproc
|
||||
- name: configure Conan
|
||||
run : |
|
||||
conan profile new default --detect || true
|
||||
@@ -66,6 +87,9 @@ jobs:
|
||||
with:
|
||||
generator: ${{ matrix.generator }}
|
||||
configuration: ${{ matrix.configuration }}
|
||||
cmake-args: ${{ matrix.cmake-args }}
|
||||
- name: test
|
||||
run: |
|
||||
${build_dir}/rippled --unittest
|
||||
n=$(nproc)
|
||||
echo "Using $n test jobs"
|
||||
${build_dir}/rippled --unittest --unittest-jobs $n
|
||||
|
||||
60
.github/workflows/missing-commits.yml
vendored
Normal file
60
.github/workflows/missing-commits.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: missing-commits
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
# Only check that the branches are up to date when updating the
|
||||
# relevant branches.
|
||||
- develop
|
||||
- release
|
||||
|
||||
jobs:
|
||||
up_to_date:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Check for missing commits
|
||||
id: commits
|
||||
env:
|
||||
SUGGESTION: |
|
||||
|
||||
If you are reading this, then the commits indicated above are
|
||||
missing from "develop" and/or "release". Do a reverse-merge
|
||||
as soon as possible. See CONTRIBUTING.md for instructions.
|
||||
run: |
|
||||
set -o pipefail
|
||||
# Branches ordered by how "canonical" they are. Every commit in
|
||||
# one branch should be in all the branches behind it
|
||||
order=( master release develop )
|
||||
branches=()
|
||||
for branch in "${order[@]}"
|
||||
do
|
||||
# Check that the branches exist so that this job will work on
|
||||
# forked repos, which don't necessarily have master and
|
||||
# release branches.
|
||||
if git ls-remote --exit-code --heads origin \
|
||||
refs/heads/${branch} > /dev/null
|
||||
then
|
||||
branches+=( origin/${branch} )
|
||||
fi
|
||||
done
|
||||
|
||||
prior=()
|
||||
for branch in "${branches[@]}"
|
||||
do
|
||||
if [[ ${#prior[@]} -ne 0 ]]
|
||||
then
|
||||
echo "Checking ${prior[@]} for commits missing from ${branch}"
|
||||
git log --oneline --no-merges "${prior[@]}" \
|
||||
^$branch | tee -a "missing-commits.txt"
|
||||
echo
|
||||
fi
|
||||
prior+=( "${branch}" )
|
||||
done
|
||||
if [[ $( cat missing-commits.txt | wc -l ) -ne 0 ]]
|
||||
then
|
||||
echo "${SUGGESTION}"
|
||||
exit 1
|
||||
fi
|
||||
118
.github/workflows/nix.yml
vendored
118
.github/workflows/nix.yml
vendored
@@ -10,14 +10,14 @@ on:
|
||||
- release
|
||||
- master
|
||||
# Branches that opt-in to running
|
||||
- 'ci/**'
|
||||
- "ci/**"
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# This workflow has two job matrixes.
|
||||
# They can be considered phases because the second matrix ("test")
|
||||
# depends on the first ("dependencies").
|
||||
# This workflow has multiple job matrixes.
|
||||
# They can be considered phases because most of the matrices ("test",
|
||||
# "coverage", "conan", ) depend on the first ("dependencies").
|
||||
#
|
||||
# The first phase has a job in the matrix for each combination of
|
||||
# variables that affects dependency ABI:
|
||||
@@ -30,12 +30,14 @@ concurrency:
|
||||
# to hold the binaries if they are built locally.
|
||||
# We must use the "{upload,download}-artifact" actions instead.
|
||||
#
|
||||
# The second phase has a job in the matrix for each test configuration.
|
||||
# It installs dependency binaries from the cache, whichever was used,
|
||||
# and builds and tests rippled.
|
||||
# The remaining phases have a job in the matrix for each test
|
||||
# configuration. They install dependency binaries from the cache,
|
||||
# whichever was used, and build and test rippled.
|
||||
#
|
||||
# "instrumentation" is independent, but is included here because it also
|
||||
# builds on linux in the same "on:" conditions.
|
||||
|
||||
jobs:
|
||||
|
||||
dependencies:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -72,6 +74,8 @@ jobs:
|
||||
- name: check environment
|
||||
run: |
|
||||
echo ${PATH} | tr ':' '\n'
|
||||
lsb_release -a || true
|
||||
${{ matrix.profile.cc }} --version
|
||||
conan --version
|
||||
cmake --version
|
||||
env | sort
|
||||
@@ -97,13 +101,12 @@ jobs:
|
||||
with:
|
||||
configuration: ${{ matrix.configuration }}
|
||||
- name: upload archive
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }}
|
||||
path: conan.tar
|
||||
if-no-files-found: error
|
||||
|
||||
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -129,7 +132,7 @@ jobs:
|
||||
run: |
|
||||
pip install --upgrade "conan<2"
|
||||
- name: download cache
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }}
|
||||
- name: extract cache
|
||||
@@ -160,7 +163,6 @@ jobs:
|
||||
run: |
|
||||
${build_dir}/rippled --unittest --unittest-jobs $(nproc)
|
||||
|
||||
|
||||
coverage:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -181,7 +183,7 @@ jobs:
|
||||
run: |
|
||||
pip install --upgrade "conan<2"
|
||||
- name: download cache
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }}
|
||||
- name: extract cache
|
||||
@@ -223,7 +225,7 @@ jobs:
|
||||
run: |
|
||||
mv "${build_dir}/coverage.xml" ./
|
||||
- name: archive coverage report
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage.xml
|
||||
path: coverage.xml
|
||||
@@ -254,7 +256,7 @@ jobs:
|
||||
run: |
|
||||
pip install --upgrade "conan<2"
|
||||
- name: download cache
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: linux-gcc-${{ env.configuration }}
|
||||
- name: extract cache
|
||||
@@ -294,3 +296,89 @@ jobs:
|
||||
-DCMAKE_BUILD_TYPE=${configuration}
|
||||
cmake --build .
|
||||
./example | grep '^[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+'
|
||||
|
||||
# NOTE we are not using dependencies built above because it lags with
|
||||
# compiler versions. Instrumentation requires clang version 16 or
|
||||
# later
|
||||
|
||||
instrumentation-build:
|
||||
env:
|
||||
CLANG_RELEASE: 16
|
||||
strategy:
|
||||
fail-fast: false
|
||||
runs-on: [self-hosted, heavy]
|
||||
container: debian:bookworm
|
||||
steps:
|
||||
- name: install prerequisites
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install --yes --no-install-recommends \
|
||||
clang-${CLANG_RELEASE} clang++-${CLANG_RELEASE} \
|
||||
python3-pip python-is-python3 make cmake git wget
|
||||
apt-get clean
|
||||
update-alternatives --install \
|
||||
/usr/bin/clang clang /usr/bin/clang-${CLANG_RELEASE} 100 \
|
||||
--slave /usr/bin/clang++ clang++ /usr/bin/clang++-${CLANG_RELEASE}
|
||||
update-alternatives --auto clang
|
||||
pip install --no-cache --break-system-packages "conan<2"
|
||||
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: prepare environment
|
||||
run: |
|
||||
mkdir ${GITHUB_WORKSPACE}/.build
|
||||
echo "SOURCE_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
||||
echo "BUILD_DIR=$GITHUB_WORKSPACE/.build" >> $GITHUB_ENV
|
||||
echo "CC=/usr/bin/clang" >> $GITHUB_ENV
|
||||
echo "CXX=/usr/bin/clang++" >> $GITHUB_ENV
|
||||
|
||||
- name: configure Conan
|
||||
run: |
|
||||
conan profile new --detect default
|
||||
conan profile update settings.compiler=clang default
|
||||
conan profile update settings.compiler.version=${CLANG_RELEASE} default
|
||||
conan profile update settings.compiler.libcxx=libstdc++11 default
|
||||
conan profile update settings.compiler.cppstd=20 default
|
||||
conan profile update options.rocksdb=False default
|
||||
conan profile update \
|
||||
'conf.tools.build:compiler_executables={"c": "/usr/bin/clang", "cpp": "/usr/bin/clang++"}' default
|
||||
conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_DISABLE_CONCEPTS"' default
|
||||
conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_DISABLE_CONCEPTS"]' default
|
||||
conan export external/snappy snappy/1.1.10@
|
||||
conan export external/soci soci/4.0.3@
|
||||
|
||||
- name: build dependencies
|
||||
run: |
|
||||
cd ${BUILD_DIR}
|
||||
conan install ${SOURCE_DIR} \
|
||||
--output-folder ${BUILD_DIR} \
|
||||
--install-folder ${BUILD_DIR} \
|
||||
--build missing \
|
||||
--settings build_type=Debug
|
||||
|
||||
- name: build with instrumentation
|
||||
run: |
|
||||
cd ${BUILD_DIR}
|
||||
cmake -S ${SOURCE_DIR} -B ${BUILD_DIR} \
|
||||
-Dvoidstar=ON \
|
||||
-Dtests=ON \
|
||||
-Dxrpld=ON \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DSECP256K1_BUILD_BENCHMARK=OFF \
|
||||
-DSECP256K1_BUILD_TESTS=OFF \
|
||||
-DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${BUILD_DIR}/build/generators/conan_toolchain.cmake
|
||||
cmake --build . --parallel $(nproc)
|
||||
|
||||
- name: verify instrumentation enabled
|
||||
run: |
|
||||
cd ${BUILD_DIR}
|
||||
./rippled --version | grep libvoidstar
|
||||
|
||||
- name: run unit tests
|
||||
run: |
|
||||
cd ${BUILD_DIR}
|
||||
./rippled -u --unittest-jobs $(( $(nproc)/4 ))
|
||||
|
||||
36
.github/workflows/windows.yml
vendored
36
.github/workflows/windows.yml
vendored
@@ -4,7 +4,7 @@ on:
|
||||
pull_request:
|
||||
push:
|
||||
# If the branches list is ever changed, be sure to change it on all
|
||||
# build/test jobs (nix, macos, windows)
|
||||
# build/test jobs (nix, macos, windows, instrumentation)
|
||||
branches:
|
||||
# Always build the package branches
|
||||
- develop
|
||||
@@ -24,16 +24,18 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
generator:
|
||||
- Visual Studio 16 2019
|
||||
version:
|
||||
- generator: Visual Studio 17 2022
|
||||
runs-on: windows-2022
|
||||
configuration:
|
||||
- Release
|
||||
# Github hosted runners tend to hang when running Debug unit tests.
|
||||
# Instead of trying to work around it, disable the Debug job until
|
||||
# something beefier (i.e. a heavy self-hosted runner) becomes
|
||||
# available.
|
||||
# - Debug
|
||||
runs-on: windows-2019
|
||||
- type: Release
|
||||
tests: true
|
||||
- type: Debug
|
||||
# Skip running unit tests on debug builds, because they
|
||||
# take an unreasonable amount of time
|
||||
tests: false
|
||||
runtime: d
|
||||
runs-on: ${{ matrix.version.runs-on }}
|
||||
env:
|
||||
build_dir: .build
|
||||
steps:
|
||||
@@ -68,7 +70,9 @@ jobs:
|
||||
run: |
|
||||
conan profile new default --detect
|
||||
conan profile update settings.compiler.cppstd=20 default
|
||||
conan profile update settings.compiler.runtime=MT${{ matrix.configuration == 'Debug' && 'd' || '' }} default
|
||||
conan profile update \
|
||||
settings.compiler.runtime=MT${{ matrix.configuration.runtime }} \
|
||||
default
|
||||
- name: build dependencies
|
||||
uses: ./.github/actions/dependencies
|
||||
env:
|
||||
@@ -76,16 +80,18 @@ jobs:
|
||||
CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }}
|
||||
CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }}
|
||||
with:
|
||||
configuration: ${{ matrix.configuration }}
|
||||
configuration: ${{ matrix.configuration.type }}
|
||||
- name: build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
generator: '${{ matrix.generator }}'
|
||||
configuration: ${{ matrix.configuration }}
|
||||
generator: '${{ matrix.version.generator }}'
|
||||
configuration: ${{ matrix.configuration.type }}
|
||||
# Hard code for now. Move to the matrix if varied options are needed
|
||||
cmake-args: '-Dassert=ON -Dreporting=OFF -Dunity=ON'
|
||||
cmake-target: install
|
||||
- name: test
|
||||
shell: bash
|
||||
if: ${{ matrix.configuration.tests }}
|
||||
run: |
|
||||
${build_dir}/${{ matrix.configuration }}/rippled --unittest --unittest-jobs $(nproc)
|
||||
${build_dir}/${{ matrix.configuration.type }}/rippled --unittest \
|
||||
--unittest-jobs $(nproc)
|
||||
|
||||
@@ -83,28 +83,52 @@ The [commandline](https://xrpl.org/docs/references/http-websocket-apis/api-conve
|
||||
|
||||
The `network_id` field was added in the `server_info` response in version 1.5.0 (2019), but it is not returned in [reporting mode](https://xrpl.org/rippled-server-modes.html#reporting-mode). However, use of reporting mode is now discouraged, in favor of using [Clio](https://github.com/XRPLF/clio) instead.
|
||||
|
||||
## XRP Ledger server version 2.2.0
|
||||
## XRP Ledger server version 2.4.0
|
||||
|
||||
The following is a non-breaking addition to the API.
|
||||
As of 2025-01-28, version 2.4.0 is in development. You can use a pre-release version by building from source or [using the `nightly` package](https://xrpl.org/docs/infrastructure/installation/install-rippled-on-ubuntu).
|
||||
|
||||
- The `feature` method now has a non-admin mode for users. (It was previously only available to admin connections.) The method returns an updated list of amendments, including their names and other information. ([#4781](https://github.com/XRPLF/rippled/pull/4781))
|
||||
### Additions and bugfixes in 2.4.0
|
||||
|
||||
### Breaking change in 2.3
|
||||
- `ledger_entry`: `state` is added an alias for `ripple_state`.
|
||||
- `ledger_entry`: Enables case-insensitive filtering by canonical name in addition to case-sensitive filtering by RPC name.
|
||||
- `validators`: Added new field `validator_list_threshold` in response.
|
||||
- `simulate`: A new RPC that executes a [dry run of a transaction submission](https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0069d-simulate#2-rpc-simulate)
|
||||
- Signing methods autofill fees better and properly handle transactions that don't have a base fee, and will also autofill the `NetworkID` field.
|
||||
|
||||
## XRP Ledger server version 2.3.0
|
||||
|
||||
[Version 2.3.0](https://github.com/XRPLF/rippled/releases/tag/2.3.0) was released on Nov 25, 2024.
|
||||
|
||||
### Breaking changes in 2.3.0
|
||||
|
||||
- `book_changes`: If the requested ledger version is not available on this node, a `ledgerNotFound` error is returned and the node does not attempt to acquire the ledger from the p2p network (as with other non-admin RPCs).
|
||||
|
||||
Admins can still attempt to retrieve old ledgers with the `ledger_request` RPC.
|
||||
|
||||
### Addition in 2.3
|
||||
### Additions and bugfixes in 2.3.0
|
||||
|
||||
- `book_changes`: Returns a `validated` field in its response, which was missing in prior versions.
|
||||
|
||||
The following additions are non-breaking (because they are purely additive).
|
||||
## XRP Ledger server version 2.2.0
|
||||
|
||||
[Version 2.2.0](https://github.com/XRPLF/rippled/releases/tag/2.2.0) was released on Jun 5, 2024. The following additions are non-breaking (because they are purely additive):
|
||||
|
||||
- The `feature` method now has a non-admin mode for users. (It was previously only available to admin connections.) The method returns an updated list of amendments, including their names and other information. ([#4781](https://github.com/XRPLF/rippled/pull/4781))
|
||||
|
||||
## XRP Ledger server version 2.0.0
|
||||
|
||||
[Version 2.0.0](https://github.com/XRPLF/rippled/releases/tag/2.0.0) was released on Jan 9, 2024. The following additions are non-breaking (because they are purely additive):
|
||||
|
||||
- `server_definitions`: A new RPC that generates a `definitions.json`-like output that can be used in XRPL libraries.
|
||||
- In `Payment` transactions, `DeliverMax` has been added. This is a replacement for the `Amount` field, which should not be used. Typically, the `delivered_amount` (in transaction metadata) should be used. To ease the transition, `DeliverMax` is present regardless of API version, since adding a field is non-breaking.
|
||||
- API version 2 has been moved from beta to supported, meaning that it is generally available (regardless of the `beta_rpc_api` setting).
|
||||
|
||||
## XRP Ledger server version 2.2.0
|
||||
|
||||
The following is a non-breaking addition to the API.
|
||||
|
||||
- The `feature` method now has a non-admin mode for users. (It was previously only available to admin connections.) The method returns an updated list of amendments, including their names and other information. ([#4781](https://github.com/XRPLF/rippled/pull/4781))
|
||||
|
||||
## XRP Ledger server version 1.12.0
|
||||
|
||||
[Version 1.12.0](https://github.com/XRPLF/rippled/releases/tag/1.12.0) was released on Sep 6, 2023. The following additions are non-breaking (because they are purely additive).
|
||||
|
||||
34
BUILD.md
34
BUILD.md
@@ -222,13 +222,15 @@ It fixes some source files to add missing `#include`s.
|
||||
the `install-folder` or `-if` option to every `conan install` command
|
||||
in the next step.
|
||||
|
||||
2. Generate CMake files for every configuration you want to build.
|
||||
2. Use conan to generate CMake files for every configuration you want to build:
|
||||
|
||||
```
|
||||
conan install .. --output-folder . --build missing --settings build_type=Release
|
||||
conan install .. --output-folder . --build missing --settings build_type=Debug
|
||||
```
|
||||
|
||||
To build Debug, in the next step, be sure to set `-DCMAKE_BUILD_TYPE=Debug`
|
||||
|
||||
For a single-configuration generator, e.g. `Unix Makefiles` or `Ninja`,
|
||||
you only need to run this command once.
|
||||
For a multi-configuration generator, e.g. `Visual Studio`, you may want to
|
||||
@@ -258,13 +260,16 @@ It fixes some source files to add missing `#include`s.
|
||||
|
||||
Single-config generators:
|
||||
|
||||
Pass the CMake variable [`CMAKE_BUILD_TYPE`][build_type]
|
||||
and make sure it matches the one of the `build_type` settings
|
||||
you chose in the previous step.
|
||||
|
||||
For example, to build Debug, in the next command, replace "Release" with "Debug"
|
||||
|
||||
```
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release -Dxrpld=ON -Dtests=ON ..
|
||||
```
|
||||
|
||||
Pass the CMake variable [`CMAKE_BUILD_TYPE`][build_type]
|
||||
and make sure it matches the `build_type` setting you chose in the previous
|
||||
step.
|
||||
|
||||
Multi-config generators:
|
||||
|
||||
@@ -274,7 +279,7 @@ It fixes some source files to add missing `#include`s.
|
||||
|
||||
**Note:** You can pass build options for `rippled` in this step.
|
||||
|
||||
4. Build `rippled`.
|
||||
5. Build `rippled`.
|
||||
|
||||
For a single-configuration generator, it will build whatever configuration
|
||||
you passed for `CMAKE_BUILD_TYPE`. For a multi-configuration generator,
|
||||
@@ -293,7 +298,7 @@ It fixes some source files to add missing `#include`s.
|
||||
cmake --build . --config Debug
|
||||
```
|
||||
|
||||
5. Test rippled.
|
||||
6. Test rippled.
|
||||
|
||||
Single-config generators:
|
||||
|
||||
@@ -403,6 +408,23 @@ After any updates or changes to dependencies, you may need to do the following:
|
||||
4. Re-run [conan install](#build-and-test).
|
||||
|
||||
|
||||
### 'protobuf/port_def.inc' file not found
|
||||
|
||||
If `cmake --build .` results in an error due to a missing a protobuf file, then you might have generated CMake files for a different `build_type` than the `CMAKE_BUILD_TYPE` you passed to conan.
|
||||
|
||||
```
|
||||
/rippled/.build/pb-xrpl.libpb/xrpl/proto/ripple.pb.h:10:10: fatal error: 'google/protobuf/port_def.inc' file not found
|
||||
10 | #include <google/protobuf/port_def.inc>
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
1 error generated.
|
||||
```
|
||||
|
||||
For example, if you want to build Debug:
|
||||
|
||||
1. For conan install, pass `--settings build_type=Debug`
|
||||
2. For cmake, pass `-DCMAKE_BUILD_TYPE=Debug`
|
||||
|
||||
|
||||
### no std::result_of
|
||||
|
||||
If your compiler version is recent enough to have removed `std::result_of` as
|
||||
|
||||
@@ -21,7 +21,7 @@ mkdir results
|
||||
includes="$( pwd )/results/rawincludes.txt"
|
||||
pushd ../..
|
||||
echo Raw includes:
|
||||
grep -r '#include.*/.*\.h' include src | \
|
||||
grep -r '^[ ]*#include.*/.*\.h' include src | \
|
||||
grep -v boost | tee ${includes}
|
||||
popd
|
||||
pushd results
|
||||
|
||||
@@ -4,9 +4,6 @@ Loop: test.jtx test.toplevel
|
||||
Loop: test.jtx test.unit_test
|
||||
test.unit_test == test.jtx
|
||||
|
||||
Loop: xrpl.basics xrpl.json
|
||||
xrpl.json == xrpl.basics
|
||||
|
||||
Loop: xrpld.app xrpld.core
|
||||
xrpld.app > xrpld.core
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
libxrpl.basics > xrpl.basics
|
||||
libxrpl.basics > xrpl.protocol
|
||||
libxrpl.crypto > xrpl.basics
|
||||
libxrpl.json > xrpl.basics
|
||||
libxrpl.json > xrpl.json
|
||||
@@ -20,6 +19,7 @@ test.app > xrpl.basics
|
||||
test.app > xrpld.app
|
||||
test.app > xrpld.core
|
||||
test.app > xrpld.ledger
|
||||
test.app > xrpld.nodestore
|
||||
test.app > xrpld.overlay
|
||||
test.app > xrpld.rpc
|
||||
test.app > xrpl.json
|
||||
@@ -131,6 +131,7 @@ test.shamap > xrpl.protocol
|
||||
test.toplevel > test.csf
|
||||
test.toplevel > xrpl.json
|
||||
test.unit_test > xrpl.basics
|
||||
xrpl.json > xrpl.basics
|
||||
xrpl.protocol > xrpl.basics
|
||||
xrpl.protocol > xrpl.json
|
||||
xrpl.resource > xrpl.basics
|
||||
|
||||
@@ -19,13 +19,21 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
# make GIT_COMMIT_HASH define available to all sources
|
||||
find_package(Git)
|
||||
if(Git_FOUND)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git describe --always --abbrev=40
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse HEAD
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gch)
|
||||
if(gch)
|
||||
set(GIT_COMMIT_HASH "${gch}")
|
||||
message(STATUS gch: ${GIT_COMMIT_HASH})
|
||||
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git rev-parse --abbrev-ref HEAD
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE gb)
|
||||
if(gb)
|
||||
set(GIT_BRANCH "${gb}")
|
||||
message(STATUS gb: ${GIT_BRANCH})
|
||||
add_definitions(-DGIT_BRANCH="${GIT_BRANCH}")
|
||||
endif()
|
||||
endif() #git
|
||||
|
||||
if(thread_safety_analysis)
|
||||
@@ -73,6 +81,7 @@ set(SECP256K1_INSTALL TRUE)
|
||||
add_subdirectory(external/secp256k1)
|
||||
add_library(secp256k1::secp256k1 ALIAS secp256k1)
|
||||
add_subdirectory(external/ed25519-donna)
|
||||
add_subdirectory(external/antithesis-sdk)
|
||||
find_package(gRPC REQUIRED)
|
||||
find_package(lz4 REQUIRED)
|
||||
# Target names with :: are not allowed in a generator expression.
|
||||
|
||||
875
CONTRIBUTING.md
875
CONTRIBUTING.md
@@ -5,15 +5,12 @@ XRPL.
|
||||
# Contributing
|
||||
|
||||
We assume you are familiar with the general practice of [making
|
||||
contributions on GitHub][1]. This file includes only special
|
||||
contributions on GitHub][contrib]. This file includes only special
|
||||
instructions specific to this project.
|
||||
|
||||
|
||||
## Before you start
|
||||
|
||||
In general, contributions should be developed in your personal
|
||||
[fork](https://github.com/XRPLF/rippled/fork).
|
||||
|
||||
The following branches exist in the main project repository:
|
||||
|
||||
- `develop`: The latest set of unreleased features, and the most common
|
||||
@@ -26,9 +23,20 @@ The tip of each branch must be signed. In order for GitHub to sign a
|
||||
squashed commit that it builds from your pull request, GitHub must know
|
||||
your verifying key. Please set up [signature verification][signing].
|
||||
|
||||
[rippled]: https://github.com/XRPLF/rippled
|
||||
[signing]:
|
||||
https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification
|
||||
In general, external contributions should be developed in your personal
|
||||
[fork][forking]. Contributions from developers with write permissions
|
||||
should be done in [the main repository][rippled] in a branch with
|
||||
a permitted prefix. Permitted prefixes are:
|
||||
* XLS-[a-zA-Z0-9]+/.+
|
||||
* e.g. XLS-0033d/mpt-clarify-STEitherAmount
|
||||
* [GitHub username]/.+
|
||||
* e.g. JoelKatz/fix-rpc-webhook-queue
|
||||
* [Organization name]/.+
|
||||
* e.g. ripple/antithesis
|
||||
|
||||
Regardless of where the branch is created, please open a *draft* pull
|
||||
request as soon as possible after pushing the branch to Github, to
|
||||
increase visibility, and ease feedback during the development process.
|
||||
|
||||
|
||||
## Major contributions
|
||||
@@ -49,6 +57,7 @@ author delegates that responsibility to others.
|
||||
|
||||
|
||||
## Before making a pull request
|
||||
(Or marking a draft pull request as ready.)
|
||||
|
||||
Changes that alter transaction processing must be guarded by an
|
||||
[Amendment](https://xrpl.org/amendments.html).
|
||||
@@ -57,18 +66,19 @@ Amendment.
|
||||
|
||||
Ensure that your code compiles according to the build instructions in
|
||||
[`BUILD.md`](./BUILD.md).
|
||||
If you create new source files, they must go under `src/ripple`.
|
||||
You will need to add them to one of the
|
||||
[source lists](./Builds/CMake/RippledCore.cmake) in CMake.
|
||||
|
||||
Please write tests for your code.
|
||||
If you create new test source files, they must go under `src/test`.
|
||||
You will need to add them to one of the
|
||||
[source lists](./Builds/CMake/RippledCore.cmake) in CMake.
|
||||
If your test can be run offline, in under 60 seconds, then it can be an
|
||||
automatic test run by `rippled --unittest`.
|
||||
Otherwise, it must be a manual test.
|
||||
|
||||
If you create new source files, they must be organized as follows:
|
||||
* If the files are in any of the `libxrpl` modules, the headers (`.h`) must go
|
||||
under `include/xrpl`, and source (`.cpp`) files must go under
|
||||
`src/libxrpl`.
|
||||
* All other non-test files must go under `src/xrpld`.
|
||||
* All test source files must go under `src/test`.
|
||||
|
||||
The source must be formatted according to the style guide below.
|
||||
|
||||
Header includes must be [levelized](./Builds/levelization).
|
||||
@@ -97,6 +107,19 @@ Refer to
|
||||
["How to Write a Git Commit Message"](https://cbea.ms/git-commit/)
|
||||
for general rules on writing a good commit message.
|
||||
|
||||
tl;dr
|
||||
> 1. Separate subject from body with a blank line.
|
||||
> 2. Limit the subject line to 50 characters.
|
||||
> * [...]shoot for 50 characters, but consider 72 the hard limit.
|
||||
> 3. Capitalize the subject line.
|
||||
> 4. Do not end the subject line with a period.
|
||||
> 5. Use the imperative mood in the subject line.
|
||||
> * A properly formed Git commit subject line should always be able
|
||||
> to complete the following sentence: "If applied, this commit will
|
||||
> _your subject line here_".
|
||||
> 6. Wrap the body at 72 characters.
|
||||
> 7. Use the body to explain what and why vs. how.
|
||||
|
||||
In addition to those guidelines, please add one of the following
|
||||
prefixes to the subject line if appropriate.
|
||||
* `fix:` - The primary purpose is to fix an existing bug.
|
||||
@@ -119,7 +142,10 @@ unit tests for Feature X (#1234)`.
|
||||
## Pull requests
|
||||
|
||||
In general, pull requests use `develop` as the base branch.
|
||||
(Hotfixes are an exception.)
|
||||
The exceptions are
|
||||
* Fixes and improvements to a release candidate use `release` as the
|
||||
base.
|
||||
* Hotfixes use `master` as the base.
|
||||
|
||||
If your changes are not quite ready, but you want to make it easily available
|
||||
for preliminary examination or review, you can create a "Draft" pull request.
|
||||
@@ -142,14 +168,12 @@ before it can be considered for merge by a Maintainer.
|
||||
Maintainers retain discretion to require more approvals if they feel the
|
||||
credibility of the existing approvals is insufficient.
|
||||
|
||||
Pull requests must be merged by [squash-and-merge][2]
|
||||
Pull requests must be merged by [squash-and-merge][squash]
|
||||
to preserve a linear history for the `develop` branch.
|
||||
|
||||
### When and how to merge pull requests
|
||||
### "Ready to merge"
|
||||
|
||||
#### "Passed"
|
||||
|
||||
A pull request should only have the "Passed" label added when it
|
||||
A pull request should only have the "Ready to merge" label added when it
|
||||
meets a few criteria:
|
||||
|
||||
1. It must have two approving reviews [as described
|
||||
@@ -166,142 +190,17 @@ meets a few criteria:
|
||||
merge, they should also ensure the commit message(s) are updated
|
||||
as well.
|
||||
4. The PR branch must be up to date with the base branch (usually
|
||||
`develop`). This is usually accomplised by merging the base branch
|
||||
`develop`). This is usually accomplished by merging the base branch
|
||||
into the feature branch, but if the other criteria are met, the
|
||||
changes can be squashed and rebased on top of the base branch.
|
||||
5. Finally, and most importantly, the author of the PR must
|
||||
positively indicate that the PR is ready to merge. That can be
|
||||
accomplished by adding the "Passed" label if their role allows,
|
||||
or by leaving a comment to the effect that the PR is ready to
|
||||
accomplished by adding the "Ready to merge" label if their role
|
||||
allows, or by leaving a comment to the effect that the PR is ready to
|
||||
merge.
|
||||
|
||||
Once the "Passed" label is added, a maintainer may merge the PR at
|
||||
any time, so don't use it lightly.
|
||||
|
||||
#### Instructions for maintainers
|
||||
|
||||
The maintainer should double-check that the PR has met all the
|
||||
necessary criteria, and can request additional information from the
|
||||
owner, or additional reviews, and can always feel free to remove the
|
||||
"Passed" label if appropriate. The maintainer has final say on
|
||||
whether a PR gets merged, and are encouraged to communicate and
|
||||
issues or concerns to other maintainers.
|
||||
|
||||
##### Most pull requests: "Squash and merge"
|
||||
|
||||
Most pull requests don't need special handling, and can simply be
|
||||
merged using the "Squash and merge" button on the Github UI. Update
|
||||
the suggested commit message if necessary.
|
||||
|
||||
##### Slightly more complicated pull requests
|
||||
|
||||
Some pull requests need to be pushed to `develop` as more than one
|
||||
commit. There are multiple ways to accomplish this. If the author
|
||||
describes a process, and it is reasonable, follow it. Otherwise, do
|
||||
a fast forward only merge (`--ff-only`) on the command line and push.
|
||||
|
||||
Either way, check that:
|
||||
* The commits are based on the current tip of `develop`.
|
||||
* The commits are clean: No merge commits (except when reverse
|
||||
merging), no "[FOLD]" or "fixup!" messages.
|
||||
* All commits are signed. If the commits are not signed by the author, use
|
||||
`git commit --amend -S` to sign them yourself.
|
||||
* At least one (but preferably all) of the commits has the PR number
|
||||
in the commit message.
|
||||
|
||||
**Never use the "Create a merge commit" or "Rebase and merge"
|
||||
functions!**
|
||||
|
||||
##### Releases, release candidates, and betas
|
||||
|
||||
All releases, including release candidates and betas, are handled
|
||||
differently from typical PRs. Most importantly, never use
|
||||
the Github UI to merge a release.
|
||||
|
||||
1. There are two possible conditions that the `develop` branch will
|
||||
be in when preparing a release.
|
||||
1. Ready or almost ready to go: There may be one or two PRs that
|
||||
need to be merged, but otherwise, the only change needed is to
|
||||
update the version number in `BuildInfo.cpp`. In this case,
|
||||
merge those PRs as appropriate, updating the second one, and
|
||||
waiting for CI to finish in between. Then update
|
||||
`BuildInfo.cpp`.
|
||||
2. Several pending PRs: In this case, do not use the Github UI,
|
||||
because the delays waiting for CI in between each merge will be
|
||||
unnecessarily onerous. Instead, create a working branch (e.g.
|
||||
`develop-next`) based off of `develop`. Squash the changes
|
||||
from each PR onto the branch, one commit each (unless
|
||||
more are needed), being sure to sign each commit and update
|
||||
the commit message to include the PR number. You may be able
|
||||
to use a fast-forward merge for the first PR. The workflow may
|
||||
look something like:
|
||||
```
|
||||
git fetch upstream
|
||||
git checkout upstream/develop
|
||||
git checkout -b develop-next
|
||||
# Use -S on the ff-only merge if prbranch1 isn't signed.
|
||||
# Or do another branch first.
|
||||
git merge --ff-only user1/prbranch1
|
||||
git merge --squash user2/prbranch2
|
||||
git commit -S
|
||||
git merge --squash user3/prbranch3
|
||||
git commit -S
|
||||
[...]
|
||||
git push --set-upstream origin develop-next
|
||||
</pre>
|
||||
```
|
||||
2. Create the Pull Request with `release` as the base branch. If any
|
||||
of the included PRs are still open,
|
||||
[use closing keywords](https://docs.github.com/articles/closing-issues-using-keywords)
|
||||
in the description to ensure they are closed when the code is
|
||||
released. e.g. "Closes #1234"
|
||||
3. Instead of the default template, reuse and update the message from
|
||||
the previous release. Include the following verbiage somewhere in
|
||||
the description:
|
||||
```
|
||||
The base branch is release. All releases (including betas) go in
|
||||
release. This PR will be merged with --ff-only (not squashed or
|
||||
rebased, and not using the GitHub UI) to both release and develop.
|
||||
```
|
||||
4. Sign-offs for the three platforms usually occur offline, but at
|
||||
least one approval will be needed on the PR.
|
||||
5. Once everything is ready to go, open a terminal, and do the
|
||||
fast-forward merges manually. Do not push any branches until you
|
||||
verify that all of them update correctly.
|
||||
```
|
||||
git fetch upstream
|
||||
git checkout -b upstream--develop -t upstream/develop || git checkout upstream--develop
|
||||
git reset --hard upstream/develop
|
||||
# develop-next must be signed already!
|
||||
git merge --ff-only origin/develop-next
|
||||
git checkout -b upstream--release -t upstream/release || git checkout upstream--release
|
||||
git reset --hard upstream/release
|
||||
git merge --ff-only origin/develop-next
|
||||
# Only do these 3 steps if pushing a release. No betas or RCs
|
||||
git checkout -b upstream--master -t upstream/master || git checkout upstream--master
|
||||
git reset --hard upstream/master
|
||||
git merge --ff-only origin/develop-next
|
||||
# Check that all of the branches are updated
|
||||
git log -1 --oneline
|
||||
# The output should look like:
|
||||
# 02ec8b7962 (HEAD -> upstream--master, origin/develop-next, upstream--release, upstream--develop, develop-next) Set version to 2.2.0-rc1
|
||||
# Note that all of the upstream--develop/release/master are on this commit.
|
||||
# (Master will be missing for betas, etc.)
|
||||
# Just to be safe, do a dry run first:
|
||||
git push --dry-run upstream-push HEAD:develop
|
||||
git push --dry-run upstream-push HEAD:release
|
||||
# git push --dry-run upstream-push HEAD:master
|
||||
# Now push
|
||||
git push upstream-push HEAD:develop
|
||||
git push upstream-push HEAD:release
|
||||
# git push upstream-push HEAD:master
|
||||
# Don't forget to tag the release, too.
|
||||
git tag <version number>
|
||||
git push upstream-push <version number>
|
||||
```
|
||||
6. Finally
|
||||
[create a new release on Github](https://github.com/XRPLF/rippled/releases).
|
||||
|
||||
Once the "Ready to merge" label is added, a maintainer may merge the PR
|
||||
at any time, so don't use it lightly.
|
||||
|
||||
# Style guide
|
||||
|
||||
@@ -312,7 +211,7 @@ coherent rather than a set of _thou shalt not_ commandments.
|
||||
|
||||
## Formatting
|
||||
|
||||
All code must conform to `clang-format` version 10,
|
||||
All code must conform to `clang-format` version 18,
|
||||
according to the settings in [`.clang-format`](./.clang-format),
|
||||
unless the result would be unreasonably difficult to read or maintain.
|
||||
To demarcate lines that should be left as-is, surround them with comments like
|
||||
@@ -343,6 +242,68 @@ pip3 install pre-commit
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
## Contracts and instrumentation
|
||||
|
||||
We are using [Antithesis](https://antithesis.com/) for continuous fuzzing,
|
||||
and keep a copy of [Antithesis C++ SDK](https://github.com/antithesishq/antithesis-sdk-cpp/)
|
||||
in `external/antithesis-sdk`. One of the aims of fuzzing is to identify bugs
|
||||
by finding external conditions which cause contracts violations inside `rippled`.
|
||||
The contracts are expressed as `XRPL_ASSERT` or `UNREACHABLE` (defined in
|
||||
`include/xrpl/beast/utility/instrumentation.h`), which are effectively (outside
|
||||
of Antithesis) wrappers for `assert(...)` with added name. The purpose of name
|
||||
is to provide contracts with stable identity which does not rely on line numbers.
|
||||
|
||||
When `rippled` is built with the Antithesis instrumentation enabled
|
||||
(using `voidstar` CMake option) and ran on the Antithesis platform, the
|
||||
contracts become
|
||||
[test properties](https://antithesis.com/docs/using_antithesis/properties.html);
|
||||
otherwise they are just like a regular `assert`.
|
||||
To learn more about Antithesis, see
|
||||
[How Antithesis Works](https://antithesis.com/docs/introduction/how_antithesis_works.html)
|
||||
and [C++ SDK](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html#)
|
||||
|
||||
We continue to use the old style `assert` or `assert(false)` in certain
|
||||
locations, where the reporting of contract violations on the Antithesis
|
||||
platform is either not possible or not useful.
|
||||
|
||||
For this reason:
|
||||
* The locations where `assert` or `assert(false)` contracts should continue to be used:
|
||||
* `constexpr` functions
|
||||
* unit tests i.e. files under `src/test`
|
||||
* unit tests-related modules (files under `beast/test` and `beast/unit_test`)
|
||||
* Outside of the listed locations, do not use `assert`; use `XRPL_ASSERT` instead,
|
||||
giving it unique name, with the short description of the contract.
|
||||
* Outside of the listed locations, do not use `assert(false)`; use
|
||||
`UNREACHABLE` instead, giving it unique name, with the description of the
|
||||
condition being violated
|
||||
* The contract name should start with a full name (including scope) of the
|
||||
function, optionally a named lambda, followed by a colon ` : ` and a brief
|
||||
(typically at most five words) description. `UNREACHABLE` contracts
|
||||
can use slightly longer descriptions. If there are multiple overloads of the
|
||||
function, use common sense to balance both brevity and unambiguity of the
|
||||
function name. NOTE: the purpose of name is to provide stable means of
|
||||
unique identification of every contract; for this reason try to avoid elements
|
||||
which can change in some obvious refactors or when reinforcing the condition.
|
||||
* Contract description typically (except for `UNREACHABLE`) should describe the
|
||||
_expected_ condition, as in "I assert that _expected_ is true".
|
||||
* Contract description for `UNREACHABLE` should describe the _unexpected_
|
||||
situation which caused the line to have been reached.
|
||||
* Example good name for an
|
||||
`UNREACHABLE` macro `"Json::operator==(Value, Value) : invalid type"`; example
|
||||
good name for an `XRPL_ASSERT` macro `"Json::Value::asCString : valid type"`.
|
||||
* Example **bad** name
|
||||
`"RFC1751::insert(char* s, int x, int start, int length) : length is greater than or equal zero"`
|
||||
(missing namespace, unnecessary full function signature, description too verbose).
|
||||
Good name: `"ripple::RFC1751::insert : minimum length"`.
|
||||
* In **few** well-justified cases a non-standard name can be used, in which case a
|
||||
comment should be placed to explain the rationale (example in `contract.cpp`)
|
||||
* Do **not** rename a contract without a good reason (e.g. the name no longer
|
||||
reflects the location or the condition being checked)
|
||||
* Do not use `std::unreachable`
|
||||
* Do not put contracts where they can be violated by an external condition
|
||||
(e.g. timing, data payload before mandatory validation etc.) as this creates
|
||||
bogus bug reports (and causes crashes of Debug builds)
|
||||
|
||||
## Unit Tests
|
||||
To execute all unit tests:
|
||||
|
||||
@@ -415,17 +376,22 @@ existing maintainer without a vote.
|
||||
|
||||
## Current Maintainers
|
||||
|
||||
Maintainers are users with admin access to the repo. Maintainers do not typically approve or deny pull requests.
|
||||
Maintainers are users with maintain or admin access to the repo.
|
||||
|
||||
* [bthomee](https://github.com/bthomee) (Ripple)
|
||||
* [intelliot](https://github.com/intelliot) (Ripple)
|
||||
* [JoelKatz](https://github.com/JoelKatz) (Ripple)
|
||||
* [nixer89](https://github.com/nixer89) (XRP Ledger Foundation)
|
||||
* [RichardAH](https://github.com/RichardAH) (XRP Ledger Foundation)
|
||||
* [Silkjaer](https://github.com/Silkjaer) (XRP Ledger Foundation)
|
||||
* [WietseWind](https://github.com/WietseWind) (XRPL Labs + XRP Ledger Foundation)
|
||||
* [ximinez](https://github.com/ximinez) (Ripple)
|
||||
|
||||
|
||||
## Current Code Reviewers
|
||||
|
||||
Code Reviewers are developers who have the ability to review and approve source code changes.
|
||||
Code Reviewers are developers who have the ability to review, approve, and
|
||||
in some cases merge source code changes.
|
||||
|
||||
* [HowardHinnant](https://github.com/HowardHinnant) (Ripple)
|
||||
* [scottschurr](https://github.com/scottschurr) (Ripple)
|
||||
@@ -449,6 +415,607 @@ Code Reviewers are developers who have the ability to review and approve source
|
||||
* [RichardAH](https://github.com/RichardAH) (XRPL Labs + XRP Ledger Foundation)
|
||||
* [dangell7](https://github.com/dangell7) (XRPL Labs)
|
||||
|
||||
Developers not on this list are able and encouraged to submit feedback
|
||||
on pending code changes (open pull requests).
|
||||
|
||||
[1]: https://docs.github.com/en/get-started/quickstart/contributing-to-projects
|
||||
[2]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges#squash-and-merge-your-commits
|
||||
## Instructions for maintainers
|
||||
|
||||
These instructions assume you have your git upstream remotes configured
|
||||
to avoid accidental pushes to the main repo, and a remote group
|
||||
specifying both of them. e.g.
|
||||
```
|
||||
$ git remote -v | grep upstream
|
||||
upstream https://github.com/XRPLF/rippled.git (fetch)
|
||||
upstream https://github.com/XRPLF/rippled.git (push)
|
||||
upstream-push git@github.com:XRPLF/rippled.git (fetch)
|
||||
upstream-push git@github.com:XRPLF/rippled.git (push)
|
||||
|
||||
$ git config remotes.upstreams
|
||||
upstream upstream-push
|
||||
```
|
||||
|
||||
You can use the [setup-upstreams] script to set this up.
|
||||
|
||||
It also assumes you have a default gpg signing key set up in git. e.g.
|
||||
```
|
||||
$ git config user.signingkey
|
||||
968479A1AFF927E37D1A566BB5690EEEBB952194
|
||||
# (This is github's key. Use your own.)
|
||||
```
|
||||
|
||||
### When and how to merge pull requests
|
||||
|
||||
The maintainer should double-check that the PR has met all the
|
||||
necessary criteria, and can request additional information from the
|
||||
owner, or additional reviews, and can always feel free to remove the
|
||||
"Ready to merge" label if appropriate. The maintainer has final say on
|
||||
whether a PR gets merged, and are encouraged to communicate and issues
|
||||
or concerns to other maintainers.
|
||||
|
||||
#### Most pull requests: "Squash and merge"
|
||||
|
||||
Most pull requests don't need special handling, and can simply be
|
||||
merged using the "Squash and merge" button on the Github UI. Update
|
||||
the suggested commit message, or modify it as needed.
|
||||
|
||||
#### Slightly more complicated pull requests
|
||||
|
||||
Some pull requests need to be pushed to `develop` as more than one
|
||||
commit. A PR author may *request* to merge as separate commits. They
|
||||
must *justify* why separate commits are needed, and *specify* how they
|
||||
would like the commits to be merged. If you disagree with the author,
|
||||
discuss it with them directly.
|
||||
|
||||
If the process is reasonable, follow it. The simplest option is to do a
|
||||
fast forward only merge (`--ff-only`) on the command line and push to
|
||||
`develop`.
|
||||
|
||||
Some examples of when separate commits are worthwhile are:
|
||||
1. PRs where source files are reorganized in multiple steps.
|
||||
2. PRs where the commits are mostly independent and *could* be separate
|
||||
PRs, but are pulled together into one PR under a commit theme or
|
||||
issue.
|
||||
3. PRs that are complicated enough that `git bisect` would not be much
|
||||
help if it determined this PR introduced a problem.
|
||||
|
||||
Either way, check that:
|
||||
* The commits are based on the current tip of `develop`.
|
||||
* The commits are clean: No merge commits (except when reverse
|
||||
merging), no "[FOLD]" or "fixup!" messages.
|
||||
* All commits are signed. If the commits are not signed by the author, use
|
||||
`git commit --amend -S` to sign them yourself.
|
||||
* At least one (but preferably all) of the commits has the PR number
|
||||
in the commit message.
|
||||
|
||||
The "Create a merge commit" and "Rebase and merge" options should be
|
||||
disabled in the Github UI, but if you ever find them available **Do not
|
||||
use them!**
|
||||
|
||||
### Releases
|
||||
|
||||
All releases, including release candidates and betas, are handled
|
||||
differently from typical PRs. Most importantly, never use
|
||||
the Github UI to merge a release.
|
||||
|
||||
Rippled uses a linear workflow model that can be summarized as:
|
||||
|
||||
1. In between releases, developers work against the `develop` branch.
|
||||
2. Periodically, a maintainer will build and tag a beta version from
|
||||
`develop`, which is pushed to `release`.
|
||||
* Betas are usually released every two to three weeks, though that
|
||||
schedule can vary depending on progress, availability, and other
|
||||
factors.
|
||||
3. When the changes in `develop` are considered stable and mature enough
|
||||
to be ready to release, a release candidate (RC) is built and tagged
|
||||
from `develop`, and merged to `release`.
|
||||
* Further development for that release (primarily fixes) then
|
||||
continues against `release`, while other development continues on
|
||||
`develop`. Effectively, `release` is forked from `develop`. Changes
|
||||
to `release` must be reverse merged to `develop`.
|
||||
4. When the candidate has passed testing and is ready for release, the
|
||||
final release is merged to `master`.
|
||||
5. If any issues are found post-release, a hotfix / point release may be
|
||||
created, which is merged to `master`, and then reverse merged to
|
||||
`develop`.
|
||||
|
||||
#### Betas, and the first release candidate
|
||||
|
||||
##### Preparing the `develop` branch
|
||||
|
||||
1. Optimally, the `develop` branch will be ready to go, with all
|
||||
relevant PRs already merged.
|
||||
2. If there are any PRs pending, merge them **BEFORE** preparing the beta.
|
||||
1. If only one or two PRs need to be merged, merge those PRs [as
|
||||
normal](#when-and-how-to-merge-pull-requests), updating the second
|
||||
one, and waiting for CI to finish in between.
|
||||
2. If there are several pending PRs, do not use the Github UI,
|
||||
because the delays waiting for CI in between each merge will be
|
||||
unnecessarily onerous. (Incidentally, this process can also be
|
||||
used to merge if the Github UI has issues.) Merge each PR branch
|
||||
directly to a `release-next` on your local machine and create a single
|
||||
PR, then push your branch to `develop`.
|
||||
1. Squash the changes from each PR, one commit each (unless more
|
||||
are needed), being sure to sign each commit and update the
|
||||
commit message to include the PR number. You may be able to use
|
||||
a fast-forward merge for the first PR.
|
||||
2. Push your branch.
|
||||
3. Continue to [Making the release](#making-the-release) to update
|
||||
the version number, etc.
|
||||
|
||||
The workflow may look something like:
|
||||
```
|
||||
git fetch --multiple upstreams user1 user2 user3 [...]
|
||||
git checkout -B release-next --no-track upstream/develop
|
||||
|
||||
# Only do an ff-only merge if prbranch1 is either already
|
||||
# squashed, or needs to be merged with separate commits,
|
||||
# and has no merge commits.
|
||||
# Use -S on the ff-only merge if prbranch1 isn't signed.
|
||||
git merge [-S] --ff-only user1/prbranch1
|
||||
|
||||
git merge --squash user2/prbranch2
|
||||
git commit -S # Use the commit message provided on the PR
|
||||
|
||||
git merge --squash user3/prbranch3
|
||||
git commit -S # Use the commit message provided on the PR
|
||||
|
||||
[...]
|
||||
|
||||
# Make sure the commits look right
|
||||
git log --show-signature "upstream/develop..HEAD"
|
||||
|
||||
git push --set-upstream origin
|
||||
|
||||
# Continue to "Making the release" to update the version number, so
|
||||
# everything can be done in one PR.
|
||||
```
|
||||
|
||||
You can also use the [squash-branches] script.
|
||||
|
||||
You may also need to manually close the open PRs after the changes are
|
||||
merged to `develop`. Be sure to include the commit ID.
|
||||
|
||||
##### Making the release
|
||||
|
||||
This includes, betas, and the first release candidate (RC).
|
||||
|
||||
1. If you didn't create one [preparing the `develop`
|
||||
branch](#preparing-the-develop-branch), Ensure there is no old
|
||||
`release-next` branch hanging around. Then make a `release-next`
|
||||
branch that only changes the version number. e.g.
|
||||
```
|
||||
git fetch upstreams
|
||||
|
||||
git checkout --no-track -B release-next upstream/develop
|
||||
|
||||
v="A.B.C-bD"
|
||||
build=$( find -name BuildInfo.cpp )
|
||||
sed 's/\(^.*versionString =\).*$/\1 "'${v}'"/' ${build} > version.cpp && mv -vi version.cpp ${build}
|
||||
|
||||
git diff
|
||||
|
||||
git add ${build}
|
||||
|
||||
git commit -S -m "Set version to ${v}"
|
||||
|
||||
# You could use your "origin" repo, but some CI tests work better on upstream.
|
||||
git push upstream-push
|
||||
git fetch upstreams
|
||||
git branch --set-upstream-to=upstream/release-next
|
||||
```
|
||||
You can also use the [update-version] script.
|
||||
2. Create a Pull Request for `release-next` with **`develop`** as
|
||||
the base branch.
|
||||
1. Use the title "[TRIVIAL] Set version to X.X.X-bX".
|
||||
2. Instead of the default description template, use the following:
|
||||
```
|
||||
## High Level Overview of Change
|
||||
|
||||
This PR only changes the version number. It will be merged as
|
||||
soon as Github CI actions successfully complete.
|
||||
```
|
||||
3. Wait for CI to successfully complete, and get someone to approve
|
||||
the PR. (It is safe to ignore known CI issues.)
|
||||
4. Push the updated `develop` branch using your `release-next`
|
||||
branch. **Do not use the Github UI. It's important to preserve
|
||||
commit IDs.**
|
||||
```
|
||||
git push upstream-push release-next:develop
|
||||
```
|
||||
5. In the unlikely event that the push fails because someone has merged
|
||||
something else in the meantime, rebase your branch onto the updated
|
||||
`develop` branch, push again, and go back to step 3.
|
||||
6. Ensure that your PR against `develop` is closed. Github should do it
|
||||
automatically.
|
||||
7. Once this is done, forward progress on `develop` can continue
|
||||
(other PRs may be merged).
|
||||
8. Now create a Pull Request for `release-next` with **`release`** as
|
||||
the base branch. Instead of the default template, reuse and update
|
||||
the message from the previous release. Include the following verbiage
|
||||
somewhere in the description:
|
||||
```
|
||||
The base branch is `release`. [All releases (including
|
||||
betas)](https://github.com/XRPLF/rippled/blob/develop/CONTRIBUTING.md#before-you-start)
|
||||
go in `release`. This PR branch will be pushed directly to `release` (not
|
||||
squashed or rebased, and not using the GitHub UI).
|
||||
```
|
||||
7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur
|
||||
offline, but at least one approval will be needed on the PR.
|
||||
* If issues are discovered during testing, simply abandon the
|
||||
release. It's easy to start a new release, it should be easy to
|
||||
abandon one. **DO NOT REUSE THE VERSION NUMBER.** e.g. If you
|
||||
abandon 2.4.0-b1, the next attempt will be 2.4.0-b2.
|
||||
8. Once everything is ready to go, push to `release`.
|
||||
```
|
||||
git fetch upstreams
|
||||
|
||||
# Just to be safe, do a dry run first:
|
||||
git push --dry-run upstream-push release-next:release
|
||||
|
||||
# If everything looks right, push the branch
|
||||
git push upstream-push release-next:release
|
||||
|
||||
# Check that all of the branches are updated
|
||||
git fetch upstreams
|
||||
git log -1 --oneline
|
||||
# The output should look like:
|
||||
# 0123456789 (HEAD -> upstream/release-next, upstream/release,
|
||||
# upstream/develop) Set version to 2.4.0-b1
|
||||
# Note that upstream/develop may not be on this commit, but
|
||||
# upstream/release must be.
|
||||
# Other branches, including some from upstream-push, may also be
|
||||
# present.
|
||||
```
|
||||
9. Tag the release, too.
|
||||
```
|
||||
git tag <version number>
|
||||
git push upstream-push <version number>
|
||||
```
|
||||
10. Delete the `release-next` branch on the repo. Use the Github UI or:
|
||||
```
|
||||
git push --delete upstream-push release-next
|
||||
```
|
||||
11. Finally [create a new release on
|
||||
Github](https://github.com/XRPLF/rippled/releases).
|
||||
|
||||
#### Release candidates after the first
|
||||
|
||||
Once the first release candidate is [merged into
|
||||
release](#making-the-release), then `release` and `develop` *are allowed
|
||||
to diverge*.
|
||||
|
||||
If a bug or issue is discovered in a version that has a release
|
||||
candidate being tested, any fix and new version will need to be applied
|
||||
against `release`, then reverse-merged to `develop`. This helps keep git
|
||||
history as linear as possible.
|
||||
|
||||
A `release-next` branch will be created from `release`, and any further
|
||||
work for that release must be based on `release-next`. Specifically,
|
||||
PRs must use `release-next` as the base, and those PRs will be merged
|
||||
directly to `release-next` when approved. Changes should be restricted
|
||||
to bug fixes, but other changes may be necessary from time to time.
|
||||
|
||||
1. Open any PRs for the pending release using `release-next` as the base,
|
||||
so they can be merged directly in to it. Unlike `develop`, though,
|
||||
`release-next` can be thrown away and recreated if necessary.
|
||||
2. Once a new release candidate is ready, create a version commit as in
|
||||
step 1 [above](#making-the-release) on `release-next`. You can use
|
||||
the [update-version] script for this, too.
|
||||
3. Jump to step 8 ("Now create a Pull Request for `release-next` with
|
||||
**`release`** as the base") from the process
|
||||
[above](#making-the-release) to merge `release-next` into `release`.
|
||||
|
||||
##### Follow up: reverse merge
|
||||
|
||||
Once the RC is merged and tagged, it needs to be reverse merged into
|
||||
`develop` as soon as possible.
|
||||
|
||||
1. Create a branch, based on `upstream/develop`.
|
||||
The branch name is not important, but could include "mergeNNNrcN".
|
||||
E.g. For release A.B.C-rcD, use `mergeABCrcD`.
|
||||
```
|
||||
git fetch upstreams
|
||||
|
||||
git checkout --no-track -b mergeABCrcD upstream/develop
|
||||
```
|
||||
2. Merge `release` into your branch.
|
||||
```
|
||||
# I like the "--edit --log --verbose" parameters, but they are
|
||||
# not required.
|
||||
git merge upstream/release
|
||||
```
|
||||
3. `BuildInfo.cpp` will have a conflict with the version number.
|
||||
Resolve it with the version from `develop` - the higher version.
|
||||
4. Push your branch to your repo (or `upstream` if you have permission),
|
||||
and open a normal PR against `develop`. The "High level overview" can
|
||||
simply indicate that this is a merge of the RC. The "Context" should
|
||||
summarize the changes from the RC. Include the following text
|
||||
prominently:
|
||||
```
|
||||
This PR must be merged manually using a push. Do not use the Github UI.
|
||||
```
|
||||
5. Depending on the complexity of the changes, and/or merge conflicts,
|
||||
the PR may need a thorough review, or just a sign-off that the
|
||||
merge was done correctly.
|
||||
6. If `develop` is updated before this PR is merged, do not merge
|
||||
`develop` back into your branch. Instead rebase preserving merges,
|
||||
or do the merge again. (See also the `rerere` git config setting.)
|
||||
```
|
||||
git rebase --rebase-merges upstream/develop
|
||||
# OR
|
||||
git reset --hard upstream/develop
|
||||
git merge upstream/release
|
||||
```
|
||||
7. When the PR is ready, push it to `develop`.
|
||||
```
|
||||
git fetch upstreams
|
||||
|
||||
# Make sure the commits look right
|
||||
git log --show-signature "upstream/develop^..HEAD"
|
||||
|
||||
git push upstream-push mergeABCrcD:develop
|
||||
|
||||
git fetch upstreams
|
||||
```
|
||||
Development on `develop` can proceed as normal.
|
||||
|
||||
|
||||
#### Final releases
|
||||
|
||||
A final release is any release that is not a beta or RC, such as 2.2.0.
|
||||
|
||||
Only code that has already been tested and vetted across all three
|
||||
platforms should be included in a final release. Most of the time, that
|
||||
means that the commit immediately preceding the commit setting the
|
||||
version number will be an RC. Occasionally, there may be last-minute bug
|
||||
fixes included as well. If so, those bug fixes must have been tested
|
||||
internally as if they were RCs (at minimum, ensuring unit tests pass,
|
||||
and the app starts, syncs, and stops cleanly across all three
|
||||
platforms.)
|
||||
|
||||
*If in doubt, make an RC first.*
|
||||
|
||||
The process for building a final release is very similar to [the process
|
||||
for building a beta](#making-the-release), except the code will be
|
||||
moving from `release` to `master` instead of from `develop` to
|
||||
`release`, and both branches will be pushed at the same time.
|
||||
|
||||
1. Ensure there is no old `master-next` branch hanging around.
|
||||
Then make a `master-next` branch that only changes the version
|
||||
number. As above, or using the
|
||||
[update-version] script.
|
||||
2. Create a Pull Request for `master-next` with **`master`** as
|
||||
the base branch. Instead of the default template, reuse and update
|
||||
the message from the previous final release. Include the following verbiage
|
||||
somewhere in the description:
|
||||
```
|
||||
The base branch is `master`. This PR branch will be pushed directly to
|
||||
`release` and `master` (not squashed or rebased, and not using the
|
||||
GitHub UI).
|
||||
```
|
||||
7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur
|
||||
offline, but at least one approval will be needed on the PR.
|
||||
* If issues are discovered during testing, close the PR, delete
|
||||
`master-next`, and move development back to `release`, [issuing
|
||||
more RCs as necessary](#release-candidates-after-the-first)
|
||||
8. Once everything is ready to go, push to `release` and `master`.
|
||||
```
|
||||
git fetch upstreams
|
||||
|
||||
# Just to be safe, do dry runs first:
|
||||
git push --dry-run upstream-push master-next:release
|
||||
git push --dry-run upstream-push master-next:master
|
||||
|
||||
# If everything looks right, push the branch
|
||||
git push upstream-push master-next:release
|
||||
git push upstream-push master-next:master
|
||||
|
||||
# Check that all of the branches are updated
|
||||
git fetch upstreams
|
||||
git log -1 --oneline
|
||||
# The output should look like:
|
||||
# 0123456789 (HEAD -> upstream/master-next, upstream/master,
|
||||
# upstream/release) Set version to A.B.0
|
||||
# Note that both upstream/release and upstream/master must be on this
|
||||
# commit.
|
||||
# Other branches, including some from upstream-push, may also be
|
||||
# present.
|
||||
```
|
||||
9. Tag the release, too.
|
||||
```
|
||||
git tag <version number>
|
||||
git push upstream-push <version number>
|
||||
```
|
||||
10. Delete the `master-next` branch on the repo. Use the Github UI or:
|
||||
```
|
||||
git push --delete upstream-push master-next
|
||||
```
|
||||
11. [Create a new release on
|
||||
Github](https://github.com/XRPLF/rippled/releases). Be sure that
|
||||
"Set as the latest release" is checked.
|
||||
12. Finally [reverse merge the release into `develop`](#follow-up-reverse-merge).
|
||||
|
||||
#### Special cases: point releases, hotfixes, etc.
|
||||
|
||||
On occassion, a bug or issue is discovered in a version that already
|
||||
had a final release. Most of the time, development will have started
|
||||
on the next version, and will usually have changes in `develop`
|
||||
and often in `release`.
|
||||
|
||||
Because git history is kept as linear as possible, any fix and new
|
||||
version will need to be applied against `master`.
|
||||
|
||||
The process for building a hotfix release is very similar to [the
|
||||
process for building release candidates after the
|
||||
first](#release-candidates-after-the-first) and [for building a final
|
||||
release](#final-releases), except the changes will be done against
|
||||
`master` instead of `release`.
|
||||
|
||||
If there is only a single issue for the hotfix, the work can be done in
|
||||
any branch. When it's ready to merge, jump to step 3 using your branch
|
||||
instead of `master-next`.
|
||||
|
||||
1. Create a `master-next` branch from `master`.
|
||||
```
|
||||
git checkout --no-track -b master-next upstream/master
|
||||
git push upstream-push
|
||||
git fetch upstreams
|
||||
```
|
||||
2. Open any PRs for the pending hotfix using `master-next` as the base,
|
||||
so they can be merged directly in to it. Unlike `develop`, though,
|
||||
`master-next` can be thrown away and recreated if necessary.
|
||||
3. Once the hotfix is ready, create a version commit using the same
|
||||
steps as above, or use the
|
||||
[update-version] script.
|
||||
4. Create a Pull Request for `master-next` with **`master`** as
|
||||
the base branch. Instead of the default template, reuse and update
|
||||
the message from the previous final release. Include the following verbiage
|
||||
somewhere in the description:
|
||||
```
|
||||
The base branch is `master`. This PR branch will be pushed directly to
|
||||
`master` (not squashed or rebased, and not using the GitHub UI).
|
||||
```
|
||||
7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur
|
||||
offline, but at least one approval will be needed on the PR.
|
||||
* If issues are discovered during testing, update `master-next` as
|
||||
needed, but ensure that the changes are properly squashed, and the
|
||||
version setting commit remains last
|
||||
8. Once everything is ready to go, push to `master` **only**.
|
||||
```
|
||||
git fetch upstreams
|
||||
|
||||
# Just to be safe, do a dry run first:
|
||||
git push --dry-run upstream-push master-next:master
|
||||
|
||||
# If everything looks right, push the branch
|
||||
git push upstream-push master-next:master
|
||||
|
||||
# Check that all of the branches are updated
|
||||
git fetch upstreams
|
||||
git log -1 --oneline
|
||||
# The output should look like:
|
||||
# 0123456789 (HEAD -> upstream/master-next, upstream/master) Set version
|
||||
# to 2.4.1
|
||||
# Note that upstream/master must be on this commit. upstream/release and
|
||||
# upstream/develop should not.
|
||||
# Other branches, including some from upstream-push, may also be
|
||||
# present.
|
||||
```
|
||||
9. Tag the release, too.
|
||||
```
|
||||
git tag <version number>
|
||||
git push upstream-push <version number>
|
||||
```
|
||||
9. Delete the `master-next` branch on the repo.
|
||||
```
|
||||
git push --delete upstream-push master-next
|
||||
```
|
||||
10. [Create a new release on
|
||||
Github](https://github.com/XRPLF/rippled/releases). Be sure that
|
||||
"Set as the latest release" is checked.
|
||||
|
||||
Once the hotfix is released, it needs to be reverse merged into
|
||||
`develop` as soon as possible. It may also need to be merged into
|
||||
`release` if a release candidate is under development.
|
||||
|
||||
1. Create a branch in your own repo, based on `upstream/develop`.
|
||||
The branch name is not important, but could include "mergeNNN".
|
||||
E.g. For release 2.2.3, use `merge223`.
|
||||
```
|
||||
git fetch upstreams
|
||||
|
||||
git checkout --no-track -b merge223 upstream/develop
|
||||
```
|
||||
2. Merge master into your branch.
|
||||
```
|
||||
# I like the "--edit --log --verbose" parameters, but they are
|
||||
# not required.
|
||||
git merge upstream/master
|
||||
```
|
||||
3. `BuildInfo.cpp` will have a conflict with the version number.
|
||||
Resolve it with the version from `develop` - the higher version.
|
||||
4. Push your branch to your repo, and open a normal PR against
|
||||
`develop`. The "High level overview" can simply indicate that this
|
||||
is a merge of the hotfix version. The "Context" should summarize
|
||||
the changes from the hotfix. Include the following text
|
||||
prominently:
|
||||
```
|
||||
This PR must be merged manually using a --ff-only merge. Do not use the Github UI.
|
||||
```
|
||||
5. Depending on the complexity of the hotfix, and/or merge conflicts,
|
||||
the PR may need a thorough review, or just a sign-off that the
|
||||
merge was done correctly.
|
||||
6. If `develop` is updated before this PR is merged, do not merge
|
||||
`develop` back into your branch. Instead rebase preserving merges,
|
||||
or do the merge again. (See also the `rerere` git config setting.)
|
||||
```
|
||||
git rebase --rebase-merges upstream/develop
|
||||
# OR
|
||||
git reset --hard upstream/develop
|
||||
git merge upstream/master
|
||||
```
|
||||
7. When the PR is ready, push it to `develop`.
|
||||
```
|
||||
git fetch upstreams
|
||||
|
||||
# Make sure the commits look right
|
||||
git log --show-signature "upstream/develop..HEAD"
|
||||
|
||||
git push upstream-push HEAD:develop
|
||||
```
|
||||
Development on `develop` can proceed as normal. It is recommended to
|
||||
create a beta (or RC) immediately to ensure that everything worked as
|
||||
expected.
|
||||
|
||||
##### An even rarer scenario: A hotfix on an old release
|
||||
|
||||
Historically, once a final release is tagged and packages are released,
|
||||
versions older than the latest final release are no longer supported.
|
||||
However, there is a possibility that a very high severity bug may occur
|
||||
in a non-amendment blocked version that is still being run by
|
||||
a significant fraction of users, which would necessitate a hotfix / point
|
||||
release to that version as well as any later versions.
|
||||
|
||||
This scenario would follow the same basic procedure as above,
|
||||
except that *none* of `develop`, `release`, or `master`
|
||||
would be touched during the release process.
|
||||
|
||||
In this example, consider if version 2.1.1 needed to be patched.
|
||||
|
||||
1. Create two branches in the main (`upstream`) repo.
|
||||
```
|
||||
git fetch upstreams
|
||||
|
||||
# Create a base branch off the tag
|
||||
git checkout --no-track -b master-2.1.2 2.1.1
|
||||
git push upstream-push
|
||||
|
||||
# Create a working branch
|
||||
git checkout --no-track -b master212-next master-2.1.2
|
||||
git push upstream-push
|
||||
|
||||
git fetch upstreams
|
||||
```
|
||||
2. Work continues as above, except using `master-2.1.2`as
|
||||
the base branch for any merging, packaging, etc.
|
||||
3. After the release is tagged and packages are built, you could
|
||||
potentially delete both branches, e.g. `master-2.1.2` and
|
||||
`master212-next`. However, it may be useful to keep `master-2.1.2`
|
||||
around indefinitely for reference.
|
||||
4. Assuming that a hotfix is also released for the latest
|
||||
version in parallel with this one, or if the issue is
|
||||
already fixed in the latest version, do no do any
|
||||
reverse merges. However, if it is not, it probably makes
|
||||
sense to reverse merge `master-2.1.2` into `master`,
|
||||
release a hotfix for _that_ version, then reverse merge
|
||||
from `master` to `develop`. (Please don't do this unless absolutely
|
||||
necessary.)
|
||||
|
||||
[contrib]: https://docs.github.com/en/get-started/quickstart/contributing-to-projects
|
||||
[squash]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges#squash-and-merge-your-commits
|
||||
[forking]: https://github.com/XRPLF/rippled/fork
|
||||
[rippled]: https://github.com/XRPLF/rippled
|
||||
[signing]: https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification
|
||||
[setup-upstreams]: ./bin/git/setup-upstreams.sh
|
||||
[squash-branches]: ./bin/git/squash-branches.sh
|
||||
[update-version]: ./bin/git/update-version.sh
|
||||
|
||||
86
bin/git/setup-upstreams.sh
Executable file
86
bin/git/setup-upstreams.sh
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ $# -ne 1 || "$1" == "--help" || "$1" == "-h" ]]
|
||||
then
|
||||
name=$( basename $0 )
|
||||
cat <<- USAGE
|
||||
Usage: $name <username>
|
||||
|
||||
Where <username> is the Github username of the upstream repo. e.g. XRPLF
|
||||
USAGE
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create upstream remotes based on origin
|
||||
shift
|
||||
user="$1"
|
||||
# Get the origin URL. Expect it be an SSH-style URL
|
||||
origin=$( git remote get-url origin )
|
||||
if [[ "${origin}" == "" ]]
|
||||
then
|
||||
echo Invalid origin remote >&2
|
||||
exit 1
|
||||
fi
|
||||
# echo "Origin: ${origin}"
|
||||
# Parse the origin
|
||||
ifs_orig="${IFS}"
|
||||
IFS=':' read remote originpath <<< "${origin}"
|
||||
# echo "Remote: ${remote}, Originpath: ${originpath}"
|
||||
IFS='@' read sshuser server <<< "${remote}"
|
||||
# echo "SSHUser: ${sshuser}, Server: ${server}"
|
||||
IFS='/' read originuser repo <<< "${originpath}"
|
||||
# echo "Originuser: ${originuser}, Repo: ${repo}"
|
||||
if [[ "${sshuser}" == "" || "${server}" == "" || "${originuser}" == ""
|
||||
|| "${repo}" == "" ]]
|
||||
then
|
||||
echo "Can't parse origin URL: ${origin}" >&2
|
||||
exit 1
|
||||
fi
|
||||
upstream="https://${server}/${user}/${repo}"
|
||||
upstreampush="${remote}:${user}/${repo}"
|
||||
upstreamgroup="upstream upstream-push"
|
||||
current=$( git remote get-url upstream 2>/dev/null )
|
||||
currentpush=$( git remote get-url upstream-push 2>/dev/null )
|
||||
currentgroup=$( git config remotes.upstreams )
|
||||
if [[ "${current}" == "${upstream}" ]]
|
||||
then
|
||||
echo "Upstream already set up correctly. Skip"
|
||||
elif [[ -n "${current}" && "${current}" != "${upstream}" &&
|
||||
"${current}" != "${upstreampush}" ]]
|
||||
then
|
||||
echo "Upstream already set up as: ${current}. Skip"
|
||||
else
|
||||
if [[ "${current}" == "${upstreampush}" ]]
|
||||
then
|
||||
echo "Upstream set to dangerous push URL. Update."
|
||||
_run git remote rename upstream upstream-push || \
|
||||
_run git remote remove upstream
|
||||
currentpush=$( git remote get-url upstream-push 2>/dev/null )
|
||||
fi
|
||||
_run git remote add upstream "${upstream}"
|
||||
fi
|
||||
|
||||
if [[ "${currentpush}" == "${upstreampush}" ]]
|
||||
then
|
||||
echo "upstream-push already set up correctly. Skip"
|
||||
elif [[ -n "${currentpush}" && "${currentpush}" != "${upstreampush}" ]]
|
||||
then
|
||||
echo "upstream-push already set up as: ${currentpush}. Skip"
|
||||
else
|
||||
_run git remote add upstream-push "${upstreampush}"
|
||||
fi
|
||||
|
||||
if [[ "${currentgroup}" == "${upstreamgroup}" ]]
|
||||
then
|
||||
echo "Upstreams group already set up correctly. Skip"
|
||||
elif [[ -n "${currentgroup}" && "${currentgroup}" != "${upstreamgroup}" ]]
|
||||
then
|
||||
echo "Upstreams group already set up as: ${currentgroup}. Skip"
|
||||
else
|
||||
_run git config --add remotes.upstreams "${upstreamgroup}"
|
||||
fi
|
||||
|
||||
_run git fetch --jobs=$(nproc) upstreams
|
||||
|
||||
exit 0
|
||||
|
||||
69
bin/git/squash-branches.sh
Executable file
69
bin/git/squash-branches.sh
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ $# -lt 3 || "$1" == "--help" || "$1" = "-h" ]]
|
||||
then
|
||||
name=$( basename $0 )
|
||||
cat <<- USAGE
|
||||
Usage: $name workbranch base/branch user/branch [user/branch [...]]
|
||||
|
||||
* workbranch will be created locally from base/branch
|
||||
* base/branch and user/branch may be specified as user:branch to allow
|
||||
easy copying from Github PRs
|
||||
* Remotes for each user must already be set up
|
||||
USAGE
|
||||
exit 0
|
||||
fi
|
||||
|
||||
work="$1"
|
||||
shift
|
||||
|
||||
branches=( $( echo "${@}" | sed "s/:/\//" ) )
|
||||
base="${branches[0]}"
|
||||
unset branches[0]
|
||||
|
||||
set -e
|
||||
|
||||
users=()
|
||||
for b in "${branches[@]}"
|
||||
do
|
||||
users+=( $( echo $b | cut -d/ -f1 ) )
|
||||
done
|
||||
|
||||
users=( $( printf '%s\n' "${users[@]}" | sort -u ) )
|
||||
|
||||
git fetch --multiple upstreams "${users[@]}"
|
||||
git checkout -B "$work" --no-track "$base"
|
||||
|
||||
for b in "${branches[@]}"
|
||||
do
|
||||
git merge --squash "${b}"
|
||||
git commit -S # Use the commit message provided on the PR
|
||||
done
|
||||
|
||||
# Make sure the commits look right
|
||||
git log --show-signature "$base..HEAD"
|
||||
|
||||
parts=( $( echo $base | sed "s/\// /" ) )
|
||||
repo="${parts[0]}"
|
||||
b="${parts[1]}"
|
||||
push=$repo
|
||||
if [[ "$push" == "upstream" ]]
|
||||
then
|
||||
push="upstream-push"
|
||||
fi
|
||||
if [[ "$repo" == "upstream" ]]
|
||||
then
|
||||
repo="upstreams"
|
||||
fi
|
||||
cat << PUSH
|
||||
|
||||
-------------------------------------------------------------------
|
||||
This script will not push. Verify everything is correct, then push
|
||||
to your repo, and create a PR if necessary. Once the PR is approved,
|
||||
run:
|
||||
|
||||
git push $push HEAD:$b
|
||||
git fetch $repo
|
||||
-------------------------------------------------------------------
|
||||
PUSH
|
||||
|
||||
58
bin/git/update-version.sh
Executable file
58
bin/git/update-version.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ $# -ne 3 || "$1" == "--help" || "$1" = "-h" ]]
|
||||
then
|
||||
name=$( basename $0 )
|
||||
cat <<- USAGE
|
||||
Usage: $name workbranch base/branch version
|
||||
|
||||
* workbranch will be created locally from base/branch. If it exists,
|
||||
it will be reused, so make sure you don't overwrite any work.
|
||||
* base/branch may be specified as user:branch to allow easy copying
|
||||
from Github PRs.
|
||||
USAGE
|
||||
exit 0
|
||||
fi
|
||||
|
||||
work="$1"
|
||||
shift
|
||||
|
||||
base=$( echo "$1" | sed "s/:/\//" )
|
||||
shift
|
||||
|
||||
version=$1
|
||||
shift
|
||||
|
||||
set -e
|
||||
|
||||
git fetch upstreams
|
||||
|
||||
git checkout -B "${work}" --no-track "${base}"
|
||||
|
||||
push=$( git rev-parse --abbrev-ref --symbolic-full-name '@{push}' \
|
||||
2>/dev/null ) || true
|
||||
if [[ "${push}" != "" ]]
|
||||
then
|
||||
echo "Warning: ${push} may already exist."
|
||||
fi
|
||||
|
||||
build=$( find -name BuildInfo.cpp )
|
||||
sed 's/\(^.*versionString =\).*$/\1 "'${version}'"/' ${build} > version.cpp && \
|
||||
diff "${build}" version.cpp && exit 1 || \
|
||||
mv -vi version.cpp ${build}
|
||||
|
||||
git diff
|
||||
|
||||
git add ${build}
|
||||
|
||||
git commit -S -m "Set version to ${version}"
|
||||
|
||||
git log --oneline --first-parent ${base}^..
|
||||
|
||||
cat << PUSH
|
||||
|
||||
-------------------------------------------------------------------
|
||||
This script will not push. Verify everything is correct, then push
|
||||
to your repo, and create a PR as described in CONTRIBUTING.md.
|
||||
-------------------------------------------------------------------
|
||||
PUSH
|
||||
@@ -410,9 +410,11 @@
|
||||
# starter list is included in the code and used if no other hostnames are
|
||||
# available.
|
||||
#
|
||||
# One address or domain name per line is allowed. A port may must be
|
||||
# specified after adding a space to the address. The ordering of entries
|
||||
# does not generally matter.
|
||||
# One address or domain name per line is allowed. A port may be specified
|
||||
# after adding a space to the address. If a port is not specified, the default
|
||||
# port of 2459 will be used. Many servers still use the legacy port of 51235.
|
||||
# To connect to such servers, you must specify the port number. The ordering
|
||||
# of entries does not generally matter.
|
||||
#
|
||||
# The default list of entries is:
|
||||
# - r.ripple.com 51235
|
||||
@@ -1423,6 +1425,9 @@ admin = 127.0.0.1
|
||||
protocol = http
|
||||
|
||||
[port_peer]
|
||||
# Many servers still use the legacy port of 51235, so for backward-compatibility
|
||||
# we maintain that port number here. However, for new servers we recommend
|
||||
# changing this to the default port of 2459.
|
||||
port = 51235
|
||||
ip = 0.0.0.0
|
||||
# alternatively, to accept connections on IPv4 + IPv6, use:
|
||||
|
||||
@@ -60,7 +60,7 @@ https://vl.xrplf.org
|
||||
#vl.ripple.com
|
||||
ED2677ABFFD1B33AC6FBC3062B71F1E8397C1505E1C42C64D11AD1B28FF73F4734
|
||||
# vl.xrplf.org
|
||||
ED45D1840EE724BE327ABE9146503D5848EFD5F38B6D5FEDE71E80ACCE5E6E738B
|
||||
ED42AEC58B701EEBB77356FFFEC26F83C1F0407263530F068C7C73D392C7E06FD1
|
||||
|
||||
# To use the test network (see https://xrpl.org/connect-your-rippled-to-the-xrp-test-net.html),
|
||||
# use the following configuration instead:
|
||||
@@ -70,3 +70,21 @@ ED45D1840EE724BE327ABE9146503D5848EFD5F38B6D5FEDE71E80ACCE5E6E738B
|
||||
#
|
||||
# [validator_list_keys]
|
||||
# ED264807102805220DA0F312E71FC2C69E1552C9C5790F6C25E3729DEB573D5860
|
||||
|
||||
|
||||
# [validator_list_threshold]
|
||||
#
|
||||
# Minimum number of validator lists on which a validator must be listed in
|
||||
# order to be used.
|
||||
#
|
||||
# This can be set explicitly to any positive integer number not greater than
|
||||
# the size of [validator_list_keys]. If it is not set, or set to 0, the
|
||||
# value will be calculated at startup from the size of [validator_list_keys],
|
||||
# where the calculation is:
|
||||
#
|
||||
# threshold = size(validator_list_keys) < 3
|
||||
# ? 1
|
||||
# : floor(size(validator_list_keys) / 2) + 1
|
||||
|
||||
[validator_list_threshold]
|
||||
0
|
||||
|
||||
@@ -120,7 +120,7 @@ else ()
|
||||
target_link_libraries (common
|
||||
INTERFACE
|
||||
-rdynamic
|
||||
$<$<BOOL:${is_linux}>:-Wl,-z,relro,-z,now>
|
||||
$<$<BOOL:${is_linux}>:-Wl,-z,relro,-z,now,--build-id>
|
||||
# link to static libc/c++ iff:
|
||||
# * static option set and
|
||||
# * NOT APPLE (AppleClang does not support static libc/c++) and
|
||||
@@ -131,6 +131,17 @@ else ()
|
||||
>)
|
||||
endif ()
|
||||
|
||||
# Antithesis instrumentation will only be built and deployed using machines running Linux.
|
||||
if (voidstar)
|
||||
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message(FATAL_ERROR "Antithesis instrumentation requires Debug build type, aborting...")
|
||||
elseif (NOT is_linux)
|
||||
message(FATAL_ERROR "Antithesis instrumentation requires Linux, aborting...")
|
||||
elseif (NOT (is_clang AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0))
|
||||
message(FATAL_ERROR "Antithesis instrumentation requires Clang version 16 or later, aborting...")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (use_mold)
|
||||
# use mold linker if available
|
||||
execute_process (
|
||||
|
||||
@@ -9,6 +9,7 @@ include(target_protobuf_sources)
|
||||
# define a bunch of `static const` variables with the same names,
|
||||
# so we just build them as a separate library.
|
||||
add_library(xrpl.libpb)
|
||||
set_target_properties(xrpl.libpb PROPERTIES UNITY_BUILD OFF)
|
||||
target_protobuf_sources(xrpl.libpb xrpl/proto
|
||||
LANGUAGE cpp
|
||||
IMPORT_DIRS include/xrpl/proto
|
||||
@@ -47,37 +48,11 @@ target_link_libraries(xrpl.libpb
|
||||
gRPC::grpc++
|
||||
)
|
||||
|
||||
add_library(xrpl.libxrpl)
|
||||
set_target_properties(xrpl.libxrpl PROPERTIES OUTPUT_NAME xrpl)
|
||||
if(unity)
|
||||
set_target_properties(xrpl.libxrpl PROPERTIES UNITY_BUILD ON)
|
||||
endif()
|
||||
# TODO: Clean up the number of library targets later.
|
||||
add_library(xrpl.imports.main INTERFACE)
|
||||
|
||||
add_library(xrpl::libxrpl ALIAS xrpl.libxrpl)
|
||||
|
||||
file(GLOB_RECURSE sources CONFIGURE_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/libxrpl/*.cpp"
|
||||
)
|
||||
target_sources(xrpl.libxrpl PRIVATE ${sources})
|
||||
|
||||
target_include_directories(xrpl.libxrpl
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
|
||||
target_compile_definitions(xrpl.libxrpl
|
||||
PUBLIC
|
||||
BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT
|
||||
BOOST_CONTAINER_FWD_BAD_DEQUE
|
||||
HAS_UNCAUGHT_EXCEPTIONS=1)
|
||||
|
||||
target_compile_options(xrpl.libxrpl
|
||||
PUBLIC
|
||||
$<$<BOOL:${is_gcc}>:-Wno-maybe-uninitialized>
|
||||
)
|
||||
|
||||
target_link_libraries(xrpl.libxrpl
|
||||
PUBLIC
|
||||
target_link_libraries(xrpl.imports.main
|
||||
INTERFACE
|
||||
LibArchive::LibArchive
|
||||
OpenSSL::Crypto
|
||||
Ripple::boost
|
||||
@@ -89,13 +64,76 @@ target_link_libraries(xrpl.libxrpl
|
||||
secp256k1::secp256k1
|
||||
xrpl.libpb
|
||||
xxHash::xxhash
|
||||
$<$<BOOL:${voidstar}>:antithesis-sdk-cpp>
|
||||
)
|
||||
|
||||
include(add_module)
|
||||
include(target_link_modules)
|
||||
|
||||
# Level 01
|
||||
add_module(xrpl beast)
|
||||
target_link_libraries(xrpl.libxrpl.beast PUBLIC
|
||||
xrpl.imports.main
|
||||
xrpl.libpb
|
||||
)
|
||||
|
||||
# Level 02
|
||||
add_module(xrpl basics)
|
||||
target_link_libraries(xrpl.libxrpl.basics PUBLIC xrpl.libxrpl.beast)
|
||||
|
||||
# Level 03
|
||||
add_module(xrpl json)
|
||||
target_link_libraries(xrpl.libxrpl.json PUBLIC xrpl.libxrpl.basics)
|
||||
|
||||
add_module(xrpl crypto)
|
||||
target_link_libraries(xrpl.libxrpl.crypto PUBLIC xrpl.libxrpl.basics)
|
||||
|
||||
# Level 04
|
||||
add_module(xrpl protocol)
|
||||
target_link_libraries(xrpl.libxrpl.protocol PUBLIC
|
||||
xrpl.libxrpl.crypto
|
||||
xrpl.libxrpl.json
|
||||
)
|
||||
|
||||
# Level 05
|
||||
add_module(xrpl resource)
|
||||
target_link_libraries(xrpl.libxrpl.resource PUBLIC xrpl.libxrpl.protocol)
|
||||
|
||||
add_module(xrpl server)
|
||||
target_link_libraries(xrpl.libxrpl.server PUBLIC xrpl.libxrpl.protocol)
|
||||
|
||||
|
||||
add_library(xrpl.libxrpl)
|
||||
set_target_properties(xrpl.libxrpl PROPERTIES OUTPUT_NAME xrpl)
|
||||
|
||||
add_library(xrpl::libxrpl ALIAS xrpl.libxrpl)
|
||||
|
||||
file(GLOB_RECURSE sources CONFIGURE_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/libxrpl/*.cpp"
|
||||
)
|
||||
target_sources(xrpl.libxrpl PRIVATE ${sources})
|
||||
|
||||
target_link_modules(xrpl PUBLIC
|
||||
basics
|
||||
beast
|
||||
crypto
|
||||
json
|
||||
protocol
|
||||
resource
|
||||
server
|
||||
)
|
||||
|
||||
# All headers in libxrpl are in modules.
|
||||
# Uncomment this stanza if you have not yet moved new headers into a module.
|
||||
# target_include_directories(xrpl.libxrpl
|
||||
# PRIVATE
|
||||
# $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
|
||||
# PUBLIC
|
||||
# $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
# $<INSTALL_INTERFACE:include>)
|
||||
|
||||
if(xrpld)
|
||||
add_executable(rippled)
|
||||
if(unity)
|
||||
set_target_properties(rippled PROPERTIES UNITY_BUILD ON)
|
||||
endif()
|
||||
if(tests)
|
||||
target_compile_definitions(rippled PUBLIC ENABLE_TESTS)
|
||||
endif()
|
||||
@@ -129,6 +167,19 @@ if(xrpld)
|
||||
target_compile_definitions(rippled PRIVATE RIPPLED_RUNNING_IN_CI)
|
||||
endif ()
|
||||
|
||||
if(voidstar)
|
||||
target_compile_options(rippled
|
||||
PRIVATE
|
||||
-fsanitize-coverage=trace-pc-guard
|
||||
)
|
||||
# rippled requires access to antithesis-sdk-cpp implementation file
|
||||
# antithesis_instrumentation.h, which is not exported as INTERFACE
|
||||
target_include_directories(rippled
|
||||
PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/external/antithesis-sdk
|
||||
)
|
||||
endif()
|
||||
|
||||
# any files that don't play well with unity should be added here
|
||||
if(tests)
|
||||
set_source_files_properties(
|
||||
|
||||
@@ -2,14 +2,25 @@
|
||||
install stuff
|
||||
#]===================================================================]
|
||||
|
||||
include(create_symbolic_link)
|
||||
|
||||
install (
|
||||
TARGETS
|
||||
common
|
||||
opts
|
||||
ripple_syslibs
|
||||
ripple_boost
|
||||
xrpl.imports.main
|
||||
xrpl.libpb
|
||||
xrpl.libxrpl.basics
|
||||
xrpl.libxrpl.beast
|
||||
xrpl.libxrpl.crypto
|
||||
xrpl.libxrpl.json
|
||||
xrpl.libxrpl.protocol
|
||||
xrpl.libxrpl.resource
|
||||
xrpl.libxrpl.server
|
||||
xrpl.libxrpl
|
||||
antithesis-sdk-cpp
|
||||
EXPORT RippleExports
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
@@ -21,12 +32,12 @@ install(
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
|
||||
if(NOT WIN32)
|
||||
install(
|
||||
CODE "file(CREATE_LINK xrpl \
|
||||
\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/ripple SYMBOLIC)"
|
||||
)
|
||||
endif()
|
||||
install(CODE "
|
||||
set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\")
|
||||
include(create_symbolic_link)
|
||||
create_symbolic_link(xrpl \
|
||||
\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/ripple)
|
||||
")
|
||||
|
||||
install (EXPORT RippleExports
|
||||
FILE RippleTargets.cmake
|
||||
@@ -55,12 +66,12 @@ if (is_root_project AND TARGET rippled)
|
||||
copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/rippled-example.cfg\" etc rippled.cfg)
|
||||
copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/validators-example.txt\" etc validators.txt)
|
||||
")
|
||||
if(NOT WIN32)
|
||||
install(
|
||||
CODE "file(CREATE_LINK rippled${suffix} \
|
||||
\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/xrpld${suffix} SYMBOLIC)"
|
||||
)
|
||||
endif()
|
||||
install(CODE "
|
||||
set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\")
|
||||
include(create_symbolic_link)
|
||||
create_symbolic_link(rippled${suffix} \
|
||||
\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/xrpld${suffix})
|
||||
")
|
||||
endif ()
|
||||
|
||||
install (
|
||||
|
||||
@@ -7,6 +7,9 @@ add_library (Ripple::opts ALIAS opts)
|
||||
target_compile_definitions (opts
|
||||
INTERFACE
|
||||
BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS
|
||||
BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT
|
||||
BOOST_CONTAINER_FWD_BAD_DEQUE
|
||||
HAS_UNCAUGHT_EXCEPTIONS=1
|
||||
$<$<BOOL:${boost_show_deprecated}>:
|
||||
BOOST_ASIO_NO_DEPRECATED
|
||||
BOOST_FILESYSTEM_NO_DEPRECATED
|
||||
@@ -18,10 +21,12 @@ target_compile_definitions (opts
|
||||
>
|
||||
$<$<BOOL:${beast_no_unit_test_inline}>:BEAST_NO_UNIT_TEST_INLINE=1>
|
||||
$<$<BOOL:${beast_disable_autolink}>:BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES=1>
|
||||
$<$<BOOL:${single_io_service_thread}>:RIPPLE_SINGLE_IO_SERVICE_THREAD=1>)
|
||||
$<$<BOOL:${single_io_service_thread}>:RIPPLE_SINGLE_IO_SERVICE_THREAD=1>
|
||||
$<$<BOOL:${voidstar}>:ENABLE_VOIDSTAR>)
|
||||
target_compile_options (opts
|
||||
INTERFACE
|
||||
$<$<AND:$<BOOL:${is_gcc}>,$<COMPILE_LANGUAGE:CXX>>:-Wsuggest-override>
|
||||
$<$<BOOL:${is_gcc}>:-Wno-maybe-uninitialized>
|
||||
$<$<BOOL:${perf}>:-fno-omit-frame-pointer>
|
||||
$<$<AND:$<BOOL:${is_gcc}>,$<BOOL:${coverage}>>:-g --coverage -fprofile-abs-path>
|
||||
$<$<AND:$<BOOL:${is_clang}>,$<BOOL:${coverage}>>:-g --coverage>
|
||||
|
||||
@@ -17,6 +17,10 @@ if(unity)
|
||||
if(NOT is_ci)
|
||||
set(CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "")
|
||||
endif()
|
||||
set(CMAKE_UNITY_BUILD ON CACHE BOOL "Do a unity build")
|
||||
endif()
|
||||
if(is_clang AND is_linux)
|
||||
option(voidstar "Enable Antithesis instrumentation." OFF)
|
||||
endif()
|
||||
if(is_gcc OR is_clang)
|
||||
option(coverage "Generates coverage info." OFF)
|
||||
|
||||
37
cmake/add_module.cmake
Normal file
37
cmake/add_module.cmake
Normal file
@@ -0,0 +1,37 @@
|
||||
include(isolate_headers)
|
||||
|
||||
# Create an OBJECT library target named
|
||||
#
|
||||
# ${PROJECT_NAME}.lib${parent}.${name}
|
||||
#
|
||||
# with sources in src/lib${parent}/${name}
|
||||
# and headers in include/${parent}/${name}
|
||||
# that cannot include headers from other directories in include/
|
||||
# unless they come through linked libraries.
|
||||
#
|
||||
# add_module(parent a)
|
||||
# add_module(parent b)
|
||||
# target_link_libraries(project.libparent.b PUBLIC project.libparent.a)
|
||||
function(add_module parent name)
|
||||
set(target ${PROJECT_NAME}.lib${parent}.${name})
|
||||
add_library(${target} OBJECT)
|
||||
file(GLOB_RECURSE sources CONFIGURE_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/lib${parent}/${name}/*.cpp"
|
||||
)
|
||||
target_sources(${target} PRIVATE ${sources})
|
||||
target_include_directories(${target} PUBLIC
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||
)
|
||||
isolate_headers(
|
||||
${target}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include/${parent}/${name}"
|
||||
PUBLIC
|
||||
)
|
||||
isolate_headers(
|
||||
${target}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/lib${parent}/${name}"
|
||||
PRIVATE
|
||||
)
|
||||
endfunction()
|
||||
20
cmake/create_symbolic_link.cmake
Normal file
20
cmake/create_symbolic_link.cmake
Normal file
@@ -0,0 +1,20 @@
|
||||
# file(CREATE_SYMLINK) only works on Windows with administrator privileges.
|
||||
# https://stackoverflow.com/a/61244115/618906
|
||||
function(create_symbolic_link target link)
|
||||
if(WIN32)
|
||||
if(NOT IS_SYMLINK "${link}")
|
||||
if(NOT IS_ABSOLUTE "${target}")
|
||||
# Relative links work do not work on Windows.
|
||||
set(target "${link}/../${target}")
|
||||
endif()
|
||||
file(TO_NATIVE_PATH "${target}" target)
|
||||
file(TO_NATIVE_PATH "${link}" link)
|
||||
execute_process(COMMAND cmd.exe /c mklink /J "${link}" "${target}")
|
||||
endif()
|
||||
else()
|
||||
file(CREATE_LINK "${target}" "${link}" SYMBOLIC)
|
||||
endif()
|
||||
if(NOT IS_SYMLINK "${link}")
|
||||
message(ERROR "failed to create symlink: <${link}>")
|
||||
endif()
|
||||
endfunction()
|
||||
48
cmake/isolate_headers.cmake
Normal file
48
cmake/isolate_headers.cmake
Normal file
@@ -0,0 +1,48 @@
|
||||
include(create_symbolic_link)
|
||||
|
||||
# Consider include directory B nested under prefix A:
|
||||
#
|
||||
# /path/to/A/then/to/B/...
|
||||
#
|
||||
# Call C the relative path from A to B.
|
||||
# C is what we want to write in `#include` directives:
|
||||
#
|
||||
# #include <then/to/B/...>
|
||||
#
|
||||
# Examples, all from the `jobqueue` module:
|
||||
#
|
||||
# - Library public headers:
|
||||
# B = /include/xrpl/jobqueue
|
||||
# A = /include/
|
||||
# C = xrpl/jobqueue
|
||||
#
|
||||
# - Library private headers:
|
||||
# B = /src/libxrpl/jobqueue
|
||||
# A = /src/
|
||||
# C = libxrpl/jobqueue
|
||||
#
|
||||
# - Test private headers:
|
||||
# B = /tests/jobqueue
|
||||
# A = /
|
||||
# C = tests/jobqueue
|
||||
#
|
||||
# To isolate headers from each other,
|
||||
# we want to create a symlink Y that points to B,
|
||||
# within a subdirectory X of the `CMAKE_BINARY_DIR`,
|
||||
# that has the same relative path C between X and Y,
|
||||
# and then add X as an include directory of the target,
|
||||
# sometimes `PUBLIC` and sometimes `PRIVATE`.
|
||||
# The Cs are all guaranteed to be unique.
|
||||
# We can guarantee a unique X per target by using
|
||||
# `${CMAKE_CURRENT_BINARY_DIR}/include/${target}`.
|
||||
#
|
||||
# isolate_headers(target A B scope)
|
||||
function(isolate_headers target A B scope)
|
||||
file(RELATIVE_PATH C "${A}" "${B}")
|
||||
set(X "${CMAKE_CURRENT_BINARY_DIR}/modules/${target}")
|
||||
set(Y "${X}/${C}")
|
||||
cmake_path(GET Y PARENT_PATH parent)
|
||||
file(MAKE_DIRECTORY "${parent}")
|
||||
create_symbolic_link("${B}" "${Y}")
|
||||
target_include_directories(${target} ${scope} "$<BUILD_INTERFACE:${X}>")
|
||||
endfunction()
|
||||
24
cmake/target_link_modules.cmake
Normal file
24
cmake/target_link_modules.cmake
Normal file
@@ -0,0 +1,24 @@
|
||||
# Link a library to its modules (see: `add_module`)
|
||||
# and remove the module sources from the library's sources.
|
||||
#
|
||||
# add_module(parent a)
|
||||
# add_module(parent b)
|
||||
# target_link_libraries(project.libparent.b PUBLIC project.libparent.a)
|
||||
# add_library(project.libparent)
|
||||
# target_link_modules(parent PUBLIC a b)
|
||||
function(target_link_modules parent scope)
|
||||
set(library ${PROJECT_NAME}.lib${parent})
|
||||
foreach(name ${ARGN})
|
||||
set(module ${library}.${name})
|
||||
get_target_property(sources ${library} SOURCES)
|
||||
list(LENGTH sources before)
|
||||
get_target_property(dupes ${module} SOURCES)
|
||||
list(LENGTH dupes expected)
|
||||
list(REMOVE_ITEM sources ${dupes})
|
||||
list(LENGTH sources after)
|
||||
math(EXPR actual "${before} - ${after}")
|
||||
message(STATUS "${module} with ${expected} sources took ${actual} sources from ${library}")
|
||||
set_target_properties(${library} PROPERTIES SOURCES "${sources}")
|
||||
target_link_libraries(${library} ${scope} ${module})
|
||||
endforeach()
|
||||
endfunction()
|
||||
14
conanfile.py
14
conanfile.py
@@ -24,14 +24,14 @@ class Xrpl(ConanFile):
|
||||
}
|
||||
|
||||
requires = [
|
||||
'date/3.0.1',
|
||||
'date/3.0.3',
|
||||
'grpc/1.50.1',
|
||||
'libarchive/3.6.2',
|
||||
'libarchive/3.7.6',
|
||||
'nudb/2.0.8',
|
||||
'openssl/1.1.1u',
|
||||
'openssl/1.1.1v',
|
||||
'soci/4.0.3',
|
||||
'xxhash/0.8.2',
|
||||
'zlib/1.2.13',
|
||||
'zlib/1.3.1',
|
||||
]
|
||||
|
||||
tool_requires = [
|
||||
@@ -99,10 +99,10 @@ class Xrpl(ConanFile):
|
||||
self.options['boost'].visibility = 'global'
|
||||
|
||||
def requirements(self):
|
||||
self.requires('boost/1.82.0', force=True)
|
||||
self.requires('lz4/1.9.3', force=True)
|
||||
self.requires('boost/1.83.0', force=True)
|
||||
self.requires('lz4/1.10.0', force=True)
|
||||
self.requires('protobuf/3.21.9', force=True)
|
||||
self.requires('sqlite3/3.42.0', force=True)
|
||||
self.requires('sqlite3/3.47.0', force=True)
|
||||
if self.options.jemalloc:
|
||||
self.requires('jemalloc/5.3.0')
|
||||
if self.options.rocksdb:
|
||||
|
||||
1
external/README.md
vendored
1
external/README.md
vendored
@@ -6,6 +6,7 @@ The Conan recipes include patches we have not yet pushed upstream.
|
||||
|
||||
| Folder | Upstream | Description |
|
||||
|:----------------|:---------------------------------------------|:------------|
|
||||
| `antithesis-sdk`| [Project](https://github.com/antithesishq/antithesis-sdk-cpp/) | [Antithesis](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html) SDK for C++ |
|
||||
| `ed25519-donna` | [Project](https://github.com/floodyberry/ed25519-donna) | [Ed25519](http://ed25519.cr.yp.to/) digital signatures |
|
||||
| `rocksdb` | [Recipe](https://github.com/conan-io/conan-center-index/tree/master/recipes/rocksdb) | Fast key/value database. (Supports rotational disks better than NuDB.) |
|
||||
| `secp256k1` | [Project](https://github.com/bitcoin-core/secp256k1) | ECDSA digital signatures using the **secp256k1** curve |
|
||||
|
||||
3
external/antithesis-sdk/.clang-format
vendored
Normal file
3
external/antithesis-sdk/.clang-format
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
DisableFormat: true
|
||||
SortIncludes: false
|
||||
17
external/antithesis-sdk/CMakeLists.txt
vendored
Normal file
17
external/antithesis-sdk/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
|
||||
# Note, version set explicitly by rippled project
|
||||
project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX)
|
||||
|
||||
add_library(antithesis-sdk-cpp INTERFACE antithesis_sdk.h)
|
||||
|
||||
# Note, both sections below created by rippled project
|
||||
target_include_directories(antithesis-sdk-cpp INTERFACE
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
)
|
||||
|
||||
install(
|
||||
FILES antithesis_sdk.h
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
BIN
external/antithesis-sdk/LICENSE
vendored
Normal file
BIN
external/antithesis-sdk/LICENSE
vendored
Normal file
Binary file not shown.
8
external/antithesis-sdk/README.md
vendored
Normal file
8
external/antithesis-sdk/README.md
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Antithesis C++ SDK
|
||||
|
||||
This library provides methods for C++ programs to configure the [Antithesis](https://antithesis.com) platform. It contains three kinds of functionality:
|
||||
* Assertion macros that allow you to define test properties about your software or workload.
|
||||
* Randomness functions for requesting both structured and unstructured randomness from the Antithesis platform.
|
||||
* Lifecycle functions that inform the Antithesis environment that particular test phases or milestones have been reached.
|
||||
|
||||
For general usage guidance see the [Antithesis C++ SDK Documentation](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview/)
|
||||
113
external/antithesis-sdk/antithesis_instrumentation.h
vendored
Normal file
113
external/antithesis-sdk/antithesis_instrumentation.h
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
This header file enables code coverage instrumentation. It is distributed with the Antithesis C++ SDK.
|
||||
|
||||
This header file can be used in both C and C++ programs. (The rest of the SDK works only for C++ programs.)
|
||||
|
||||
You should include it in a single .cpp or .c file.
|
||||
|
||||
The instructions (such as required compiler flags) and usage guidance are found at https://antithesis.com/docs/using_antithesis/sdk/cpp/overview/.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
// If the libvoidstar(determ) library is present,
|
||||
// pass thru trace_pc_guard related callbacks to it
|
||||
typedef void (*trace_pc_guard_init_fn)(uint32_t *start, uint32_t *stop);
|
||||
typedef void (*trace_pc_guard_fn)(uint32_t *guard, uint64_t edge);
|
||||
|
||||
static trace_pc_guard_init_fn trace_pc_guard_init = NULL;
|
||||
static trace_pc_guard_fn trace_pc_guard = NULL;
|
||||
static bool did_check_libvoidstar = false;
|
||||
static bool has_libvoidstar = false;
|
||||
|
||||
static __attribute__((no_sanitize("coverage"))) void debug_message_out(const char *msg) {
|
||||
(void)printf("%s\n", msg);
|
||||
return;
|
||||
}
|
||||
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
#endif
|
||||
__attribute__((no_sanitize("coverage"))) void antithesis_load_libvoidstar() {
|
||||
#ifdef __cplusplus
|
||||
constexpr
|
||||
#endif
|
||||
const char* LIB_PATH = "/usr/lib/libvoidstar.so";
|
||||
|
||||
if (did_check_libvoidstar) {
|
||||
return;
|
||||
}
|
||||
debug_message_out("TRYING TO LOAD libvoidstar");
|
||||
did_check_libvoidstar = true;
|
||||
void* shared_lib = dlopen(LIB_PATH, RTLD_NOW);
|
||||
if (!shared_lib) {
|
||||
debug_message_out("Can not load the Antithesis native library");
|
||||
return;
|
||||
}
|
||||
|
||||
void* trace_pc_guard_init_sym = dlsym(shared_lib, "__sanitizer_cov_trace_pc_guard_init");
|
||||
if (!trace_pc_guard_init_sym) {
|
||||
debug_message_out("Can not forward calls to libvoidstar for __sanitizer_cov_trace_pc_guard_init");
|
||||
return;
|
||||
}
|
||||
|
||||
void* trace_pc_guard_sym = dlsym(shared_lib, "__sanitizer_cov_trace_pc_guard_internal");
|
||||
if (!trace_pc_guard_sym) {
|
||||
debug_message_out("Can not forward calls to libvoidstar for __sanitizer_cov_trace_pc_guard");
|
||||
return;
|
||||
}
|
||||
|
||||
trace_pc_guard_init = (trace_pc_guard_init_fn)(trace_pc_guard_init_sym);
|
||||
trace_pc_guard = (trace_pc_guard_fn)(trace_pc_guard_sym);
|
||||
has_libvoidstar = true;
|
||||
debug_message_out("LOADED libvoidstar");
|
||||
}
|
||||
|
||||
// The following symbols are indeed reserved identifiers, since we're implementing functions defined
|
||||
// in the compiler runtime. Not clear how to get Clang on board with that besides narrowly suppressing
|
||||
// the warning in this case. The sample code on the CoverageSanitizer documentation page fails this
|
||||
// warning!
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wreserved-identifier"
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
#endif
|
||||
void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
|
||||
debug_message_out("SDK forwarding to libvoidstar for __sanitizer_cov_trace_pc_guard_init()");
|
||||
if (!did_check_libvoidstar) {
|
||||
antithesis_load_libvoidstar();
|
||||
}
|
||||
if (has_libvoidstar) {
|
||||
trace_pc_guard_init(start, stop);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
extern
|
||||
#ifdef __cplusplus
|
||||
"C"
|
||||
#endif
|
||||
void __sanitizer_cov_trace_pc_guard( uint32_t *guard ) {
|
||||
if (has_libvoidstar) {
|
||||
uint64_t edge = (uint64_t)(__builtin_return_address(0));
|
||||
trace_pc_guard(guard, edge);
|
||||
} else {
|
||||
if (guard) {
|
||||
*guard = 0;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
1105
external/antithesis-sdk/antithesis_sdk.h
vendored
Normal file
1105
external/antithesis-sdk/antithesis_sdk.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
6
external/rocksdb/conanfile.py
vendored
6
external/rocksdb/conanfile.py
vendored
@@ -89,13 +89,13 @@ class RocksDBConan(ConanFile):
|
||||
if self.options.with_snappy:
|
||||
self.requires("snappy/1.1.10")
|
||||
if self.options.with_lz4:
|
||||
self.requires("lz4/1.9.4")
|
||||
self.requires("lz4/1.10.0")
|
||||
if self.options.with_zlib:
|
||||
self.requires("zlib/[>=1.2.11 <2]")
|
||||
if self.options.with_zstd:
|
||||
self.requires("zstd/1.5.5")
|
||||
self.requires("zstd/1.5.6")
|
||||
if self.options.get_safe("with_tbb"):
|
||||
self.requires("onetbb/2021.10.0")
|
||||
self.requires("onetbb/2021.12.0")
|
||||
if self.options.with_jemalloc:
|
||||
self.requires("jemalloc/5.3.0")
|
||||
|
||||
|
||||
414
external/secp256k1/.cirrus.yml
vendored
414
external/secp256k1/.cirrus.yml
vendored
@@ -10,8 +10,8 @@ env:
|
||||
MAKEFLAGS: -j4
|
||||
BUILD: check
|
||||
### secp256k1 config
|
||||
ECMULTWINDOW: auto
|
||||
ECMULTGENPRECISION: auto
|
||||
ECMULTWINDOW: 15
|
||||
ECMULTGENKB: 22
|
||||
ASM: no
|
||||
WIDEMUL: auto
|
||||
WITH_VALGRIND: yes
|
||||
@@ -20,20 +20,18 @@ env:
|
||||
EXPERIMENTAL: no
|
||||
ECDH: no
|
||||
RECOVERY: no
|
||||
EXTRAKEYS: no
|
||||
SCHNORRSIG: no
|
||||
MUSIG: no
|
||||
ELLSWIFT: no
|
||||
### test options
|
||||
SECP256K1_TEST_ITERS:
|
||||
SECP256K1_TEST_ITERS: 64
|
||||
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:
|
||||
@@ -53,357 +51,51 @@ cat_logs_snippet: &CAT_LOGS
|
||||
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: arm32}
|
||||
<< : *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 -E env CFLAGS="/WX" cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON
|
||||
linux_arm64_container_snippet: &LINUX_ARM64_CONTAINER
|
||||
env_script:
|
||||
- env | tee /tmp/env
|
||||
build_script:
|
||||
- '%x64_NATIVE_TOOLS%'
|
||||
- cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5
|
||||
check_script:
|
||||
- '%x64_NATIVE_TOOLS%'
|
||||
- ctest -C RelWithDebInfo --test-dir build -j 5
|
||||
- build\src\RelWithDebInfo\bench_ecmult.exe
|
||||
- build\src\RelWithDebInfo\bench_internal.exe
|
||||
- build\src\RelWithDebInfo\bench.exe
|
||||
- DOCKER_BUILDKIT=1 docker build --file "ci/linux-debian.Dockerfile" --tag="ci_secp256k1_arm"
|
||||
- docker image prune --force # Cleanup stale layers
|
||||
test_script:
|
||||
- docker run --rm --mount "type=bind,src=./,dst=/ci_secp256k1" --env-file /tmp/env --replace --name "ci_secp256k1_arm" "ci_secp256k1_arm" bash -c "cd /ci_secp256k1/ && ./ci/ci.sh"
|
||||
|
||||
task:
|
||||
name: "ARM64: Linux (Debian stable)"
|
||||
persistent_worker:
|
||||
labels:
|
||||
type: arm64
|
||||
env:
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
EXTRAKEYS: yes
|
||||
SCHNORRSIG: yes
|
||||
MUSIG: yes
|
||||
ELLSWIFT: yes
|
||||
matrix:
|
||||
# Currently only gcc-snapshot, the other compilers are tested on GHA with QEMU
|
||||
- env: { CC: 'gcc-snapshot' }
|
||||
<< : *LINUX_ARM64_CONTAINER
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "ARM64: Linux (Debian stable), Valgrind"
|
||||
persistent_worker:
|
||||
labels:
|
||||
type: arm64
|
||||
env:
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
EXTRAKEYS: yes
|
||||
SCHNORRSIG: yes
|
||||
MUSIG: yes
|
||||
ELLSWIFT: yes
|
||||
WRAPPER_CMD: 'valgrind --error-exitcode=42'
|
||||
SECP256K1_TEST_ITERS: 2
|
||||
matrix:
|
||||
- env: { CC: 'gcc' }
|
||||
- env: { CC: 'clang' }
|
||||
- env: { CC: 'gcc-snapshot' }
|
||||
- env: { CC: 'clang-snapshot' }
|
||||
<< : *LINUX_ARM64_CONTAINER
|
||||
<< : *CAT_LOGS
|
||||
|
||||
2
external/secp256k1/.gitignore
vendored
2
external/secp256k1/.gitignore
vendored
@@ -10,6 +10,8 @@ ctime_tests
|
||||
ecdh_example
|
||||
ecdsa_example
|
||||
schnorr_example
|
||||
ellswift_example
|
||||
musig_example
|
||||
*.exe
|
||||
*.so
|
||||
*.a
|
||||
|
||||
83
external/secp256k1/CHANGELOG.md
vendored
83
external/secp256k1/CHANGELOG.md
vendored
@@ -5,6 +5,83 @@ 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).
|
||||
|
||||
## [0.6.0] - 2024-11-04
|
||||
|
||||
#### Added
|
||||
- New module `musig` implements the MuSig2 multisignature scheme according to the [BIP 327 specification](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki). See:
|
||||
- Header file `include/secp256k1_musig.h` which defines the new API.
|
||||
- Document `doc/musig.md` for further notes on API usage.
|
||||
- Usage example `examples/musig.c`.
|
||||
- New CMake variable `SECP256K1_APPEND_LDFLAGS` for appending linker flags to the build command.
|
||||
|
||||
#### Changed
|
||||
- API functions now use a significantly more robust method to clear secrets from the stack before returning. However, secret clearing remains a best-effort security measure and cannot guarantee complete removal.
|
||||
- Any type `secp256k1_foo` can now be forward-declared using `typedef struct secp256k1_foo secp256k1_foo;` (or also `struct secp256k1_foo;` in C++).
|
||||
- Organized CMake build artifacts into dedicated directories (`bin/` for executables, `lib/` for libraries) to improve build output structure and Windows shared library compatibility.
|
||||
|
||||
#### Removed
|
||||
- Removed the `secp256k1_scratch_space` struct and its associated functions `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` because the scratch space was unused in the API.
|
||||
|
||||
#### ABI Compatibility
|
||||
The symbols `secp256k1_scratch_space_create` and `secp256k1_scratch_space_destroy` were removed.
|
||||
Otherwise, the library maintains backward compatibility with versions 0.3.x through 0.5.x.
|
||||
|
||||
## [0.5.1] - 2024-08-01
|
||||
|
||||
#### Added
|
||||
- Added usage example for an ElligatorSwift key exchange.
|
||||
|
||||
#### Changed
|
||||
- The default size of the precomputed table for signing was changed from 22 KiB to 86 KiB. The size can be changed with the configure option `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake).
|
||||
- "auto" is no longer an accepted value for the `--with-ecmult-window` and `--with-ecmult-gen-kb` configure options (this also applies to `SECP256K1_ECMULT_WINDOW_SIZE` and `SECP256K1_ECMULT_GEN_KB` in CMake). To achieve the same configuration as previously provided by the "auto" value, omit setting the configure option explicitly.
|
||||
|
||||
#### Fixed
|
||||
- Fixed compilation when the extrakeys module is disabled.
|
||||
|
||||
#### ABI Compatibility
|
||||
The ABI is backward compatible with versions 0.5.0, 0.4.x and 0.3.x.
|
||||
|
||||
## [0.5.0] - 2024-05-06
|
||||
|
||||
#### Added
|
||||
- New function `secp256k1_ec_pubkey_sort` that sorts public keys using lexicographic (of compressed serialization) order.
|
||||
|
||||
#### Changed
|
||||
- The implementation of the point multiplication algorithm used for signing and public key generation was changed, resulting in improved performance for those operations.
|
||||
- The related configure option `--ecmult-gen-precision` was replaced with `--ecmult-gen-kb` (`SECP256K1_ECMULT_GEN_KB` for CMake).
|
||||
- This changes the supported precomputed table sizes for these operations. The new supported sizes are 2 KiB, 22 KiB, or 86 KiB (while the old supported sizes were 32 KiB, 64 KiB, or 512 KiB).
|
||||
|
||||
#### ABI Compatibility
|
||||
The ABI is backward compatible with versions 0.4.x and 0.3.x.
|
||||
|
||||
## [0.4.1] - 2023-12-21
|
||||
|
||||
#### Changed
|
||||
- The point multiplication algorithm used for ECDH operations (module `ecdh`) was replaced with a slightly faster one.
|
||||
- Optional handwritten x86_64 assembly for field operations was removed because modern C compilers are able to output more efficient assembly. This change results in a significant speedup of some library functions when handwritten x86_64 assembly is enabled (`--with-asm=x86_64` in GNU Autotools, `-DSECP256K1_ASM=x86_64` in CMake), which is the default on x86_64. Benchmarks with GCC 10.5.0 show a 10% speedup for `secp256k1_ecdsa_verify` and `secp256k1_schnorrsig_verify`.
|
||||
|
||||
#### ABI Compatibility
|
||||
The ABI is backward compatible with versions 0.4.0 and 0.3.x.
|
||||
|
||||
## [0.4.0] - 2023-09-04
|
||||
|
||||
#### Added
|
||||
- New module `ellswift` implements ElligatorSwift encoding for public keys and x-only Diffie-Hellman key exchange for them.
|
||||
ElligatorSwift permits representing secp256k1 public keys as 64-byte arrays which cannot be distinguished from uniformly random. See:
|
||||
- Header file `include/secp256k1_ellswift.h` which defines the new API.
|
||||
- Document `doc/ellswift.md` which explains the mathematical background of the scheme.
|
||||
- The [paper](https://eprint.iacr.org/2022/759) on which the scheme is based.
|
||||
- We now test the library with unreleased development snapshots of GCC and Clang. This gives us an early chance to catch miscompilations and constant-time issues introduced by the compiler (such as those that led to the previous two releases).
|
||||
|
||||
#### Fixed
|
||||
- Fixed symbol visibility in Windows DLL builds, where three internal library symbols were wrongly exported.
|
||||
|
||||
#### Changed
|
||||
- When consuming libsecp256k1 as a static library on Windows, the user must now define the `SECP256K1_STATIC` macro before including `secp256k1.h`.
|
||||
|
||||
#### ABI Compatibility
|
||||
This release is backward compatible with the ABI of 0.3.0, 0.3.1, and 0.3.2. Symbol visibility is now believed to be handled properly on supported platforms and is now considered to be part of the ABI. Please report any improperly exported symbols as a bug.
|
||||
|
||||
## [0.3.2] - 2023-05-13
|
||||
We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`.
|
||||
|
||||
@@ -85,7 +162,11 @@ 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.2...HEAD
|
||||
[0.6.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.1...v0.6.0
|
||||
[0.5.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.0...v0.5.1
|
||||
[0.5.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.1...v0.5.0
|
||||
[0.4.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.0...v0.4.1
|
||||
[0.4.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...v0.4.0
|
||||
[0.3.2]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...v0.3.2
|
||||
[0.3.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...v0.3.1
|
||||
[0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0
|
||||
|
||||
226
external/secp256k1/CMakeLists.txt
vendored
226
external/secp256k1/CMakeLists.txt
vendored
@@ -1,32 +1,29 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15)
|
||||
# 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()
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
#=============================
|
||||
# Project / Package metadata
|
||||
#=============================
|
||||
project(libsecp256k1
|
||||
# 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.
|
||||
VERSION 0.3.2
|
||||
VERSION 0.6.0
|
||||
DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1."
|
||||
HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1"
|
||||
LANGUAGES C
|
||||
)
|
||||
enable_testing()
|
||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 3.21)
|
||||
get_directory_property(parent_directory PARENT_DIRECTORY)
|
||||
if(parent_directory)
|
||||
set(PROJECT_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
|
||||
set(${PROJECT_NAME}_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
|
||||
# Emulates CMake 3.21+ behavior.
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
set(PROJECT_IS_TOP_LEVEL ON)
|
||||
set(${PROJECT_NAME}_IS_TOP_LEVEL ON)
|
||||
else()
|
||||
set(PROJECT_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
|
||||
set(${PROJECT_NAME}_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
|
||||
set(PROJECT_IS_TOP_LEVEL OFF)
|
||||
set(${PROJECT_NAME}_IS_TOP_LEVEL OFF)
|
||||
endif()
|
||||
unset(parent_directory)
|
||||
endif()
|
||||
|
||||
# The library version is based on libtool versioning of the ABI. The set of
|
||||
@@ -34,15 +31,19 @@ endif()
|
||||
# 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 2)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_CURRENT 5)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_REVISION 0)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_AGE 0)
|
||||
|
||||
#=============================
|
||||
# Language setup
|
||||
#=============================
|
||||
set(CMAKE_C_STANDARD 90)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
|
||||
#=============================
|
||||
# Configurable options
|
||||
#=============================
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries." ON)
|
||||
option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF)
|
||||
if(SECP256K1_DISABLE_SHARED)
|
||||
@@ -51,24 +52,49 @@ endif()
|
||||
|
||||
option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL})
|
||||
|
||||
## Modules
|
||||
|
||||
# We declare all options before processing them, to make sure we can express
|
||||
# dependendencies while processing.
|
||||
option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON)
|
||||
if(SECP256K1_ENABLE_MODULE_ECDH)
|
||||
add_compile_definitions(ENABLE_MODULE_ECDH=1)
|
||||
option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF)
|
||||
option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
|
||||
option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON)
|
||||
option(SECP256K1_ENABLE_MODULE_MUSIG "Enable musig module." ON)
|
||||
option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON)
|
||||
|
||||
# Processing must be done in a topological sorting of the dependency graph
|
||||
# (dependent module first).
|
||||
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
||||
add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_MUSIG)
|
||||
if(DEFINED SECP256K1_ENABLE_MODULE_SCHNORRSIG AND NOT SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
message(FATAL_ERROR "Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.")
|
||||
endif()
|
||||
set(SECP256K1_ENABLE_MODULE_SCHNORRSIG ON)
|
||||
add_compile_definitions(ENABLE_MODULE_MUSIG=1)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
if(DEFINED SECP256K1_ENABLE_MODULE_EXTRAKEYS AND NOT SECP256K1_ENABLE_MODULE_EXTRAKEYS)
|
||||
message(FATAL_ERROR "Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.")
|
||||
endif()
|
||||
set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON)
|
||||
add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
|
||||
add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1)
|
||||
endif()
|
||||
|
||||
option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF)
|
||||
if(SECP256K1_ENABLE_MODULE_RECOVERY)
|
||||
add_compile_definitions(ENABLE_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_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1)
|
||||
endif()
|
||||
if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
|
||||
add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1)
|
||||
if(SECP256K1_ENABLE_MODULE_ECDH)
|
||||
add_compile_definitions(ENABLE_MODULE_ECDH=1)
|
||||
endif()
|
||||
|
||||
option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF)
|
||||
@@ -76,22 +102,25 @@ if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS)
|
||||
add_compile_definitions(USE_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)
|
||||
set(SECP256K1_ECMULT_WINDOW_SIZE 15 CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. The default value is a reasonable setting for desktop machines (currently 15). [default=15]")
|
||||
set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS 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_compile_definitions(ECMULT_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)
|
||||
set(SECP256K1_ECMULT_GEN_KB 86 CACHE STRING "The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms). Larger values result in possibly better signing or key generation performance at the cost of a larger table. Valid choices are 2, 22, 86. The default value is a reasonable setting for desktop machines (currently 86). [default=86]")
|
||||
set_property(CACHE SECP256K1_ECMULT_GEN_KB PROPERTY STRINGS 2 22 86)
|
||||
check_string_option_value(SECP256K1_ECMULT_GEN_KB)
|
||||
if(SECP256K1_ECMULT_GEN_KB EQUAL 2)
|
||||
add_compile_definitions(COMB_BLOCKS=2)
|
||||
add_compile_definitions(COMB_TEETH=5)
|
||||
elseif(SECP256K1_ECMULT_GEN_KB EQUAL 22)
|
||||
add_compile_definitions(COMB_BLOCKS=11)
|
||||
add_compile_definitions(COMB_TEETH=6)
|
||||
elseif(SECP256K1_ECMULT_GEN_KB EQUAL 86)
|
||||
add_compile_definitions(COMB_BLOCKS=43)
|
||||
add_compile_definitions(COMB_TEETH=6)
|
||||
endif()
|
||||
add_compile_definitions(ECMULT_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")
|
||||
@@ -102,7 +131,7 @@ if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
|
||||
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 \"arm32\" (experimental). [default=AUTO]")
|
||||
set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]")
|
||||
set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32")
|
||||
check_string_option_value(SECP256K1_ASM)
|
||||
if(SECP256K1_ASM STREQUAL "arm32")
|
||||
@@ -112,7 +141,7 @@ if(SECP256K1_ASM STREQUAL "arm32")
|
||||
if(HAVE_ARM32_ASM)
|
||||
add_compile_definitions(USE_EXTERNAL_ASM=1)
|
||||
else()
|
||||
message(FATAL_ERROR "ARM32 assembly optimization requested but not available.")
|
||||
message(FATAL_ERROR "ARM32 assembly requested but not available.")
|
||||
endif()
|
||||
elseif(SECP256K1_ASM)
|
||||
include(CheckX86_64Assembly)
|
||||
@@ -123,14 +152,14 @@ elseif(SECP256K1_ASM)
|
||||
elseif(SECP256K1_ASM STREQUAL "AUTO")
|
||||
set(SECP256K1_ASM "OFF")
|
||||
else()
|
||||
message(FATAL_ERROR "x86_64 assembly optimization requested but not available.")
|
||||
message(FATAL_ERROR "x86_64 assembly requested but not available.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF)
|
||||
if(NOT SECP256K1_EXPERIMENTAL)
|
||||
if(SECP256K1_ASM STREQUAL "arm32")
|
||||
message(FATAL_ERROR "ARM32 assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
|
||||
message(FATAL_ERROR "ARM32 assembly is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -167,7 +196,7 @@ else()
|
||||
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}")
|
||||
string(REGEX REPLACE "-O3( |$)" "-O2\\1" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
|
||||
endif()
|
||||
|
||||
# Define custom "Coverage" build type.
|
||||
@@ -189,31 +218,37 @@ mark_as_advanced(
|
||||
CMAKE_SHARED_LINKER_FLAGS_COVERAGE
|
||||
)
|
||||
|
||||
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
set(default_build_type "RelWithDebInfo")
|
||||
if(is_multi_config)
|
||||
set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING
|
||||
"Supported configuration types."
|
||||
FORCE
|
||||
)
|
||||
else()
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
|
||||
STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage"
|
||||
)
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
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."
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
set(default_build_type "RelWithDebInfo")
|
||||
if(is_multi_config)
|
||||
set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING
|
||||
"Supported configuration types."
|
||||
FORCE
|
||||
)
|
||||
else()
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
|
||||
STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage"
|
||||
)
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
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()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(TryAppendCFlags)
|
||||
if(MSVC)
|
||||
# Keep the following commands ordered lexicographically.
|
||||
try_append_c_flags(/W2) # Moderate warning level.
|
||||
try_append_c_flags(/W3) # Production quality warning level.
|
||||
try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
|
||||
try_append_c_flags(/wd4244) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data".
|
||||
try_append_c_flags(/wd4267) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data".
|
||||
# Eliminate deprecation warnings for the older, less secure functions.
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
# Keep the following commands ordered lexicographically.
|
||||
try_append_c_flags(-pedantic)
|
||||
@@ -234,17 +269,41 @@ 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()
|
||||
set(print_msan_notice)
|
||||
if(SECP256K1_BUILD_CTIME_TESTS)
|
||||
include(CheckMemorySanitizer)
|
||||
check_memory_sanitizer(msan_enabled)
|
||||
if(msan_enabled)
|
||||
try_append_c_flags(-fno-sanitize-memory-param-retval)
|
||||
set(print_msan_notice YES)
|
||||
endif()
|
||||
unset(msan_enabled)
|
||||
endif()
|
||||
|
||||
set(SECP256K1_APPEND_CFLAGS "" CACHE STRING "Compiler flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.")
|
||||
if(SECP256K1_APPEND_CFLAGS)
|
||||
# Appending to this low-level rule variable is the only way to
|
||||
# guarantee that the flags appear at the end of the command line.
|
||||
string(APPEND CMAKE_C_COMPILE_OBJECT " ${SECP256K1_APPEND_CFLAGS}")
|
||||
endif()
|
||||
|
||||
set(SECP256K1_APPEND_LDFLAGS "" CACHE STRING "Linker flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.")
|
||||
if(SECP256K1_APPEND_LDFLAGS)
|
||||
# Appending to this low-level rule variable is the only way to
|
||||
# guarantee that the flags appear at the end of the command line.
|
||||
string(APPEND CMAKE_C_CREATE_SHARED_LIBRARY " ${SECP256K1_APPEND_LDFLAGS}")
|
||||
string(APPEND CMAKE_C_LINK_EXECUTABLE " ${SECP256K1_APPEND_LDFLAGS}")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
endif()
|
||||
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
||||
endif()
|
||||
if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
||||
endif()
|
||||
add_subdirectory(src)
|
||||
if(SECP256K1_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
@@ -266,11 +325,13 @@ 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(" musig ............................... ${SECP256K1_ENABLE_MODULE_MUSIG}")
|
||||
message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}")
|
||||
message("Parameters:")
|
||||
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
|
||||
message(" ecmult gen precision bits ........... ${SECP256K1_ECMULT_GEN_PREC_BITS}")
|
||||
message(" ecmult gen table size ............... ${SECP256K1_ECMULT_GEN_KB} KiB")
|
||||
message("Optional features:")
|
||||
message(" assembly optimization ............... ${SECP256K1_ASM}")
|
||||
message(" assembly ............................ ${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}")
|
||||
@@ -297,7 +358,7 @@ 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("C compiler ............................ ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}, ${CMAKE_C_COMPILER}")
|
||||
message("CFLAGS ................................ ${CMAKE_C_FLAGS}")
|
||||
get_directory_property(compile_options COMPILE_OPTIONS)
|
||||
string(REPLACE ";" " " compile_options "${compile_options}")
|
||||
@@ -320,7 +381,20 @@ else()
|
||||
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}")
|
||||
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}")
|
||||
endif()
|
||||
message("\n")
|
||||
if(SECP256K1_APPEND_CFLAGS)
|
||||
message("SECP256K1_APPEND_CFLAGS ............... ${SECP256K1_APPEND_CFLAGS}")
|
||||
endif()
|
||||
if(SECP256K1_APPEND_LDFLAGS)
|
||||
message("SECP256K1_APPEND_LDFLAGS .............. ${SECP256K1_APPEND_LDFLAGS}")
|
||||
endif()
|
||||
message("")
|
||||
if(print_msan_notice)
|
||||
message(
|
||||
"Note:\n"
|
||||
" MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to compile options\n"
|
||||
" to avoid false positives in ctime_tests. Pass -DSECP256K1_BUILD_CTIME_TESTS=OFF to avoid this.\n"
|
||||
)
|
||||
endif()
|
||||
if(SECP256K1_EXPERIMENTAL)
|
||||
message(
|
||||
" ******\n"
|
||||
|
||||
108
external/secp256k1/CONTRIBUTING.md
vendored
Normal file
108
external/secp256k1/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
# Contributing to libsecp256k1
|
||||
|
||||
## Scope
|
||||
|
||||
libsecp256k1 is a library for elliptic curve cryptography on the curve secp256k1, not a general-purpose cryptography library.
|
||||
The library primarily serves the needs of the Bitcoin Core project but provides additional functionality for the benefit of the wider Bitcoin ecosystem.
|
||||
|
||||
## Adding new functionality or modules
|
||||
|
||||
The libsecp256k1 project welcomes contributions in the form of new functionality or modules, provided they are within the project's scope.
|
||||
|
||||
It is the responsibility of the contributors to convince the maintainers that the proposed functionality is within the project's scope, high-quality and maintainable.
|
||||
Contributors are recommended to provide the following in addition to the new code:
|
||||
|
||||
* **Specification:**
|
||||
A specification can help significantly in reviewing the new code as it provides documentation and context.
|
||||
It may justify various design decisions, give a motivation and outline security goals.
|
||||
If the specification contains pseudocode, a reference implementation or test vectors, these can be used to compare with the proposed libsecp256k1 code.
|
||||
* **Security Arguments:**
|
||||
In addition to a defining the security goals, it should be argued that the new functionality meets these goals.
|
||||
Depending on the nature of the new functionality, a wide range of security arguments are acceptable, ranging from being "obviously secure" to rigorous proofs of security.
|
||||
* **Relevance Arguments:**
|
||||
The relevance of the new functionality for the Bitcoin ecosystem should be argued by outlining clear use cases.
|
||||
|
||||
These are not the only factors taken into account when considering to add new functionality.
|
||||
The proposed new libsecp256k1 code must be of high quality, including API documentation and tests, as well as featuring a misuse-resistant API design.
|
||||
|
||||
We recommend reaching out to other contributors (see [Communication Channels](#communication-channels)) and get feedback before implementing new functionality.
|
||||
|
||||
## Communication channels
|
||||
|
||||
Most communication about libsecp256k1 occurs on the GitHub repository: in issues, pull request or on the discussion board.
|
||||
|
||||
Additionally, there is an IRC channel dedicated to libsecp256k1, with biweekly meetings (see channel topic).
|
||||
The channel is `#secp256k1` on Libera Chat.
|
||||
The easiest way to participate on IRC is with the web client, [web.libera.chat](https://web.libera.chat/#secp256k1).
|
||||
Chat history logs can be found at https://gnusha.org/secp256k1/.
|
||||
|
||||
## Contributor workflow & peer review
|
||||
|
||||
The Contributor Workflow & Peer Review in libsecp256k1 are similar to Bitcoin Core's workflow and review processes described in its [CONTRIBUTING.md](https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md).
|
||||
|
||||
### Coding conventions
|
||||
|
||||
In addition, libsecp256k1 tries to maintain the following coding conventions:
|
||||
|
||||
* No runtime heap allocation (e.g., no `malloc`) unless explicitly requested by the caller (via `secp256k1_context_create` or `secp256k1_scratch_space_create`, for example). Moreover, it should be possible to use the library without any heap allocations.
|
||||
* The tests should cover all lines and branches of the library (see [Test coverage](#coverage)).
|
||||
* Operations involving secret data should be tested for being constant time with respect to the secrets (see [src/ctime_tests.c](src/ctime_tests.c)).
|
||||
* Local variables containing secret data should be cleared explicitly to try to delete secrets from memory.
|
||||
* Use `secp256k1_memcmp_var` instead of `memcmp` (see [#823](https://github.com/bitcoin-core/secp256k1/issues/823)).
|
||||
* As a rule of thumb, the default values for configuration options should target standard desktop machines and align with Bitcoin Core's defaults, and the tests should mostly exercise the default configuration (see [#1549](https://github.com/bitcoin-core/secp256k1/issues/1549#issuecomment-2200559257)).
|
||||
|
||||
#### Style conventions
|
||||
|
||||
* Commits should be atomic and diffs should be easy to read. For this reason, do not mix any formatting fixes or code moves with actual code changes. Make sure each individual commit is hygienic: that it builds successfully on its own without warnings, errors, regressions, or test failures.
|
||||
* New code should adhere to the style of existing, in particular surrounding, code. Other than that, we do not enforce strict rules for code formatting.
|
||||
* The code conforms to C89. Most notably, that means that only `/* ... */` comments are allowed (no `//` line comments). Moreover, any declarations in a `{ ... }` block (e.g., a function) must appear at the beginning of the block before any statements. When you would like to declare a variable in the middle of a block, you can open a new block:
|
||||
```C
|
||||
void secp256k_foo(void) {
|
||||
unsigned int x; /* declaration */
|
||||
int y = 2*x; /* declaration */
|
||||
x = 17; /* statement */
|
||||
{
|
||||
int a, b; /* declaration */
|
||||
a = x + y; /* statement */
|
||||
secp256k_bar(x, &b); /* statement */
|
||||
}
|
||||
}
|
||||
```
|
||||
* Use `unsigned int` instead of just `unsigned`.
|
||||
* Use `void *ptr` instead of `void* ptr`.
|
||||
* Arguments of the publicly-facing API must have a specific order defined in [include/secp256k1.h](include/secp256k1.h).
|
||||
* User-facing comment lines in headers should be limited to 80 chars if possible.
|
||||
* All identifiers in file scope should start with `secp256k1_`.
|
||||
* Avoid trailing whitespace.
|
||||
|
||||
### Tests
|
||||
|
||||
#### Coverage
|
||||
|
||||
This library aims to have full coverage of 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
|
||||
|
||||
#### Exhaustive tests
|
||||
|
||||
There are tests of several functions in which a small group replaces secp256k1.
|
||||
These tests are *exhaustive* since they provide all elements and scalars of the small group as input arguments (see [src/tests_exhaustive.c](src/tests_exhaustive.c)).
|
||||
|
||||
### Benchmarks
|
||||
|
||||
See `src/bench*.c` for examples of benchmarks.
|
||||
45
external/secp256k1/Makefile.am
vendored
45
external/secp256k1/Makefile.am
vendored
@@ -37,7 +37,6 @@ 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
|
||||
@@ -46,6 +45,7 @@ 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/testutil.h
|
||||
noinst_HEADERS += src/util.h
|
||||
noinst_HEADERS += src/int128.h
|
||||
noinst_HEADERS += src/int128_impl.h
|
||||
@@ -64,6 +64,8 @@ noinst_HEADERS += src/field.h
|
||||
noinst_HEADERS += src/field_impl.h
|
||||
noinst_HEADERS += src/bench.h
|
||||
noinst_HEADERS += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h
|
||||
noinst_HEADERS += src/hsort.h
|
||||
noinst_HEADERS += src/hsort_impl.h
|
||||
noinst_HEADERS += contrib/lax_der_parsing.h
|
||||
noinst_HEADERS += contrib/lax_der_parsing.c
|
||||
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
|
||||
@@ -153,7 +155,7 @@ endif
|
||||
if USE_EXAMPLES
|
||||
noinst_PROGRAMS += ecdsa_example
|
||||
ecdsa_example_SOURCES = examples/ecdsa.c
|
||||
ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include
|
||||
ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
|
||||
ecdsa_example_LDADD = libsecp256k1.la
|
||||
ecdsa_example_LDFLAGS = -static
|
||||
if BUILD_WINDOWS
|
||||
@@ -163,7 +165,7 @@ 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_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
|
||||
ecdh_example_LDADD = libsecp256k1.la
|
||||
ecdh_example_LDFLAGS = -static
|
||||
if BUILD_WINDOWS
|
||||
@@ -174,7 +176,7 @@ endif
|
||||
if ENABLE_MODULE_SCHNORRSIG
|
||||
noinst_PROGRAMS += schnorr_example
|
||||
schnorr_example_SOURCES = examples/schnorr.c
|
||||
schnorr_example_CPPFLAGS = -I$(top_srcdir)/include
|
||||
schnorr_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
|
||||
schnorr_example_LDADD = libsecp256k1.la
|
||||
schnorr_example_LDFLAGS = -static
|
||||
if BUILD_WINDOWS
|
||||
@@ -182,6 +184,28 @@ schnorr_example_LDFLAGS += -lbcrypt
|
||||
endif
|
||||
TESTS += schnorr_example
|
||||
endif
|
||||
if ENABLE_MODULE_ELLSWIFT
|
||||
noinst_PROGRAMS += ellswift_example
|
||||
ellswift_example_SOURCES = examples/ellswift.c
|
||||
ellswift_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
|
||||
ellswift_example_LDADD = libsecp256k1.la
|
||||
ellswift_example_LDFLAGS = -static
|
||||
if BUILD_WINDOWS
|
||||
ellswift_example_LDFLAGS += -lbcrypt
|
||||
endif
|
||||
TESTS += ellswift_example
|
||||
endif
|
||||
if ENABLE_MODULE_MUSIG
|
||||
noinst_PROGRAMS += musig_example
|
||||
musig_example_SOURCES = examples/musig.c
|
||||
musig_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
|
||||
musig_example_LDADD = libsecp256k1.la
|
||||
musig_example_LDFLAGS = -static
|
||||
if BUILD_WINDOWS
|
||||
musig_example_LDFLAGS += -lbcrypt
|
||||
endif
|
||||
TESTS += musig_example
|
||||
endif
|
||||
endif
|
||||
|
||||
### Precomputed tables
|
||||
@@ -189,11 +213,11 @@ 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_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY
|
||||
precompute_ecmult_LDADD = $(COMMON_LIB)
|
||||
|
||||
precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c
|
||||
precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES)
|
||||
precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY
|
||||
precompute_ecmult_gen_LDADD = $(COMMON_LIB)
|
||||
|
||||
# See Automake manual, Section "Errors with distclean".
|
||||
@@ -241,6 +265,7 @@ maintainer-clean-local: clean-testvectors
|
||||
### Additional files to distribute
|
||||
EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md
|
||||
EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.md
|
||||
EXTRA_DIST += doc/ellswift.md doc/musig.md
|
||||
EXTRA_DIST += examples/EXAMPLES_COPYING
|
||||
EXTRA_DIST += sage/gen_exhaustive_groups.sage
|
||||
EXTRA_DIST += sage/gen_split_lambda_constants.sage
|
||||
@@ -267,3 +292,11 @@ endif
|
||||
if ENABLE_MODULE_SCHNORRSIG
|
||||
include src/modules/schnorrsig/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_MUSIG
|
||||
include src/modules/musig/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_ELLSWIFT
|
||||
include src/modules/ellswift/Makefile.am.include
|
||||
endif
|
||||
|
||||
41
external/secp256k1/README.md
vendored
41
external/secp256k1/README.md
vendored
@@ -1,11 +1,10 @@
|
||||
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.
|
||||
High-performance high-assurance C library for digital signatures and other cryptographic primitives on the secp256k1 elliptic curve.
|
||||
|
||||
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.
|
||||
|
||||
@@ -21,6 +20,8 @@ Features:
|
||||
* 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).
|
||||
* Optional module for ElligatorSwift key exchange according to [BIP-324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki).
|
||||
* Optional module for MuSig2 Schnorr multi-signatures according to [BIP-327](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki).
|
||||
|
||||
Implementation details
|
||||
----------------------
|
||||
@@ -34,7 +35,7 @@ Implementation details
|
||||
* 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 5 52-bit limbs
|
||||
* 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
|
||||
@@ -80,9 +81,9 @@ To maintain a pristine source tree, CMake encourages to perform an out-of-source
|
||||
|
||||
$ mkdir build && cd build
|
||||
$ cmake ..
|
||||
$ make
|
||||
$ make check # run the test suite
|
||||
$ sudo make install # optional
|
||||
$ cmake --build .
|
||||
$ ctest # run the test suite
|
||||
$ sudo cmake --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.
|
||||
|
||||
@@ -114,31 +115,10 @@ Usage examples can be found in the [examples](examples) directory. To compile th
|
||||
* [ECDSA example](examples/ecdsa.c)
|
||||
* [Schnorr signatures example](examples/schnorr.c)
|
||||
* [Deriving a shared secret (ECDH) example](examples/ecdh.c)
|
||||
* [ElligatorSwift key exchange example](examples/ellswift.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.
|
||||
@@ -155,3 +135,8 @@ Reporting a vulnerability
|
||||
------------
|
||||
|
||||
See [SECURITY.md](SECURITY.md)
|
||||
|
||||
Contributing to libsecp256k1
|
||||
------------
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
16
external/secp256k1/build-aux/m4/bitcoin_secp.m4
vendored
16
external/secp256k1/build-aux/m4/bitcoin_secp.m4
vendored
@@ -45,6 +45,22 @@ fi
|
||||
AC_MSG_RESULT($has_valgrind)
|
||||
])
|
||||
|
||||
AC_DEFUN([SECP_MSAN_CHECK], [
|
||||
AC_MSG_CHECKING(whether MemorySanitizer is enabled)
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(memory_sanitizer)
|
||||
/* MemorySanitizer is enabled. */
|
||||
# elif
|
||||
# error "MemorySanitizer is disabled."
|
||||
# endif
|
||||
#else
|
||||
# error "__has_feature is not defined."
|
||||
#endif
|
||||
]])], [msan_enabled=yes], [msan_enabled=no])
|
||||
AC_MSG_RESULT([$msan_enabled])
|
||||
])
|
||||
|
||||
dnl SECP_TRY_APPEND_CFLAGS(flags, VAR)
|
||||
dnl Append flags to VAR if CC accepts them.
|
||||
AC_DEFUN([SECP_TRY_APPEND_CFLAGS], [
|
||||
|
||||
@@ -4,19 +4,21 @@ set -eux
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
# Print relevant CI environment to allow reproducing the job outside of CI.
|
||||
# Print commit and relevant CI environment to allow reproducing the job outside of CI.
|
||||
git show --no-patch
|
||||
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 \
|
||||
ECMULTWINDOW ECMULTGENKB ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
|
||||
EXPERIMENTAL ECDH RECOVERY EXTRAKEYS MUSIG SCHNORRSIG ELLSWIFT \
|
||||
SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
|
||||
EXAMPLES \
|
||||
HOST WRAPPER_CMD \
|
||||
CC CFLAGS CPPFLAGS AR NM
|
||||
CC CFLAGS CPPFLAGS AR NM \
|
||||
UBSAN_OPTIONS ASAN_OPTIONS LSAN_OPTIONS
|
||||
do
|
||||
eval "isset=\${$var+x}"
|
||||
if [ -n "$isset" ]; then
|
||||
@@ -30,19 +32,15 @@ print_environment() {
|
||||
}
|
||||
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
|
||||
env >> test_env.log
|
||||
|
||||
# If gcc is requested, assert that it's in fact gcc (and not some symlinked Apple clang).
|
||||
case "${CC:-undefined}" in
|
||||
*gcc*)
|
||||
$CC -v 2>&1 | grep -q "gcc version" || exit 1;
|
||||
;;
|
||||
esac
|
||||
|
||||
env >> test_env.log
|
||||
|
||||
if [ -n "${CC+x}" ]; then
|
||||
# The MSVC compiler "cl" doesn't understand "-v"
|
||||
$CC -v || true
|
||||
@@ -54,22 +52,55 @@ if [ -n "$WRAPPER_CMD" ]; then
|
||||
$WRAPPER_CMD --version
|
||||
fi
|
||||
|
||||
# Workaround for https://bugs.kde.org/show_bug.cgi?id=452758 (fixed in valgrind 3.20.0).
|
||||
case "${CC:-undefined}" in
|
||||
clang*)
|
||||
if [ "$CTIMETESTS" = "yes" ] && [ "$WITH_VALGRIND" = "yes" ]
|
||||
then
|
||||
export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4"
|
||||
else
|
||||
case "$WRAPPER_CMD" in
|
||||
valgrind*)
|
||||
export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
./autogen.sh
|
||||
|
||||
./configure \
|
||||
--enable-experimental="$EXPERIMENTAL" \
|
||||
--with-test-override-wide-multiply="$WIDEMUL" --with-asm="$ASM" \
|
||||
--with-ecmult-window="$ECMULTWINDOW" \
|
||||
--with-ecmult-gen-precision="$ECMULTGENPRECISION" \
|
||||
--with-ecmult-gen-kb="$ECMULTGENKB" \
|
||||
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
|
||||
--enable-module-ellswift="$ELLSWIFT" \
|
||||
--enable-module-extrakeys="$EXTRAKEYS" \
|
||||
--enable-module-schnorrsig="$SCHNORRSIG" \
|
||||
--enable-module-musig="$MUSIG" \
|
||||
--enable-examples="$EXAMPLES" \
|
||||
--enable-ctime-tests="$CTIMETESTS" \
|
||||
--with-valgrind="$WITH_VALGRIND" \
|
||||
--host="$HOST" $EXTRAFLAGS
|
||||
|
||||
# We have set "-j<n>" in MAKEFLAGS.
|
||||
make
|
||||
build_exit_code=0
|
||||
make > make.log 2>&1 || build_exit_code=$?
|
||||
cat make.log
|
||||
if [ $build_exit_code -ne 0 ]; then
|
||||
case "${CC:-undefined}" in
|
||||
*snapshot*)
|
||||
# Ignore internal compiler errors in gcc-snapshot and clang-snapshot
|
||||
grep -e "internal compiler error:" -e "PLEASE submit a bug report" make.log
|
||||
return $?;
|
||||
;;
|
||||
*)
|
||||
return 1;
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Print information about binaries so that we can see that the architecture is correct
|
||||
file *tests* || true
|
||||
76
external/secp256k1/ci/linux-debian.Dockerfile
vendored
76
external/secp256k1/ci/linux-debian.Dockerfile
vendored
@@ -1,4 +1,17 @@
|
||||
FROM debian:stable
|
||||
FROM debian:stable-slim
|
||||
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
|
||||
WORKDIR /root
|
||||
|
||||
# A too high maximum number of file descriptors (with the default value
|
||||
# inherited from the docker host) can cause issues with some of our tools:
|
||||
# - sanitizers hanging: https://github.com/google/sanitizers/issues/1662
|
||||
# - valgrind crashing: https://stackoverflow.com/a/75293014
|
||||
# This is not be a problem on our CI hosts, but developers who run the image
|
||||
# on their machines may run into this (e.g., on Arch Linux), so warn them.
|
||||
# (Note that .bashrc is only executed in interactive bash shells.)
|
||||
RUN echo 'if [[ $(ulimit -n) -gt 200000 ]]; then echo "WARNING: Very high value reported by \"ulimit -n\". Consider passing \"--ulimit nofile=32768\" to \"docker run\"."; fi' >> /root/.bashrc
|
||||
|
||||
RUN dpkg --add-architecture i386 && \
|
||||
dpkg --add-architecture s390x && \
|
||||
@@ -11,27 +24,56 @@ RUN dpkg --add-architecture i386 && \
|
||||
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 \
|
||||
gcc clang llvm libclang-rt-dev libc6-dbg \
|
||||
g++ \
|
||||
gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan6:i386 \
|
||||
gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan8: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
|
||||
python3 && \
|
||||
if ! ( dpkg --print-architecture | grep --quiet "arm64" ) ; then \
|
||||
apt-get install --no-install-recommends -y \
|
||||
gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 ;\
|
||||
fi && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
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
|
||||
# Build and install gcc snapshot
|
||||
ARG GCC_SNAPSHOT_MAJOR=15
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \
|
||||
mkdir gcc && cd gcc && \
|
||||
wget --progress=dot:giga --https-only --recursive --accept '*.tar.xz' --level 1 --no-directories "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}" && \
|
||||
wget "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}/sha512.sum" && \
|
||||
sha512sum --check --ignore-missing sha512.sum && \
|
||||
# We should have downloaded exactly one tar.xz file
|
||||
ls && \
|
||||
[ $(ls *.tar.xz | wc -l) -eq "1" ] && \
|
||||
tar xf *.tar.xz && \
|
||||
mkdir gcc-build && cd gcc-build && \
|
||||
../*/configure --prefix=/opt/gcc-snapshot --enable-languages=c --disable-bootstrap --disable-multilib --without-isl && \
|
||||
make -j $(nproc) && \
|
||||
make install && \
|
||||
cd ../.. && rm -rf gcc && \
|
||||
ln -s /opt/gcc-snapshot/bin/gcc /usr/bin/gcc-snapshot && \
|
||||
apt-get autoremove -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install clang snapshot, see https://apt.llvm.org/
|
||||
RUN \
|
||||
# Setup GPG keys of LLVM repository
|
||||
apt-get update && apt-get install --no-install-recommends -y wget && \
|
||||
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \
|
||||
# Add repository for this Debian release
|
||||
. /etc/os-release && echo "deb http://apt.llvm.org/${VERSION_CODENAME} llvm-toolchain-${VERSION_CODENAME} main" >> /etc/apt/sources.list && \
|
||||
apt-get update && \
|
||||
# Determine the version number of the LLVM development branch
|
||||
LLVM_VERSION=$(apt-cache search --names-only '^clang-[0-9]+$' | sort -V | tail -1 | cut -f1 -d" " | cut -f2 -d"-" ) && \
|
||||
# Install
|
||||
apt-get install --no-install-recommends -y "clang-${LLVM_VERSION}" && \
|
||||
# Create symlink
|
||||
ln -s "/usr/bin/clang-${LLVM_VERSION}" /usr/bin/clang-snapshot && \
|
||||
# Clean up
|
||||
apt-get autoremove -y wget && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
function(check_arm32_assembly)
|
||||
try_compile(HAVE_ARM32_ASM
|
||||
${CMAKE_BINARY_DIR}/check_arm32_assembly
|
||||
SOURCES ${CMAKE_SOURCE_DIR}/cmake/source_arm32.s
|
||||
${PROJECT_BINARY_DIR}/check_arm32_assembly
|
||||
SOURCES ${PROJECT_SOURCE_DIR}/cmake/source_arm32.s
|
||||
)
|
||||
endfunction()
|
||||
|
||||
18
external/secp256k1/cmake/CheckMemorySanitizer.cmake
vendored
Normal file
18
external/secp256k1/cmake/CheckMemorySanitizer.cmake
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
include_guard(GLOBAL)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
function(check_memory_sanitizer output)
|
||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||
check_c_source_compiles("
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(memory_sanitizer)
|
||||
/* MemorySanitizer is enabled. */
|
||||
# elif
|
||||
# error \"MemorySanitizer is disabled.\"
|
||||
# endif
|
||||
#else
|
||||
# error \"__has_feature is not defined.\"
|
||||
#endif
|
||||
" HAVE_MSAN)
|
||||
set(${output} ${HAVE_MSAN} PARENT_SCOPE)
|
||||
endfunction()
|
||||
8
external/secp256k1/cmake/GeneratePkgConfigFile.cmake
vendored
Normal file
8
external/secp256k1/cmake/GeneratePkgConfigFile.cmake
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
function(generate_pkg_config_file in_file)
|
||||
set(prefix ${CMAKE_INSTALL_PREFIX})
|
||||
set(exec_prefix \${prefix})
|
||||
set(libdir \${exec_prefix}/${CMAKE_INSTALL_LIBDIR})
|
||||
set(includedir \${prefix}/${CMAKE_INSTALL_INCLUDEDIR})
|
||||
set(PACKAGE_VERSION ${PROJECT_VERSION})
|
||||
configure_file(${in_file} ${PROJECT_NAME}.pc @ONLY)
|
||||
endfunction()
|
||||
168
external/secp256k1/configure.ac
vendored
168
external/secp256k1/configure.ac
vendored
@@ -4,8 +4,8 @@ AC_PREREQ([2.60])
|
||||
# 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, 2)
|
||||
define(_PKG_VERSION_MINOR, 6)
|
||||
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
|
||||
@@ -13,8 +13,8 @@ define(_PKG_VERSION_IS_RELEASE, true)
|
||||
# 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, 2)
|
||||
define(_LIB_VERSION_CURRENT, 5)
|
||||
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])
|
||||
@@ -121,13 +121,12 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
|
||||
# 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"
|
||||
# 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"
|
||||
SECP_TRY_APPEND_CFLAGS([-W3], $1) # Production quality warning level.
|
||||
SECP_TRY_APPEND_CFLAGS([-wd4146], $1) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
|
||||
SECP_TRY_APPEND_CFLAGS([-wd4244], $1) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data".
|
||||
SECP_TRY_APPEND_CFLAGS([-wd4267], $1) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data".
|
||||
# Eliminate deprecation warnings for the older, less secure functions.
|
||||
CPPFLAGS="-D_CRT_SECURE_NO_WARNINGS $CPPFLAGS"
|
||||
fi
|
||||
])
|
||||
SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS)
|
||||
@@ -185,6 +184,14 @@ 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(module_musig,
|
||||
AS_HELP_STRING([--enable-module-musig],[enable MuSig2 module [default=yes]]), [],
|
||||
[SECP_SET_DEFAULT([enable_module_musig], [yes], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(module_ellswift,
|
||||
AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [],
|
||||
[SECP_SET_DEFAULT([enable_module_ellswift], [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])])
|
||||
@@ -198,25 +205,24 @@ AC_ARG_ENABLE(external_default_callbacks,
|
||||
AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
|
||||
|
||||
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto],
|
||||
[assembly optimizations to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto])
|
||||
[assembly to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto])
|
||||
|
||||
AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto],
|
||||
AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE],
|
||||
[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]]
|
||||
[The default value is a reasonable setting for desktop machines (currently 15). [default=15]]
|
||||
)],
|
||||
[req_ecmult_window=$withval], [req_ecmult_window=auto])
|
||||
[set_ecmult_window=$withval], [set_ecmult_window=15])
|
||||
|
||||
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]]
|
||||
AC_ARG_WITH([ecmult-gen-kb], [AS_HELP_STRING([--with-ecmult-gen-kb=2|22|86],
|
||||
[The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms).]
|
||||
[Larger values result in possibly better signing/keygeneration performance at the cost of a larger table.]
|
||||
[The default value is a reasonable setting for desktop machines (currently 86). [default=86]]
|
||||
)],
|
||||
[req_ecmult_gen_precision=$withval], [req_ecmult_gen_precision=auto])
|
||||
[set_ecmult_gen_kb=$withval], [set_ecmult_gen_kb=86])
|
||||
|
||||
AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind=yes|no|auto],
|
||||
[Build with extra checks for running inside Valgrind [default=auto]]
|
||||
@@ -245,6 +251,20 @@ if test x"$enable_ctime_tests" = x"auto"; then
|
||||
enable_ctime_tests=$enable_valgrind
|
||||
fi
|
||||
|
||||
print_msan_notice=no
|
||||
if test x"$enable_ctime_tests" = x"yes"; then
|
||||
SECP_MSAN_CHECK
|
||||
# MSan on Clang >=16 reports unitialized memory in function parameters and return values, even if
|
||||
# the uninitalized variable is never actually "used". This is called "eager" checking, and it's
|
||||
# sounds like good idea for normal use of MSan. However, it yields many false positives in the
|
||||
# ctime_tests because many return values depend on secret (i.e., "uninitialized") values, and
|
||||
# we're only interested in detecting branches (which count as "uses") on secret data.
|
||||
if test x"$msan_enabled" = x"yes"; then
|
||||
SECP_TRY_APPEND_CFLAGS([-fno-sanitize-memory-param-retval], SECP_CFLAGS)
|
||||
print_msan_notice=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$enable_coverage" = x"yes"; then
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOVERAGE=1"
|
||||
SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS"
|
||||
@@ -276,24 +296,24 @@ else
|
||||
x86_64)
|
||||
SECP_X86_64_ASM_CHECK
|
||||
if test x"$has_x86_64_asm" != x"yes"; then
|
||||
AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
|
||||
AC_MSG_ERROR([x86_64 assembly requested but not available])
|
||||
fi
|
||||
;;
|
||||
arm32)
|
||||
SECP_ARM32_ASM_CHECK
|
||||
if test x"$has_arm32_asm" != x"yes"; then
|
||||
AC_MSG_ERROR([ARM32 assembly optimization requested but not available])
|
||||
AC_MSG_ERROR([ARM32 assembly requested but not available])
|
||||
fi
|
||||
;;
|
||||
no)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([invalid assembly optimization selection])
|
||||
AC_MSG_ERROR([invalid assembly selection])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Select assembly optimization
|
||||
# Select assembly
|
||||
enable_external_asm=no
|
||||
|
||||
case $set_asm in
|
||||
@@ -306,7 +326,7 @@ arm32)
|
||||
no)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([invalid assembly optimizations])
|
||||
AC_MSG_ERROR([invalid assembly selection])
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -333,14 +353,7 @@ auto)
|
||||
;;
|
||||
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"']
|
||||
error_window_size=['window size for ecmult precomputation not an integer in range [2..24]']
|
||||
case $set_ecmult_window in
|
||||
''|*[[!0-9]]*)
|
||||
# no valid integer
|
||||
@@ -355,19 +368,18 @@ case $set_ecmult_window in
|
||||
;;
|
||||
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"
|
||||
case $set_ecmult_gen_kb in
|
||||
2)
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=2 -DCOMB_TEETH=5"
|
||||
;;
|
||||
22)
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=11 -DCOMB_TEETH=6"
|
||||
;;
|
||||
86)
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=43 -DCOMB_TEETH=6"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR(['ecmult gen precision not 2, 4, 8 or "auto"'])
|
||||
AC_MSG_ERROR(['ecmult gen table size not 2, 22 or 86'])
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -384,23 +396,38 @@ 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"
|
||||
# Processing must be done in a reverse topological sorting of the dependency graph
|
||||
# (dependent module first).
|
||||
if test x"$enable_module_ellswift" = x"yes"; then
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1"
|
||||
fi
|
||||
|
||||
if test x"$enable_module_musig" = x"yes"; then
|
||||
if test x"$enable_module_schnorrsig" = x"no"; then
|
||||
AC_MSG_ERROR([Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.])
|
||||
fi
|
||||
enable_module_schnorrsig=yes
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_MUSIG=1"
|
||||
fi
|
||||
|
||||
if test x"$enable_module_schnorrsig" = x"yes"; then
|
||||
if test x"$enable_module_extrakeys" = x"no"; then
|
||||
AC_MSG_ERROR([Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.])
|
||||
fi
|
||||
enable_module_extrakeys=yes
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG=1"
|
||||
fi
|
||||
|
||||
if test x"$enable_module_extrakeys" = x"yes"; then
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_EXTRAKEYS=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"
|
||||
if test x"$enable_module_ecdh" = x"yes"; then
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1"
|
||||
fi
|
||||
|
||||
if test x"$enable_external_default_callbacks" = x"yes"; then
|
||||
@@ -411,14 +438,9 @@ 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"$enable_experimental" = x"no"; then
|
||||
if test x"$set_asm" = x"arm32"; then
|
||||
AC_MSG_ERROR([ARM32 assembly optimization is experimental. Use --enable-experimental to allow.])
|
||||
AC_MSG_ERROR([ARM32 assembly is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -439,6 +461,8 @@ 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([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"])
|
||||
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
|
||||
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"])
|
||||
AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"])
|
||||
@@ -460,10 +484,12 @@ 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 " module musig = $enable_module_musig"
|
||||
echo " module ellswift = $enable_module_ellswift"
|
||||
echo
|
||||
echo " asm = $set_asm"
|
||||
echo " ecmult window size = $set_ecmult_window"
|
||||
echo " ecmult gen prec. bits = $set_ecmult_gen_precision"
|
||||
echo " ecmult gen table size = $set_ecmult_gen_kb KiB"
|
||||
# Hide test-only options unless they're used.
|
||||
if test x"$set_widemul" != xauto; then
|
||||
echo " wide multiplication = $set_widemul"
|
||||
@@ -475,3 +501,17 @@ echo " CPPFLAGS = $CPPFLAGS"
|
||||
echo " SECP_CFLAGS = $SECP_CFLAGS"
|
||||
echo " CFLAGS = $CFLAGS"
|
||||
echo " LDFLAGS = $LDFLAGS"
|
||||
|
||||
if test x"$print_msan_notice" = x"yes"; then
|
||||
echo
|
||||
echo "Note:"
|
||||
echo " MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to SECP_CFLAGS"
|
||||
echo " to avoid false positives in ctime_tests. Pass --disable-ctime-tests to avoid this."
|
||||
fi
|
||||
|
||||
if test x"$enable_experimental" = x"yes"; then
|
||||
echo
|
||||
echo "WARNING: Experimental build"
|
||||
echo " Experimental features do not have stable APIs or properties, and may not be safe for"
|
||||
echo " production use."
|
||||
fi
|
||||
|
||||
4
external/secp256k1/contrib/lax_der_parsing.h
vendored
4
external/secp256k1/contrib/lax_der_parsing.h
vendored
@@ -67,8 +67,8 @@ extern "C" {
|
||||
*
|
||||
* 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
|
||||
* Out: sig: pointer to a signature object
|
||||
* In: input: 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
|
||||
|
||||
483
external/secp256k1/doc/ellswift.md
vendored
Normal file
483
external/secp256k1/doc/ellswift.md
vendored
Normal file
@@ -0,0 +1,483 @@
|
||||
# ElligatorSwift for secp256k1 explained
|
||||
|
||||
In this document we explain how the `ellswift` module implementation is related to the
|
||||
construction in the
|
||||
["SwiftEC: Shallue–van de Woestijne Indifferentiable Function To Elliptic Curves"](https://eprint.iacr.org/2022/759)
|
||||
paper by Jorge Chávez-Saab, Francisco Rodríguez-Henríquez, and Mehdi Tibouchi.
|
||||
|
||||
* [1. Introduction](#1-introduction)
|
||||
* [2. The decoding function](#2-the-decoding-function)
|
||||
+ [2.1 Decoding for `secp256k1`](#21-decoding-for-secp256k1)
|
||||
* [3. The encoding function](#3-the-encoding-function)
|
||||
+ [3.1 Switching to *v, w* coordinates](#31-switching-to-v-w-coordinates)
|
||||
+ [3.2 Avoiding computing all inverses](#32-avoiding-computing-all-inverses)
|
||||
+ [3.3 Finding the inverse](#33-finding-the-inverse)
|
||||
+ [3.4 Dealing with special cases](#34-dealing-with-special-cases)
|
||||
+ [3.5 Encoding for `secp256k1`](#35-encoding-for-secp256k1)
|
||||
* [4. Encoding and decoding full *(x, y)* coordinates](#4-encoding-and-decoding-full-x-y-coordinates)
|
||||
+ [4.1 Full *(x, y)* coordinates for `secp256k1`](#41-full-x-y-coordinates-for-secp256k1)
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
The `ellswift` module effectively introduces a new 64-byte public key format, with the property
|
||||
that (uniformly random) public keys can be encoded as 64-byte arrays which are computationally
|
||||
indistinguishable from uniform byte arrays. The module provides functions to convert public keys
|
||||
from and to this format, as well as convenience functions for key generation and ECDH that operate
|
||||
directly on ellswift-encoded keys.
|
||||
|
||||
The encoding consists of the concatenation of two (32-byte big endian) encoded field elements $u$
|
||||
and $t.$ Together they encode an x-coordinate on the curve $x$, or (see further) a full point $(x, y)$ on
|
||||
the curve.
|
||||
|
||||
**Decoding** consists of decoding the field elements $u$ and $t$ (values above the field size $p$
|
||||
are taken modulo $p$), and then evaluating $F_u(t)$, which for every $u$ and $t$ results in a valid
|
||||
x-coordinate on the curve. The functions $F_u$ will be defined in [Section 2](#2-the-decoding-function).
|
||||
|
||||
**Encoding** a given $x$ coordinate is conceptually done as follows:
|
||||
* Loop:
|
||||
* Pick a uniformly random field element $u.$
|
||||
* Compute the set $L = F_u^{-1}(x)$ of $t$ values for which $F_u(t) = x$, which may have up to *8* elements.
|
||||
* With probability $1 - \dfrac{\\#L}{8}$, restart the loop.
|
||||
* Select a uniformly random $t \in L$ and return $(u, t).$
|
||||
|
||||
This is the *ElligatorSwift* algorithm, here given for just x-coordinates. An extension to full
|
||||
$(x, y)$ points will be given in [Section 4](#4-encoding-and-decoding-full-x-y-coordinates).
|
||||
The algorithm finds a uniformly random $(u, t)$ among (almost all) those
|
||||
for which $F_u(t) = x.$ Section 3.2 in the paper proves that the number of such encodings for
|
||||
almost all x-coordinates on the curve (all but at most 39) is close to two times the field size
|
||||
(specifically, it lies in the range $2q \pm (22\sqrt{q} + O(1))$, where $q$ is the size of the field).
|
||||
|
||||
## 2. The decoding function
|
||||
|
||||
First some definitions:
|
||||
* $\mathbb{F}$ is the finite field of size $q$, of characteristic 5 or more, and $q \equiv 1 \mod 3.$
|
||||
* For `secp256k1`, $q = 2^{256} - 2^{32} - 977$, which satisfies that requirement.
|
||||
* Let $E$ be the elliptic curve of points $(x, y) \in \mathbb{F}^2$ for which $y^2 = x^3 + ax + b$, with $a$ and $b$
|
||||
public constants, for which $\Delta_E = -16(4a^3 + 27b^2)$ is a square, and at least one of $(-b \pm \sqrt{-3 \Delta_E} / 36)/2$ is a square.
|
||||
This implies that the order of $E$ is either odd, or a multiple of *4*.
|
||||
If $a=0$, this condition is always fulfilled.
|
||||
* For `secp256k1`, $a=0$ and $b=7.$
|
||||
* Let the function $g(x) = x^3 + ax + b$, so the $E$ curve equation is also $y^2 = g(x).$
|
||||
* Let the function $h(x) = 3x^3 + 4a.$
|
||||
* Define $V$ as the set of solutions $(x_1, x_2, x_3, z)$ to $z^2 = g(x_1)g(x_2)g(x_3).$
|
||||
* Define $S_u$ as the set of solutions $(X, Y)$ to $X^2 + h(u)Y^2 = -g(u)$ and $Y \neq 0.$
|
||||
* $P_u$ is a function from $\mathbb{F}$ to $S_u$ that will be defined below.
|
||||
* $\psi_u$ is a function from $S_u$ to $V$ that will be defined below.
|
||||
|
||||
**Note**: In the paper:
|
||||
* $F_u$ corresponds to $F_{0,u}$ there.
|
||||
* $P_u(t)$ is called $P$ there.
|
||||
* All $S_u$ sets together correspond to $S$ there.
|
||||
* All $\psi_u$ functions together (operating on elements of $S$) correspond to $\psi$ there.
|
||||
|
||||
Note that for $V$, the left hand side of the equation $z^2$ is square, and thus the right
|
||||
hand must also be square. As multiplying non-squares results in a square in $\mathbb{F}$,
|
||||
out of the three right-hand side factors an even number must be non-squares.
|
||||
This implies that exactly *1* or exactly *3* out of
|
||||
$\\{g(x_1), g(x_2), g(x_3)\\}$ must be square, and thus that for any $(x_1,x_2,x_3,z) \in V$,
|
||||
at least one of $\\{x_1, x_2, x_3\\}$ must be a valid x-coordinate on $E.$ There is one exception
|
||||
to this, namely when $z=0$, but even then one of the three values is a valid x-coordinate.
|
||||
|
||||
**Define** the decoding function $F_u(t)$ as:
|
||||
* Let $(x_1, x_2, x_3, z) = \psi_u(P_u(t)).$
|
||||
* Return the first element $x$ of $(x_3, x_2, x_1)$ which is a valid x-coordinate on $E$ (i.e., $g(x)$ is square).
|
||||
|
||||
$P_u(t) = (X(u, t), Y(u, t))$, where:
|
||||
|
||||
$$
|
||||
\begin{array}{lcl}
|
||||
X(u, t) & = & \left\\{\begin{array}{ll}
|
||||
\dfrac{g(u) - t^2}{2t} & a = 0 \\
|
||||
\dfrac{g(u) + h(u)(Y_0(u) - X_0(u)t)^2}{X_0(u)(1 + h(u)t^2)} & a \neq 0
|
||||
\end{array}\right. \\
|
||||
Y(u, t) & = & \left\\{\begin{array}{ll}
|
||||
\dfrac{X(u, t) + t}{u \sqrt{-3}} = \dfrac{g(u) + t^2}{2tu\sqrt{-3}} & a = 0 \\
|
||||
Y_0(u) + t(X(u, t) - X_0(u)) & a \neq 0
|
||||
\end{array}\right.
|
||||
\end{array}
|
||||
$$
|
||||
|
||||
$P_u(t)$ is defined:
|
||||
* For $a=0$, unless:
|
||||
* $u = 0$ or $t = 0$ (division by zero)
|
||||
* $g(u) = -t^2$ (would give $Y=0$).
|
||||
* For $a \neq 0$, unless:
|
||||
* $X_0(u) = 0$ or $h(u)t^2 = -1$ (division by zero)
|
||||
* $Y_0(u) (1 - h(u)t^2) = 2X_0(u)t$ (would give $Y=0$).
|
||||
|
||||
The functions $X_0(u)$ and $Y_0(u)$ are defined in Appendix A of the paper, and depend on various properties of $E.$
|
||||
|
||||
The function $\psi_u$ is the same for all curves: $\psi_u(X, Y) = (x_1, x_2, x_3, z)$, where:
|
||||
|
||||
$$
|
||||
\begin{array}{lcl}
|
||||
x_1 & = & \dfrac{X}{2Y} - \dfrac{u}{2} && \\
|
||||
x_2 & = & -\dfrac{X}{2Y} - \dfrac{u}{2} && \\
|
||||
x_3 & = & u + 4Y^2 && \\
|
||||
z & = & \dfrac{g(x_3)}{2Y}(u^2 + ux_1 + x_1^2 + a) = \dfrac{-g(u)g(x_3)}{8Y^3}
|
||||
\end{array}
|
||||
$$
|
||||
|
||||
### 2.1 Decoding for `secp256k1`
|
||||
|
||||
Put together and specialized for $a=0$ curves, decoding $(u, t)$ to an x-coordinate is:
|
||||
|
||||
**Define** $F_u(t)$ as:
|
||||
* Let $X = \dfrac{u^3 + b - t^2}{2t}.$
|
||||
* Let $Y = \dfrac{X + t}{u\sqrt{-3}}.$
|
||||
* Return the first $x$ in $(u + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u}{2}, \dfrac{X}{2Y} - \dfrac{u}{2})$ for which $g(x)$ is square.
|
||||
|
||||
To make sure that every input decodes to a valid x-coordinate, we remap the inputs in case
|
||||
$P_u$ is not defined (when $u=0$, $t=0$, or $g(u) = -t^2$):
|
||||
|
||||
**Define** $F_u(t)$ as:
|
||||
* Let $u'=u$ if $u \neq 0$; $1$ otherwise (guaranteeing $u' \neq 0$).
|
||||
* Let $t'=t$ if $t \neq 0$; $1$ otherwise (guaranteeing $t' \neq 0$).
|
||||
* Let $t''=t'$ if $g(u') \neq -t'^2$; $2t'$ otherwise (guaranteeing $t'' \neq 0$ and $g(u') \neq -t''^2$).
|
||||
* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
|
||||
* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
|
||||
* Return the first $x$ in $(u' + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u'}{2}, \dfrac{X}{2Y} - \dfrac{u'}{2})$ for which $x^3 + b$ is square.
|
||||
|
||||
The choices here are not strictly necessary. Just returning a fixed constant in any of the undefined cases would suffice,
|
||||
but the approach here is simple enough and gives fairly uniform output even in these cases.
|
||||
|
||||
**Note**: in the paper these conditions result in $\infty$ as output, due to the use of projective coordinates there.
|
||||
We wish to avoid the need for callers to deal with this special case.
|
||||
|
||||
This is implemented in `secp256k1_ellswift_xswiftec_frac_var` (which decodes to an x-coordinate represented as a fraction), and
|
||||
in `secp256k1_ellswift_xswiftec_var` (which outputs the actual x-coordinate).
|
||||
|
||||
## 3. The encoding function
|
||||
|
||||
To implement $F_u^{-1}(x)$, the function to find the set of inverses $t$ for which $F_u(t) = x$, we have to reverse the process:
|
||||
* Find all the $(X, Y) \in S_u$ that could have given rise to $x$, through the $x_1$, $x_2$, or $x_3$ formulas in $\psi_u.$
|
||||
* Map those $(X, Y)$ solutions to $t$ values using $P_u^{-1}(X, Y).$
|
||||
* For each of the found $t$ values, verify that $F_u(t) = x.$
|
||||
* Return the remaining $t$ values.
|
||||
|
||||
The function $P_u^{-1}$, which finds $t$ given $(X, Y) \in S_u$, is significantly simpler than $P_u:$
|
||||
|
||||
$$
|
||||
P_u^{-1}(X, Y) = \left\\{\begin{array}{ll}
|
||||
Yu\sqrt{-3} - X & a = 0 \\
|
||||
\dfrac{Y-Y_0(u)}{X-X_0(u)} & a \neq 0 \land X \neq X_0(u) \\
|
||||
\dfrac{-X_0(u)}{h(u)Y_0(u)} & a \neq 0 \land X = X_0(u) \land Y = Y_0(u)
|
||||
\end{array}\right.
|
||||
$$
|
||||
|
||||
The third step above, verifying that $F_u(t) = x$, is necessary because for the $(X, Y)$ values found through the $x_1$ and $x_2$ expressions,
|
||||
it is possible that decoding through $\psi_u(X, Y)$ yields a valid $x_3$ on the curve, which would take precedence over the
|
||||
$x_1$ or $x_2$ decoding. These $(X, Y)$ solutions must be rejected.
|
||||
|
||||
Since we know that exactly one or exactly three out of $\\{x_1, x_2, x_3\\}$ are valid x-coordinates for any $t$,
|
||||
the case where either $x_1$ or $x_2$ is valid and in addition also $x_3$ is valid must mean that all three are valid.
|
||||
This means that instead of checking whether $x_3$ is on the curve, it is also possible to check whether the other one out of
|
||||
$x_1$ and $x_2$ is on the curve. This is significantly simpler, as it turns out.
|
||||
|
||||
Observe that $\psi_u$ guarantees that $x_1 + x_2 = -u.$ So given either $x = x_1$ or $x = x_2$, the other one of the two can be computed as
|
||||
$-u - x.$ Thus, when encoding $x$ through the $x_1$ or $x_2$ expressions, one can simply check whether $g(-u-x)$ is a square,
|
||||
and if so, not include the corresponding $t$ values in the returned set. As this does not need $X$, $Y$, or $t$, this condition can be determined
|
||||
before those values are computed.
|
||||
|
||||
It is not possible that an encoding found through the $x_1$ expression decodes to a different valid x-coordinate using $x_2$ (which would
|
||||
take precedence), for the same reason: if both $x_1$ and $x_2$ decodings were valid, $x_3$ would be valid as well, and thus take
|
||||
precedence over both. Because of this, the $g(-u-x)$ being square test for $x_1$ and $x_2$ is the only test necessary to guarantee the found $t$
|
||||
values round-trip back to the input $x$ correctly. This is the reason for choosing the $(x_3, x_2, x_1)$ precedence order in the decoder;
|
||||
any order which does not place $x_3$ first requires more complicated round-trip checks in the encoder.
|
||||
|
||||
### 3.1 Switching to *v, w* coordinates
|
||||
|
||||
Before working out the formulas for all this, we switch to different variables for $S_u.$ Let $v = (X/Y - u)/2$, and
|
||||
$w = 2Y.$ Or in the other direction, $X = w(u/2 + v)$ and $Y = w/2:$
|
||||
* $S_u'$ becomes the set of $(v, w)$ for which $w^2 (u^2 + uv + v^2 + a) = -g(u)$ and $w \neq 0.$
|
||||
* For $a=0$ curves, $P_u^{-1}$ can be stated for $(v,w)$ as $P_u^{'-1}(v, w) = w\left(\frac{\sqrt{-3}-1}{2}u - v\right).$
|
||||
* $\psi_u$ can be stated for $(v, w)$ as $\psi_u'(v, w) = (x_1, x_2, x_3, z)$, where
|
||||
|
||||
$$
|
||||
\begin{array}{lcl}
|
||||
x_1 & = & v \\
|
||||
x_2 & = & -u - v \\
|
||||
x_3 & = & u + w^2 \\
|
||||
z & = & \dfrac{g(x_3)}{w}(u^2 + uv + v^2 + a) = \dfrac{-g(u)g(x_3)}{w^3}
|
||||
\end{array}
|
||||
$$
|
||||
|
||||
We can now write the expressions for finding $(v, w)$ given $x$ explicitly, by solving each of the $\\{x_1, x_2, x_3\\}$
|
||||
expressions for $v$ or $w$, and using the $S_u'$ equation to find the other variable:
|
||||
* Assuming $x = x_1$, we find $v = x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
|
||||
* Assuming $x = x_2$, we find $v = -u-x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
|
||||
* Assuming $x = x_3$, we find $w = \pm\sqrt{x-u}$ and $v = -u/2 \pm \sqrt{-w^2(4g(u) + w^2h(u))}/(2w^2)$ (four solutions).
|
||||
|
||||
### 3.2 Avoiding computing all inverses
|
||||
|
||||
The *ElligatorSwift* algorithm as stated in Section 1 requires the computation of $L = F_u^{-1}(x)$ (the
|
||||
set of all $t$ such that $(u, t)$ decode to $x$) in full. This is unnecessary.
|
||||
|
||||
Observe that the procedure of restarting with probability $(1 - \frac{\\#L}{8})$ and otherwise returning a
|
||||
uniformly random element from $L$ is actually equivalent to always padding $L$ with $\bot$ values up to length 8,
|
||||
picking a uniformly random element from that, restarting whenever $\bot$ is picked:
|
||||
|
||||
**Define** *ElligatorSwift(x)* as:
|
||||
* Loop:
|
||||
* Pick a uniformly random field element $u.$
|
||||
* Compute the set $L = F_u^{-1}(x).$
|
||||
* Let $T$ be the 8-element vector consisting of the elements of $L$, plus $8 - \\#L$ times $\\{\bot\\}.$
|
||||
* Select a uniformly random $t \in T.$
|
||||
* If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
|
||||
|
||||
Now notice that the order of elements in $T$ does not matter, as all we do is pick a uniformly
|
||||
random element in it, so we do not need to have all $\bot$ values at the end.
|
||||
As we have 8 distinct formulas for finding $(v, w)$ (taking the variants due to $\pm$ into account),
|
||||
we can associate every index in $T$ with exactly one of those formulas, making sure that:
|
||||
* Formulas that yield no solutions (due to division by zero or non-existing square roots) or invalid solutions are made to return $\bot.$
|
||||
* For the $x_1$ and $x_2$ cases, if $g(-u-x)$ is a square, $\bot$ is returned instead (the round-trip check).
|
||||
* In case multiple formulas would return the same non- $\bot$ result, all but one of those must be turned into $\bot$ to avoid biasing those.
|
||||
|
||||
The last condition above only occurs with negligible probability for cryptographically-sized curves, but is interesting
|
||||
to take into account as it allows exhaustive testing in small groups. See [Section 3.4](#34-dealing-with-special-cases)
|
||||
for an analysis of all the negligible cases.
|
||||
|
||||
If we define $T = (G_{0,u}(x), G_{1,u}(x), \ldots, G_{7,u}(x))$, with each $G_{i,u}$ matching one of the formulas,
|
||||
the loop can be simplified to only compute one of the inverses instead of all of them:
|
||||
|
||||
**Define** *ElligatorSwift(x)* as:
|
||||
* Loop:
|
||||
* Pick a uniformly random field element $u.$
|
||||
* Pick a uniformly random integer $c$ in $[0,8).$
|
||||
* Let $t = G_{c,u}(x).$
|
||||
* If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
|
||||
|
||||
This is implemented in `secp256k1_ellswift_xelligatorswift_var`.
|
||||
|
||||
### 3.3 Finding the inverse
|
||||
|
||||
To implement $G_{c,u}$, we map $c=0$ to the $x_1$ formula, $c=1$ to the $x_2$ formula, and $c=2$ and $c=3$ to the $x_3$ formula.
|
||||
Those are then repeated as $c=4$ through $c=7$ for the other sign of $w$ (noting that in each formula, $w$ is a square root of some expression).
|
||||
Ignoring the negligible cases, we get:
|
||||
|
||||
**Define** $G_{c,u}(x)$ as:
|
||||
* If $c \in \\{0, 1, 4, 5\\}$ (for $x_1$ and $x_2$ formulas):
|
||||
* If $g(-u-x)$ is square, return $\bot$ (as $x_3$ would be valid and take precedence).
|
||||
* If $c \in \\{0, 4\\}$ (the $x_1$ formula) let $v = x$, otherwise let $v = -u-x$ (the $x_2$ formula)
|
||||
* Let $s = -g(u)/(u^2 + uv + v^2 + a)$ (using $s = w^2$ in what follows).
|
||||
* Otherwise, when $c \in \\{2, 3, 6, 7\\}$ (for $x_3$ formulas):
|
||||
* Let $s = x-u.$
|
||||
* Let $r = \sqrt{-s(4g(u) + sh(u))}.$
|
||||
* Let $v = (r/s - u)/2$ if $c \in \\{3, 7\\}$; $(-r/s - u)/2$ otherwise.
|
||||
* Let $w = \sqrt{s}.$
|
||||
* Depending on $c:$
|
||||
* If $c \in \\{0, 1, 2, 3\\}:$ return $P_u^{'-1}(v, w).$
|
||||
* If $c \in \\{4, 5, 6, 7\\}:$ return $P_u^{'-1}(v, -w).$
|
||||
|
||||
Whenever a square root of a non-square is taken, $\bot$ is returned; for both square roots this happens with roughly
|
||||
50% on random inputs. Similarly, when a division by 0 would occur, $\bot$ is returned as well; this will only happen
|
||||
with negligible probability. A division by 0 in the first branch in fact cannot occur at all, because $u^2 + uv + v^2 + a = 0$
|
||||
implies $g(-u-x) = g(x)$ which would mean the $g(-u-x)$ is square condition has triggered
|
||||
and $\bot$ would have been returned already.
|
||||
|
||||
**Note**: In the paper, the $case$ variable corresponds roughly to the $c$ above, but only takes on 4 possible values (1 to 4).
|
||||
The conditional negation of $w$ at the end is done randomly, which is equivalent, but makes testing harder. We choose to
|
||||
have the $G_{c,u}$ be deterministic, and capture all choices in $c.$
|
||||
|
||||
Now observe that the $c \in \\{1, 5\\}$ and $c \in \\{3, 7\\}$ conditions effectively perform the same $v \rightarrow -u-v$
|
||||
transformation. Furthermore, that transformation has no effect on $s$ in the first branch
|
||||
as $u^2 + ux + x^2 + a = u^2 + u(-u-x) + (-u-x)^2 + a.$ Thus we can extract it out and move it down:
|
||||
|
||||
**Define** $G_{c,u}(x)$ as:
|
||||
* If $c \in \\{0, 1, 4, 5\\}:$
|
||||
* If $g(-u-x)$ is square, return $\bot.$
|
||||
* Let $s = -g(u)/(u^2 + ux + x^2 + a).$
|
||||
* Let $v = x.$
|
||||
* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
|
||||
* Let $s = x-u.$
|
||||
* Let $r = \sqrt{-s(4g(u) + sh(u))}.$
|
||||
* Let $v = (r/s - u)/2.$
|
||||
* Let $w = \sqrt{s}.$
|
||||
* Depending on $c:$
|
||||
* If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w).$
|
||||
* If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w).$
|
||||
* If $c \in \\{4, 6\\}:$ return $P_u^{'-1}(v, -w).$
|
||||
* If $c \in \\{5, 7\\}:$ return $P_u^{'-1}(-u-v, -w).$
|
||||
|
||||
This shows there will always be exactly 0, 4, or 8 $t$ values for a given $(u, x)$ input.
|
||||
There can be 0, 1, or 2 $(v, w)$ pairs before invoking $P_u^{'-1}$, and each results in 4 distinct $t$ values.
|
||||
|
||||
### 3.4 Dealing with special cases
|
||||
|
||||
As mentioned before there are a few cases to deal with which only happen in a negligibly small subset of inputs.
|
||||
For cryptographically sized fields, if only random inputs are going to be considered, it is unnecessary to deal with these. Still, for completeness
|
||||
we analyse them here. They generally fall into two categories: cases in which the encoder would produce $t$ values that
|
||||
do not decode back to $x$ (or at least cannot guarantee that they do), and cases in which the encoder might produce the same
|
||||
$t$ value for multiple $c$ inputs (thereby biasing that encoding):
|
||||
|
||||
* In the branch for $x_1$ and $x_2$ (where $c \in \\{0, 1, 4, 5\\}$):
|
||||
* When $g(u) = 0$, we would have $s=w=Y=0$, which is not on $S_u.$ This is only possible on even-ordered curves.
|
||||
Excluding this also removes the one condition under which the simplified check for $x_3$ on the curve
|
||||
fails (namely when $g(x_1)=g(x_2)=0$ but $g(x_3)$ is not square).
|
||||
This does exclude some valid encodings: when both $g(u)=0$ and $u^2+ux+x^2+a=0$ (also implying $g(x)=0$),
|
||||
the $S_u'$ equation degenerates to $0 = 0$, and many valid $t$ values may exist. Yet, these cannot be targeted uniformly by the
|
||||
encoder anyway as there will generally be more than 8.
|
||||
* When $g(x) = 0$, the same $t$ would be produced as in the $x_3$ branch (where $c \in \\{2, 3, 6, 7\\}$) which we give precedence
|
||||
as it can deal with $g(u)=0$.
|
||||
This is again only possible on even-ordered curves.
|
||||
* In the branch for $x_3$ (where $c \in \\{2, 3, 6, 7\\}$):
|
||||
* When $s=0$, a division by zero would occur.
|
||||
* When $v = -u-v$ and $c \in \\{3, 7\\}$, the same $t$ would be returned as in the $c \in \\{2, 6\\}$ cases.
|
||||
It is equivalent to checking whether $r=0$.
|
||||
This cannot occur in the $x_1$ or $x_2$ branches, as it would trigger the $g(-u-x)$ is square condition.
|
||||
A similar concern for $w = -w$ does not exist, as $w=0$ is already impossible in both branches: in the first
|
||||
it requires $g(u)=0$ which is already outlawed on even-ordered curves and impossible on others; in the second it would trigger division by zero.
|
||||
* Curve-specific special cases also exist that need to be rejected, because they result in $(u,t)$ which is invalid to the decoder, or because of division by zero in the encoder:
|
||||
* For $a=0$ curves, when $u=0$ or when $t=0$. The latter can only be reached by the encoder when $g(u)=0$, which requires an even-ordered curve.
|
||||
* For $a \neq 0$ curves, when $X_0(u)=0$, when $h(u)t^2 = -1$, or when $w(u + 2v) = 2X_0(u)$ while also either $w \neq 2Y_0(u)$ or $h(u)=0$.
|
||||
|
||||
**Define** a version of $G_{c,u}(x)$ which deals with all these cases:
|
||||
* If $a=0$ and $u=0$, return $\bot.$
|
||||
* If $a \neq 0$ and $X_0(u)=0$, return $\bot.$
|
||||
* If $c \in \\{0, 1, 4, 5\\}:$
|
||||
* If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
|
||||
* If $g(-u-x)$ is square, return $\bot.$
|
||||
* Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
|
||||
* Let $v = x.$
|
||||
* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
|
||||
* Let $s = x-u.$
|
||||
* Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
|
||||
* If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
|
||||
* If $s = 0$, return $\bot.$
|
||||
* Let $v = (r/s - u)/2.$
|
||||
* Let $w = \sqrt{s}$; return $\bot$ if not square.
|
||||
* If $a \neq 0$ and $w(u+2v) = 2X_0(u)$ and either $w \neq 2Y_0(u)$ or $h(u) = 0$, return $\bot.$
|
||||
* Depending on $c:$
|
||||
* If $c \in \\{0, 2\\}$, let $t = P_u^{'-1}(v, w).$
|
||||
* If $c \in \\{1, 3\\}$, let $t = P_u^{'-1}(-u-v, w).$
|
||||
* If $c \in \\{4, 6\\}$, let $t = P_u^{'-1}(v, -w).$
|
||||
* If $c \in \\{5, 7\\}$, let $t = P_u^{'-1}(-u-v, -w).$
|
||||
* If $a=0$ and $t=0$, return $\bot$ (even curves only).
|
||||
* If $a \neq 0$ and $h(u)t^2 = -1$, return $\bot.$
|
||||
* Return $t.$
|
||||
|
||||
Given any $u$, using this algorithm over all $x$ and $c$ values, every $t$ value will be reached exactly once,
|
||||
for an $x$ for which $F_u(t) = x$ holds, except for these cases that will not be reached:
|
||||
* All cases where $P_u(t)$ is not defined:
|
||||
* For $a=0$ curves, when $u=0$, $t=0$, or $g(u) = -t^2.$
|
||||
* For $a \neq 0$ curves, when $h(u)t^2 = -1$, $X_0(u) = 0$, or $Y_0(u) (1 - h(u) t^2) = 2X_0(u)t.$
|
||||
* When $g(u)=0$, the potentially many $t$ values that decode to an $x$ satisfying $g(x)=0$ using the $x_2$ formula. These were excluded by the $g(u)=0$ condition in the $c \in \\{0, 1, 4, 5\\}$ branch.
|
||||
|
||||
These cases form a negligible subset of all $(u, t)$ for cryptographically sized curves.
|
||||
|
||||
### 3.5 Encoding for `secp256k1`
|
||||
|
||||
Specialized for odd-ordered $a=0$ curves:
|
||||
|
||||
**Define** $G_{c,u}(x)$ as:
|
||||
* If $u=0$, return $\bot.$
|
||||
* If $c \in \\{0, 1, 4, 5\\}:$
|
||||
* If $(-u-x)^3 + b$ is square, return $\bot$
|
||||
* Let $s = -(u^3 + b)/(u^2 + ux + x^2)$ (cannot cause division by 0).
|
||||
* Let $v = x.$
|
||||
* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
|
||||
* Let $s = x-u.$
|
||||
* Let $r = \sqrt{-s(4(u^3 + b) + 3su^2)}$; return $\bot$ if not square.
|
||||
* If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
|
||||
* If $s = 0$, return $\bot.$
|
||||
* Let $v = (r/s - u)/2.$
|
||||
* Let $w = \sqrt{s}$; return $\bot$ if not square.
|
||||
* Depending on $c:$
|
||||
* If $c \in \\{0, 2\\}:$ return $w(\frac{\sqrt{-3}-1}{2}u - v).$
|
||||
* If $c \in \\{1, 3\\}:$ return $w(\frac{\sqrt{-3}+1}{2}u + v).$
|
||||
* If $c \in \\{4, 6\\}:$ return $w(\frac{-\sqrt{-3}+1}{2}u + v).$
|
||||
* If $c \in \\{5, 7\\}:$ return $w(\frac{-\sqrt{-3}-1}{2}u - v).$
|
||||
|
||||
This is implemented in `secp256k1_ellswift_xswiftec_inv_var`.
|
||||
|
||||
And the x-only ElligatorSwift encoding algorithm is still:
|
||||
|
||||
**Define** *ElligatorSwift(x)* as:
|
||||
* Loop:
|
||||
* Pick a uniformly random field element $u.$
|
||||
* Pick a uniformly random integer $c$ in $[0,8).$
|
||||
* Let $t = G_{c,u}(x).$
|
||||
* If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
|
||||
|
||||
Note that this logic does not take the remapped $u=0$, $t=0$, and $g(u) = -t^2$ cases into account; it just avoids them.
|
||||
While it is not impossible to make the encoder target them, this would increase the maximum number of $t$ values for a given $(u, x)$
|
||||
combination beyond 8, and thereby slow down the ElligatorSwift loop proportionally, for a negligible gain in uniformity.
|
||||
|
||||
## 4. Encoding and decoding full *(x, y)* coordinates
|
||||
|
||||
So far we have only addressed encoding and decoding x-coordinates, but in some cases an encoding
|
||||
for full points with $(x, y)$ coordinates is desirable. It is possible to encode this information
|
||||
in $t$ as well.
|
||||
|
||||
Note that for any $(X, Y) \in S_u$, $(\pm X, \pm Y)$ are all on $S_u.$ Moreover, all of these are
|
||||
mapped to the same x-coordinate. Negating $X$ or negating $Y$ just results in $x_1$ and $x_2$
|
||||
being swapped, and does not affect $x_3.$ This will not change the outcome x-coordinate as the order
|
||||
of $x_1$ and $x_2$ only matters if both were to be valid, and in that case $x_3$ would be used instead.
|
||||
|
||||
Still, these four $(X, Y)$ combinations all correspond to distinct $t$ values, so we can encode
|
||||
the sign of the y-coordinate in the sign of $X$ or the sign of $Y.$ They correspond to the
|
||||
four distinct $P_u^{'-1}$ calls in the definition of $G_{u,c}.$
|
||||
|
||||
**Note**: In the paper, the sign of the y coordinate is encoded in a separately-coded bit.
|
||||
|
||||
To encode the sign of $y$ in the sign of $Y:$
|
||||
|
||||
**Define** *Decode(u, t)* for full $(x, y)$ as:
|
||||
* Let $(X, Y) = P_u(t).$
|
||||
* Let $x$ be the first value in $(u + 4Y^2, \frac{-X}{2Y} - \frac{u}{2}, \frac{X}{2Y} - \frac{u}{2})$ for which $g(x)$ is square.
|
||||
* Let $y = \sqrt{g(x)}.$
|
||||
* If $sign(y) = sign(Y)$, return $(x, y)$; otherwise return $(x, -y).$
|
||||
|
||||
And encoding would be done using a $G_{c,u}(x, y)$ function defined as:
|
||||
|
||||
**Define** $G_{c,u}(x, y)$ as:
|
||||
* If $c \in \\{0, 1\\}:$
|
||||
* If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
|
||||
* If $g(-u-x)$ is square, return $\bot.$
|
||||
* Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
|
||||
* Let $v = x.$
|
||||
* Otherwise, when $c \in \\{2, 3\\}:$
|
||||
* Let $s = x-u.$
|
||||
* Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
|
||||
* If $c = 3$ and $r = 0$, return $\bot.$
|
||||
* Let $v = (r/s - u)/2.$
|
||||
* Let $w = \sqrt{s}$; return $\bot$ if not square.
|
||||
* Let $w' = w$ if $sign(w/2) = sign(y)$; $-w$ otherwise.
|
||||
* Depending on $c:$
|
||||
* If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w').$
|
||||
* If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w').$
|
||||
|
||||
Note that $c$ now only ranges $[0,4)$, as the sign of $w'$ is decided based on that of $y$, rather than on $c.$
|
||||
This change makes some valid encodings unreachable: when $y = 0$ and $sign(Y) \neq sign(0)$.
|
||||
|
||||
In the above logic, $sign$ can be implemented in several ways, such as parity of the integer representation
|
||||
of the input field element (for prime-sized fields) or the quadratic residuosity (for fields where
|
||||
$-1$ is not square). The choice does not matter, as long as it only takes on two possible values, and for $x \neq 0$ it holds that $sign(x) \neq sign(-x)$.
|
||||
|
||||
### 4.1 Full *(x, y)* coordinates for `secp256k1`
|
||||
|
||||
For $a=0$ curves, there is another option. Note that for those,
|
||||
the $P_u(t)$ function translates negations of $t$ to negations of (both) $X$ and $Y.$ Thus, we can use $sign(t)$ to
|
||||
encode the y-coordinate directly. Combined with the earlier remapping to guarantee all inputs land on the curve, we get
|
||||
as decoder:
|
||||
|
||||
**Define** *Decode(u, t)* as:
|
||||
* Let $u'=u$ if $u \neq 0$; $1$ otherwise.
|
||||
* Let $t'=t$ if $t \neq 0$; $1$ otherwise.
|
||||
* Let $t''=t'$ if $u'^3 + b + t'^2 \neq 0$; $2t'$ otherwise.
|
||||
* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
|
||||
* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
|
||||
* Let $x$ be the first element of $(u' + 4Y^2, \frac{-X}{2Y} - \frac{u'}{2}, \frac{X}{2Y} - \frac{u'}{2})$ for which $g(x)$ is square.
|
||||
* Let $y = \sqrt{g(x)}.$
|
||||
* Return $(x, y)$ if $sign(y) = sign(t)$; $(x, -y)$ otherwise.
|
||||
|
||||
This is implemented in `secp256k1_ellswift_swiftec_var`. The used $sign(x)$ function is the parity of $x$ when represented as in integer in $[0,q).$
|
||||
|
||||
The corresponding encoder would invoke the x-only one, but negating the output $t$ if $sign(t) \neq sign(y).$
|
||||
|
||||
This is implemented in `secp256k1_ellswift_elligatorswift_var`.
|
||||
|
||||
Note that this is only intended for encoding points where both the x-coordinate and y-coordinate are unpredictable. When encoding x-only points
|
||||
where the y-coordinate is implicitly even (or implicitly square, or implicitly in $[0,q/2]$), the encoder in
|
||||
[Section 3.5](#35-encoding-for-secp256k1) must be used, or a bias is reintroduced that undoes all the benefit of using ElligatorSwift
|
||||
in the first place.
|
||||
54
external/secp256k1/doc/musig.md
vendored
Normal file
54
external/secp256k1/doc/musig.md
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
Notes on the musig module API
|
||||
===========================
|
||||
|
||||
The following sections contain additional notes on the API of the musig module (`include/secp256k1_musig.h`).
|
||||
A usage example can be found in `examples/musig.c`.
|
||||
|
||||
## API misuse
|
||||
|
||||
The musig API is designed with a focus on misuse resistance.
|
||||
However, due to the interactive nature of the MuSig protocol, there are additional failure modes that are not present in regular (single-party) Schnorr signature creation.
|
||||
While the results can be catastrophic (e.g. leaking of the secret key), it is unfortunately not possible for the musig implementation to prevent all such failure modes.
|
||||
|
||||
Therefore, users of the musig module must take great care to make sure of the following:
|
||||
|
||||
1. A unique nonce per signing session is generated in `secp256k1_musig_nonce_gen`.
|
||||
See the corresponding comment in `include/secp256k1_musig.h` for how to ensure that.
|
||||
2. The `secp256k1_musig_secnonce` structure is never copied or serialized.
|
||||
See also the comment on `secp256k1_musig_secnonce` in `include/secp256k1_musig.h`.
|
||||
3. Opaque data structures are never written to or read from directly.
|
||||
Instead, only the provided accessor functions are used.
|
||||
|
||||
## Key Aggregation and (Taproot) Tweaking
|
||||
|
||||
Given a set of public keys, the aggregate public key is computed with `secp256k1_musig_pubkey_agg`.
|
||||
A plain tweak can be added to the resulting public key with `secp256k1_ec_pubkey_tweak_add` by setting the `tweak32` argument to the hash defined in BIP 32. Similarly, a Taproot tweak can be added with `secp256k1_xonly_pubkey_tweak_add` by setting the `tweak32` argument to the TapTweak hash defined in BIP 341.
|
||||
Both types of tweaking can be combined and invoked multiple times if the specific application requires it.
|
||||
|
||||
## Signing
|
||||
|
||||
This is covered by `examples/musig.c`.
|
||||
Essentially, the protocol proceeds in the following steps:
|
||||
|
||||
1. Generate a keypair with `secp256k1_keypair_create` and obtain the public key with `secp256k1_keypair_pub`.
|
||||
2. Call `secp256k1_musig_pubkey_agg` with the pubkeys of all participants.
|
||||
3. Optionally add a (Taproot) tweak with `secp256k1_musig_pubkey_xonly_tweak_add` and a plain tweak with `secp256k1_musig_pubkey_ec_tweak_add`.
|
||||
4. Generate a pair of secret and public nonce with `secp256k1_musig_nonce_gen` and send the public nonce to the other signers.
|
||||
5. Someone (not necessarily the signer) aggregates the public nonces with `secp256k1_musig_nonce_agg` and sends it to the signers.
|
||||
6. Process the aggregate nonce with `secp256k1_musig_nonce_process`.
|
||||
7. Create a partial signature with `secp256k1_musig_partial_sign`.
|
||||
8. Verify the partial signatures (optional in some scenarios) with `secp256k1_musig_partial_sig_verify`.
|
||||
9. Someone (not necessarily the signer) obtains all partial signatures and aggregates them into the final Schnorr signature using `secp256k1_musig_partial_sig_agg`.
|
||||
|
||||
The aggregate signature can be verified with `secp256k1_schnorrsig_verify`.
|
||||
|
||||
Steps 1 through 5 above can occur before or after the signers are aware of the message to be signed.
|
||||
Whenever possible, it is recommended to generate the nonces only after the message is known.
|
||||
This provides enhanced defense-in-depth measures, protecting against potential API misuse in certain scenarios.
|
||||
However, it does require two rounds of communication during the signing process.
|
||||
The alternative, generating the nonces in a pre-processing step before the message is known, eliminates these additional protective measures but allows for non-interactive signing.
|
||||
Similarly, the API supports an alternative protocol flow where generating the aggregate key (steps 1 to 3) is allowed to happen after exchanging nonces (steps 4 to 5).
|
||||
|
||||
## Verification
|
||||
|
||||
A participant who wants to verify the partial signatures, but does not sign itself may do so using the above instructions except that the verifier skips steps 1, 4 and 7.
|
||||
75
external/secp256k1/doc/release-process.md
vendored
75
external/secp256k1/doc/release-process.md
vendored
@@ -1,4 +1,4 @@
|
||||
# Release Process
|
||||
# Release process
|
||||
|
||||
This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`.
|
||||
|
||||
@@ -12,50 +12,83 @@ It is best if the maintainers are present during the release, so they can help e
|
||||
|
||||
This process also assumes that there will be no minor releases for old major releases.
|
||||
|
||||
We aim to cut a regular release every 3-4 months, approximately twice as frequent as major Bitcoin Core releases. Every second release should be published one month before the feature freeze of the next major Bitcoin Core release, allowing sufficient time to update the library in Core.
|
||||
|
||||
## Sanity checks
|
||||
Perform these checks when reviewing the release PR (see below):
|
||||
|
||||
1. Ensure `make distcheck` doesn't fail.
|
||||
```shell
|
||||
./autogen.sh && ./configure --enable-dev-mode && make distcheck
|
||||
```
|
||||
2. Check installation with autotools:
|
||||
```shell
|
||||
dir=$(mktemp -d)
|
||||
./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -RlAh $dir
|
||||
gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa
|
||||
```
|
||||
3. Check installation with CMake:
|
||||
```shell
|
||||
dir=$(mktemp -d)
|
||||
build=$(mktemp -d)
|
||||
cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build && cmake --install $build && ls -RlAh $dir
|
||||
gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa
|
||||
```
|
||||
4. Use the [`check-abi.sh`](/tools/check-abi.sh) tool to verify that there are no unexpected ABI incompatibilities and that the version number and the release notes accurately reflect all potential ABI changes. To run this tool, the `abi-dumper` and `abi-compliance-checker` packages are required.
|
||||
```shell
|
||||
tools/check-abi.sh
|
||||
```
|
||||
|
||||
## 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`),
|
||||
* sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and
|
||||
* if this is not a patch release
|
||||
* updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac` and
|
||||
* finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) by
|
||||
* adding a section for the release (make sure that the version number is a link to a diff between the previous and new version),
|
||||
* removing the `[Unreleased]` section header,
|
||||
* ensuring that the release notes are not missing entries (check the `needs-changelog` label on github), and
|
||||
* including an entry for `### ABI Compatibility` if it doesn't exist,
|
||||
* sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and,
|
||||
* if this is not a patch release,
|
||||
* updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac`, and
|
||||
* updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`.
|
||||
2. After the PR is merged, tag the commit and push it:
|
||||
2. Perform the [sanity checks](#sanity-checks) on the PR branch.
|
||||
3. After the PR is merged, tag the commit, and push the tag:
|
||||
```
|
||||
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 increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`, and
|
||||
* increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`.
|
||||
4. 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 increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`,
|
||||
* increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and
|
||||
* adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md).
|
||||
|
||||
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).
|
||||
5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
|
||||
6. Send an announcement email to the bitcoin-dev mailing list.
|
||||
|
||||
## Maintenance release
|
||||
|
||||
Note that bugfixes only need to be backported to releases for which no compatible release without the bug exists.
|
||||
Note that bug fixes need to be backported only to releases for which no compatible release without the bug exists.
|
||||
|
||||
1. If `$PATCH = 1`, create maintenance branch `$MAJOR.$MINOR`:
|
||||
1. If there's no maintenance branch `$MAJOR.$MINOR`, create one:
|
||||
```
|
||||
git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.0
|
||||
git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.$((PATCH - 1))
|
||||
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,
|
||||
* includes the bug fixes,
|
||||
* finalizes the release notes similar to a regular release,
|
||||
* increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`
|
||||
and the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`
|
||||
(with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example).
|
||||
3. After the PRs are merged, update the release branch and tag the commit:
|
||||
3. Perform the [sanity checks](#sanity-checks) on the PR branch.
|
||||
4. After the PRs are merged, update the release branch, tag the commit, and push the tag:
|
||||
```
|
||||
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).
|
||||
6. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
|
||||
7. Send an announcement email to the bitcoin-dev mailing list.
|
||||
8. 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).
|
||||
|
||||
44
external/secp256k1/examples/CMakeLists.txt
vendored
44
external/secp256k1/examples/CMakeLists.txt
vendored
@@ -1,27 +1,31 @@
|
||||
add_library(example INTERFACE)
|
||||
target_include_directories(example INTERFACE
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
)
|
||||
target_link_libraries(example INTERFACE
|
||||
secp256k1
|
||||
$<$<PLATFORM_ID:Windows>:bcrypt>
|
||||
)
|
||||
if(NOT BUILD_SHARED_LIBS AND MSVC)
|
||||
target_link_options(example INTERFACE /IGNORE:4217)
|
||||
endif()
|
||||
function(add_example name)
|
||||
set(target_name ${name}_example)
|
||||
add_executable(${target_name} ${name}.c)
|
||||
target_include_directories(${target_name} PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
)
|
||||
target_link_libraries(${target_name}
|
||||
secp256k1
|
||||
$<$<PLATFORM_ID:Windows>:bcrypt>
|
||||
)
|
||||
set(test_name ${name}_example)
|
||||
add_test(NAME secp256k1_${test_name} COMMAND ${target_name})
|
||||
endfunction()
|
||||
|
||||
add_executable(ecdsa_example ecdsa.c)
|
||||
target_link_libraries(ecdsa_example example)
|
||||
add_test(NAME ecdsa_example COMMAND ecdsa_example)
|
||||
add_example(ecdsa)
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_ECDH)
|
||||
add_executable(ecdh_example ecdh.c)
|
||||
target_link_libraries(ecdh_example example)
|
||||
add_test(NAME ecdh_example COMMAND ecdh_example)
|
||||
add_example(ecdh)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
add_executable(schnorr_example schnorr.c)
|
||||
target_link_libraries(schnorr_example example)
|
||||
add_test(NAME schnorr_example COMMAND schnorr_example)
|
||||
add_example(schnorr)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
||||
add_example(ellswift)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_MUSIG)
|
||||
add_example(musig)
|
||||
endif()
|
||||
|
||||
24
external/secp256k1/examples/ecdh.c
vendored
24
external/secp256k1/examples/ecdh.c
vendored
@@ -42,18 +42,16 @@ int main(void) {
|
||||
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;
|
||||
}
|
||||
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* If the secret key is zero or out of range (greater than secp256k1's
|
||||
* order), we fail. Note that the probability of this occurring is negligible
|
||||
* with a properly functioning random number generator. */
|
||||
if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) {
|
||||
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Public key creation using a valid context with a verified secret key should never fail */
|
||||
@@ -108,7 +106,7 @@ int main(void) {
|
||||
|
||||
/* 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
|
||||
* 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
|
||||
|
||||
24
external/secp256k1/examples/ecdsa.c
vendored
24
external/secp256k1/examples/ecdsa.c
vendored
@@ -49,18 +49,16 @@ int main(void) {
|
||||
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;
|
||||
}
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* If the secret key is zero or out of range (greater than secp256k1's
|
||||
* order), we fail. Note that the probability of this occurring is negligible
|
||||
* with a properly functioning random number generator. */
|
||||
if (!secp256k1_ec_seckey_verify(ctx, seckey)) {
|
||||
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Public key creation using a valid context with a verified secret key should never fail */
|
||||
@@ -128,7 +126,7 @@ int main(void) {
|
||||
|
||||
/* 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
|
||||
* 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
|
||||
|
||||
121
external/secp256k1/examples/ellswift.c
vendored
Normal file
121
external/secp256k1/examples/ellswift.c
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
/*************************************************************************
|
||||
* Written in 2024 by Sebastian Falbesoner *
|
||||
* 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 *
|
||||
*************************************************************************/
|
||||
|
||||
/** This file demonstrates how to use the ElligatorSwift module to perform
|
||||
* a key exchange according to BIP 324. Additionally, see the documentation
|
||||
* in include/secp256k1_ellswift.h and doc/ellswift.md.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_ellswift.h>
|
||||
|
||||
#include "examples_util.h"
|
||||
|
||||
int main(void) {
|
||||
secp256k1_context* ctx;
|
||||
unsigned char randomize[32];
|
||||
unsigned char auxrand1[32];
|
||||
unsigned char auxrand2[32];
|
||||
unsigned char seckey1[32];
|
||||
unsigned char seckey2[32];
|
||||
unsigned char ellswift_pubkey1[64];
|
||||
unsigned char ellswift_pubkey2[64];
|
||||
unsigned char shared_secret1[32];
|
||||
unsigned char shared_secret2[32];
|
||||
int return_val;
|
||||
|
||||
/* Create a 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);
|
||||
|
||||
/*** Generate secret keys ***/
|
||||
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* If the secret key is zero or out of range (greater than secp256k1's
|
||||
* order), we fail. Note that the probability of this occurring is negligible
|
||||
* with a properly functioning random number generator. */
|
||||
if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) {
|
||||
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generate ElligatorSwift public keys. This should never fail with valid context and
|
||||
verified secret keys. Note that providing additional randomness (fourth parameter) is
|
||||
optional, but recommended. */
|
||||
if (!fill_random(auxrand1, sizeof(auxrand1)) || !fill_random(auxrand2, sizeof(auxrand2))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
return_val = secp256k1_ellswift_create(ctx, ellswift_pubkey1, seckey1, auxrand1);
|
||||
assert(return_val);
|
||||
return_val = secp256k1_ellswift_create(ctx, ellswift_pubkey2, seckey2, auxrand2);
|
||||
assert(return_val);
|
||||
|
||||
/*** Create the shared secret on each side ***/
|
||||
|
||||
/* Perform x-only ECDH with seckey1 and ellswift_pubkey2. Should never fail
|
||||
* with a verified seckey and valid pubkey. Note that both parties pass both
|
||||
* EllSwift pubkeys in the same order; the pubkey of the calling party is
|
||||
* determined by the "party" boolean (sixth parameter). */
|
||||
return_val = secp256k1_ellswift_xdh(ctx, shared_secret1, ellswift_pubkey1, ellswift_pubkey2,
|
||||
seckey1, 0, secp256k1_ellswift_xdh_hash_function_bip324, NULL);
|
||||
assert(return_val);
|
||||
|
||||
/* Perform x-only ECDH with seckey2 and ellswift_pubkey1. Should never fail
|
||||
* with a verified seckey and valid pubkey. */
|
||||
return_val = secp256k1_ellswift_xdh(ctx, shared_secret2, ellswift_pubkey1, ellswift_pubkey2,
|
||||
seckey2, 1, secp256k1_ellswift_xdh_hash_function_bip324, 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( "EllSwift Pubkey1: ");
|
||||
print_hex(ellswift_pubkey1, sizeof(ellswift_pubkey1));
|
||||
printf("\n Secret Key2: ");
|
||||
print_hex(seckey2, sizeof(seckey2));
|
||||
printf( "EllSwift Pubkey2: ");
|
||||
print_hex(ellswift_pubkey2, sizeof(ellswift_pubkey2));
|
||||
printf("\n Shared 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;
|
||||
}
|
||||
2
external/secp256k1/examples/examples_util.h
vendored
2
external/secp256k1/examples/examples_util.h
vendored
@@ -95,7 +95,7 @@ static void secure_erase(void *ptr, size_t len) {
|
||||
* 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,
|
||||
* pretty efficient, because the compiler can still implement the memset() efficiently,
|
||||
* just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
|
||||
* Yang et al. (USENIX Security 2017) for more background.
|
||||
*/
|
||||
|
||||
260
external/secp256k1/examples/musig.c
vendored
Normal file
260
external/secp256k1/examples/musig.c
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
/*************************************************************************
|
||||
* 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 *
|
||||
*************************************************************************/
|
||||
|
||||
/** This file demonstrates how to use the MuSig module to create a
|
||||
* 3-of-3 multisignature. Additionally, see the documentation in
|
||||
* include/secp256k1_musig.h and doc/musig.md.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_extrakeys.h>
|
||||
#include <secp256k1_musig.h>
|
||||
#include <secp256k1_schnorrsig.h>
|
||||
|
||||
#include "examples_util.h"
|
||||
|
||||
struct signer_secrets {
|
||||
secp256k1_keypair keypair;
|
||||
secp256k1_musig_secnonce secnonce;
|
||||
};
|
||||
|
||||
struct signer {
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_musig_pubnonce pubnonce;
|
||||
secp256k1_musig_partial_sig partial_sig;
|
||||
};
|
||||
|
||||
/* Number of public keys involved in creating the aggregate signature */
|
||||
#define N_SIGNERS 3
|
||||
/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */
|
||||
static int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) {
|
||||
unsigned char seckey[32];
|
||||
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 0;
|
||||
}
|
||||
/* Try to create a keypair with a valid context. This only fails if the
|
||||
* secret key is zero or out of range (greater than secp256k1's order). Note
|
||||
* that the probability of this occurring is negligible with a properly
|
||||
* functioning random number generator. */
|
||||
if (!secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secure_erase(seckey, sizeof(seckey));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Tweak the pubkey corresponding to the provided keyagg cache, update the cache
|
||||
* and return the tweaked aggregate pk. */
|
||||
static int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache) {
|
||||
secp256k1_pubkey output_pk;
|
||||
/* For BIP 32 tweaking the plain_tweak is set to a hash as defined in BIP
|
||||
* 32. */
|
||||
unsigned char plain_tweak[32] = "this could be a BIP32 tweak....";
|
||||
/* For Taproot tweaking the xonly_tweak is set to the TapTweak hash as
|
||||
* defined in BIP 341 */
|
||||
unsigned char xonly_tweak[32] = "this could be a Taproot tweak..";
|
||||
|
||||
|
||||
/* Plain tweaking which, for example, allows deriving multiple child
|
||||
* public keys from a single aggregate key using BIP32 */
|
||||
if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, cache, plain_tweak)) {
|
||||
return 0;
|
||||
}
|
||||
/* Note that we did not provide an output_pk argument, because the
|
||||
* resulting pk is also saved in the cache and so if one is just interested
|
||||
* in signing, the output_pk argument is unnecessary. On the other hand, if
|
||||
* one is not interested in signing, the same output_pk can be obtained by
|
||||
* calling `secp256k1_musig_pubkey_get` right after key aggregation to get
|
||||
* the full pubkey and then call `secp256k1_ec_pubkey_tweak_add`. */
|
||||
|
||||
/* Xonly tweaking which, for example, allows creating Taproot commitments */
|
||||
if (!secp256k1_musig_pubkey_xonly_tweak_add(ctx, &output_pk, cache, xonly_tweak)) {
|
||||
return 0;
|
||||
}
|
||||
/* Note that if we wouldn't care about signing, we can arrive at the same
|
||||
* output_pk by providing the untweaked public key to
|
||||
* `secp256k1_xonly_pubkey_tweak_add` (after converting it to an xonly pubkey
|
||||
* if necessary with `secp256k1_xonly_pubkey_from_pubkey`). */
|
||||
|
||||
/* Now we convert the output_pk to an xonly pubkey to allow to later verify
|
||||
* the Schnorr signature against it. For this purpose we can ignore the
|
||||
* `pk_parity` output argument; we would need it if we would have to open
|
||||
* the Taproot commitment. */
|
||||
if (!secp256k1_xonly_pubkey_from_pubkey(ctx, agg_pk, NULL, &output_pk)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Sign a message hash with the given key pairs and store the result in sig */
|
||||
static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const secp256k1_musig_keyagg_cache *cache, const unsigned char *msg32, unsigned char *sig64) {
|
||||
int i;
|
||||
const secp256k1_musig_pubnonce *pubnonces[N_SIGNERS];
|
||||
const secp256k1_musig_partial_sig *partial_sigs[N_SIGNERS];
|
||||
/* The same for all signers */
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_musig_aggnonce agg_pubnonce;
|
||||
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
unsigned char seckey[32];
|
||||
unsigned char session_secrand[32];
|
||||
/* Create random session ID. It is absolutely necessary that the session ID
|
||||
* is unique for every call of secp256k1_musig_nonce_gen. Otherwise
|
||||
* it's trivial for an attacker to extract the secret key! */
|
||||
if (!fill_random(session_secrand, sizeof(session_secrand))) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) {
|
||||
return 0;
|
||||
}
|
||||
/* Initialize session and create secret nonce for signing and public
|
||||
* nonce to send to the other signers. */
|
||||
if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_secrand, seckey, &signer[i].pubkey, msg32, NULL, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
pubnonces[i] = &signer[i].pubnonce;
|
||||
|
||||
secure_erase(seckey, sizeof(seckey));
|
||||
}
|
||||
|
||||
/* Communication round 1: Every signer sends their pubnonce to the
|
||||
* coordinator. The coordinator runs secp256k1_musig_nonce_agg and sends
|
||||
* agg_pubnonce to each signer */
|
||||
if (!secp256k1_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Every signer creates a partial signature */
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
/* Initialize the signing session by processing the aggregate nonce */
|
||||
if (!secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, cache)) {
|
||||
return 0;
|
||||
}
|
||||
/* partial_sign will clear the secnonce by setting it to 0. That's because
|
||||
* you must _never_ reuse the secnonce (or use the same session_secrand to
|
||||
* create a secnonce). If you do, you effectively reuse the nonce and
|
||||
* leak the secret key. */
|
||||
if (!secp256k1_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, cache, &session)) {
|
||||
return 0;
|
||||
}
|
||||
partial_sigs[i] = &signer[i].partial_sig;
|
||||
}
|
||||
/* Communication round 2: Every signer sends their partial signature to the
|
||||
* coordinator, who verifies the partial signatures and aggregates them. */
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
/* To check whether signing was successful, it suffices to either verify
|
||||
* the aggregate signature with the aggregate public key using
|
||||
* secp256k1_schnorrsig_verify, or verify all partial signatures of all
|
||||
* signers individually. Verifying the aggregate signature is cheaper but
|
||||
* verifying the individual partial signatures has the advantage that it
|
||||
* can be used to determine which of the partial signatures are invalid
|
||||
* (if any), i.e., which of the partial signatures cause the aggregate
|
||||
* signature to be invalid and thus the protocol run to fail. It's also
|
||||
* fine to first verify the aggregate sig, and only verify the individual
|
||||
* sigs if it does not work.
|
||||
*/
|
||||
if (!secp256k1_musig_partial_sig_verify(ctx, &signer[i].partial_sig, &signer[i].pubnonce, &signer[i].pubkey, cache, &session)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return secp256k1_musig_partial_sig_agg(ctx, sig64, &session, partial_sigs, N_SIGNERS);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
secp256k1_context* ctx;
|
||||
int i;
|
||||
struct signer_secrets signer_secrets[N_SIGNERS];
|
||||
struct signer signers[N_SIGNERS];
|
||||
const secp256k1_pubkey *pubkeys_ptr[N_SIGNERS];
|
||||
secp256k1_xonly_pubkey agg_pk;
|
||||
secp256k1_musig_keyagg_cache cache;
|
||||
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg";
|
||||
unsigned char sig[64];
|
||||
|
||||
/* Create a secp256k1 context */
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
printf("Creating key pairs......");
|
||||
fflush(stdout);
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
if (!create_keypair(ctx, &signer_secrets[i], &signers[i])) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
pubkeys_ptr[i] = &signers[i].pubkey;
|
||||
}
|
||||
printf("ok\n");
|
||||
|
||||
/* The aggregate public key produced by secp256k1_musig_pubkey_agg depends
|
||||
* on the order of the provided public keys. If there is no canonical order
|
||||
* of the signers, the individual public keys can optionally be sorted with
|
||||
* secp256k1_ec_pubkey_sort to ensure that the aggregate public key is
|
||||
* independent of the order of signers. */
|
||||
printf("Sorting public keys.....");
|
||||
fflush(stdout);
|
||||
if (!secp256k1_ec_pubkey_sort(ctx, pubkeys_ptr, N_SIGNERS)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
|
||||
printf("Combining public keys...");
|
||||
fflush(stdout);
|
||||
/* If you just want to aggregate and not sign, you can call
|
||||
* secp256k1_musig_pubkey_agg with the keyagg_cache argument set to NULL
|
||||
* while providing a non-NULL agg_pk argument. */
|
||||
if (!secp256k1_musig_pubkey_agg(ctx, NULL, &cache, pubkeys_ptr, N_SIGNERS)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Tweaking................");
|
||||
fflush(stdout);
|
||||
/* Optionally tweak the aggregate key */
|
||||
if (!tweak(ctx, &agg_pk, &cache)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Signing message.........");
|
||||
fflush(stdout);
|
||||
if (!sign(ctx, signer_secrets, signers, &cache, msg, sig)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Verifying signature.....");
|
||||
fflush(stdout);
|
||||
if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &agg_pk)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
|
||||
/* 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 secret key material with zeros.
|
||||
*
|
||||
* Here we are preventing these writes from being optimized out, as any good compiler
|
||||
* will remove any writes that aren't used. */
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
secure_erase(&signer_secrets[i], sizeof(signer_secrets[i]));
|
||||
}
|
||||
secp256k1_context_destroy(ctx);
|
||||
return 0;
|
||||
}
|
||||
31
external/secp256k1/examples/schnorr.c
vendored
31
external/secp256k1/examples/schnorr.c
vendored
@@ -18,9 +18,9 @@
|
||||
#include "examples_util.h"
|
||||
|
||||
int main(void) {
|
||||
unsigned char msg[12] = "Hello World!";
|
||||
unsigned char msg[] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'};
|
||||
unsigned char msg_hash[32];
|
||||
unsigned char tag[17] = "my_fancy_protocol";
|
||||
unsigned char tag[] = {'m', 'y', '_', 'f', 'a', 'n', 'c', 'y', '_', 'p', 'r', 'o', 't', 'o', 'c', 'o', 'l'};
|
||||
unsigned char seckey[32];
|
||||
unsigned char randomize[32];
|
||||
unsigned char auxiliary_rand[32];
|
||||
@@ -43,20 +43,17 @@ int main(void) {
|
||||
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;
|
||||
}
|
||||
if (!fill_random(seckey, sizeof(seckey))) {
|
||||
printf("Failed to generate randomness\n");
|
||||
return 1;
|
||||
}
|
||||
/* Try to create a keypair with a valid context. This only fails if the
|
||||
* secret key is zero or out of range (greater than secp256k1's order). Note
|
||||
* that the probability of this occurring is negligible with a properly
|
||||
* functioning random number generator. */
|
||||
if (!secp256k1_keypair_create(ctx, &keypair, seckey)) {
|
||||
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Extract the X-only public key from the keypair. We pass NULL for
|
||||
@@ -146,7 +143,7 @@ int main(void) {
|
||||
|
||||
/* 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
|
||||
* 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
|
||||
|
||||
197
external/secp256k1/include/secp256k1.h
vendored
197
external/secp256k1/include/secp256k1.h
vendored
@@ -49,19 +49,6 @@ extern "C" {
|
||||
*/
|
||||
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
|
||||
@@ -71,11 +58,11 @@ typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space;
|
||||
* use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. To
|
||||
* compare keys, use secp256k1_ec_pubkey_cmp.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct secp256k1_pubkey {
|
||||
unsigned char data[64];
|
||||
} secp256k1_pubkey;
|
||||
|
||||
/** Opaque data structured that holds a parsed ECDSA signature.
|
||||
/** Opaque data structure 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
|
||||
@@ -84,7 +71,7 @@ typedef struct {
|
||||
* comparison, use the secp256k1_ecdsa_signature_serialize_* and
|
||||
* secp256k1_ecdsa_signature_parse_* functions.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct secp256k1_ecdsa_signature {
|
||||
unsigned char data[64];
|
||||
} secp256k1_ecdsa_signature;
|
||||
|
||||
@@ -133,28 +120,45 @@ typedef int (*secp256k1_nonce_function)(
|
||||
# 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)
|
||||
/* Symbol visibility. */
|
||||
#if defined(_WIN32)
|
||||
/* GCC for Windows (e.g., MinGW) accepts the __declspec syntax
|
||||
* for MSVC compatibility. A __declspec declaration implies (but is not
|
||||
* exactly equivalent to) __attribute__ ((visibility("default"))), and so we
|
||||
* actually want __declspec even on GCC, see "Microsoft Windows Function
|
||||
* Attributes" in the GCC manual and the recommendations in
|
||||
* https://gcc.gnu.org/wiki/Visibility. */
|
||||
# if defined(SECP256K1_BUILD)
|
||||
# if defined(DLL_EXPORT) || defined(SECP256K1_DLL_EXPORT)
|
||||
/* Building libsecp256k1 as a DLL.
|
||||
* 1. If using Libtool, it defines DLL_EXPORT automatically.
|
||||
* 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */
|
||||
# define SECP256K1_API extern __declspec (dllexport)
|
||||
# else
|
||||
/* Building libsecp256k1 as a static library on Windows.
|
||||
* No declspec is needed, and so we would want the non-Windows-specific
|
||||
* logic below take care of this case. However, this may result in setting
|
||||
* __attribute__ ((visibility("default"))), which is supposed to be a noop
|
||||
* on Windows but may trigger warnings when compiling with -flto due to a
|
||||
* bug in GCC, see
|
||||
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116478 . */
|
||||
# define SECP256K1_API extern
|
||||
# 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)
|
||||
/* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static
|
||||
* library on Windows. */
|
||||
# elif !defined(SECP256K1_STATIC)
|
||||
/* Consuming libsecp256k1 as a DLL. */
|
||||
# define SECP256K1_API extern __declspec (dllimport)
|
||||
# endif
|
||||
#endif
|
||||
#ifndef SECP256K1_API
|
||||
/* All cases not captured by the Windows-specific logic. */
|
||||
# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
|
||||
# define SECP256K1_API __attribute__ ((visibility ("default")))
|
||||
# define SECP256K1_API_VAR extern __attribute__ ((visibility ("default")))
|
||||
/* Building libsecp256k1 using GCC or compatible. */
|
||||
# define SECP256K1_API extern __attribute__ ((visibility ("default")))
|
||||
# else
|
||||
# define SECP256K1_API
|
||||
# define SECP256K1_API_VAR extern
|
||||
/* Fall back to standard C's extern. */
|
||||
# define SECP256K1_API extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -226,10 +230,10 @@ typedef int (*secp256k1_nonce_function)(
|
||||
*
|
||||
* It is highly recommended to call secp256k1_selftest before using this context.
|
||||
*/
|
||||
SECP256K1_API_VAR const secp256k1_context *secp256k1_context_static;
|
||||
SECP256K1_API const secp256k1_context *secp256k1_context_static;
|
||||
|
||||
/** Deprecated alias for secp256k1_context_static. */
|
||||
SECP256K1_API_VAR const secp256k1_context *secp256k1_context_no_precomp
|
||||
SECP256K1_API 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)
|
||||
@@ -258,7 +262,7 @@ SECP256K1_API void secp256k1_selftest(void);
|
||||
* memory allocation entirely, see secp256k1_context_static and the functions in
|
||||
* secp256k1_preallocated.h.
|
||||
*
|
||||
* Returns: a newly created context object.
|
||||
* Returns: pointer to 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
|
||||
@@ -289,8 +293,8 @@ SECP256K1_API secp256k1_context *secp256k1_context_create(
|
||||
* 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)
|
||||
* Returns: pointer to a newly created context object.
|
||||
* Args: ctx: pointer to a context to copy (not secp256k1_context_static).
|
||||
*/
|
||||
SECP256K1_API secp256k1_context *secp256k1_context_clone(
|
||||
const secp256k1_context *ctx
|
||||
@@ -306,7 +310,7 @@ SECP256K1_API secp256k1_context *secp256k1_context_clone(
|
||||
* behaviour is undefined. In that case, secp256k1_context_preallocated_destroy must
|
||||
* be used instead.
|
||||
*
|
||||
* Args: ctx: an existing context to destroy, constructed using
|
||||
* Args: ctx: pointer to a context to destroy, constructed using
|
||||
* secp256k1_context_create or secp256k1_context_clone
|
||||
* (i.e., not secp256k1_context_static).
|
||||
*/
|
||||
@@ -343,8 +347,8 @@ SECP256K1_API void secp256k1_context_destroy(
|
||||
* 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
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In: fun: 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.
|
||||
@@ -370,8 +374,8 @@ SECP256K1_API void 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,
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In: fun: 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).
|
||||
@@ -385,34 +389,11 @@ SECP256K1_API void secp256k1_context_set_error_callback(
|
||||
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.
|
||||
* Args: ctx: pointer to a 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
|
||||
@@ -432,14 +413,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
|
||||
/** 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
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: output: 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
|
||||
* In/Out: outputlen: 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
|
||||
* In: pubkey: 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.
|
||||
@@ -457,7 +438,7 @@ SECP256K1_API int secp256k1_ec_pubkey_serialize(
|
||||
* 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.
|
||||
* Args: ctx: pointer to a context object
|
||||
* In: pubkey1: first public key to compare
|
||||
* pubkey2: second public key to compare
|
||||
*/
|
||||
@@ -467,12 +448,26 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp(
|
||||
const secp256k1_pubkey *pubkey2
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Sort public keys using lexicographic (of compressed serialization) order
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
||||
*
|
||||
* Args: ctx: pointer to a context object
|
||||
* In: pubkeys: array of pointers to pubkeys to sort
|
||||
* n_pubkeys: number of elements in the pubkeys array
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ec_pubkey_sort(
|
||||
const secp256k1_context *ctx,
|
||||
const secp256k1_pubkey **pubkeys,
|
||||
size_t n_pubkeys
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** 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
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: sig: pointer to a signature object
|
||||
* In: input64: 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
|
||||
@@ -491,9 +486,9 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
|
||||
/** 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
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: sig: pointer to a signature object
|
||||
* In: input: 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
|
||||
@@ -513,13 +508,13 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_der(
|
||||
/** 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
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: output: pointer to an array to store the DER serialization
|
||||
* In/Out: outputlen: 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
|
||||
* In: sig: pointer to an initialized signature object
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_signature_serialize_der(
|
||||
const secp256k1_context *ctx,
|
||||
@@ -531,9 +526,9 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_der(
|
||||
/** 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
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: output64: pointer to a 64-byte array to store the compact serialization
|
||||
* In: sig: pointer to an initialized signature object
|
||||
*
|
||||
* See secp256k1_ecdsa_signature_parse_compact for details about the encoding.
|
||||
*/
|
||||
@@ -547,7 +542,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
|
||||
*
|
||||
* Returns: 1: correct signature
|
||||
* 0: incorrect or unparseable signature
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Args: ctx: pointer to a 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
|
||||
@@ -578,12 +573,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
|
||||
/** 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,
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: sigout: 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)
|
||||
* In: sigin: 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
|
||||
@@ -626,10 +621,10 @@ SECP256K1_API int secp256k1_ecdsa_signature_normalize(
|
||||
* 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;
|
||||
SECP256K1_API 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;
|
||||
SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_default;
|
||||
|
||||
/** Create an ECDSA signature.
|
||||
*
|
||||
@@ -658,12 +653,14 @@ SECP256K1_API int secp256k1_ecdsa_sign(
|
||||
const void *ndata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Verify an ECDSA secret key.
|
||||
/** Verify an elliptic curve 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.
|
||||
* invalid secret key is negligible. However, if it does happen it should
|
||||
* be assumed that the randomness source is severely broken and there should
|
||||
* be no retry.
|
||||
*
|
||||
* Returns: 1: secret key is valid
|
||||
* 0: secret key is invalid
|
||||
@@ -733,10 +730,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
|
||||
* 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).
|
||||
* In: tweak32: pointer to a 32-byte tweak, which must be valid according to
|
||||
* secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly
|
||||
* random 32-byte tweaks, 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,
|
||||
@@ -761,10 +758,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
|
||||
* 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).
|
||||
* In: tweak32: pointer to a 32-byte tweak, which must be valid according to
|
||||
* secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly
|
||||
* random 32-byte tweaks, 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,
|
||||
|
||||
6
external/secp256k1/include/secp256k1_ecdh.h
vendored
6
external/secp256k1/include/secp256k1_ecdh.h
vendored
@@ -27,11 +27,11 @@ typedef int (*secp256k1_ecdh_hash_function)(
|
||||
|
||||
/** 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;
|
||||
SECP256K1_API 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;
|
||||
SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
|
||||
|
||||
/** Compute an EC Diffie-Hellman secret in constant time
|
||||
*
|
||||
@@ -39,7 +39,7 @@ SECP256K1_API_VAR const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_functio
|
||||
* 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.
|
||||
* In: pubkey: 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
|
||||
|
||||
200
external/secp256k1/include/secp256k1_ellswift.h
vendored
Normal file
200
external/secp256k1/include/secp256k1_ellswift.h
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
#ifndef SECP256K1_ELLSWIFT_H
|
||||
#define SECP256K1_ELLSWIFT_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This module provides an implementation of ElligatorSwift as well as a
|
||||
* version of x-only ECDH using it (including compatibility with BIP324).
|
||||
*
|
||||
* ElligatorSwift is described in https://eprint.iacr.org/2022/759 by
|
||||
* Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding
|
||||
* uniformly chosen public keys as 64-byte arrays which are indistinguishable
|
||||
* from uniformly random arrays.
|
||||
*
|
||||
* Let f be the function from pairs of field elements to point X coordinates,
|
||||
* defined as follows (all operations modulo p = 2^256 - 2^32 - 977)
|
||||
* f(u,t):
|
||||
* - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852,
|
||||
* a square root of -3.
|
||||
* - If u=0, set u=1 instead.
|
||||
* - If t=0, set t=1 instead.
|
||||
* - If u^3 + t^2 + 7 = 0, multiply t by 2.
|
||||
* - Let X = (u^3 + 7 - t^2) / (2 * t)
|
||||
* - Let Y = (X + t) / (C * u)
|
||||
* - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an
|
||||
* X coordinate on the curve (at least one of them is, for any u and t).
|
||||
*
|
||||
* Then an ElligatorSwift encoding of x consists of the 32-byte big-endian
|
||||
* encodings of field elements u and t concatenated, where f(u,t) = x.
|
||||
* The encoding algorithm is described in the paper, and effectively picks a
|
||||
* uniformly random pair (u,t) among those which encode x.
|
||||
*
|
||||
* If the Y coordinate is relevant, it is given the same parity as t.
|
||||
*
|
||||
* Changes w.r.t. the paper:
|
||||
* - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point
|
||||
* at infinity in the paper. Here they are remapped to finite points.
|
||||
* - The paper uses an additional encoding bit for the parity of y. Here the
|
||||
* parity of t is used (negating t does not affect the decoded x coordinate,
|
||||
* so this is possible).
|
||||
*
|
||||
* For mathematical background about the scheme, see the doc/ellswift.md file.
|
||||
*/
|
||||
|
||||
/** A pointer to a function used by secp256k1_ellswift_xdh to hash the shared X
|
||||
* coordinate along with the encoded public keys to a uniform shared secret.
|
||||
*
|
||||
* Returns: 1 if a shared secret was successfully computed.
|
||||
* 0 will cause secp256k1_ellswift_xdh to fail and return 0.
|
||||
* Other return values are not allowed, and the behaviour of
|
||||
* secp256k1_ellswift_xdh is undefined for other return values.
|
||||
* Out: output: pointer to an array to be filled by the function
|
||||
* In: x32: pointer to the 32-byte serialized X coordinate
|
||||
* of the resulting shared point (will not be NULL)
|
||||
* ell_a64: pointer to the 64-byte encoded public key of party A
|
||||
* (will not be NULL)
|
||||
* ell_b64: pointer to the 64-byte encoded public key of party B
|
||||
* (will not be NULL)
|
||||
* data: arbitrary data pointer that is passed through
|
||||
*/
|
||||
typedef int (*secp256k1_ellswift_xdh_hash_function)(
|
||||
unsigned char *output,
|
||||
const unsigned char *x32,
|
||||
const unsigned char *ell_a64,
|
||||
const unsigned char *ell_b64,
|
||||
void *data
|
||||
);
|
||||
|
||||
/** An implementation of an secp256k1_ellswift_xdh_hash_function which uses
|
||||
* SHA256(prefix64 || ell_a64 || ell_b64 || x32), where prefix64 is the 64-byte
|
||||
* array pointed to by data. */
|
||||
SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix;
|
||||
|
||||
/** An implementation of an secp256k1_ellswift_xdh_hash_function compatible with
|
||||
* BIP324. It returns H_tag(ell_a64 || ell_b64 || x32), where H_tag is the
|
||||
* BIP340 tagged hash function with tag "bip324_ellswift_xonly_ecdh". Equivalent
|
||||
* to secp256k1_ellswift_xdh_hash_function_prefix with prefix64 set to
|
||||
* SHA256("bip324_ellswift_xonly_ecdh")||SHA256("bip324_ellswift_xonly_ecdh").
|
||||
* The data argument is ignored. */
|
||||
SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324;
|
||||
|
||||
/** Construct a 64-byte ElligatorSwift encoding of a given pubkey.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: ell64: pointer to a 64-byte array to be filled
|
||||
* In: pubkey: pointer to a secp256k1_pubkey containing an
|
||||
* initialized public key
|
||||
* rnd32: pointer to 32 bytes of randomness
|
||||
*
|
||||
* It is recommended that rnd32 consists of 32 uniformly random bytes, not
|
||||
* known to any adversary trying to detect whether public keys are being
|
||||
* encoded, though 16 bytes of randomness (padded to an array of 32 bytes,
|
||||
* e.g., with zeros) suffice to make the result indistinguishable from
|
||||
* uniform. The randomness in rnd32 must not be a deterministic function of
|
||||
* the pubkey (it can be derived from the private key, though).
|
||||
*
|
||||
* It is not guaranteed that the computed encoding is stable across versions
|
||||
* of the library, even if all arguments to this function (including rnd32)
|
||||
* are the same.
|
||||
*
|
||||
* This function runs in variable time.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ellswift_encode(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *ell64,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
const unsigned char *rnd32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Decode a 64-bytes ElligatorSwift encoded public key.
|
||||
*
|
||||
* Returns: always 1
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: pubkey: pointer to a secp256k1_pubkey that will be filled
|
||||
* In: ell64: pointer to a 64-byte array to decode
|
||||
*
|
||||
* This function runs in variable time.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ellswift_decode(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const unsigned char *ell64
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Compute an ElligatorSwift public key for a secret key.
|
||||
*
|
||||
* Returns: 1: secret was valid, public key was stored.
|
||||
* 0: secret was invalid, try again.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: ell64: pointer to a 64-byte array to receive the ElligatorSwift
|
||||
* public key
|
||||
* In: seckey32: pointer to a 32-byte secret key
|
||||
* auxrnd32: (optional) pointer to 32 bytes of randomness
|
||||
*
|
||||
* Constant time in seckey and auxrnd32, but not in the resulting public key.
|
||||
*
|
||||
* It is recommended that auxrnd32 contains 32 uniformly random bytes, though
|
||||
* it is optional (and does result in encodings that are indistinguishable from
|
||||
* uniform even without any auxrnd32). It differs from the (mandatory) rnd32
|
||||
* argument to secp256k1_ellswift_encode in this regard.
|
||||
*
|
||||
* This function can be used instead of calling secp256k1_ec_pubkey_create
|
||||
* followed by secp256k1_ellswift_encode. It is safer, as it uses the secret
|
||||
* key as entropy for the encoding (supplemented with auxrnd32, if provided).
|
||||
*
|
||||
* Like secp256k1_ellswift_encode, this function does not guarantee that the
|
||||
* computed encoding is stable across versions of the library, even if all
|
||||
* arguments (including auxrnd32) are the same.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *ell64,
|
||||
const unsigned char *seckey32,
|
||||
const unsigned char *auxrnd32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Given a private key, and ElligatorSwift public keys sent in both directions,
|
||||
* compute a shared secret using x-only Elliptic Curve Diffie-Hellman (ECDH).
|
||||
*
|
||||
* Returns: 1: shared secret was successfully computed
|
||||
* 0: secret was invalid or hashfp returned 0
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: output: pointer to an array to be filled by hashfp.
|
||||
* In: ell_a64: pointer to the 64-byte encoded public key of party A
|
||||
* (will not be NULL)
|
||||
* ell_b64: pointer to the 64-byte encoded public key of party B
|
||||
* (will not be NULL)
|
||||
* seckey32: pointer to our 32-byte secret key
|
||||
* party: boolean indicating which party we are: zero if we are
|
||||
* party A, non-zero if we are party B. seckey32 must be
|
||||
* the private key corresponding to that party's ell_?64.
|
||||
* This correspondence is not checked.
|
||||
* hashfp: pointer to a hash function.
|
||||
* data: arbitrary data pointer passed through to hashfp.
|
||||
*
|
||||
* Constant time in seckey32.
|
||||
*
|
||||
* This function is more efficient than decoding the public keys, and performing
|
||||
* ECDH on them.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_xdh(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *output,
|
||||
const unsigned char *ell_a64,
|
||||
const unsigned char *ell_b64,
|
||||
const unsigned char *seckey32,
|
||||
int party,
|
||||
secp256k1_ellswift_xdh_hash_function hashfp,
|
||||
void *data
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_ELLSWIFT_H */
|
||||
49
external/secp256k1/include/secp256k1_extrakeys.h
vendored
49
external/secp256k1/include/secp256k1_extrakeys.h
vendored
@@ -19,7 +19,7 @@ extern "C" {
|
||||
* use secp256k1_xonly_pubkey_serialize and secp256k1_xonly_pubkey_parse. To
|
||||
* compare keys, use secp256k1_xonly_pubkey_cmp.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct secp256k1_xonly_pubkey {
|
||||
unsigned char data[64];
|
||||
} secp256k1_xonly_pubkey;
|
||||
|
||||
@@ -30,7 +30,7 @@ typedef struct {
|
||||
* 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 {
|
||||
typedef struct secp256k1_keypair {
|
||||
unsigned char data[96];
|
||||
} secp256k1_keypair;
|
||||
|
||||
@@ -39,7 +39,7 @@ typedef struct {
|
||||
* 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.
|
||||
* Args: ctx: pointer to a 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.
|
||||
@@ -54,9 +54,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(
|
||||
*
|
||||
* 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.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: output32: pointer to a 32-byte array to place the serialized key in.
|
||||
* In: pubkey: pointer to a secp256k1_xonly_pubkey containing an initialized public key.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_xonly_pubkey_serialize(
|
||||
const secp256k1_context *ctx,
|
||||
@@ -69,7 +69,7 @@ SECP256K1_API int secp256k1_xonly_pubkey_serialize(
|
||||
* 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.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In: pubkey1: first public key to compare
|
||||
* pubkey2: second public key to compare
|
||||
*/
|
||||
@@ -112,10 +112,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubke
|
||||
* 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).
|
||||
* tweak32: pointer to a 32-byte tweak, which must be valid
|
||||
* according to secp256k1_ec_seckey_verify or 32 zero
|
||||
* bytes. For uniformly random 32-byte tweaks, 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,
|
||||
@@ -155,10 +155,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_
|
||||
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.
|
||||
/** Compute the keypair for a valid secret key.
|
||||
*
|
||||
* Returns: 1: secret was valid, keypair is ready to use
|
||||
* 0: secret was invalid, try again with a different secret
|
||||
* See the documentation of `secp256k1_ec_seckey_verify` for more information
|
||||
* about the validity of secret keys.
|
||||
*
|
||||
* Returns: 1: secret key is valid
|
||||
* 0: secret key is invalid
|
||||
* 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.
|
||||
@@ -185,9 +188,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
|
||||
/** 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.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: pubkey: pointer to a pubkey object, set to the keypair public key.
|
||||
* In: keypair: pointer to a keypair.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
|
||||
@@ -203,9 +205,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
|
||||
*
|
||||
* 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.
|
||||
* Out: pubkey: pointer to an xonly_pubkey object, set to the keypair
|
||||
* public key after converting it to an xonly_pubkey.
|
||||
* 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.
|
||||
@@ -231,10 +232,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
|
||||
* 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).
|
||||
* In: tweak32: pointer to a 32-byte tweak, which must be valid according to
|
||||
* secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly
|
||||
* random 32-byte tweaks, 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,
|
||||
|
||||
588
external/secp256k1/include/secp256k1_musig.h
vendored
Normal file
588
external/secp256k1/include/secp256k1_musig.h
vendored
Normal file
@@ -0,0 +1,588 @@
|
||||
#ifndef SECP256K1_MUSIG_H
|
||||
#define SECP256K1_MUSIG_H
|
||||
|
||||
#include "secp256k1_extrakeys.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** This module implements BIP 327 "MuSig2 for BIP340-compatible
|
||||
* Multi-Signatures"
|
||||
* (https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki)
|
||||
* v1.0.0. You can find an example demonstrating the musig module in
|
||||
* examples/musig.c.
|
||||
*
|
||||
* The module also supports BIP 341 ("Taproot") public key tweaking.
|
||||
*
|
||||
* It is recommended to read the documentation in this include file carefully.
|
||||
* Further notes on API usage can be found in doc/musig.md
|
||||
*
|
||||
* Since the first version of MuSig is essentially replaced by MuSig2, we use
|
||||
* MuSig, musig and MuSig2 synonymously unless noted otherwise.
|
||||
*/
|
||||
|
||||
/** Opaque data structures
|
||||
*
|
||||
* The exact representation of data inside the opaque data structures is
|
||||
* implementation defined and not guaranteed to be portable between different
|
||||
* platforms or versions. With the exception of `secp256k1_musig_secnonce`, the
|
||||
* data structures can be safely copied/moved. If you need to convert to a
|
||||
* format suitable for storage, transmission, or comparison, use the
|
||||
* corresponding serialization and parsing functions.
|
||||
*/
|
||||
|
||||
/** Opaque data structure that caches information about public key aggregation.
|
||||
*
|
||||
* Guaranteed to be 197 bytes in size. No serialization and parsing functions
|
||||
* (yet).
|
||||
*/
|
||||
typedef struct secp256k1_musig_keyagg_cache {
|
||||
unsigned char data[197];
|
||||
} secp256k1_musig_keyagg_cache;
|
||||
|
||||
/** Opaque data structure that holds a signer's _secret_ nonce.
|
||||
*
|
||||
* Guaranteed to be 132 bytes in size.
|
||||
*
|
||||
* WARNING: This structure MUST NOT be copied or read or written to directly. A
|
||||
* signer who is online throughout the whole process and can keep this
|
||||
* structure in memory can use the provided API functions for a safe standard
|
||||
* workflow.
|
||||
*
|
||||
* Copying this data structure can result in nonce reuse which will leak the
|
||||
* secret signing key.
|
||||
*/
|
||||
typedef struct secp256k1_musig_secnonce {
|
||||
unsigned char data[132];
|
||||
} secp256k1_musig_secnonce;
|
||||
|
||||
/** Opaque data structure that holds a signer's public nonce.
|
||||
*
|
||||
* Guaranteed to be 132 bytes in size. Serialized and parsed with
|
||||
* `musig_pubnonce_serialize` and `musig_pubnonce_parse`.
|
||||
*/
|
||||
typedef struct secp256k1_musig_pubnonce {
|
||||
unsigned char data[132];
|
||||
} secp256k1_musig_pubnonce;
|
||||
|
||||
/** Opaque data structure that holds an aggregate public nonce.
|
||||
*
|
||||
* Guaranteed to be 132 bytes in size. Serialized and parsed with
|
||||
* `musig_aggnonce_serialize` and `musig_aggnonce_parse`.
|
||||
*/
|
||||
typedef struct secp256k1_musig_aggnonce {
|
||||
unsigned char data[132];
|
||||
} secp256k1_musig_aggnonce;
|
||||
|
||||
/** Opaque data structure that holds a MuSig session.
|
||||
*
|
||||
* This structure is not required to be kept secret for the signing protocol to
|
||||
* be secure. Guaranteed to be 133 bytes in size. No serialization and parsing
|
||||
* functions (yet).
|
||||
*/
|
||||
typedef struct secp256k1_musig_session {
|
||||
unsigned char data[133];
|
||||
} secp256k1_musig_session;
|
||||
|
||||
/** Opaque data structure that holds a partial MuSig signature.
|
||||
*
|
||||
* Guaranteed to be 36 bytes in size. Serialized and parsed with
|
||||
* `musig_partial_sig_serialize` and `musig_partial_sig_parse`.
|
||||
*/
|
||||
typedef struct secp256k1_musig_partial_sig {
|
||||
unsigned char data[36];
|
||||
} secp256k1_musig_partial_sig;
|
||||
|
||||
/** Parse a signer's public nonce.
|
||||
*
|
||||
* Returns: 1 when the nonce could be parsed, 0 otherwise.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: nonce: pointer to a nonce object
|
||||
* In: in66: pointer to the 66-byte nonce to be parsed
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubnonce_parse(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_pubnonce *nonce,
|
||||
const unsigned char *in66
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a signer's public nonce
|
||||
*
|
||||
* Returns: 1 always
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: out66: pointer to a 66-byte array to store the serialized nonce
|
||||
* In: nonce: pointer to the nonce
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_pubnonce_serialize(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *out66,
|
||||
const secp256k1_musig_pubnonce *nonce
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Parse an aggregate public nonce.
|
||||
*
|
||||
* Returns: 1 when the nonce could be parsed, 0 otherwise.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: nonce: pointer to a nonce object
|
||||
* In: in66: pointer to the 66-byte nonce to be parsed
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_aggnonce_parse(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_aggnonce *nonce,
|
||||
const unsigned char *in66
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize an aggregate public nonce
|
||||
*
|
||||
* Returns: 1 always
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: out66: pointer to a 66-byte array to store the serialized nonce
|
||||
* In: nonce: pointer to the nonce
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_aggnonce_serialize(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *out66,
|
||||
const secp256k1_musig_aggnonce *nonce
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Parse a MuSig partial signature.
|
||||
*
|
||||
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: sig: pointer to a signature object
|
||||
* In: in32: pointer to the 32-byte signature to be parsed
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_parse(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_partial_sig *sig,
|
||||
const unsigned char *in32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a MuSig partial signature
|
||||
*
|
||||
* Returns: 1 always
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: out32: pointer to a 32-byte array to store the serialized signature
|
||||
* In: sig: pointer to the signature
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_partial_sig_serialize(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *out32,
|
||||
const secp256k1_musig_partial_sig *sig
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Computes an aggregate public key and uses it to initialize a keyagg_cache
|
||||
*
|
||||
* Different orders of `pubkeys` result in different `agg_pk`s.
|
||||
*
|
||||
* Before aggregating, the pubkeys can be sorted with `secp256k1_ec_pubkey_sort`
|
||||
* which ensures the same `agg_pk` result for the same multiset of pubkeys.
|
||||
* This is useful to do before `pubkey_agg`, such that the order of pubkeys
|
||||
* does not affect the aggregate public key.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: agg_pk: the MuSig-aggregated x-only public key. If you do not need it,
|
||||
* this arg can be NULL.
|
||||
* keyagg_cache: if non-NULL, pointer to a musig_keyagg_cache struct that
|
||||
* is required for signing (or observing the signing session
|
||||
* and verifying partial signatures).
|
||||
* In: pubkeys: input array of pointers to public keys to aggregate. The order
|
||||
* is important; a different order will result in a different
|
||||
* aggregate public key.
|
||||
* n_pubkeys: length of pubkeys array. Must be greater than 0.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_agg(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_xonly_pubkey *agg_pk,
|
||||
secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const secp256k1_pubkey * const *pubkeys,
|
||||
size_t n_pubkeys
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Obtain the aggregate public key from a keyagg_cache.
|
||||
*
|
||||
* This is only useful if you need the non-xonly public key, in particular for
|
||||
* plain (non-xonly) tweaking or batch-verifying multiple key aggregations
|
||||
* (not implemented).
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: agg_pk: the MuSig-aggregated public key.
|
||||
* In: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by
|
||||
* `musig_pubkey_agg`
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *agg_pk,
|
||||
const secp256k1_musig_keyagg_cache *keyagg_cache
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Apply plain "EC" tweaking to a public key in a given keyagg_cache by adding
|
||||
* the generator multiplied with `tweak32` to it. This is useful for deriving
|
||||
* child keys from an aggregate public key via BIP 32 where `tweak32` is set to
|
||||
* a hash as defined in BIP 32.
|
||||
*
|
||||
* Callers are responsible for deriving `tweak32` in a way that does not reduce
|
||||
* the security of MuSig (for example, by following BIP 32).
|
||||
*
|
||||
* The tweaking method is the same as `secp256k1_ec_pubkey_tweak_add`. So after
|
||||
* the following pseudocode buf and buf2 have identical contents (absent
|
||||
* earlier failures).
|
||||
*
|
||||
* secp256k1_musig_pubkey_agg(..., keyagg_cache, pubkeys, ...)
|
||||
* secp256k1_musig_pubkey_get(..., agg_pk, keyagg_cache)
|
||||
* secp256k1_musig_pubkey_ec_tweak_add(..., output_pk, tweak32, keyagg_cache)
|
||||
* secp256k1_ec_pubkey_serialize(..., buf, ..., output_pk, ...)
|
||||
* secp256k1_ec_pubkey_tweak_add(..., agg_pk, tweak32)
|
||||
* secp256k1_ec_pubkey_serialize(..., buf2, ..., agg_pk, ...)
|
||||
*
|
||||
* This function is required if you want to _sign_ for a tweaked aggregate key.
|
||||
* If you are only computing a public key but not intending to create a
|
||||
* signature for it, use `secp256k1_ec_pubkey_tweak_add` instead.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 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. If you
|
||||
* do not need it, this arg can be NULL.
|
||||
* In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by
|
||||
* `musig_pubkey_agg`
|
||||
* In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes
|
||||
* `secp256k1_ec_seckey_verify` and is not equal to the
|
||||
* secret key corresponding to the public key represented
|
||||
* by keyagg_cache or its negation. 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_musig_pubkey_ec_tweak_add(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *output_pubkey,
|
||||
secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Apply x-only tweaking to a public key in a given keyagg_cache by adding the
|
||||
* generator multiplied with `tweak32` to it. This is useful for creating
|
||||
* Taproot outputs where `tweak32` is set to a TapTweak hash as defined in BIP
|
||||
* 341.
|
||||
*
|
||||
* Callers are responsible for deriving `tweak32` in a way that does not reduce
|
||||
* the security of MuSig (for example, by following Taproot BIP 341).
|
||||
*
|
||||
* The tweaking method is the same as `secp256k1_xonly_pubkey_tweak_add`. So in
|
||||
* the following pseudocode xonly_pubkey_tweak_add_check (absent earlier
|
||||
* failures) returns 1.
|
||||
*
|
||||
* secp256k1_musig_pubkey_agg(..., agg_pk, keyagg_cache, pubkeys, ...)
|
||||
* secp256k1_musig_pubkey_xonly_tweak_add(..., output_pk, keyagg_cache, tweak32)
|
||||
* secp256k1_xonly_pubkey_serialize(..., buf, output_pk)
|
||||
* secp256k1_xonly_pubkey_tweak_add_check(..., buf, ..., agg_pk, tweak32)
|
||||
*
|
||||
* This function is required if you want to _sign_ for a tweaked aggregate key.
|
||||
* If you are only computing a public key but not intending to create a
|
||||
* signature for it, use `secp256k1_xonly_pubkey_tweak_add` instead.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 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. If you
|
||||
* do not need it, this arg can be NULL.
|
||||
* In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by
|
||||
* `musig_pubkey_agg`
|
||||
* In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes
|
||||
* `secp256k1_ec_seckey_verify` and is not equal to the
|
||||
* secret key corresponding to the public key represented
|
||||
* by keyagg_cache or its negation. 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_musig_pubkey_xonly_tweak_add(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *output_pubkey,
|
||||
secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Starts a signing session by generating a nonce
|
||||
*
|
||||
* This function outputs a secret nonce that will be required for signing and a
|
||||
* corresponding public nonce that is intended to be sent to other signers.
|
||||
*
|
||||
* MuSig differs from regular Schnorr signing in that implementers _must_ take
|
||||
* special care to not reuse a nonce. This can be ensured by following these rules:
|
||||
*
|
||||
* 1. Each call to this function must have a UNIQUE session_secrand32 that must
|
||||
* NOT BE REUSED in subsequent calls to this function and must be KEPT
|
||||
* SECRET (even from other signers).
|
||||
* 2. If you already know the seckey, message or aggregate public key
|
||||
* cache, they can be optionally provided to derive the nonce and increase
|
||||
* misuse-resistance. The extra_input32 argument can be used to provide
|
||||
* additional data that does not repeat in normal scenarios, such as the
|
||||
* current time.
|
||||
* 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
|
||||
* that it is used more than once for signing.
|
||||
*
|
||||
* If you don't have access to good randomness for session_secrand32, but you
|
||||
* have access to a non-repeating counter, then see
|
||||
* secp256k1_musig_nonce_gen_counter.
|
||||
*
|
||||
* Remember that nonce reuse will leak the secret key!
|
||||
* Note that using the same seckey for multiple MuSig sessions is fine.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid and 1 otherwise
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static)
|
||||
* Out: secnonce: pointer to a structure to store the secret nonce
|
||||
* pubnonce: pointer to a structure to store the public nonce
|
||||
* In/Out:
|
||||
* session_secrand32: a 32-byte session_secrand32 as explained above. Must be unique to this
|
||||
* call to secp256k1_musig_nonce_gen and must be uniformly
|
||||
* random. If the function call is successful, the
|
||||
* session_secrand32 buffer is invalidated to prevent reuse.
|
||||
* In:
|
||||
* seckey: the 32-byte secret key that will later be used for signing, if
|
||||
* already known (can be NULL)
|
||||
* pubkey: public key of the signer creating the nonce. The secnonce
|
||||
* output of this function cannot be used to sign for any
|
||||
* other public key. While the public key should correspond
|
||||
* to the provided seckey, a mismatch will not cause the
|
||||
* function to return 0.
|
||||
* msg32: the 32-byte message that will later be signed, if already known
|
||||
* (can be NULL)
|
||||
* keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate
|
||||
* (and potentially tweaked) public key if already known
|
||||
* (can be NULL)
|
||||
* extra_input32: an optional 32-byte array that is input to the nonce
|
||||
* derivation function (can be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_secnonce *secnonce,
|
||||
secp256k1_musig_pubnonce *pubnonce,
|
||||
unsigned char *session_secrand32,
|
||||
const unsigned char *seckey,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const unsigned char *extra_input32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6);
|
||||
|
||||
|
||||
/** Alternative way to generate a nonce and start a signing session
|
||||
*
|
||||
* This function outputs a secret nonce that will be required for signing and a
|
||||
* corresponding public nonce that is intended to be sent to other signers.
|
||||
*
|
||||
* This function differs from `secp256k1_musig_nonce_gen` by accepting a
|
||||
* non-repeating counter value instead of a secret random value. This requires
|
||||
* that a secret key is provided to `secp256k1_musig_nonce_gen_counter`
|
||||
* (through the keypair argument), as opposed to `secp256k1_musig_nonce_gen`
|
||||
* where the seckey argument is optional.
|
||||
*
|
||||
* MuSig differs from regular Schnorr signing in that implementers _must_ take
|
||||
* special care to not reuse a nonce. This can be ensured by following these rules:
|
||||
*
|
||||
* 1. The nonrepeating_cnt argument must be a counter value that never repeats,
|
||||
* i.e., you must never call `secp256k1_musig_nonce_gen_counter` twice with
|
||||
* the same keypair and nonrepeating_cnt value. For example, this implies
|
||||
* that if the same keypair is used with `secp256k1_musig_nonce_gen_counter`
|
||||
* on multiple devices, none of the devices should have the same counter
|
||||
* value as any other device.
|
||||
* 2. If the seckey, message or aggregate public key cache is already available
|
||||
* at this stage, any of these can be optionally provided, in which case
|
||||
* they will be used in the derivation of the nonce and increase
|
||||
* misuse-resistance. The extra_input32 argument can be used to provide
|
||||
* additional data that does not repeat in normal scenarios, such as the
|
||||
* current time.
|
||||
* 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
|
||||
* that it is used more than once for signing.
|
||||
*
|
||||
* Remember that nonce reuse will leak the secret key!
|
||||
* Note that using the same keypair for multiple MuSig sessions is fine.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid and 1 otherwise
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static)
|
||||
* Out: secnonce: pointer to a structure to store the secret nonce
|
||||
* pubnonce: pointer to a structure to store the public nonce
|
||||
* In:
|
||||
* nonrepeating_cnt: the value of a counter as explained above. Must be
|
||||
* unique to this call to secp256k1_musig_nonce_gen.
|
||||
* keypair: keypair of the signer creating the nonce. The secnonce
|
||||
* output of this function cannot be used to sign for any
|
||||
* other keypair.
|
||||
* msg32: the 32-byte message that will later be signed, if already known
|
||||
* (can be NULL)
|
||||
* keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate
|
||||
* (and potentially tweaked) public key if already known
|
||||
* (can be NULL)
|
||||
* extra_input32: an optional 32-byte array that is input to the nonce
|
||||
* derivation function (can be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen_counter(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_secnonce *secnonce,
|
||||
secp256k1_musig_pubnonce *pubnonce,
|
||||
uint64_t nonrepeating_cnt,
|
||||
const secp256k1_keypair *keypair,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const unsigned char *extra_input32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Aggregates the nonces of all signers into a single nonce
|
||||
*
|
||||
* This can be done by an untrusted party to reduce the communication
|
||||
* between signers. Instead of everyone sending nonces to everyone else, there
|
||||
* can be one party receiving all nonces, aggregating the nonces with this
|
||||
* function and then sending only the aggregate nonce back to the signers.
|
||||
*
|
||||
* If the aggregator does not compute the aggregate nonce correctly, the final
|
||||
* signature will be invalid.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: aggnonce: pointer to an aggregate public nonce object for
|
||||
* musig_nonce_process
|
||||
* In: pubnonces: array of pointers to public nonces sent by the
|
||||
* signers
|
||||
* n_pubnonces: number of elements in the pubnonces array. Must be
|
||||
* greater than 0.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_nonce_agg(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_aggnonce *aggnonce,
|
||||
const secp256k1_musig_pubnonce * const *pubnonces,
|
||||
size_t n_pubnonces
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Takes the aggregate nonce and creates a session that is required for signing
|
||||
* and verification of partial signatures.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: session: pointer to a struct to store the session
|
||||
* In: aggnonce: pointer to an aggregate public nonce object that is the
|
||||
* output of musig_nonce_agg
|
||||
* msg32: the 32-byte message to sign
|
||||
* keyagg_cache: pointer to the keyagg_cache that was used to create the
|
||||
* aggregate (and potentially tweaked) pubkey
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_process(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_session *session,
|
||||
const secp256k1_musig_aggnonce *aggnonce,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_musig_keyagg_cache *keyagg_cache
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Produces a partial signature
|
||||
*
|
||||
* This function overwrites the given secnonce with zeros and will abort if given a
|
||||
* secnonce that is all zeros. This is a best effort attempt to protect against nonce
|
||||
* reuse. However, this is of course easily defeated if the secnonce has been
|
||||
* copied (or serialized). Remember that nonce reuse will leak the secret key!
|
||||
*
|
||||
* For signing to succeed, the secnonce provided to this function must have
|
||||
* been generated for the provided keypair. This means that when signing for a
|
||||
* keypair consisting of a seckey and pubkey, the secnonce must have been
|
||||
* created by calling musig_nonce_gen with that pubkey. Otherwise, the
|
||||
* illegal_callback is called.
|
||||
*
|
||||
* This function does not verify the output partial signature, deviating from
|
||||
* the BIP 327 specification. It is recommended to verify the output partial
|
||||
* signature with `secp256k1_musig_partial_sig_verify` to prevent random or
|
||||
* adversarially provoked computation errors.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the provided secnonce has already
|
||||
* been used for signing, 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: partial_sig: pointer to struct to store the partial signature
|
||||
* In/Out: secnonce: pointer to the secnonce struct created in
|
||||
* musig_nonce_gen that has been never used in a
|
||||
* partial_sign call before and has been created for the
|
||||
* keypair
|
||||
* In: keypair: pointer to keypair to sign the message with
|
||||
* keyagg_cache: pointer to the keyagg_cache that was output when the
|
||||
* aggregate public key for this session
|
||||
* session: pointer to the session that was created with
|
||||
* musig_nonce_process
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_partial_sign(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_partial_sig *partial_sig,
|
||||
secp256k1_musig_secnonce *secnonce,
|
||||
const secp256k1_keypair *keypair,
|
||||
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const secp256k1_musig_session *session
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
|
||||
|
||||
/** Verifies an individual signer's partial signature
|
||||
*
|
||||
* The signature is verified for a specific signing session. In order to avoid
|
||||
* accidentally verifying a signature from a different or non-existing signing
|
||||
* session, you must ensure the following:
|
||||
* 1. The `keyagg_cache` argument is identical to the one used to create the
|
||||
* `session` with `musig_nonce_process`.
|
||||
* 2. The `pubkey` argument must be identical to the one sent by the signer
|
||||
* before aggregating it with `musig_pubkey_agg` to create the
|
||||
* `keyagg_cache`.
|
||||
* 3. The `pubnonce` argument must be identical to the one sent by the signer
|
||||
* before aggregating it with `musig_nonce_agg` and using the result to
|
||||
* create the `session` with `musig_nonce_process`.
|
||||
*
|
||||
* It is not required to call this function in regular MuSig sessions, because
|
||||
* if any partial signature does not verify, the final signature will not
|
||||
* verify either, so the problem will be caught. However, this function
|
||||
* provides the ability to identify which specific partial signature fails
|
||||
* verification.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the partial signature does not
|
||||
* verify, 1 otherwise
|
||||
* Args ctx: pointer to a context object
|
||||
* In: partial_sig: pointer to partial signature to verify, sent by
|
||||
* the signer associated with `pubnonce` and `pubkey`
|
||||
* pubnonce: public nonce of the signer in the signing session
|
||||
* pubkey: public key of the signer in the signing session
|
||||
* keyagg_cache: pointer to the keyagg_cache that was output when the
|
||||
* aggregate public key for this signing session
|
||||
* session: pointer to the session that was created with
|
||||
* `musig_nonce_process`
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify(
|
||||
const secp256k1_context *ctx,
|
||||
const secp256k1_musig_partial_sig *partial_sig,
|
||||
const secp256k1_musig_pubnonce *pubnonce,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const secp256k1_musig_session *session
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
|
||||
|
||||
/** Aggregates partial signatures
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean
|
||||
* the resulting signature verifies).
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: sig64: complete (but possibly invalid) Schnorr signature
|
||||
* In: session: pointer to the session that was created with
|
||||
* musig_nonce_process
|
||||
* partial_sigs: array of pointers to partial signatures to aggregate
|
||||
* n_sigs: number of elements in the partial_sigs array. Must be
|
||||
* greater than 0.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_partial_sig_agg(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *sig64,
|
||||
const secp256k1_musig_session *session,
|
||||
const secp256k1_musig_partial_sig * const *partial_sigs,
|
||||
size_t n_sigs
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -52,8 +52,8 @@ SECP256K1_API size_t secp256k1_context_preallocated_size(
|
||||
* 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
|
||||
* Returns: pointer to newly created context object.
|
||||
* In: prealloc: 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.
|
||||
@@ -72,7 +72,7 @@ SECP256K1_API secp256k1_context *secp256k1_context_preallocated_create(
|
||||
* caller-provided memory.
|
||||
*
|
||||
* Returns: the required size of the caller-provided memory block.
|
||||
* In: ctx: an existing context to copy.
|
||||
* In: ctx: pointer to a context to copy.
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
|
||||
const secp256k1_context *ctx
|
||||
@@ -91,9 +91,9 @@ SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
|
||||
* 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
|
||||
* Returns: pointer to a newly created context object.
|
||||
* Args: ctx: pointer to a context to copy (not secp256k1_context_static).
|
||||
* In: prealloc: pointer to a rewritable contiguous block of memory of
|
||||
* size at least secp256k1_context_preallocated_size(flags)
|
||||
* bytes, as detailed above.
|
||||
*/
|
||||
@@ -118,7 +118,7 @@ SECP256K1_API secp256k1_context *secp256k1_context_preallocated_clone(
|
||||
* preallocated pointer given to secp256k1_context_preallocated_create or
|
||||
* secp256k1_context_preallocated_clone.
|
||||
*
|
||||
* Args: ctx: an existing context to destroy, constructed using
|
||||
* Args: ctx: pointer to a context to destroy, constructed using
|
||||
* secp256k1_context_preallocated_create or
|
||||
* secp256k1_context_preallocated_clone
|
||||
* (i.e., not secp256k1_context_static).
|
||||
|
||||
24
external/secp256k1/include/secp256k1_recovery.h
vendored
24
external/secp256k1/include/secp256k1_recovery.h
vendored
@@ -7,7 +7,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Opaque data structured that holds a parsed ECDSA signature,
|
||||
/** Opaque data structure that holds a parsed ECDSA signature,
|
||||
* supporting pubkey recovery.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
@@ -21,16 +21,16 @@ extern "C" {
|
||||
* recoverability) will have identical representation, so they can be
|
||||
* memcmp'ed.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct secp256k1_ecdsa_recoverable_signature {
|
||||
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
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: sig: pointer to a signature object
|
||||
* In: input64: 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(
|
||||
@@ -43,9 +43,9 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact(
|
||||
/** 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.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: sig: pointer to a normal signature.
|
||||
* In: sigin: pointer to a recoverable signature.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert(
|
||||
const secp256k1_context *ctx,
|
||||
@@ -56,10 +56,10 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert(
|
||||
/** 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.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: output64: pointer to a 64-byte array of the compact signature.
|
||||
* recid: pointer to an integer to hold the recovery id.
|
||||
* In: sig: pointer to an initialized signature object.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
|
||||
const secp256k1_context *ctx,
|
||||
|
||||
@@ -61,7 +61,7 @@ typedef int (*secp256k1_nonce_function_hardened)(
|
||||
* 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;
|
||||
SECP256K1_API const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
|
||||
|
||||
/** Data structure that contains additional arguments for schnorrsig_sign_custom.
|
||||
*
|
||||
@@ -79,7 +79,7 @@ SECP256K1_API_VAR const secp256k1_nonce_function_hardened secp256k1_nonce_functi
|
||||
* secp256k1_nonce_function_bip340 is used, then ndata must be a
|
||||
* pointer to 32-byte auxiliary randomness as per BIP-340.
|
||||
*/
|
||||
typedef struct {
|
||||
typedef struct secp256k1_schnorrsig_extraparams {
|
||||
unsigned char magic[4];
|
||||
secp256k1_nonce_function_hardened noncefp;
|
||||
void *ndata;
|
||||
@@ -169,11 +169,11 @@ SECP256K1_API int secp256k1_schnorrsig_sign_custom(
|
||||
*
|
||||
* Returns: 1: correct signature
|
||||
* 0: incorrect signature
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Args: ctx: pointer to a 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)
|
||||
* pubkey: pointer to an x-only public key to verify with
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
|
||||
const secp256k1_context *ctx,
|
||||
|
||||
2
external/secp256k1/sage/group_prover.sage
vendored
2
external/secp256k1/sage/group_prover.sage
vendored
@@ -198,7 +198,7 @@ def normalize_factor(p):
|
||||
(8) * (-bx + ax)^3
|
||||
```
|
||||
"""
|
||||
# Assert p is not 0 and that its non-zero coeffients are coprime.
|
||||
# Assert p is not 0 and that its non-zero coefficients 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
|
||||
|
||||
41
external/secp256k1/src/CMakeLists.txt
vendored
41
external/secp256k1/src/CMakeLists.txt
vendored
@@ -20,10 +20,10 @@ if(SECP256K1_ASM STREQUAL "arm32")
|
||||
target_link_libraries(secp256k1_asm INTERFACE secp256k1_asm_arm)
|
||||
endif()
|
||||
|
||||
# Define our export symbol only for Win32 and only for shared libs.
|
||||
# This matches libtool's usage of DLL_EXPORT
|
||||
if(WIN32)
|
||||
set_target_properties(secp256k1 PROPERTIES DEFINE_SYMBOL "DLL_EXPORT")
|
||||
# Define our export symbol only for shared libs.
|
||||
set_target_properties(secp256k1 PROPERTIES DEFINE_SYMBOL SECP256K1_DLL_EXPORT)
|
||||
target_compile_definitions(secp256k1 INTERFACE $<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:SECP256K1_STATIC>)
|
||||
endif()
|
||||
|
||||
# Object libs don't know if they're being built for a shared or static lib.
|
||||
@@ -64,16 +64,9 @@ elseif(APPLE)
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
set(${PROJECT_NAME}_windows "secp256k1")
|
||||
# This step is commented out from the original. It is bad practice to change
|
||||
# the binary base name depending on the platform. CMake already manipulates
|
||||
# the base name into a final name that fits the conventions of the platform.
|
||||
# Linkers accept base names on the command line and then look for
|
||||
# conventional names on disk. This way, developers can use base names
|
||||
# everywhere (in the CMake and Conan they write) and the tools will do the
|
||||
# right thing.
|
||||
# if(MSVC)
|
||||
# set(${PROJECT_NAME}_windows "${PROJECT_NAME}")
|
||||
# endif()
|
||||
if(MSVC)
|
||||
set(${PROJECT_NAME}_windows "${PROJECT_NAME}")
|
||||
endif()
|
||||
set_target_properties(secp256k1 PROPERTIES
|
||||
ARCHIVE_OUTPUT_NAME "${${PROJECT_NAME}_windows}"
|
||||
RUNTIME_OUTPUT_NAME "${${PROJECT_NAME}_windows}-${${PROJECT_NAME}_soversion}"
|
||||
@@ -94,12 +87,12 @@ endif()
|
||||
if(SECP256K1_BUILD_TESTS)
|
||||
add_executable(noverify_tests tests.c)
|
||||
target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm)
|
||||
add_test(NAME noverify_tests COMMAND noverify_tests)
|
||||
add_test(NAME secp256k1_noverify_tests COMMAND noverify_tests)
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage")
|
||||
add_executable(tests tests.c)
|
||||
target_compile_definitions(tests PRIVATE VERIFY)
|
||||
target_link_libraries(tests secp256k1_precomputed secp256k1_asm)
|
||||
add_test(NAME tests COMMAND tests)
|
||||
add_test(NAME secp256k1_tests COMMAND tests)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -108,7 +101,7 @@ if(SECP256K1_BUILD_EXHAUSTIVE_TESTS)
|
||||
add_executable(exhaustive_tests tests_exhaustive.c)
|
||||
target_link_libraries(exhaustive_tests secp256k1_asm)
|
||||
target_compile_definitions(exhaustive_tests PRIVATE $<$<NOT:$<CONFIG:Coverage>>:VERIFY>)
|
||||
add_test(NAME exhaustive_tests COMMAND exhaustive_tests)
|
||||
add_test(NAME secp256k1_exhaustive_tests COMMAND exhaustive_tests)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_BUILD_CTIME_TESTS)
|
||||
@@ -139,6 +132,12 @@ if(SECP256K1_INSTALL)
|
||||
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h")
|
||||
endif()
|
||||
if(SECP256K1_ENABLE_MODULE_MUSIG)
|
||||
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_musig.h")
|
||||
endif()
|
||||
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
||||
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h")
|
||||
endif()
|
||||
install(FILES ${${PROJECT_NAME}_headers}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
)
|
||||
@@ -165,5 +164,13 @@ if(SECP256K1_INSTALL)
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
)
|
||||
|
||||
include(GeneratePkgConfigFile)
|
||||
generate_pkg_config_file(${PROJECT_SOURCE_DIR}/libsecp256k1.pc.in)
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
|
||||
)
|
||||
endif()
|
||||
|
||||
1
external/secp256k1/src/asm/field_10x26_arm.s
vendored
1
external/secp256k1/src/asm/field_10x26_arm.s
vendored
@@ -913,3 +913,4 @@ secp256k1_fe_sqr_inner:
|
||||
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
|
||||
.size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
100
external/secp256k1/src/assumptions.h
vendored
100
external/secp256k1/src/assumptions.h
vendored
@@ -19,65 +19,69 @@
|
||||
reduce the odds of experiencing an unwelcome surprise.
|
||||
*/
|
||||
|
||||
struct secp256k1_assumption_checker {
|
||||
/* This uses a trick to implement a static assertion in C89: a type with an array of negative size is not
|
||||
allowed. */
|
||||
int dummy_array[(
|
||||
/* Bytes are 8 bits. */
|
||||
(CHAR_BIT == 8) &&
|
||||
#if defined(__has_attribute)
|
||||
# if __has_attribute(__unavailable__)
|
||||
__attribute__((__unavailable__("Don't call this function. It only exists because STATIC_ASSERT cannot be used outside a function.")))
|
||||
# endif
|
||||
#endif
|
||||
static void secp256k1_assumption_checker(void) {
|
||||
/* Bytes are 8 bits. */
|
||||
STATIC_ASSERT(CHAR_BIT == 8);
|
||||
|
||||
/* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32
|
||||
without signed overflow, which would be undefined behaviour. */
|
||||
(UINT_MAX <= UINT32_MAX) &&
|
||||
/* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32
|
||||
without signed overflow, which would be undefined behaviour. */
|
||||
STATIC_ASSERT(UINT_MAX <= UINT32_MAX);
|
||||
|
||||
/* Conversions from unsigned to signed outside of the bounds of the signed type are
|
||||
implementation-defined. Verify that they function as reinterpreting the lower
|
||||
bits of the input in two's complement notation. Do this for conversions:
|
||||
- from uint(N)_t to int(N)_t with negative result
|
||||
- from uint(2N)_t to int(N)_t with negative result
|
||||
- from int(2N)_t to int(N)_t with negative result
|
||||
- from int(2N)_t to int(N)_t with positive result */
|
||||
/* Conversions from unsigned to signed outside of the bounds of the signed type are
|
||||
implementation-defined. Verify that they function as reinterpreting the lower
|
||||
bits of the input in two's complement notation. Do this for conversions:
|
||||
- from uint(N)_t to int(N)_t with negative result
|
||||
- from uint(2N)_t to int(N)_t with negative result
|
||||
- from int(2N)_t to int(N)_t with negative result
|
||||
- from int(2N)_t to int(N)_t with positive result */
|
||||
|
||||
/* To int8_t. */
|
||||
((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55) &&
|
||||
((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33) &&
|
||||
((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF) &&
|
||||
((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34) &&
|
||||
/* To int8_t. */
|
||||
STATIC_ASSERT(((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55));
|
||||
STATIC_ASSERT((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33);
|
||||
STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF);
|
||||
STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34);
|
||||
|
||||
/* To int16_t. */
|
||||
((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322) &&
|
||||
((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C) &&
|
||||
((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4) &&
|
||||
((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678) &&
|
||||
/* To int16_t. */
|
||||
STATIC_ASSERT((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322);
|
||||
STATIC_ASSERT((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C);
|
||||
STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4);
|
||||
STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678);
|
||||
|
||||
/* To int32_t. */
|
||||
((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B) &&
|
||||
((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE) &&
|
||||
((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8) &&
|
||||
((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789) &&
|
||||
/* To int32_t. */
|
||||
STATIC_ASSERT((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B);
|
||||
STATIC_ASSERT((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE);
|
||||
STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8);
|
||||
STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789);
|
||||
|
||||
/* To int64_t. */
|
||||
((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL) &&
|
||||
/* To int64_t. */
|
||||
STATIC_ASSERT((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL);
|
||||
#if defined(SECP256K1_INT128_NATIVE)
|
||||
((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL) &&
|
||||
(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL) &&
|
||||
(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL) &&
|
||||
STATIC_ASSERT((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL);
|
||||
STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL);
|
||||
STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL);
|
||||
|
||||
/* To int128_t. */
|
||||
((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)) &&
|
||||
/* To int128_t. */
|
||||
STATIC_ASSERT((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL));
|
||||
#endif
|
||||
|
||||
/* Right shift on negative signed values is implementation defined. Verify that it
|
||||
acts as a right shift in two's complement with sign extension (i.e duplicating
|
||||
the top bit into newly added bits). */
|
||||
((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA) &&
|
||||
((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A) &&
|
||||
((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48) &&
|
||||
((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL) &&
|
||||
/* Right shift on negative signed values is implementation defined. Verify that it
|
||||
acts as a right shift in two's complement with sign extension (i.e duplicating
|
||||
the top bit into newly added bits). */
|
||||
STATIC_ASSERT((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA);
|
||||
STATIC_ASSERT((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A);
|
||||
STATIC_ASSERT((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48);
|
||||
STATIC_ASSERT((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL);
|
||||
#if defined(SECP256K1_INT128_NATIVE)
|
||||
((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)) &&
|
||||
STATIC_ASSERT((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL));
|
||||
#endif
|
||||
1) * 2 - 1];
|
||||
};
|
||||
|
||||
/* This function is not supposed to be called. */
|
||||
VERIFY_CHECK(0);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_ASSUMPTIONS_H */
|
||||
|
||||
58
external/secp256k1/src/bench.c
vendored
58
external/secp256k1/src/bench.c
vendored
@@ -38,6 +38,8 @@ static void help(int default_iters) {
|
||||
printf(" ecdsa : all ECDSA algorithms--sign, verify, recovery (if enabled)\n");
|
||||
printf(" ecdsa_sign : ECDSA siging algorithm\n");
|
||||
printf(" ecdsa_verify : ECDSA verification algorithm\n");
|
||||
printf(" ec : all EC public key algorithms (keygen)\n");
|
||||
printf(" ec_keygen : EC public key generation\n");
|
||||
|
||||
#ifdef ENABLE_MODULE_RECOVERY
|
||||
printf(" ecdsa_recover : ECDSA public key recovery algorithm\n");
|
||||
@@ -53,6 +55,14 @@ static void help(int default_iters) {
|
||||
printf(" schnorrsig_verify : Schnorr verification algorithm\n");
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
printf(" ellswift : all ElligatorSwift benchmarks (encode, decode, keygen, ecdh)\n");
|
||||
printf(" ellswift_encode : ElligatorSwift encoding\n");
|
||||
printf(" ellswift_decode : ElligatorSwift decoding\n");
|
||||
printf(" ellswift_keygen : ElligatorSwift key generation\n");
|
||||
printf(" ellswift_ecdh : ECDH on ElligatorSwift keys\n");
|
||||
#endif
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -115,6 +125,30 @@ static void bench_sign_run(void* arg, int iters) {
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_keygen_setup(void* arg) {
|
||||
int i;
|
||||
bench_data *data = (bench_data*)arg;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
data->key[i] = i + 65;
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_keygen_run(void *arg, int iters) {
|
||||
int i;
|
||||
bench_data *data = (bench_data*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
unsigned char pub33[33];
|
||||
size_t len = 33;
|
||||
secp256k1_pubkey pubkey;
|
||||
CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->key));
|
||||
CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pub33, &len, &pubkey, SECP256K1_EC_COMPRESSED));
|
||||
memcpy(data->key, pub33 + 1, 32);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_MODULE_ECDH
|
||||
# include "modules/ecdh/bench_impl.h"
|
||||
#endif
|
||||
@@ -127,6 +161,10 @@ static void bench_sign_run(void* arg, int iters) {
|
||||
# include "modules/schnorrsig/bench_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
# include "modules/ellswift/bench_impl.h"
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int i;
|
||||
secp256k1_pubkey pubkey;
|
||||
@@ -139,7 +177,9 @@ int main(int argc, char** argv) {
|
||||
|
||||
/* Check for invalid user arguments */
|
||||
char* valid_args[] = {"ecdsa", "verify", "ecdsa_verify", "sign", "ecdsa_sign", "ecdh", "recover",
|
||||
"ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign"};
|
||||
"ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign", "ec",
|
||||
"keygen", "ec_keygen", "ellswift", "encode", "ellswift_encode", "decode",
|
||||
"ellswift_decode", "ellswift_keygen", "ellswift_ecdh"};
|
||||
size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]);
|
||||
int invalid_args = have_invalid_args(argc, argv, valid_args, valid_args_size);
|
||||
|
||||
@@ -181,6 +221,16 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_MODULE_ELLSWIFT
|
||||
if (have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ellswift_encode") || have_flag(argc, argv, "ellswift_decode") ||
|
||||
have_flag(argc, argv, "encode") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_keygen") ||
|
||||
have_flag(argc, argv, "ellswift_ecdh")) {
|
||||
fprintf(stderr, "./bench: ElligatorSwift module not enabled.\n");
|
||||
fprintf(stderr, "Use ./configure --enable-module-ellswift.\n\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ECDSA benchmark */
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
|
||||
@@ -201,6 +251,7 @@ int main(int argc, char** argv) {
|
||||
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters);
|
||||
|
||||
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters);
|
||||
if (d || have_flag(argc, argv, "ec") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ec_keygen")) run_benchmark("ec_keygen", bench_keygen_run, bench_keygen_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
|
||||
@@ -219,5 +270,10 @@ int main(int argc, char** argv) {
|
||||
run_schnorrsig_bench(iters, argc, argv);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
/* ElligatorSwift benchmarks */
|
||||
run_ellswift_bench(iters, argc, argv);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
9
external/secp256k1/src/bench_ecmult.c
vendored
9
external/secp256k1/src/bench_ecmult.c
vendored
@@ -71,7 +71,7 @@ static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset
|
||||
secp256k1_scalar sum_scalars;
|
||||
|
||||
secp256k1_gej_set_infinity(&sum_output);
|
||||
secp256k1_scalar_clear(&sum_scalars);
|
||||
secp256k1_scalar_set_int(&sum_scalars, 0);
|
||||
for (i = 0; i < iters; ++i) {
|
||||
secp256k1_gej_add_var(&sum_output, &sum_output, &data->output[i], NULL);
|
||||
if (scalar_gen_offset != NULL) {
|
||||
@@ -138,12 +138,10 @@ static void bench_ecmult_1p_teardown(void* arg, int iters) {
|
||||
|
||||
static void bench_ecmult_0p_g(void* arg, int iters) {
|
||||
bench_data* data = (bench_data*)arg;
|
||||
secp256k1_scalar zero;
|
||||
int i;
|
||||
|
||||
secp256k1_scalar_set_int(&zero, 0);
|
||||
for (i = 0; i < iters; ++i) {
|
||||
secp256k1_ecmult(&data->output[i], NULL, &zero, &data->scalars[(data->offset1+i) % POINTS]);
|
||||
secp256k1_ecmult(&data->output[i], NULL, &secp256k1_scalar_zero, &data->scalars[(data->offset1+i) % POINTS]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,7 +244,6 @@ static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) {
|
||||
|
||||
static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_g, int num_iters) {
|
||||
char str[32];
|
||||
static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
size_t iters = 1 + num_iters / count;
|
||||
size_t iter;
|
||||
|
||||
@@ -264,7 +261,7 @@ static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_
|
||||
secp256k1_scalar_add(&total, &total, &tmp);
|
||||
}
|
||||
secp256k1_scalar_negate(&total, &total);
|
||||
secp256k1_ecmult(&data->expected_output[iter], NULL, &zero, &total);
|
||||
secp256k1_ecmult(&data->expected_output[iter], NULL, &secp256k1_scalar_zero, &total);
|
||||
}
|
||||
|
||||
/* Run the benchmark. */
|
||||
|
||||
59
external/secp256k1/src/bench_internal.c
vendored
59
external/secp256k1/src/bench_internal.c
vendored
@@ -14,10 +14,28 @@
|
||||
#include "field_impl.h"
|
||||
#include "group_impl.h"
|
||||
#include "scalar_impl.h"
|
||||
#include "ecmult_const_impl.h"
|
||||
#include "ecmult_impl.h"
|
||||
#include "bench.h"
|
||||
|
||||
static void help(int default_iters) {
|
||||
printf("Benchmarks various internal routines.\n");
|
||||
printf("\n");
|
||||
printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters);
|
||||
printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n");
|
||||
printf("\n");
|
||||
printf("Usage: ./bench_internal [args]\n");
|
||||
printf("By default, all benchmarks will be run.\n");
|
||||
printf("args:\n");
|
||||
printf(" help : display this help and exit\n");
|
||||
printf(" scalar : all scalar operations (add, half, inverse, mul, negate, split)\n");
|
||||
printf(" field : all field operations (half, inverse, issquare, mul, normalize, sqr, sqrt)\n");
|
||||
printf(" group : all group operations (add, double, to_affine)\n");
|
||||
printf(" ecmult : all point multiplication operations (ecmult_wnaf) \n");
|
||||
printf(" hash : all hash algorithms (hmac, rng6979, sha256)\n");
|
||||
printf(" context : all context object operations (context_create)\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
secp256k1_scalar scalar[2];
|
||||
secp256k1_fe fe[4];
|
||||
@@ -98,6 +116,18 @@ static void bench_scalar_negate(void* arg, int iters) {
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_scalar_half(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
secp256k1_scalar s = data->scalar[0];
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_scalar_half(&s, &s);
|
||||
}
|
||||
|
||||
data->scalar[0] = s;
|
||||
}
|
||||
|
||||
static void bench_scalar_mul(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
@@ -309,18 +339,6 @@ static void bench_ecmult_wnaf(void* arg, int iters) {
|
||||
CHECK(bits <= 256*iters);
|
||||
}
|
||||
|
||||
static void bench_wnaf_const(void* arg, int iters) {
|
||||
int i, bits = 0, overflow = 0;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
bits += secp256k1_wnaf_const(data->wnaf, &data->scalar[0], WINDOW_A, 256);
|
||||
overflow += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
|
||||
}
|
||||
CHECK(overflow >= 0);
|
||||
CHECK(bits <= 256*iters);
|
||||
}
|
||||
|
||||
static void bench_sha256(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
@@ -366,10 +384,22 @@ static void bench_context(void* arg, int iters) {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
bench_inv data;
|
||||
int iters = get_iters(20000);
|
||||
int default_iters = 20000;
|
||||
int iters = get_iters(default_iters);
|
||||
int d = argc == 1; /* default */
|
||||
|
||||
if (argc > 1) {
|
||||
if (have_flag(argc, argv, "-h")
|
||||
|| have_flag(argc, argv, "--help")
|
||||
|| have_flag(argc, argv, "help")) {
|
||||
help(default_iters);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
print_output_table_header_row();
|
||||
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "half")) run_benchmark("scalar_half", bench_scalar_half, bench_setup, NULL, &data, 10, iters*100);
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100);
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100);
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10);
|
||||
@@ -394,7 +424,6 @@ int main(int argc, char **argv) {
|
||||
if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_zinv_var", bench_group_add_zinv_var, bench_setup, NULL, &data, 10, iters*10);
|
||||
if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "to_affine")) run_benchmark("group_to_affine_var", bench_group_to_affine_var, bench_setup, NULL, &data, 10, iters);
|
||||
|
||||
if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, iters);
|
||||
if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, iters);
|
||||
|
||||
if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, iters);
|
||||
|
||||
14
external/secp256k1/src/checkmem.h
vendored
14
external/secp256k1/src/checkmem.h
vendored
@@ -30,6 +30,8 @@
|
||||
* - SECP256K1_CHECKMEM_DEFINE(p, len):
|
||||
* - marks the len-byte memory pointed to by p as defined data (public data, in the
|
||||
* context of constant-time checking).
|
||||
* - SECP256K1_CHECKMEM_MSAN_DEFINE(p, len):
|
||||
* - Like SECP256K1_CHECKMEM_DEFINE, but applies only to memory_sanitizer.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -48,17 +50,29 @@
|
||||
# define SECP256K1_CHECKMEM_ENABLED 1
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len))
|
||||
# define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len))
|
||||
# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) __msan_unpoison((p), (len))
|
||||
# define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len))
|
||||
# define SECP256K1_CHECKMEM_RUNNING() (1)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined SECP256K1_CHECKMEM_MSAN_DEFINE
|
||||
# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
|
||||
#endif
|
||||
|
||||
/* If valgrind integration is desired (through the VALGRIND define), implement the
|
||||
* SECP256K1_CHECKMEM_* macros using valgrind. */
|
||||
#if !defined SECP256K1_CHECKMEM_ENABLED
|
||||
# if defined VALGRIND
|
||||
# include <stddef.h>
|
||||
# if defined(__clang__) && defined(__APPLE__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wreserved-identifier"
|
||||
# endif
|
||||
# include <valgrind/memcheck.h>
|
||||
# if defined(__clang__) && defined(__APPLE__)
|
||||
# pragma clang diagnostic pop
|
||||
# endif
|
||||
# define SECP256K1_CHECKMEM_ENABLED 1
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len))
|
||||
# define SECP256K1_CHECKMEM_DEFINE(p, len) VALGRIND_MAKE_MEM_DEFINED((p), (len))
|
||||
|
||||
92
external/secp256k1/src/ctime_tests.c
vendored
92
external/secp256k1/src/ctime_tests.c
vendored
@@ -5,6 +5,7 @@
|
||||
***********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../include/secp256k1.h"
|
||||
#include "assumptions.h"
|
||||
@@ -30,6 +31,14 @@
|
||||
#include "../include/secp256k1_schnorrsig.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_MUSIG
|
||||
#include "../include/secp256k1_musig.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
#include "../include/secp256k1_ellswift.h"
|
||||
#endif
|
||||
|
||||
static void run_tests(secp256k1_context *ctx, unsigned char *key);
|
||||
|
||||
int main(void) {
|
||||
@@ -80,6 +89,10 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
||||
#ifdef ENABLE_MODULE_EXTRAKEYS
|
||||
secp256k1_keypair keypair;
|
||||
#endif
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
unsigned char ellswift[64];
|
||||
static const unsigned char prefix[64] = {'t', 'e', 's', 't'};
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
msg[i] = i + 1;
|
||||
@@ -171,4 +184,83 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_MUSIG
|
||||
{
|
||||
secp256k1_pubkey pk;
|
||||
const secp256k1_pubkey *pk_ptr[1];
|
||||
secp256k1_xonly_pubkey agg_pk;
|
||||
unsigned char session_secrand[32];
|
||||
uint64_t nonrepeating_cnt = 0;
|
||||
secp256k1_musig_secnonce secnonce;
|
||||
secp256k1_musig_pubnonce pubnonce;
|
||||
const secp256k1_musig_pubnonce *pubnonce_ptr[1];
|
||||
secp256k1_musig_aggnonce aggnonce;
|
||||
secp256k1_musig_keyagg_cache cache;
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_musig_partial_sig partial_sig;
|
||||
unsigned char extra_input[32];
|
||||
|
||||
pk_ptr[0] = &pk;
|
||||
pubnonce_ptr[0] = &pubnonce;
|
||||
SECP256K1_CHECKMEM_DEFINE(key, 32);
|
||||
memcpy(session_secrand, key, sizeof(session_secrand));
|
||||
session_secrand[0] = session_secrand[0] + 1;
|
||||
memcpy(extra_input, key, sizeof(extra_input));
|
||||
extra_input[0] = extra_input[0] + 2;
|
||||
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, key));
|
||||
CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair));
|
||||
CHECK(secp256k1_musig_pubkey_agg(ctx, &agg_pk, &cache, pk_ptr, 1));
|
||||
|
||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||
SECP256K1_CHECKMEM_UNDEFINE(session_secrand, sizeof(session_secrand));
|
||||
SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input));
|
||||
ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_secrand, key, &pk, msg, &cache, extra_input);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
ret = secp256k1_musig_nonce_gen_counter(ctx, &secnonce, &pubnonce, nonrepeating_cnt, &keypair, msg, &cache, extra_input);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1));
|
||||
/* Make sure that previous tests don't undefine msg. It's not used as a secret here. */
|
||||
SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg));
|
||||
CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache) == 1);
|
||||
|
||||
ret = secp256k1_keypair_create(ctx, &keypair, key);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
ret = secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &cache, &session);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||
ret = secp256k1_ellswift_create(ctx, ellswift, key, NULL);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||
ret = secp256k1_ellswift_create(ctx, ellswift, key, ellswift);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift));
|
||||
ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_bip324, NULL);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift));
|
||||
ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_prefix, (void *)prefix);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
28
external/secp256k1/src/ecdsa_impl.h
vendored
28
external/secp256k1/src/ecdsa_impl.h
vendored
@@ -16,17 +16,8 @@
|
||||
#include "ecdsa.h"
|
||||
|
||||
/** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1
|
||||
* sage: for t in xrange(1023, -1, -1):
|
||||
* .. p = 2**256 - 2**32 - t
|
||||
* .. if p.is_prime():
|
||||
* .. print '%x'%p
|
||||
* .. break
|
||||
* 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'
|
||||
* sage: a = 0
|
||||
* sage: b = 7
|
||||
* sage: F = FiniteField (p)
|
||||
* sage: '%x' % (EllipticCurve ([F (a), F (b)]).order())
|
||||
* 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141'
|
||||
* $ sage -c 'load("secp256k1_params.sage"); print(hex(N))'
|
||||
* 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
|
||||
*/
|
||||
static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST(
|
||||
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL,
|
||||
@@ -35,12 +26,8 @@ static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST
|
||||
|
||||
/** Difference between field and order, values 'p' and 'n' values defined in
|
||||
* "Standards for Efficient Cryptography" (SEC2) 2.7.1.
|
||||
* sage: p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
|
||||
* sage: a = 0
|
||||
* sage: b = 7
|
||||
* sage: F = FiniteField (p)
|
||||
* sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order())
|
||||
* '14551231950b75fc4402da1722fc9baee'
|
||||
* $ sage -c 'load("secp256k1_params.sage"); print(hex(P-N))'
|
||||
* 0x14551231950b75fc4402da1722fc9baee
|
||||
*/
|
||||
static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST(
|
||||
0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL
|
||||
@@ -79,8 +66,7 @@ static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const
|
||||
}
|
||||
if (lenleft > sizeof(size_t)) {
|
||||
/* The resulting length would exceed the range of a size_t, so
|
||||
* certainly longer than the passed array size.
|
||||
*/
|
||||
* it is certainly longer than the passed array size. */
|
||||
return 0;
|
||||
}
|
||||
while (lenleft > 0) {
|
||||
@@ -89,7 +75,9 @@ static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const
|
||||
lenleft--;
|
||||
}
|
||||
if (*len > (size_t)(sigend - *sigp)) {
|
||||
/* Result exceeds the length of the passed array. */
|
||||
/* Result exceeds the length of the passed array.
|
||||
(Checking this is the responsibility of the caller but it
|
||||
can't hurt do it here, too.) */
|
||||
return 0;
|
||||
}
|
||||
if (*len < 128) {
|
||||
|
||||
8
external/secp256k1/src/eckey_impl.h
vendored
8
external/secp256k1/src/eckey_impl.h
vendored
@@ -59,10 +59,8 @@ static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp25
|
||||
|
||||
static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak) {
|
||||
secp256k1_gej pt;
|
||||
secp256k1_scalar one;
|
||||
secp256k1_gej_set_ge(&pt, key);
|
||||
secp256k1_scalar_set_int(&one, 1);
|
||||
secp256k1_ecmult(&pt, &pt, &one, tweak);
|
||||
secp256k1_ecmult(&pt, &pt, &secp256k1_scalar_one, tweak);
|
||||
|
||||
if (secp256k1_gej_is_infinity(&pt)) {
|
||||
return 0;
|
||||
@@ -80,15 +78,13 @@ static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp25
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_scalar *tweak) {
|
||||
secp256k1_scalar zero;
|
||||
secp256k1_gej pt;
|
||||
if (secp256k1_scalar_is_zero(tweak)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_int(&zero, 0);
|
||||
secp256k1_gej_set_ge(&pt, key);
|
||||
secp256k1_ecmult(&pt, &pt, tweak, &zero);
|
||||
secp256k1_ecmult(&pt, &pt, tweak, &secp256k1_scalar_zero);
|
||||
secp256k1_ge_set_gej(key, &pt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
2
external/secp256k1/src/ecmult.h
vendored
2
external/secp256k1/src/ecmult.h
vendored
@@ -22,7 +22,7 @@
|
||||
# pragma message DEBUG_CONFIG_DEF(ECMULT_WINDOW_SIZE)
|
||||
#endif
|
||||
|
||||
/* Noone will ever need more than a window size of 24. The code might
|
||||
/* No one will ever need more than a window size of 24. The code might
|
||||
* be correct for larger values of ECMULT_WINDOW_SIZE but this is not
|
||||
* tested.
|
||||
*
|
||||
|
||||
385
external/secp256k1/src/ecmult_const_impl.h
vendored
385
external/secp256k1/src/ecmult_const_impl.h
vendored
@@ -1,5 +1,5 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2015 Pieter Wuille, Andrew Poelstra *
|
||||
* Copyright (c) 2015, 2022 Pieter Wuille, Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
@@ -12,208 +12,259 @@
|
||||
#include "ecmult_const.h"
|
||||
#include "ecmult_impl.h"
|
||||
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
/* We need 2^ECMULT_CONST_GROUP_SIZE - 1 to be less than EXHAUSTIVE_TEST_ORDER, because
|
||||
* the tables cannot have infinities in them (this breaks the effective-affine technique's
|
||||
* z-ratio tracking) */
|
||||
# if EXHAUSTIVE_TEST_ORDER == 199
|
||||
# define ECMULT_CONST_GROUP_SIZE 4
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 13
|
||||
# define ECMULT_CONST_GROUP_SIZE 3
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 7
|
||||
# define ECMULT_CONST_GROUP_SIZE 2
|
||||
# else
|
||||
# error "Unknown EXHAUSTIVE_TEST_ORDER"
|
||||
# endif
|
||||
#else
|
||||
/* Group size 4 or 5 appears optimal. */
|
||||
# define ECMULT_CONST_GROUP_SIZE 5
|
||||
#endif
|
||||
|
||||
#define ECMULT_CONST_TABLE_SIZE (1L << (ECMULT_CONST_GROUP_SIZE - 1))
|
||||
#define ECMULT_CONST_GROUPS ((129 + ECMULT_CONST_GROUP_SIZE - 1) / ECMULT_CONST_GROUP_SIZE)
|
||||
#define ECMULT_CONST_BITS (ECMULT_CONST_GROUPS * ECMULT_CONST_GROUP_SIZE)
|
||||
|
||||
/** Fill a table 'pre' with precomputed odd multiples of a.
|
||||
*
|
||||
* The resulting point set is brought to a single constant Z denominator, stores the X and Y
|
||||
* coordinates as ge_storage points in pre, and stores the global Z in globalz.
|
||||
* It only operates on tables sized for WINDOW_A wnaf multiples.
|
||||
* coordinates as ge points in pre, and stores the global Z in globalz.
|
||||
*
|
||||
* 'pre' must be an array of size ECMULT_CONST_TABLE_SIZE.
|
||||
*/
|
||||
static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
|
||||
secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
static void secp256k1_ecmult_const_odd_multiples_table_globalz(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
|
||||
secp256k1_fe zr[ECMULT_CONST_TABLE_SIZE];
|
||||
|
||||
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr, globalz, a);
|
||||
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr);
|
||||
secp256k1_ecmult_odd_multiples_table(ECMULT_CONST_TABLE_SIZE, pre, zr, globalz, a);
|
||||
secp256k1_ge_table_set_globalz(ECMULT_CONST_TABLE_SIZE, pre, zr);
|
||||
}
|
||||
|
||||
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */
|
||||
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
|
||||
int m = 0; \
|
||||
/* Extract the sign-bit for a constant time absolute-value. */ \
|
||||
int volatile mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
|
||||
int abs_n = ((n) + mask) ^ mask; \
|
||||
int idx_n = abs_n >> 1; \
|
||||
/* Given a table 'pre' with odd multiples of a point, put in r the signed-bit multiplication of n with that point.
|
||||
*
|
||||
* For example, if ECMULT_CONST_GROUP_SIZE is 4, then pre is expected to contain 8 entries:
|
||||
* [1*P, 3*P, 5*P, 7*P, 9*P, 11*P, 13*P, 15*P]. n is then expected to be a 4-bit integer (range 0-15), and its
|
||||
* bits are interpreted as signs of powers of two to look up.
|
||||
*
|
||||
* For example, if n=4, which is 0100 in binary, which is interpreted as [- + - -], so the looked up value is
|
||||
* [ -(2^3) + (2^2) - (2^1) - (2^0) ]*P = -7*P. Every valid n translates to an odd number in range [-15,15],
|
||||
* which means we just need to look up one of the precomputed values, and optionally negate it.
|
||||
*/
|
||||
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n) do { \
|
||||
unsigned int m = 0; \
|
||||
/* If the top bit of n is 0, we want the negation. */ \
|
||||
volatile unsigned int negative = ((n) >> (ECMULT_CONST_GROUP_SIZE - 1)) ^ 1; \
|
||||
/* Let n[i] be the i-th bit of n, then the index is
|
||||
* sum(cnot(n[i]) * 2^i, i=0..l-2)
|
||||
* where cnot(b) = b if n[l-1] = 1 and 1 - b otherwise.
|
||||
* For example, if n = 4, in binary 0100, the index is 3, in binary 011.
|
||||
*
|
||||
* Proof:
|
||||
* Let
|
||||
* x = sum((2*n[i] - 1)*2^i, i=0..l-1)
|
||||
* = 2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 1
|
||||
* be the value represented by n.
|
||||
* The index is (x - 1)/2 if x > 0 and -(x + 1)/2 otherwise.
|
||||
* Case x > 0:
|
||||
* n[l-1] = 1
|
||||
* index = sum(n[i] * 2^i, i=0..l-1) - 2^(l-1)
|
||||
* = sum(n[i] * 2^i, i=0..l-2)
|
||||
* Case x <= 0:
|
||||
* n[l-1] = 0
|
||||
* index = -(2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 2)/2
|
||||
* = 2^(l-1) - 1 - sum(n[i] * 2^i, i=0..l-1)
|
||||
* = sum((1 - n[i]) * 2^i, i=0..l-2)
|
||||
*/ \
|
||||
unsigned int index = ((unsigned int)(-negative) ^ n) & ((1U << (ECMULT_CONST_GROUP_SIZE - 1)) - 1U); \
|
||||
secp256k1_fe neg_y; \
|
||||
VERIFY_CHECK(((n) & 1) == 1); \
|
||||
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
|
||||
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
|
||||
VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \
|
||||
VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \
|
||||
/* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one \
|
||||
VERIFY_CHECK((n) < (1U << ECMULT_CONST_GROUP_SIZE)); \
|
||||
VERIFY_CHECK(index < (1U << (ECMULT_CONST_GROUP_SIZE - 1))); \
|
||||
/* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one
|
||||
* or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \
|
||||
(r)->x = (pre)[m].x; \
|
||||
(r)->y = (pre)[m].y; \
|
||||
for (m = 1; m < ECMULT_TABLE_SIZE(w); m++) { \
|
||||
for (m = 1; m < ECMULT_CONST_TABLE_SIZE; m++) { \
|
||||
/* This loop is used to avoid secret data in array indices. See
|
||||
* the comment in ecmult_gen_impl.h for rationale. */ \
|
||||
secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \
|
||||
secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \
|
||||
secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == index); \
|
||||
secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == index); \
|
||||
} \
|
||||
(r)->infinity = 0; \
|
||||
secp256k1_fe_negate(&neg_y, &(r)->y, 1); \
|
||||
secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \
|
||||
secp256k1_fe_cmov(&(r)->y, &neg_y, negative); \
|
||||
} while(0)
|
||||
|
||||
/** Convert a number to WNAF notation.
|
||||
* The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val.
|
||||
* It has the following guarantees:
|
||||
* - each wnaf[i] an odd integer between -(1 << w) and (1 << w)
|
||||
* - each wnaf[i] is nonzero
|
||||
* - the number of words set is always WNAF_SIZE(w) + 1
|
||||
*
|
||||
* Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar
|
||||
* Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.)
|
||||
* CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlag Berlin Heidelberg 2003
|
||||
*
|
||||
* Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335
|
||||
*/
|
||||
static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w, int size) {
|
||||
int global_sign;
|
||||
int skew;
|
||||
int word = 0;
|
||||
/* For K as defined in the comment of secp256k1_ecmult_const, we have several precomputed
|
||||
* formulas/constants.
|
||||
* - in exhaustive test mode, we give an explicit expression to compute it at compile time: */
|
||||
#ifdef EXHAUSTIVE_TEST_ORDER
|
||||
static const secp256k1_scalar secp256k1_ecmult_const_K = ((SECP256K1_SCALAR_CONST(0, 0, 0, (1U << (ECMULT_CONST_BITS - 128)) - 2U, 0, 0, 0, 0) + EXHAUSTIVE_TEST_ORDER - 1U) * (1U + EXHAUSTIVE_TEST_LAMBDA)) % EXHAUSTIVE_TEST_ORDER;
|
||||
/* - for the real secp256k1 group we have constants for various ECMULT_CONST_BITS values. */
|
||||
#elif ECMULT_CONST_BITS == 129
|
||||
/* For GROUP_SIZE = 1,3. */
|
||||
static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xac9c52b3ul, 0x3fa3cf1ful, 0x5ad9e3fdul, 0x77ed9ba4ul, 0xa880b9fcul, 0x8ec739c2ul, 0xe0cfc810ul, 0xb51283ceul);
|
||||
#elif ECMULT_CONST_BITS == 130
|
||||
/* For GROUP_SIZE = 2,5. */
|
||||
static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xa4e88a7dul, 0xcb13034eul, 0xc2bdd6bful, 0x7c118d6bul, 0x589ae848ul, 0x26ba29e4ul, 0xb5c2c1dcul, 0xde9798d9ul);
|
||||
#elif ECMULT_CONST_BITS == 132
|
||||
/* For GROUP_SIZE = 4,6 */
|
||||
static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0x76b1d93dul, 0x0fae3c6bul, 0x3215874bul, 0x94e93813ul, 0x7937fe0dul, 0xb66bcaaful, 0xb3749ca5ul, 0xd7b6171bul);
|
||||
#else
|
||||
# error "Unknown ECMULT_CONST_BITS"
|
||||
#endif
|
||||
|
||||
/* 1 2 3 */
|
||||
int u_last;
|
||||
int u;
|
||||
|
||||
int flip;
|
||||
secp256k1_scalar s = *scalar;
|
||||
|
||||
VERIFY_CHECK(w > 0);
|
||||
VERIFY_CHECK(size > 0);
|
||||
|
||||
/* Note that we cannot handle even numbers by negating them to be odd, as is
|
||||
* done in other implementations, since if our scalars were specified to have
|
||||
* width < 256 for performance reasons, their negations would have width 256
|
||||
* and we'd lose any performance benefit. Instead, we use a variation of a
|
||||
* technique from Section 4.2 of the Okeya/Tagaki paper, which is to add 1 to the
|
||||
* number we are encoding when it is even, returning a skew value indicating
|
||||
* this, and having the caller compensate after doing the multiplication.
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q) {
|
||||
/* The approach below combines the signed-digit logic from Mike Hamburg's
|
||||
* "Fast and compact elliptic-curve cryptography" (https://eprint.iacr.org/2012/309)
|
||||
* Section 3.3, with the GLV endomorphism.
|
||||
*
|
||||
* In fact, we _do_ want to negate numbers to minimize their bit-lengths (and in
|
||||
* particular, to ensure that the outputs from the endomorphism-split fit into
|
||||
* 128 bits). If we negate, the parity of our number flips, affecting whether
|
||||
* we want to add to the scalar to ensure that it's odd. */
|
||||
flip = secp256k1_scalar_is_high(&s);
|
||||
skew = flip ^ secp256k1_scalar_is_even(&s);
|
||||
secp256k1_scalar_cadd_bit(&s, 0, skew);
|
||||
global_sign = secp256k1_scalar_cond_negate(&s, flip);
|
||||
* The idea there is to interpret the bits of a scalar as signs (1 = +, 0 = -), and compute a
|
||||
* point multiplication in that fashion. Let v be an n-bit non-negative integer (0 <= v < 2^n),
|
||||
* and v[i] its i'th bit (so v = sum(v[i] * 2^i, i=0..n-1)). Then define:
|
||||
*
|
||||
* C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1)
|
||||
*
|
||||
* Then it holds that C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1)
|
||||
* = (2*sum(v[i] * 2^i, i=0..l-1) + 1 - 2^l) * A
|
||||
* = (2*v + 1 - 2^l) * A
|
||||
*
|
||||
* Thus, one can compute q*A as C_256((q + 2^256 - 1) / 2, A). This is the basis for the
|
||||
* paper's signed-digit multi-comb algorithm for multiplication using a precomputed table.
|
||||
*
|
||||
* It is appealing to try to combine this with the GLV optimization: the idea that a scalar
|
||||
* s can be written as s1 + lambda*s2, where lambda is a curve-specific constant such that
|
||||
* lambda*A is easy to compute, and where s1 and s2 are small. In particular we have the
|
||||
* secp256k1_scalar_split_lambda function which performs such a split with the resulting s1
|
||||
* and s2 in range (-2^128, 2^128) mod n. This does work, but is uninteresting:
|
||||
*
|
||||
* To compute q*A:
|
||||
* - Let s1, s2 = split_lambda(q)
|
||||
* - Let R1 = C_256((s1 + 2^256 - 1) / 2, A)
|
||||
* - Let R2 = C_256((s2 + 2^256 - 1) / 2, lambda*A)
|
||||
* - Return R1 + R2
|
||||
*
|
||||
* The issue is that while s1 and s2 are small-range numbers, (s1 + 2^256 - 1) / 2 (mod n)
|
||||
* and (s2 + 2^256 - 1) / 2 (mod n) are not, undoing the benefit of the splitting.
|
||||
*
|
||||
* To make it work, we want to modify the input scalar q first, before splitting, and then only
|
||||
* add a 2^128 offset of the split results (so that they end up in the single 129-bit range
|
||||
* [0,2^129]). A slightly smaller offset would work due to the bounds on the split, but we pick
|
||||
* 2^128 for simplicity. Let s be the scalar fed to split_lambda, and f(q) the function to
|
||||
* compute it from q:
|
||||
*
|
||||
* To compute q*A:
|
||||
* - Compute s = f(q)
|
||||
* - Let s1, s2 = split_lambda(s)
|
||||
* - Let v1 = s1 + 2^128 (mod n)
|
||||
* - Let v2 = s2 + 2^128 (mod n)
|
||||
* - Let R1 = C_l(v1, A)
|
||||
* - Let R2 = C_l(v2, lambda*A)
|
||||
* - Return R1 + R2
|
||||
*
|
||||
* l will thus need to be at least 129, but we may overshoot by a few bits (see
|
||||
* further), so keep it as a variable.
|
||||
*
|
||||
* To solve for s, we reason:
|
||||
* q*A = R1 + R2
|
||||
* <=> q*A = C_l(s1 + 2^128, A) + C_l(s2 + 2^128, lambda*A)
|
||||
* <=> q*A = (2*(s1 + 2^128) + 1 - 2^l) * A + (2*(s2 + 2^128) + 1 - 2^l) * lambda*A
|
||||
* <=> q*A = (2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda)) * A
|
||||
* <=> q = 2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda) (mod n)
|
||||
* <=> q = 2*s + (2^129 + 1 - 2^l) * (1 + lambda) (mod n)
|
||||
* <=> s = (q + (2^l - 2^129 - 1) * (1 + lambda)) / 2 (mod n)
|
||||
* <=> f(q) = (q + K) / 2 (mod n)
|
||||
* where K = (2^l - 2^129 - 1)*(1 + lambda) (mod n)
|
||||
*
|
||||
* We will process the computation of C_l(v1, A) and C_l(v2, lambda*A) in groups of
|
||||
* ECMULT_CONST_GROUP_SIZE, so we set l to the smallest multiple of ECMULT_CONST_GROUP_SIZE
|
||||
* that is not less than 129; this equals ECMULT_CONST_BITS.
|
||||
*/
|
||||
|
||||
/* 4 */
|
||||
u_last = secp256k1_scalar_shr_int(&s, w);
|
||||
do {
|
||||
int even;
|
||||
|
||||
/* 4.1 4.4 */
|
||||
u = secp256k1_scalar_shr_int(&s, w);
|
||||
/* 4.2 */
|
||||
even = ((u & 1) == 0);
|
||||
/* In contrast to the original algorithm, u_last is always > 0 and
|
||||
* therefore we do not need to check its sign. In particular, it's easy
|
||||
* to see that u_last is never < 0 because u is never < 0. Moreover,
|
||||
* u_last is never = 0 because u is never even after a loop
|
||||
* iteration. The same holds analogously for the initial value of
|
||||
* u_last (in the first loop iteration). */
|
||||
VERIFY_CHECK(u_last > 0);
|
||||
VERIFY_CHECK((u_last & 1) == 1);
|
||||
u += even;
|
||||
u_last -= even * (1 << w);
|
||||
|
||||
/* 4.3, adapted for global sign change */
|
||||
wnaf[word++] = u_last * global_sign;
|
||||
|
||||
u_last = u;
|
||||
} while (word * w < size);
|
||||
wnaf[word] = u * global_sign;
|
||||
|
||||
VERIFY_CHECK(secp256k1_scalar_is_zero(&s));
|
||||
VERIFY_CHECK(word == WNAF_SIZE_BITS(size, w));
|
||||
return skew;
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) {
|
||||
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
secp256k1_ge tmpa;
|
||||
secp256k1_fe Z;
|
||||
|
||||
int skew_1;
|
||||
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
int skew_lam;
|
||||
secp256k1_scalar q_1, q_lam;
|
||||
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
|
||||
int i;
|
||||
/* The offset to add to s1 and s2 to make them non-negative. Equal to 2^128. */
|
||||
static const secp256k1_scalar S_OFFSET = SECP256K1_SCALAR_CONST(0, 0, 0, 1, 0, 0, 0, 0);
|
||||
secp256k1_scalar s, v1, v2;
|
||||
secp256k1_ge pre_a[ECMULT_CONST_TABLE_SIZE];
|
||||
secp256k1_ge pre_a_lam[ECMULT_CONST_TABLE_SIZE];
|
||||
secp256k1_fe global_z;
|
||||
int group, i;
|
||||
|
||||
/* We're allowed to be non-constant time in the point, and the code below (in particular,
|
||||
* secp256k1_ecmult_const_odd_multiples_table_globalz) cannot deal with infinity in a
|
||||
* constant-time manner anyway. */
|
||||
if (secp256k1_ge_is_infinity(a)) {
|
||||
secp256k1_gej_set_infinity(r);
|
||||
return;
|
||||
}
|
||||
|
||||
/* build wnaf representation for q. */
|
||||
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
|
||||
secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar);
|
||||
skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128);
|
||||
skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128);
|
||||
/* Compute v1 and v2. */
|
||||
secp256k1_scalar_add(&s, q, &secp256k1_ecmult_const_K);
|
||||
secp256k1_scalar_half(&s, &s);
|
||||
secp256k1_scalar_split_lambda(&v1, &v2, &s);
|
||||
secp256k1_scalar_add(&v1, &v1, &S_OFFSET);
|
||||
secp256k1_scalar_add(&v2, &v2, &S_OFFSET);
|
||||
|
||||
/* Calculate odd multiples of a.
|
||||
#ifdef VERIFY
|
||||
/* Verify that v1 and v2 are in range [0, 2^129-1]. */
|
||||
for (i = 129; i < 256; ++i) {
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&v1, i, 1) == 0);
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&v2, i, 1) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Calculate odd multiples of A and A*lambda.
|
||||
* All multiples are brought to the same Z 'denominator', which is stored
|
||||
* in Z. Due to secp256k1' isomorphism we can do all operations pretending
|
||||
* in global_z. Due to secp256k1' isomorphism we can do all operations pretending
|
||||
* that the Z coordinate was 1, use affine addition formulae, and correct
|
||||
* the Z coordinate of the result once at the end.
|
||||
*/
|
||||
VERIFY_CHECK(!a->infinity);
|
||||
secp256k1_gej_set_ge(r, a);
|
||||
secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r);
|
||||
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||
secp256k1_fe_normalize_weak(&pre_a[i].y);
|
||||
}
|
||||
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||
secp256k1_ecmult_const_odd_multiples_table_globalz(pre_a, &global_z, r);
|
||||
for (i = 0; i < ECMULT_CONST_TABLE_SIZE; i++) {
|
||||
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
|
||||
}
|
||||
|
||||
/* first loop iteration (separated out so we can directly set r, rather
|
||||
* than having it start at infinity, get doubled several times, then have
|
||||
* its new value added to it) */
|
||||
i = wnaf_1[WNAF_SIZE_BITS(128, WINDOW_A - 1)];
|
||||
VERIFY_CHECK(i != 0);
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
|
||||
secp256k1_gej_set_ge(r, &tmpa);
|
||||
i = wnaf_lam[WNAF_SIZE_BITS(128, WINDOW_A - 1)];
|
||||
VERIFY_CHECK(i != 0);
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
/* remaining loop iterations */
|
||||
for (i = WNAF_SIZE_BITS(128, WINDOW_A - 1) - 1; i >= 0; i--) {
|
||||
int n;
|
||||
/* Next, we compute r = C_l(v1, A) + C_l(v2, lambda*A).
|
||||
*
|
||||
* We proceed in groups of ECMULT_CONST_GROUP_SIZE bits, operating on that many bits
|
||||
* at a time, from high in v1, v2 to low. Call these bits1 (from v1) and bits2 (from v2).
|
||||
*
|
||||
* Now note that ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1) loads into t a point equal
|
||||
* to C_{ECMULT_CONST_GROUP_SIZE}(bits1, A), and analogously for pre_lam_a / bits2.
|
||||
* This means that all we need to do is add these looked up values together, multiplied
|
||||
* by 2^(ECMULT_GROUP_SIZE * group).
|
||||
*/
|
||||
for (group = ECMULT_CONST_GROUPS - 1; group >= 0; --group) {
|
||||
/* Using the _var get_bits function is ok here, since it's only variable in offset and count, not in the scalar. */
|
||||
unsigned int bits1 = secp256k1_scalar_get_bits_var(&v1, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE);
|
||||
unsigned int bits2 = secp256k1_scalar_get_bits_var(&v2, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE);
|
||||
secp256k1_ge t;
|
||||
int j;
|
||||
for (j = 0; j < WINDOW_A - 1; ++j) {
|
||||
secp256k1_gej_double(r, r);
|
||||
|
||||
ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1);
|
||||
if (group == ECMULT_CONST_GROUPS - 1) {
|
||||
/* Directly set r in the first iteration. */
|
||||
secp256k1_gej_set_ge(r, &t);
|
||||
} else {
|
||||
/* Shift the result so far up. */
|
||||
for (j = 0; j < ECMULT_CONST_GROUP_SIZE; ++j) {
|
||||
secp256k1_gej_double(r, r);
|
||||
}
|
||||
secp256k1_gej_add_ge(r, r, &t);
|
||||
}
|
||||
|
||||
n = wnaf_1[i];
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
|
||||
VERIFY_CHECK(n != 0);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
n = wnaf_lam[i];
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
|
||||
VERIFY_CHECK(n != 0);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
ECMULT_CONST_TABLE_GET_GE(&t, pre_a_lam, bits2);
|
||||
secp256k1_gej_add_ge(r, r, &t);
|
||||
}
|
||||
|
||||
{
|
||||
/* Correct for wNAF skew */
|
||||
secp256k1_gej tmpj;
|
||||
|
||||
secp256k1_ge_neg(&tmpa, &pre_a[0]);
|
||||
secp256k1_gej_add_ge(&tmpj, r, &tmpa);
|
||||
secp256k1_gej_cmov(r, &tmpj, skew_1);
|
||||
|
||||
secp256k1_ge_neg(&tmpa, &pre_a_lam[0]);
|
||||
secp256k1_gej_add_ge(&tmpj, r, &tmpa);
|
||||
secp256k1_gej_cmov(r, &tmpj, skew_lam);
|
||||
}
|
||||
|
||||
secp256k1_fe_mul(&r->z, &r->z, &Z);
|
||||
/* Map the result back to the secp256k1 curve from the isomorphic curve. */
|
||||
secp256k1_fe_mul(&r->z, &r->z, &global_z);
|
||||
}
|
||||
|
||||
static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int known_on_curve) {
|
||||
@@ -276,7 +327,7 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n,
|
||||
*
|
||||
* It is easy to verify that both (n*g, g^2, v) and its negation (n*g, -g^2, v) have affine X
|
||||
* coordinate n/d, and this holds even when the square root function doesn't have a
|
||||
* determinstic sign. We choose the (n*g, g^2, v) version.
|
||||
* deterministic sign. We choose the (n*g, g^2, v) version.
|
||||
*
|
||||
* Now switch to the effective affine curve using phi_v, where the input point has coordinates
|
||||
* (n*g, g^2). Compute (X, Y, Z) = q * (n*g, g^2) there.
|
||||
@@ -296,9 +347,7 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n,
|
||||
secp256k1_fe_mul(&g, &g, n);
|
||||
if (d) {
|
||||
secp256k1_fe b;
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero(d));
|
||||
#endif
|
||||
secp256k1_fe_sqr(&b, d);
|
||||
VERIFY_CHECK(SECP256K1_B <= 8); /* magnitude of b will be <= 8 after the next call */
|
||||
secp256k1_fe_mul_int(&b, SECP256K1_B);
|
||||
@@ -331,13 +380,9 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n,
|
||||
p.infinity = 0;
|
||||
|
||||
/* Perform x-only EC multiplication of P with q. */
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(!secp256k1_scalar_is_zero(q));
|
||||
#endif
|
||||
secp256k1_ecmult_const(&rj, &p, q);
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(!secp256k1_gej_is_infinity(&rj));
|
||||
#endif
|
||||
|
||||
/* The resulting (X, Y, Z) point on the effective-affine isomorphic curve corresponds to
|
||||
* (X, Y, Z*v) on the secp256k1 curve. The affine version of that has X coordinate
|
||||
|
||||
127
external/secp256k1/src/ecmult_gen.h
vendored
127
external/secp256k1/src/ecmult_gen.h
vendored
@@ -1,5 +1,5 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Copyright (c) Pieter Wuille, Peter Dettman *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
@@ -10,31 +10,126 @@
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
|
||||
#ifndef ECMULT_GEN_PREC_BITS
|
||||
# define ECMULT_GEN_PREC_BITS 4
|
||||
# ifdef DEBUG_CONFIG
|
||||
# pragma message DEBUG_CONFIG_MSG("ECMULT_GEN_PREC_BITS undefined, assuming default value")
|
||||
|
||||
/* Configuration parameters for the signed-digit multi-comb algorithm:
|
||||
*
|
||||
* - COMB_BLOCKS is the number of blocks the input is split into. Each
|
||||
* has a corresponding table.
|
||||
* - COMB_TEETH is the number of bits simultaneously covered by one table.
|
||||
* - COMB_RANGE is the number of bits in supported scalars. For production
|
||||
* purposes, only 256 is reasonable, but smaller numbers are supported for
|
||||
* exhaustive test mode.
|
||||
*
|
||||
* The comb's spacing (COMB_SPACING), or the distance between the teeth,
|
||||
* is defined as ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)). Each block covers
|
||||
* COMB_SPACING * COMB_TEETH consecutive bits in the input.
|
||||
*
|
||||
* The size of the precomputed table is COMB_BLOCKS * (1 << (COMB_TEETH - 1))
|
||||
* secp256k1_ge_storages.
|
||||
*
|
||||
* The number of point additions equals COMB_BLOCKS * COMB_SPACING. Each point
|
||||
* addition involves a cmov from (1 << (COMB_TEETH - 1)) table entries and a
|
||||
* conditional negation.
|
||||
*
|
||||
* The number of point doublings is COMB_SPACING - 1. */
|
||||
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
/* We need to control these values for exhaustive tests because
|
||||
* the table cannot have infinities in them (secp256k1_ge_storage
|
||||
* doesn't support infinities) */
|
||||
# undef COMB_BLOCKS
|
||||
# undef COMB_TEETH
|
||||
# if EXHAUSTIVE_TEST_ORDER == 7
|
||||
# define COMB_RANGE 3
|
||||
# define COMB_BLOCKS 1
|
||||
# define COMB_TEETH 2
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 13
|
||||
# define COMB_RANGE 4
|
||||
# define COMB_BLOCKS 1
|
||||
# define COMB_TEETH 2
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 199
|
||||
# define COMB_RANGE 8
|
||||
# define COMB_BLOCKS 2
|
||||
# define COMB_TEETH 3
|
||||
# else
|
||||
# error "Unknown exhaustive test order"
|
||||
# endif
|
||||
# if (COMB_RANGE >= 32) || ((EXHAUSTIVE_TEST_ORDER >> (COMB_RANGE - 1)) != 1)
|
||||
# error "COMB_RANGE != ceil(log2(EXHAUSTIVE_TEST_ORDER+1))"
|
||||
# endif
|
||||
#else /* !defined(EXHAUSTIVE_TEST_ORDER) */
|
||||
# define COMB_RANGE 256
|
||||
#endif /* defined(EXHAUSTIVE_TEST_ORDER) */
|
||||
|
||||
/* Use (11, 6) as default configuration, which results in a 22 kB table. */
|
||||
#ifndef COMB_BLOCKS
|
||||
# define COMB_BLOCKS 11
|
||||
# ifdef DEBUG_CONFIG
|
||||
# pragma message DEBUG_CONFIG_MSG("COMB_BLOCKS undefined, assuming default value")
|
||||
# endif
|
||||
#endif
|
||||
#ifndef COMB_TEETH
|
||||
# define COMB_TEETH 6
|
||||
# ifdef DEBUG_CONFIG
|
||||
# pragma message DEBUG_CONFIG_MSG("COMB_TEETH undefined, assuming default value")
|
||||
# endif
|
||||
#endif
|
||||
/* Use ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)) as COMB_SPACING. */
|
||||
#define COMB_SPACING CEIL_DIV(COMB_RANGE, COMB_BLOCKS * COMB_TEETH)
|
||||
|
||||
/* Range checks on the parameters. */
|
||||
|
||||
/* The remaining COMB_* parameters are derived values, don't modify these. */
|
||||
/* - The number of bits covered by all the blocks; must be at least COMB_RANGE. */
|
||||
#define COMB_BITS (COMB_BLOCKS * COMB_TEETH * COMB_SPACING)
|
||||
/* - The number of entries per table. */
|
||||
#define COMB_POINTS (1 << (COMB_TEETH - 1))
|
||||
|
||||
/* Sanity checks. */
|
||||
#if !(1 <= COMB_BLOCKS && COMB_BLOCKS <= 256)
|
||||
# error "COMB_BLOCKS must be in the range [1, 256]"
|
||||
#endif
|
||||
#if !(1 <= COMB_TEETH && COMB_TEETH <= 8)
|
||||
# error "COMB_TEETH must be in the range [1, 8]"
|
||||
#endif
|
||||
#if COMB_BITS < COMB_RANGE
|
||||
# error "COMB_BLOCKS * COMB_TEETH * COMB_SPACING is too low"
|
||||
#endif
|
||||
|
||||
/* These last 2 checks are not strictly required, but prevent gratuitously inefficient
|
||||
* configurations. Note that they compare with 256 rather than COMB_RANGE, so they do
|
||||
* permit somewhat excessive values for the exhaustive test case, where testing with
|
||||
* suboptimal parameters may be desirable. */
|
||||
#if (COMB_BLOCKS - 1) * COMB_TEETH * COMB_SPACING >= 256
|
||||
# error "COMB_BLOCKS can be reduced"
|
||||
#endif
|
||||
#if COMB_BLOCKS * (COMB_TEETH - 1) * COMB_SPACING >= 256
|
||||
# error "COMB_TEETH can be reduced"
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CONFIG
|
||||
# pragma message DEBUG_CONFIG_DEF(ECMULT_GEN_PREC_BITS)
|
||||
# pragma message DEBUG_CONFIG_DEF(COMB_RANGE)
|
||||
# pragma message DEBUG_CONFIG_DEF(COMB_BLOCKS)
|
||||
# pragma message DEBUG_CONFIG_DEF(COMB_TEETH)
|
||||
# pragma message DEBUG_CONFIG_DEF(COMB_SPACING)
|
||||
#endif
|
||||
|
||||
#if ECMULT_GEN_PREC_BITS != 2 && ECMULT_GEN_PREC_BITS != 4 && ECMULT_GEN_PREC_BITS != 8
|
||||
# error "Set ECMULT_GEN_PREC_BITS to 2, 4 or 8."
|
||||
#endif
|
||||
|
||||
#define ECMULT_GEN_PREC_G(bits) (1 << bits)
|
||||
#define ECMULT_GEN_PREC_N(bits) (256 / bits)
|
||||
|
||||
typedef struct {
|
||||
/* Whether the context has been built. */
|
||||
int built;
|
||||
|
||||
/* Blinding values used when computing (n-b)G + bG. */
|
||||
secp256k1_scalar blind; /* -b */
|
||||
secp256k1_gej initial; /* bG */
|
||||
/* Values chosen such that
|
||||
*
|
||||
* n*G == comb(n + scalar_offset, G/2) + ge_offset.
|
||||
*
|
||||
* This expression lets us use scalar blinding and optimize the comb precomputation. See
|
||||
* ecmult_gen_impl.h for more details. */
|
||||
secp256k1_scalar scalar_offset;
|
||||
secp256k1_ge ge_offset;
|
||||
|
||||
/* Factor used for projective blinding. This value is used to rescale the Z
|
||||
* coordinate of the first table lookup. */
|
||||
secp256k1_fe proj_blind;
|
||||
} secp256k1_ecmult_gen_context;
|
||||
|
||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell *
|
||||
* Copyright (c) Pieter Wuille, Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
@@ -9,6 +9,6 @@
|
||||
|
||||
#include "ecmult_gen.h"
|
||||
|
||||
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int bits);
|
||||
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth, int spacing);
|
||||
|
||||
#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell *
|
||||
* Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
@@ -10,71 +10,98 @@
|
||||
#include "ecmult_gen_compute_table.h"
|
||||
#include "group_impl.h"
|
||||
#include "field_impl.h"
|
||||
#include "scalar_impl.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "util.h"
|
||||
|
||||
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int bits) {
|
||||
int g = ECMULT_GEN_PREC_G(bits);
|
||||
int n = ECMULT_GEN_PREC_N(bits);
|
||||
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth, int spacing) {
|
||||
size_t points = ((size_t)1) << (teeth - 1);
|
||||
size_t points_total = points * blocks;
|
||||
secp256k1_ge* prec = checked_malloc(&default_error_callback, points_total * sizeof(*prec));
|
||||
secp256k1_gej* ds = checked_malloc(&default_error_callback, teeth * sizeof(*ds));
|
||||
secp256k1_gej* vs = checked_malloc(&default_error_callback, points_total * sizeof(*vs));
|
||||
secp256k1_gej u;
|
||||
size_t vs_pos = 0;
|
||||
secp256k1_scalar half;
|
||||
int block, i;
|
||||
|
||||
secp256k1_ge* prec = checked_malloc(&default_error_callback, n * g * sizeof(*prec));
|
||||
secp256k1_gej gj;
|
||||
secp256k1_gej nums_gej;
|
||||
int i, j;
|
||||
VERIFY_CHECK(points_total > 0);
|
||||
|
||||
/* get the generator */
|
||||
secp256k1_gej_set_ge(&gj, gen);
|
||||
|
||||
/* Construct a group element with no known corresponding scalar (nothing up my sleeve). */
|
||||
{
|
||||
static const unsigned char nums_b32[33] = "The scalar for this x is unknown";
|
||||
secp256k1_fe nums_x;
|
||||
secp256k1_ge nums_ge;
|
||||
int r;
|
||||
r = secp256k1_fe_set_b32_limit(&nums_x, nums_b32);
|
||||
(void)r;
|
||||
VERIFY_CHECK(r);
|
||||
r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0);
|
||||
(void)r;
|
||||
VERIFY_CHECK(r);
|
||||
secp256k1_gej_set_ge(&nums_gej, &nums_ge);
|
||||
/* Add G to make the bits in x uniformly distributed. */
|
||||
secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, gen, NULL);
|
||||
}
|
||||
|
||||
/* compute prec. */
|
||||
{
|
||||
secp256k1_gej gbase;
|
||||
secp256k1_gej numsbase;
|
||||
secp256k1_gej* precj = checked_malloc(&default_error_callback, n * g * sizeof(*precj)); /* Jacobian versions of prec. */
|
||||
gbase = gj; /* PREC_G^j * G */
|
||||
numsbase = nums_gej; /* 2^j * nums. */
|
||||
for (j = 0; j < n; j++) {
|
||||
/* Set precj[j*PREC_G .. j*PREC_G+(PREC_G-1)] to (numsbase, numsbase + gbase, ..., numsbase + (PREC_G-1)*gbase). */
|
||||
precj[j*g] = numsbase;
|
||||
for (i = 1; i < g; i++) {
|
||||
secp256k1_gej_add_var(&precj[j*g + i], &precj[j*g + i - 1], &gbase, NULL);
|
||||
}
|
||||
/* Multiply gbase by PREC_G. */
|
||||
for (i = 0; i < bits; i++) {
|
||||
secp256k1_gej_double_var(&gbase, &gbase, NULL);
|
||||
}
|
||||
/* Multiply numbase by 2. */
|
||||
secp256k1_gej_double_var(&numsbase, &numsbase, NULL);
|
||||
if (j == n - 2) {
|
||||
/* In the last iteration, numsbase is (1 - 2^j) * nums instead. */
|
||||
secp256k1_gej_neg(&numsbase, &numsbase);
|
||||
secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);
|
||||
}
|
||||
}
|
||||
secp256k1_ge_set_all_gej_var(prec, precj, n * g);
|
||||
free(precj);
|
||||
}
|
||||
for (j = 0; j < n; j++) {
|
||||
for (i = 0; i < g; i++) {
|
||||
secp256k1_ge_to_storage(&table[j*g + i], &prec[j*g + i]);
|
||||
/* u is the running power of two times gen we're working with, initially gen/2. */
|
||||
secp256k1_scalar_half(&half, &secp256k1_scalar_one);
|
||||
secp256k1_gej_set_infinity(&u);
|
||||
for (i = 255; i >= 0; --i) {
|
||||
/* Use a very simple multiplication ladder to avoid dependency on ecmult. */
|
||||
secp256k1_gej_double_var(&u, &u, NULL);
|
||||
if (secp256k1_scalar_get_bits_limb32(&half, i, 1)) {
|
||||
secp256k1_gej_add_ge_var(&u, &u, gen, NULL);
|
||||
}
|
||||
}
|
||||
#ifdef VERIFY
|
||||
{
|
||||
/* Verify that u*2 = gen. */
|
||||
secp256k1_gej double_u;
|
||||
secp256k1_gej_double_var(&double_u, &u, NULL);
|
||||
VERIFY_CHECK(secp256k1_gej_eq_ge_var(&double_u, gen));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (block = 0; block < blocks; ++block) {
|
||||
int tooth;
|
||||
/* Here u = 2^(block*teeth*spacing) * gen/2. */
|
||||
secp256k1_gej sum;
|
||||
secp256k1_gej_set_infinity(&sum);
|
||||
for (tooth = 0; tooth < teeth; ++tooth) {
|
||||
/* Here u = 2^((block*teeth + tooth)*spacing) * gen/2. */
|
||||
/* Make sum = sum(2^((block*teeth + t)*spacing), t=0..tooth) * gen/2. */
|
||||
secp256k1_gej_add_var(&sum, &sum, &u, NULL);
|
||||
/* Make u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */
|
||||
secp256k1_gej_double_var(&u, &u, NULL);
|
||||
/* Make ds[tooth] = u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */
|
||||
ds[tooth] = u;
|
||||
/* Make u = 2^((block*teeth + tooth + 1)*spacing) * gen/2, unless at the end. */
|
||||
if (block + tooth != blocks + teeth - 2) {
|
||||
int bit_off;
|
||||
for (bit_off = 1; bit_off < spacing; ++bit_off) {
|
||||
secp256k1_gej_double_var(&u, &u, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Now u = 2^((block*teeth + teeth)*spacing) * gen/2
|
||||
* = 2^((block+1)*teeth*spacing) * gen/2 */
|
||||
|
||||
/* Next, compute the table entries for block number block in Jacobian coordinates.
|
||||
* The entries will occupy vs[block*points + i] for i=0..points-1.
|
||||
* We start by computing the first (i=0) value corresponding to all summed
|
||||
* powers of two times G being negative. */
|
||||
secp256k1_gej_neg(&vs[vs_pos++], &sum);
|
||||
/* And then teeth-1 times "double" the range of i values for which the table
|
||||
* is computed: in each iteration, double the table by taking an existing
|
||||
* table entry and adding ds[tooth]. */
|
||||
for (tooth = 0; tooth < teeth - 1; ++tooth) {
|
||||
size_t stride = ((size_t)1) << tooth;
|
||||
size_t index;
|
||||
for (index = 0; index < stride; ++index, ++vs_pos) {
|
||||
secp256k1_gej_add_var(&vs[vs_pos], &vs[vs_pos - stride], &ds[tooth], NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY_CHECK(vs_pos == points_total);
|
||||
|
||||
/* Convert all points simultaneously from secp256k1_gej to secp256k1_ge. */
|
||||
secp256k1_ge_set_all_gej_var(prec, vs, points_total);
|
||||
/* Convert all points from secp256k1_ge to secp256k1_ge_storage output. */
|
||||
for (block = 0; block < blocks; ++block) {
|
||||
size_t index;
|
||||
for (index = 0; index < points; ++index) {
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(&prec[block * points + index]));
|
||||
secp256k1_ge_to_storage(&table[block * points + index], &prec[block * points + index]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free memory. */
|
||||
free(vs);
|
||||
free(ds);
|
||||
free(prec);
|
||||
}
|
||||
|
||||
|
||||
320
external/secp256k1/src/ecmult_gen_impl.h
vendored
320
external/secp256k1/src/ecmult_gen_impl.h
vendored
@@ -1,5 +1,5 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell *
|
||||
* Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
@@ -25,41 +25,215 @@ static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_cont
|
||||
|
||||
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {
|
||||
ctx->built = 0;
|
||||
secp256k1_scalar_clear(&ctx->blind);
|
||||
secp256k1_gej_clear(&ctx->initial);
|
||||
secp256k1_scalar_clear(&ctx->scalar_offset);
|
||||
secp256k1_ge_clear(&ctx->ge_offset);
|
||||
secp256k1_fe_clear(&ctx->proj_blind);
|
||||
}
|
||||
|
||||
/* For accelerating the computation of a*G:
|
||||
* To harden against timing attacks, use the following mechanism:
|
||||
* * Break up the multiplicand into groups of PREC_BITS bits, called n_0, n_1, n_2, ..., n_(PREC_N-1).
|
||||
* * Compute sum(n_i * (PREC_G)^i * G + U_i, i=0 ... PREC_N-1), where:
|
||||
* * U_i = U * 2^i, for i=0 ... PREC_N-2
|
||||
* * U_i = U * (1-2^(PREC_N-1)), for i=PREC_N-1
|
||||
* where U is a point with no known corresponding scalar. Note that sum(U_i, i=0 ... PREC_N-1) = 0.
|
||||
* For each i, and each of the PREC_G possible values of n_i, (n_i * (PREC_G)^i * G + U_i) is
|
||||
* precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0 ... PREC_N-1).
|
||||
* None of the resulting prec group elements have a known scalar, and neither do any of
|
||||
* the intermediate sums while computing a*G.
|
||||
* The prec values are stored in secp256k1_ecmult_gen_prec_table[i][n_i] = n_i * (PREC_G)^i * G + U_i.
|
||||
*/
|
||||
static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) {
|
||||
int bits = ECMULT_GEN_PREC_BITS;
|
||||
int g = ECMULT_GEN_PREC_G(bits);
|
||||
int n = ECMULT_GEN_PREC_N(bits);
|
||||
/* Compute the scalar (2^COMB_BITS - 1) / 2, the difference between the gn argument to
|
||||
* secp256k1_ecmult_gen, and the scalar whose encoding the table lookup bits are drawn
|
||||
* from (before applying blinding). */
|
||||
static void secp256k1_ecmult_gen_scalar_diff(secp256k1_scalar* diff) {
|
||||
int i;
|
||||
|
||||
/* Compute scalar -1/2. */
|
||||
secp256k1_scalar neghalf;
|
||||
secp256k1_scalar_half(&neghalf, &secp256k1_scalar_one);
|
||||
secp256k1_scalar_negate(&neghalf, &neghalf);
|
||||
|
||||
/* Compute offset = 2^(COMB_BITS - 1). */
|
||||
*diff = secp256k1_scalar_one;
|
||||
for (i = 0; i < COMB_BITS - 1; ++i) {
|
||||
secp256k1_scalar_add(diff, diff, diff);
|
||||
}
|
||||
|
||||
/* The result is the sum 2^(COMB_BITS - 1) + (-1/2). */
|
||||
secp256k1_scalar_add(diff, diff, &neghalf);
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) {
|
||||
uint32_t comb_off;
|
||||
secp256k1_ge add;
|
||||
secp256k1_fe neg;
|
||||
secp256k1_ge_storage adds;
|
||||
secp256k1_scalar gnb;
|
||||
int i, j, n_i;
|
||||
|
||||
secp256k1_scalar d;
|
||||
/* Array of uint32_t values large enough to store COMB_BITS bits. Only the bottom
|
||||
* 8 are ever nonzero, but having the zero padding at the end if COMB_BITS>256
|
||||
* avoids the need to deal with out-of-bounds reads from a scalar. */
|
||||
uint32_t recoded[(COMB_BITS + 31) >> 5] = {0};
|
||||
int first = 1, i;
|
||||
|
||||
memset(&adds, 0, sizeof(adds));
|
||||
*r = ctx->initial;
|
||||
/* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */
|
||||
secp256k1_scalar_add(&gnb, gn, &ctx->blind);
|
||||
add.infinity = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
n_i = secp256k1_scalar_get_bits(&gnb, i * bits, bits);
|
||||
for (j = 0; j < g; j++) {
|
||||
|
||||
/* We want to compute R = gn*G.
|
||||
*
|
||||
* To blind the scalar used in the computation, we rewrite this to be
|
||||
* R = (gn - b)*G + b*G, with a blinding value b determined by the context.
|
||||
*
|
||||
* The multiplication (gn-b)*G will be performed using a signed-digit multi-comb (see Section
|
||||
* 3.3 of "Fast and compact elliptic-curve cryptography" by Mike Hamburg,
|
||||
* https://eprint.iacr.org/2012/309).
|
||||
*
|
||||
* Let comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1), where s[i] is the i'th bit of
|
||||
* the binary representation of scalar s. So the s[i] values determine whether -2^i*P (s[i]=0)
|
||||
* or +2^i*P (s[i]=1) are added together. COMB_BITS is at least 256, so all bits of s are
|
||||
* covered. By manipulating:
|
||||
*
|
||||
* comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1)
|
||||
* <=> comb(s, P) = sum((2*s[i]-1)*2^i for i=0..COMB_BITS-1) * P
|
||||
* <=> comb(s, P) = (2*sum(s[i]*2^i for i=0..COMB_BITS-1) - sum(2^i for i=0..COMB_BITS-1)) * P
|
||||
* <=> comb(s, P) = (2*s - (2^COMB_BITS - 1)) * P
|
||||
*
|
||||
* If we wanted to compute (gn-b)*G as comb(s, G), it would need to hold that
|
||||
*
|
||||
* (gn - b) * G = (2*s - (2^COMB_BITS - 1)) * G
|
||||
* <=> s = (gn - b + (2^COMB_BITS - 1))/2 (mod order)
|
||||
*
|
||||
* We use an alternative here that avoids the modular division by two: instead we compute
|
||||
* (gn-b)*G as comb(d, G/2). For that to hold it must be the case that
|
||||
*
|
||||
* (gn - b) * G = (2*d - (2^COMB_BITS - 1)) * (G/2)
|
||||
* <=> d = gn - b + (2^COMB_BITS - 1)/2 (mod order)
|
||||
*
|
||||
* Adding precomputation, our final equations become:
|
||||
*
|
||||
* ctx->scalar_offset = (2^COMB_BITS - 1)/2 - b (mod order)
|
||||
* ctx->ge_offset = b*G
|
||||
* d = gn + ctx->scalar_offset (mod order)
|
||||
* R = comb(d, G/2) + ctx->ge_offset
|
||||
*
|
||||
* comb(d, G/2) function is then computed by summing + or - 2^(i-1)*G, for i=0..COMB_BITS-1,
|
||||
* depending on the value of the bits d[i] of the binary representation of scalar d.
|
||||
*/
|
||||
|
||||
/* Compute the scalar d = (gn + ctx->scalar_offset). */
|
||||
secp256k1_scalar_add(&d, &ctx->scalar_offset, gn);
|
||||
/* Convert to recoded array. */
|
||||
for (i = 0; i < 8 && i < ((COMB_BITS + 31) >> 5); ++i) {
|
||||
recoded[i] = secp256k1_scalar_get_bits_limb32(&d, 32 * i, 32);
|
||||
}
|
||||
secp256k1_scalar_clear(&d);
|
||||
|
||||
/* In secp256k1_ecmult_gen_prec_table we have precomputed sums of the
|
||||
* (2*d[i]-1) * 2^(i-1) * G points, for various combinations of i positions.
|
||||
* We rewrite our equation in terms of these table entries.
|
||||
*
|
||||
* Let mask(b) = sum(2^((b*COMB_TEETH + t)*COMB_SPACING) for t=0..COMB_TEETH-1),
|
||||
* with b ranging from 0 to COMB_BLOCKS-1. So for example with COMB_BLOCKS=11,
|
||||
* COMB_TEETH=6, COMB_SPACING=4, we would have:
|
||||
* mask(0) = 2^0 + 2^4 + 2^8 + 2^12 + 2^16 + 2^20,
|
||||
* mask(1) = 2^24 + 2^28 + 2^32 + 2^36 + 2^40 + 2^44,
|
||||
* mask(2) = 2^48 + 2^52 + 2^56 + 2^60 + 2^64 + 2^68,
|
||||
* ...
|
||||
* mask(10) = 2^240 + 2^244 + 2^248 + 2^252 + 2^256 + 2^260
|
||||
*
|
||||
* We will split up the bits d[i] using these masks. Specifically, each mask is
|
||||
* used COMB_SPACING times, with different shifts:
|
||||
*
|
||||
* d = (d & mask(0)<<0) + (d & mask(1)<<0) + ... + (d & mask(COMB_BLOCKS-1)<<0) +
|
||||
* (d & mask(0)<<1) + (d & mask(1)<<1) + ... + (d & mask(COMB_BLOCKS-1)<<1) +
|
||||
* ...
|
||||
* (d & mask(0)<<(COMB_SPACING-1)) + ...
|
||||
*
|
||||
* Now define table(b, m) = (m - mask(b)/2) * G, and we will precompute these values for
|
||||
* b=0..COMB_BLOCKS-1, and for all values m which (d & mask(b)) can take (so m can take on
|
||||
* 2^COMB_TEETH distinct values).
|
||||
*
|
||||
* If m=(d & mask(b)), then table(b, m) is the sum of 2^i * (2*d[i]-1) * G/2, with i
|
||||
* iterating over the set bits in mask(b). In our example, table(2, 2^48 + 2^56 + 2^68)
|
||||
* would equal (2^48 - 2^52 + 2^56 - 2^60 - 2^64 + 2^68) * G/2.
|
||||
*
|
||||
* With that, we can rewrite comb(d, G/2) as:
|
||||
*
|
||||
* 2^0 * (table(0, d>>0 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>0 & mask(COMP_BLOCKS-1)))
|
||||
* + 2^1 * (table(0, d>>1 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>1 & mask(COMP_BLOCKS-1)))
|
||||
* + 2^2 * (table(0, d>>2 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>2 & mask(COMP_BLOCKS-1)))
|
||||
* + ...
|
||||
* + 2^(COMB_SPACING-1) * (table(0, d>>(COMB_SPACING-1) & mask(0)) + ...)
|
||||
*
|
||||
* Or more generically as
|
||||
*
|
||||
* sum(2^i * sum(table(b, d>>i & mask(b)), b=0..COMB_BLOCKS-1), i=0..COMB_SPACING-1)
|
||||
*
|
||||
* This is implemented using an outer loop that runs in reverse order over the lines of this
|
||||
* equation, which in each iteration runs an inner loop that adds the terms of that line and
|
||||
* then doubles the result before proceeding to the next line.
|
||||
*
|
||||
* In pseudocode:
|
||||
* c = infinity
|
||||
* for comb_off in range(COMB_SPACING - 1, -1, -1):
|
||||
* for block in range(COMB_BLOCKS):
|
||||
* c += table(block, (d >> comb_off) & mask(block))
|
||||
* if comb_off > 0:
|
||||
* c = 2*c
|
||||
* return c
|
||||
*
|
||||
* This computes c = comb(d, G/2), and thus finally R = c + ctx->ge_offset. Note that it would
|
||||
* be possible to apply an initial offset instead of a final offset (moving ge_offset to take
|
||||
* the place of infinity above), but the chosen approach allows using (in a future improvement)
|
||||
* an incomplete addition formula for most of the multiplication.
|
||||
*
|
||||
* The last question is how to implement the table(b, m) function. For any value of b,
|
||||
* m=(d & mask(b)) can only take on at most 2^COMB_TEETH possible values (the last one may have
|
||||
* fewer as there mask(b) may exceed the curve order). So we could create COMB_BLOCK tables
|
||||
* which contain a value for each such m value.
|
||||
*
|
||||
* Now note that if m=(d & mask(b)), then flipping the relevant bits of m results in negating
|
||||
* the result of table(b, m). This is because table(b,m XOR mask(b)) = table(b, mask(b) - m) =
|
||||
* (mask(b) - m - mask(b)/2)*G = (-m + mask(b)/2)*G = -(m - mask(b)/2)*G = -table(b, m).
|
||||
* Because of this it suffices to only store the first half of the m values for every b. If an
|
||||
* entry from the second half is needed, we look up its bit-flipped version instead, and negate
|
||||
* it.
|
||||
*
|
||||
* secp256k1_ecmult_gen_prec_table[b][index] stores the table(b, m) entries. Index
|
||||
* is the relevant mask(b) bits of m packed together without gaps. */
|
||||
|
||||
/* Outer loop: iterate over comb_off from COMB_SPACING - 1 down to 0. */
|
||||
comb_off = COMB_SPACING - 1;
|
||||
while (1) {
|
||||
uint32_t block;
|
||||
uint32_t bit_pos = comb_off;
|
||||
/* Inner loop: for each block, add table entries to the result. */
|
||||
for (block = 0; block < COMB_BLOCKS; ++block) {
|
||||
/* Gather the mask(block)-selected bits of d into bits. They're packed:
|
||||
* bits[tooth] = d[(block*COMB_TEETH + tooth)*COMB_SPACING + comb_off]. */
|
||||
uint32_t bits = 0, sign, abs, index, tooth;
|
||||
/* Instead of reading individual bits here to construct the bits variable,
|
||||
* build up the result by xoring rotated reads together. In every iteration,
|
||||
* one additional bit is made correct, starting at the bottom. The bits
|
||||
* above that contain junk. This reduces leakage by avoiding computations
|
||||
* on variables that can have only a low number of possible values (e.g.,
|
||||
* just two values when reading a single bit into a variable.) See:
|
||||
* https://www.usenix.org/system/files/conference/usenixsecurity18/sec18-alam.pdf
|
||||
*/
|
||||
for (tooth = 0; tooth < COMB_TEETH; ++tooth) {
|
||||
/* Construct bitdata s.t. the bottom bit is the bit we'd like to read.
|
||||
*
|
||||
* We could just set bitdata = recoded[bit_pos >> 5] >> (bit_pos & 0x1f)
|
||||
* but this would simply discard the bits that fall off at the bottom,
|
||||
* and thus, for example, bitdata could still have only two values if we
|
||||
* happen to shift by exactly 31 positions. We use a rotation instead,
|
||||
* which ensures that bitdata doesn't loose entropy. This relies on the
|
||||
* rotation being atomic, i.e., the compiler emitting an actual rot
|
||||
* instruction. */
|
||||
uint32_t bitdata = secp256k1_rotr32(recoded[bit_pos >> 5], bit_pos & 0x1f);
|
||||
|
||||
/* Clear the bit at position tooth, but sssh, don't tell clang. */
|
||||
uint32_t volatile vmask = ~(1 << tooth);
|
||||
bits &= vmask;
|
||||
|
||||
/* Write the bit into position tooth (and junk into higher bits). */
|
||||
bits ^= bitdata << tooth;
|
||||
bit_pos += COMB_SPACING;
|
||||
}
|
||||
|
||||
/* If the top bit of bits is 1, flip them all (corresponding to looking up
|
||||
* the negated table value), and remember to negate the result in sign. */
|
||||
sign = (bits >> (COMB_TEETH - 1)) & 1;
|
||||
abs = (bits ^ -sign) & (COMB_POINTS - 1);
|
||||
VERIFY_CHECK(sign == 0 || sign == 1);
|
||||
VERIFY_CHECK(abs < COMB_POINTS);
|
||||
|
||||
/** This uses a conditional move to avoid any secret data in array indexes.
|
||||
* _Any_ use of secret indexes has been demonstrated to result in timing
|
||||
* sidechannels, even when the cache-line access patterns are uniform.
|
||||
@@ -70,34 +244,65 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
|
||||
* by Dag Arne Osvik, Adi Shamir, and Eran Tromer
|
||||
* (https://www.tau.ac.il/~tromer/papers/cache.pdf)
|
||||
*/
|
||||
secp256k1_ge_storage_cmov(&adds, &secp256k1_ecmult_gen_prec_table[i][j], j == n_i);
|
||||
for (index = 0; index < COMB_POINTS; ++index) {
|
||||
secp256k1_ge_storage_cmov(&adds, &secp256k1_ecmult_gen_prec_table[block][index], index == abs);
|
||||
}
|
||||
|
||||
/* Set add=adds or add=-adds, in constant time, based on sign. */
|
||||
secp256k1_ge_from_storage(&add, &adds);
|
||||
secp256k1_fe_negate(&neg, &add.y, 1);
|
||||
secp256k1_fe_cmov(&add.y, &neg, sign);
|
||||
|
||||
/* Add the looked up and conditionally negated value to r. */
|
||||
if (EXPECT(first, 0)) {
|
||||
/* If this is the first table lookup, we can skip addition. */
|
||||
secp256k1_gej_set_ge(r, &add);
|
||||
/* Give the entry a random Z coordinate to blind intermediary results. */
|
||||
secp256k1_gej_rescale(r, &ctx->proj_blind);
|
||||
first = 0;
|
||||
} else {
|
||||
secp256k1_gej_add_ge(r, r, &add);
|
||||
}
|
||||
}
|
||||
secp256k1_ge_from_storage(&add, &adds);
|
||||
secp256k1_gej_add_ge(r, r, &add);
|
||||
|
||||
/* Double the result, except in the last iteration. */
|
||||
if (comb_off-- == 0) break;
|
||||
secp256k1_gej_double(r, r);
|
||||
}
|
||||
n_i = 0;
|
||||
|
||||
/* Correct for the scalar_offset added at the start (ge_offset = b*G, while b was
|
||||
* subtracted from the input scalar gn). */
|
||||
secp256k1_gej_add_ge(r, r, &ctx->ge_offset);
|
||||
|
||||
/* Cleanup. */
|
||||
secp256k1_fe_clear(&neg);
|
||||
secp256k1_ge_clear(&add);
|
||||
secp256k1_scalar_clear(&gnb);
|
||||
secp256k1_memclear(&adds, sizeof(adds));
|
||||
secp256k1_memclear(&recoded, sizeof(recoded));
|
||||
}
|
||||
|
||||
/* Setup blinding values for secp256k1_ecmult_gen. */
|
||||
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) {
|
||||
secp256k1_scalar b;
|
||||
secp256k1_scalar diff;
|
||||
secp256k1_gej gb;
|
||||
secp256k1_fe s;
|
||||
secp256k1_fe f;
|
||||
unsigned char nonce32[32];
|
||||
secp256k1_rfc6979_hmac_sha256 rng;
|
||||
int overflow;
|
||||
unsigned char keydata[64];
|
||||
|
||||
/* Compute the (2^COMB_BITS - 1)/2 term once. */
|
||||
secp256k1_ecmult_gen_scalar_diff(&diff);
|
||||
|
||||
if (seed32 == NULL) {
|
||||
/* When seed is NULL, reset the initial point and blinding value. */
|
||||
secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g);
|
||||
secp256k1_gej_neg(&ctx->initial, &ctx->initial);
|
||||
secp256k1_scalar_set_int(&ctx->blind, 1);
|
||||
/* When seed is NULL, reset the final point and blinding value. */
|
||||
secp256k1_ge_neg(&ctx->ge_offset, &secp256k1_ge_const_g);
|
||||
secp256k1_scalar_add(&ctx->scalar_offset, &secp256k1_scalar_one, &diff);
|
||||
ctx->proj_blind = secp256k1_fe_one;
|
||||
return;
|
||||
}
|
||||
/* The prior blinding value (if not reset) is chained forward by including it in the hash. */
|
||||
secp256k1_scalar_get_b32(keydata, &ctx->blind);
|
||||
secp256k1_scalar_get_b32(keydata, &ctx->scalar_offset);
|
||||
/** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data,
|
||||
* and guards against weak or adversarial seeds. This is a simpler and safer interface than
|
||||
* asking the caller for blinding values directly and expecting them to retry on failure.
|
||||
@@ -105,29 +310,32 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
|
||||
VERIFY_CHECK(seed32 != NULL);
|
||||
memcpy(keydata + 32, seed32, 32);
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64);
|
||||
memset(keydata, 0, sizeof(keydata));
|
||||
/* Accept unobservably small non-uniformity. */
|
||||
secp256k1_memclear(keydata, sizeof(keydata));
|
||||
|
||||
/* Compute projective blinding factor (cannot be 0). */
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||
overflow = !secp256k1_fe_set_b32_limit(&s, nonce32);
|
||||
overflow |= secp256k1_fe_is_zero(&s);
|
||||
secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow);
|
||||
/* Randomize the projection to defend against multiplier sidechannels.
|
||||
Do this before our own call to secp256k1_ecmult_gen below. */
|
||||
secp256k1_gej_rescale(&ctx->initial, &s);
|
||||
secp256k1_fe_clear(&s);
|
||||
secp256k1_fe_set_b32_mod(&f, nonce32);
|
||||
secp256k1_fe_cmov(&f, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&f));
|
||||
ctx->proj_blind = f;
|
||||
|
||||
/* For a random blinding value b, set scalar_offset=diff-b, ge_offset=bG */
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||
secp256k1_scalar_set_b32(&b, nonce32, NULL);
|
||||
/* A blinding value of 0 works, but would undermine the projection hardening. */
|
||||
/* The blinding value cannot be zero, as that would mean ge_offset = infinity,
|
||||
* which secp256k1_gej_add_ge cannot handle. */
|
||||
secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b));
|
||||
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
||||
memset(nonce32, 0, 32);
|
||||
/* The random projection in ctx->initial ensures that gb will have a random projection. */
|
||||
secp256k1_ecmult_gen(ctx, &gb, &b);
|
||||
secp256k1_scalar_negate(&b, &b);
|
||||
ctx->blind = b;
|
||||
ctx->initial = gb;
|
||||
secp256k1_scalar_add(&ctx->scalar_offset, &b, &diff);
|
||||
secp256k1_ge_set_gej(&ctx->ge_offset, &gb);
|
||||
|
||||
/* Clean up. */
|
||||
secp256k1_memclear(nonce32, sizeof(nonce32));
|
||||
secp256k1_scalar_clear(&b);
|
||||
secp256k1_gej_clear(&gb);
|
||||
secp256k1_fe_clear(&f);
|
||||
secp256k1_rfc6979_hmac_sha256_clear(&rng);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_ECMULT_GEN_IMPL_H */
|
||||
|
||||
42
external/secp256k1/src/ecmult_impl.h
vendored
42
external/secp256k1/src/ecmult_impl.h
vendored
@@ -42,7 +42,7 @@
|
||||
#endif
|
||||
|
||||
#define WNAF_BITS 128
|
||||
#define WNAF_SIZE_BITS(bits, w) (((bits) + (w) - 1) / (w))
|
||||
#define WNAF_SIZE_BITS(bits, w) CEIL_DIV(bits, w)
|
||||
#define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w)
|
||||
|
||||
/* The number of objects allocated on the scratch space for ecmult_multi algorithms */
|
||||
@@ -171,18 +171,21 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
|
||||
VERIFY_CHECK(a != NULL);
|
||||
VERIFY_CHECK(2 <= w && w <= 31);
|
||||
|
||||
memset(wnaf, 0, len * sizeof(wnaf[0]));
|
||||
for (bit = 0; bit < len; bit++) {
|
||||
wnaf[bit] = 0;
|
||||
}
|
||||
|
||||
s = *a;
|
||||
if (secp256k1_scalar_get_bits(&s, 255, 1)) {
|
||||
if (secp256k1_scalar_get_bits_limb32(&s, 255, 1)) {
|
||||
secp256k1_scalar_negate(&s, &s);
|
||||
sign = -1;
|
||||
}
|
||||
|
||||
bit = 0;
|
||||
while (bit < len) {
|
||||
int now;
|
||||
int word;
|
||||
if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) {
|
||||
if (secp256k1_scalar_get_bits_limb32(&s, bit, 1) == (unsigned int)carry) {
|
||||
bit++;
|
||||
continue;
|
||||
}
|
||||
@@ -209,7 +212,7 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
|
||||
VERIFY_CHECK(carry == 0);
|
||||
|
||||
while (verify_bit < 256) {
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits(&s, verify_bit, 1) == 0);
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&s, verify_bit, 1) == 0);
|
||||
verify_bit++;
|
||||
}
|
||||
}
|
||||
@@ -288,7 +291,9 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
|
||||
}
|
||||
|
||||
/* Bring them to the same Z denominator. */
|
||||
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux);
|
||||
if (no) {
|
||||
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux);
|
||||
}
|
||||
|
||||
for (np = 0; np < no; ++np) {
|
||||
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||
@@ -658,7 +663,6 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_call
|
||||
struct secp256k1_pippenger_state *state_space;
|
||||
size_t idx = 0;
|
||||
size_t point_idx = 0;
|
||||
int i, j;
|
||||
int bucket_window;
|
||||
|
||||
secp256k1_gej_set_infinity(r);
|
||||
@@ -706,18 +710,6 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_call
|
||||
}
|
||||
|
||||
secp256k1_ecmult_pippenger_wnaf(buckets, bucket_window, state_space, r, scalars, points, idx);
|
||||
|
||||
/* Clear data */
|
||||
for(i = 0; (size_t)i < idx; i++) {
|
||||
secp256k1_scalar_clear(&scalars[i]);
|
||||
state_space->ps[i].skew_na = 0;
|
||||
for(j = 0; j < WNAF_SIZE(bucket_window+1); j++) {
|
||||
state_space->wnaf_na[i * WNAF_SIZE(bucket_window+1) + j] = 0;
|
||||
}
|
||||
}
|
||||
for(i = 0; i < 1<<bucket_window; i++) {
|
||||
secp256k1_gej_clear(&buckets[i]);
|
||||
}
|
||||
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
|
||||
return 1;
|
||||
}
|
||||
@@ -770,14 +762,12 @@ static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_cal
|
||||
* require a scratch space */
|
||||
static int secp256k1_ecmult_multi_simple_var(secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) {
|
||||
size_t point_idx;
|
||||
secp256k1_scalar szero;
|
||||
secp256k1_gej tmpj;
|
||||
|
||||
secp256k1_scalar_set_int(&szero, 0);
|
||||
secp256k1_gej_set_infinity(r);
|
||||
secp256k1_gej_set_infinity(&tmpj);
|
||||
/* r = inp_g_sc*G */
|
||||
secp256k1_ecmult(r, &tmpj, &szero, inp_g_sc);
|
||||
secp256k1_ecmult(r, &tmpj, &secp256k1_scalar_zero, inp_g_sc);
|
||||
for (point_idx = 0; point_idx < n_points; point_idx++) {
|
||||
secp256k1_ge point;
|
||||
secp256k1_gej pointj;
|
||||
@@ -808,8 +798,8 @@ static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n
|
||||
return 1;
|
||||
}
|
||||
/* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */
|
||||
*n_batches = 1 + (n - 1) / max_n_batch_points;
|
||||
*n_batch_points = 1 + (n - 1) / *n_batches;
|
||||
*n_batches = CEIL_DIV(n, max_n_batch_points);
|
||||
*n_batch_points = CEIL_DIV(n, *n_batches);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -825,9 +815,7 @@ static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback,
|
||||
if (inp_g_sc == NULL && n == 0) {
|
||||
return 1;
|
||||
} else if (n == 0) {
|
||||
secp256k1_scalar szero;
|
||||
secp256k1_scalar_set_int(&szero, 0);
|
||||
secp256k1_ecmult(r, r, &szero, inp_g_sc);
|
||||
secp256k1_ecmult(r, r, &secp256k1_scalar_zero, inp_g_sc);
|
||||
return 1;
|
||||
}
|
||||
if (scratch == NULL) {
|
||||
|
||||
65
external/secp256k1/src/field.h
vendored
65
external/secp256k1/src/field.h
vendored
@@ -81,15 +81,14 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST(
|
||||
# define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero
|
||||
# define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var
|
||||
# define secp256k1_fe_set_int secp256k1_fe_impl_set_int
|
||||
# define secp256k1_fe_clear secp256k1_fe_impl_clear
|
||||
# define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero
|
||||
# define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd
|
||||
# define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var
|
||||
# define secp256k1_fe_set_b32_mod secp256k1_fe_impl_set_b32_mod
|
||||
# define secp256k1_fe_set_b32_limit secp256k1_fe_impl_set_b32_limit
|
||||
# define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32
|
||||
# define secp256k1_fe_negate secp256k1_fe_impl_negate
|
||||
# define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int
|
||||
# define secp256k1_fe_negate_unchecked secp256k1_fe_impl_negate_unchecked
|
||||
# define secp256k1_fe_mul_int_unchecked secp256k1_fe_impl_mul_int_unchecked
|
||||
# define secp256k1_fe_add secp256k1_fe_impl_add
|
||||
# define secp256k1_fe_mul secp256k1_fe_impl_mul
|
||||
# define secp256k1_fe_sqr secp256k1_fe_impl_sqr
|
||||
@@ -144,11 +143,7 @@ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r);
|
||||
*/
|
||||
static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
|
||||
|
||||
/** Set a field element to 0.
|
||||
*
|
||||
* On input, a does not need to be initialized.
|
||||
* On output, a represents 0, is normalized and has magnitude 0.
|
||||
*/
|
||||
/** Clear a field element to prevent leaking sensitive information. */
|
||||
static void secp256k1_fe_clear(secp256k1_fe *a);
|
||||
|
||||
/** Determine whether a represents field element 0.
|
||||
@@ -176,12 +171,6 @@ static int secp256k1_fe_is_odd(const secp256k1_fe *a);
|
||||
*/
|
||||
static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
|
||||
/** Determine whether two field elements are equal, without constant-time guarantee.
|
||||
*
|
||||
* Identical in behavior to secp256k1_fe_equal, but not constant time in either a or b.
|
||||
*/
|
||||
static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
|
||||
/** Compare the values represented by 2 field elements, without constant-time guarantee.
|
||||
*
|
||||
* On input, a and b must be valid normalized field elements.
|
||||
@@ -190,16 +179,17 @@ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
*/
|
||||
static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
|
||||
/** Set a field element equal to a provided 32-byte big endian value, reducing it.
|
||||
/** Set a field element equal to the element represented by a provided 32-byte big endian value
|
||||
* interpreted modulo p.
|
||||
*
|
||||
* On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array.
|
||||
* On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array.
|
||||
* On output, r = a (mod p). It will have magnitude 1, and not be normalized.
|
||||
*/
|
||||
static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
|
||||
|
||||
/** Set a field element equal to a provided 32-byte big endian value, checking for overflow.
|
||||
*
|
||||
* On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array.
|
||||
* On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array.
|
||||
* On output, r = a if (a < p), it will be normalized with magnitude 1, and 1 is returned.
|
||||
* If a >= p, 0 is returned, and r will be made invalid (and must not be used without overwriting).
|
||||
*/
|
||||
@@ -214,27 +204,39 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a);
|
||||
/** Negate a field element.
|
||||
*
|
||||
* On input, r does not need to be initialized. a must be a valid field element with
|
||||
* magnitude not exceeding m. m must be an integer in [0,31].
|
||||
* magnitude not exceeding m. m must be an integer constant expression in [0,31].
|
||||
* Performs {r = -a}.
|
||||
* On output, r will not be normalized, and will have magnitude m+1.
|
||||
*/
|
||||
static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
|
||||
#define secp256k1_fe_negate(r, a, m) ASSERT_INT_CONST_AND_DO(m, secp256k1_fe_negate_unchecked(r, a, m))
|
||||
|
||||
/** Like secp256k1_fe_negate_unchecked but m is not checked to be an integer constant expression.
|
||||
*
|
||||
* Should not be called directly outside of tests.
|
||||
*/
|
||||
static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m);
|
||||
|
||||
/** Add a small integer to a field element.
|
||||
*
|
||||
* Performs {r += a}. The magnitude of r increases by 1, and normalized is cleared.
|
||||
* a must be in range [0,0xFFFF].
|
||||
* a must be in range [0,0x7FFF].
|
||||
*/
|
||||
static void secp256k1_fe_add_int(secp256k1_fe *r, int a);
|
||||
|
||||
/** Multiply a field element with a small integer.
|
||||
*
|
||||
* On input, r must be a valid field element. a must be an integer in [0,32].
|
||||
* On input, r must be a valid field element. a must be an integer constant expression in [0,32].
|
||||
* The magnitude of r times a must not exceed 32.
|
||||
* Performs {r *= a}.
|
||||
* On output, r's magnitude is multiplied by a, and r will not be normalized.
|
||||
*/
|
||||
static void secp256k1_fe_mul_int(secp256k1_fe *r, int a);
|
||||
#define secp256k1_fe_mul_int(r, a) ASSERT_INT_CONST_AND_DO(a, secp256k1_fe_mul_int_unchecked(r, a))
|
||||
|
||||
/** Like secp256k1_fe_mul_int but a is not checked to be an integer constant expression.
|
||||
*
|
||||
* Should not be called directly outside of tests.
|
||||
*/
|
||||
static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a);
|
||||
|
||||
/** Increment a field element by another.
|
||||
*
|
||||
@@ -248,8 +250,8 @@ static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
/** Multiply two field elements.
|
||||
*
|
||||
* On input, a and b must be valid field elements; r does not need to be initialized.
|
||||
* r and a may point to the same object, but neither can be equal to b. The magnitudes
|
||||
* of a and b must not exceed 8.
|
||||
* r and a may point to the same object, but neither may point to the object pointed
|
||||
* to by b. The magnitudes of a and b must not exceed 8.
|
||||
* Performs {r = a * b}
|
||||
* On output, r will have magnitude 1, but won't be normalized.
|
||||
*/
|
||||
@@ -267,8 +269,10 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
/** Compute a square root of a field element.
|
||||
*
|
||||
* On input, a must be a valid field element with magnitude<=8; r need not be initialized.
|
||||
* Performs {r = sqrt(a)} or {r = sqrt(-a)}, whichever exists. The resulting value
|
||||
* represented by r will be a square itself. Variables r and a must not point to the same object.
|
||||
* If sqrt(a) exists, performs {r = sqrt(a)} and returns 1.
|
||||
* Otherwise, sqrt(-a) exists. The function performs {r = sqrt(-a)} and returns 0.
|
||||
* The resulting value represented by r will be a square itself.
|
||||
* Variables r and a must not point to the same object.
|
||||
* On output, r will have magnitude 1 but will not be normalized.
|
||||
*/
|
||||
static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a);
|
||||
@@ -310,7 +314,9 @@ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_f
|
||||
*
|
||||
* On input, both r and a must be valid field elements. Flag must be 0 or 1.
|
||||
* Performs {r = flag ? a : r}.
|
||||
* On output, r's magnitude and normalized will equal a's in case of flag=1, unchanged otherwise.
|
||||
*
|
||||
* On output, r's magnitude will be the maximum of both input magnitudes.
|
||||
* It will be normalized if and only if both inputs were normalized.
|
||||
*/
|
||||
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
|
||||
|
||||
@@ -335,5 +341,10 @@ static int secp256k1_fe_is_square_var(const secp256k1_fe *a);
|
||||
|
||||
/** Check invariants on a field element (no-op unless VERIFY is enabled). */
|
||||
static void secp256k1_fe_verify(const secp256k1_fe *a);
|
||||
#define SECP256K1_FE_VERIFY(a) secp256k1_fe_verify(a)
|
||||
|
||||
/** Check that magnitude of a is at most m (no-op unless VERIFY is enabled). */
|
||||
static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m);
|
||||
#define SECP256K1_FE_VERIFY_MAGNITUDE(a, m) secp256k1_fe_verify_magnitude(a, m)
|
||||
|
||||
#endif /* SECP256K1_FIELD_H */
|
||||
|
||||
15
external/secp256k1/src/field_10x26_impl.h
vendored
15
external/secp256k1/src/field_10x26_impl.h
vendored
@@ -270,13 +270,6 @@ SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) {
|
||||
return a->n[0] & 1;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) {
|
||||
int i;
|
||||
for (i=0; i<10; i++) {
|
||||
a->n[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
int i;
|
||||
for (i = 9; i >= 0; i--) {
|
||||
@@ -344,7 +337,7 @@ static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
|
||||
r[31] = a->n[0] & 0xff;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
/* For all legal values of m (0..31), the following properties hold: */
|
||||
VERIFY_CHECK(0x3FFFC2FUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
|
||||
VERIFY_CHECK(0x3FFFFBFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
|
||||
@@ -365,7 +358,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const sec
|
||||
r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9];
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) {
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) {
|
||||
r->n[0] *= a;
|
||||
r->n[1] *= a;
|
||||
r->n[2] *= a;
|
||||
@@ -403,11 +396,7 @@ void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a);
|
||||
|
||||
#else
|
||||
|
||||
#ifdef VERIFY
|
||||
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
|
||||
#else
|
||||
#define VERIFY_BITS(x, n) do { } while(0)
|
||||
#endif
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) {
|
||||
uint64_t c, d;
|
||||
|
||||
504
external/secp256k1/src/field_5x52_asm_impl.h
vendored
504
external/secp256k1/src/field_5x52_asm_impl.h
vendored
@@ -1,504 +0,0 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
/**
|
||||
* Changelog:
|
||||
* - March 2013, Diederik Huys: original version
|
||||
* - November 2014, Pieter Wuille: updated to use Peter Dettman's parallel multiplication algorithm
|
||||
* - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly
|
||||
*/
|
||||
|
||||
#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
|
||||
#define SECP256K1_FIELD_INNER5X52_IMPL_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
|
||||
/**
|
||||
* Registers: rdx:rax = multiplication accumulator
|
||||
* r9:r8 = c
|
||||
* r15:rcx = d
|
||||
* r10-r14 = a0-a4
|
||||
* rbx = b
|
||||
* rdi = r
|
||||
* rsi = a / t?
|
||||
*/
|
||||
uint64_t tmp1, tmp2, tmp3;
|
||||
__asm__ __volatile__(
|
||||
"movq 0(%%rsi),%%r10\n"
|
||||
"movq 8(%%rsi),%%r11\n"
|
||||
"movq 16(%%rsi),%%r12\n"
|
||||
"movq 24(%%rsi),%%r13\n"
|
||||
"movq 32(%%rsi),%%r14\n"
|
||||
|
||||
/* d += a3 * b0 */
|
||||
"movq 0(%%rbx),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"movq %%rax,%%rcx\n"
|
||||
"movq %%rdx,%%r15\n"
|
||||
/* d += a2 * b1 */
|
||||
"movq 8(%%rbx),%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a1 * b2 */
|
||||
"movq 16(%%rbx),%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d = a0 * b3 */
|
||||
"movq 24(%%rbx),%%rax\n"
|
||||
"mulq %%r10\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* c = a4 * b4 */
|
||||
"movq 32(%%rbx),%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"movq %%rax,%%r8\n"
|
||||
"movq %%rdx,%%r9\n"
|
||||
/* d += (c & M) * R */
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* c >>= 52 (%%r8 only) */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
/* t3 (tmp1) = d & M */
|
||||
"movq %%rcx,%%rsi\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rsi\n"
|
||||
"movq %%rsi,%q1\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%r15,%%rcx\n"
|
||||
"xorq %%r15,%%r15\n"
|
||||
/* d += a4 * b0 */
|
||||
"movq 0(%%rbx),%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a3 * b1 */
|
||||
"movq 8(%%rbx),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a2 * b2 */
|
||||
"movq 16(%%rbx),%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a1 * b3 */
|
||||
"movq 24(%%rbx),%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a0 * b4 */
|
||||
"movq 32(%%rbx),%%rax\n"
|
||||
"mulq %%r10\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += c * R */
|
||||
"movq %%r8,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* t4 = d & M (%%rsi) */
|
||||
"movq %%rcx,%%rsi\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rsi\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%r15,%%rcx\n"
|
||||
"xorq %%r15,%%r15\n"
|
||||
/* tx = t4 >> 48 (tmp3) */
|
||||
"movq %%rsi,%%rax\n"
|
||||
"shrq $48,%%rax\n"
|
||||
"movq %%rax,%q3\n"
|
||||
/* t4 &= (M >> 4) (tmp2) */
|
||||
"movq $0xffffffffffff,%%rax\n"
|
||||
"andq %%rax,%%rsi\n"
|
||||
"movq %%rsi,%q2\n"
|
||||
/* c = a0 * b0 */
|
||||
"movq 0(%%rbx),%%rax\n"
|
||||
"mulq %%r10\n"
|
||||
"movq %%rax,%%r8\n"
|
||||
"movq %%rdx,%%r9\n"
|
||||
/* d += a4 * b1 */
|
||||
"movq 8(%%rbx),%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a3 * b2 */
|
||||
"movq 16(%%rbx),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a2 * b3 */
|
||||
"movq 24(%%rbx),%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a1 * b4 */
|
||||
"movq 32(%%rbx),%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* u0 = d & M (%%rsi) */
|
||||
"movq %%rcx,%%rsi\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rsi\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%r15,%%rcx\n"
|
||||
"xorq %%r15,%%r15\n"
|
||||
/* u0 = (u0 << 4) | tx (%%rsi) */
|
||||
"shlq $4,%%rsi\n"
|
||||
"movq %q3,%%rax\n"
|
||||
"orq %%rax,%%rsi\n"
|
||||
/* c += u0 * (R >> 4) */
|
||||
"movq $0x1000003d1,%%rax\n"
|
||||
"mulq %%rsi\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* r[0] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq %%rax,0(%%rdi)\n"
|
||||
/* c >>= 52 */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
"xorq %%r9,%%r9\n"
|
||||
/* c += a1 * b0 */
|
||||
"movq 0(%%rbx),%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* c += a0 * b1 */
|
||||
"movq 8(%%rbx),%%rax\n"
|
||||
"mulq %%r10\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d += a4 * b2 */
|
||||
"movq 16(%%rbx),%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a3 * b3 */
|
||||
"movq 24(%%rbx),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a2 * b4 */
|
||||
"movq 32(%%rbx),%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* c += (d & M) * R */
|
||||
"movq %%rcx,%%rax\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%r15,%%rcx\n"
|
||||
"xorq %%r15,%%r15\n"
|
||||
/* r[1] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq %%rax,8(%%rdi)\n"
|
||||
/* c >>= 52 */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
"xorq %%r9,%%r9\n"
|
||||
/* c += a2 * b0 */
|
||||
"movq 0(%%rbx),%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* c += a1 * b1 */
|
||||
"movq 8(%%rbx),%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* c += a0 * b2 (last use of %%r10 = a0) */
|
||||
"movq 16(%%rbx),%%rax\n"
|
||||
"mulq %%r10\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* fetch t3 (%%r10, overwrites a0), t4 (%%rsi) */
|
||||
"movq %q2,%%rsi\n"
|
||||
"movq %q1,%%r10\n"
|
||||
/* d += a4 * b3 */
|
||||
"movq 24(%%rbx),%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a3 * b4 */
|
||||
"movq 32(%%rbx),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* c += (d & M) * R */
|
||||
"movq %%rcx,%%rax\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d >>= 52 (%%rcx only) */
|
||||
"shrdq $52,%%r15,%%rcx\n"
|
||||
/* r[2] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq %%rax,16(%%rdi)\n"
|
||||
/* c >>= 52 */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
"xorq %%r9,%%r9\n"
|
||||
/* c += t3 */
|
||||
"addq %%r10,%%r8\n"
|
||||
/* c += d * R */
|
||||
"movq %%rcx,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* r[3] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq %%rax,24(%%rdi)\n"
|
||||
/* c >>= 52 (%%r8 only) */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
/* c += t4 (%%r8 only) */
|
||||
"addq %%rsi,%%r8\n"
|
||||
/* r[4] = c */
|
||||
"movq %%r8,32(%%rdi)\n"
|
||||
: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3)
|
||||
: "b"(b), "D"(r)
|
||||
: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) {
|
||||
/**
|
||||
* Registers: rdx:rax = multiplication accumulator
|
||||
* r9:r8 = c
|
||||
* rcx:rbx = d
|
||||
* r10-r14 = a0-a4
|
||||
* r15 = M (0xfffffffffffff)
|
||||
* rdi = r
|
||||
* rsi = a / t?
|
||||
*/
|
||||
uint64_t tmp1, tmp2, tmp3;
|
||||
__asm__ __volatile__(
|
||||
"movq 0(%%rsi),%%r10\n"
|
||||
"movq 8(%%rsi),%%r11\n"
|
||||
"movq 16(%%rsi),%%r12\n"
|
||||
"movq 24(%%rsi),%%r13\n"
|
||||
"movq 32(%%rsi),%%r14\n"
|
||||
"movq $0xfffffffffffff,%%r15\n"
|
||||
|
||||
/* d = (a0*2) * a3 */
|
||||
"leaq (%%r10,%%r10,1),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"movq %%rax,%%rbx\n"
|
||||
"movq %%rdx,%%rcx\n"
|
||||
/* d += (a1*2) * a2 */
|
||||
"leaq (%%r11,%%r11,1),%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* c = a4 * a4 */
|
||||
"movq %%r14,%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"movq %%rax,%%r8\n"
|
||||
"movq %%rdx,%%r9\n"
|
||||
/* d += (c & M) * R */
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* c >>= 52 (%%r8 only) */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
/* t3 (tmp1) = d & M */
|
||||
"movq %%rbx,%%rsi\n"
|
||||
"andq %%r15,%%rsi\n"
|
||||
"movq %%rsi,%q1\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%rcx,%%rbx\n"
|
||||
"xorq %%rcx,%%rcx\n"
|
||||
/* a4 *= 2 */
|
||||
"addq %%r14,%%r14\n"
|
||||
/* d += a0 * a4 */
|
||||
"movq %%r10,%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* d+= (a1*2) * a3 */
|
||||
"leaq (%%r11,%%r11,1),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* d += a2 * a2 */
|
||||
"movq %%r12,%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* d += c * R */
|
||||
"movq %%r8,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* t4 = d & M (%%rsi) */
|
||||
"movq %%rbx,%%rsi\n"
|
||||
"andq %%r15,%%rsi\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%rcx,%%rbx\n"
|
||||
"xorq %%rcx,%%rcx\n"
|
||||
/* tx = t4 >> 48 (tmp3) */
|
||||
"movq %%rsi,%%rax\n"
|
||||
"shrq $48,%%rax\n"
|
||||
"movq %%rax,%q3\n"
|
||||
/* t4 &= (M >> 4) (tmp2) */
|
||||
"movq $0xffffffffffff,%%rax\n"
|
||||
"andq %%rax,%%rsi\n"
|
||||
"movq %%rsi,%q2\n"
|
||||
/* c = a0 * a0 */
|
||||
"movq %%r10,%%rax\n"
|
||||
"mulq %%r10\n"
|
||||
"movq %%rax,%%r8\n"
|
||||
"movq %%rdx,%%r9\n"
|
||||
/* d += a1 * a4 */
|
||||
"movq %%r11,%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* d += (a2*2) * a3 */
|
||||
"leaq (%%r12,%%r12,1),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* u0 = d & M (%%rsi) */
|
||||
"movq %%rbx,%%rsi\n"
|
||||
"andq %%r15,%%rsi\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%rcx,%%rbx\n"
|
||||
"xorq %%rcx,%%rcx\n"
|
||||
/* u0 = (u0 << 4) | tx (%%rsi) */
|
||||
"shlq $4,%%rsi\n"
|
||||
"movq %q3,%%rax\n"
|
||||
"orq %%rax,%%rsi\n"
|
||||
/* c += u0 * (R >> 4) */
|
||||
"movq $0x1000003d1,%%rax\n"
|
||||
"mulq %%rsi\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* r[0] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq %%rax,0(%%rdi)\n"
|
||||
/* c >>= 52 */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
"xorq %%r9,%%r9\n"
|
||||
/* a0 *= 2 */
|
||||
"addq %%r10,%%r10\n"
|
||||
/* c += a0 * a1 */
|
||||
"movq %%r10,%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d += a2 * a4 */
|
||||
"movq %%r12,%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* d += a3 * a3 */
|
||||
"movq %%r13,%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* c += (d & M) * R */
|
||||
"movq %%rbx,%%rax\n"
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%rcx,%%rbx\n"
|
||||
"xorq %%rcx,%%rcx\n"
|
||||
/* r[1] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq %%rax,8(%%rdi)\n"
|
||||
/* c >>= 52 */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
"xorq %%r9,%%r9\n"
|
||||
/* c += a0 * a2 (last use of %%r10) */
|
||||
"movq %%r10,%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* fetch t3 (%%r10, overwrites a0),t4 (%%rsi) */
|
||||
"movq %q2,%%rsi\n"
|
||||
"movq %q1,%%r10\n"
|
||||
/* c += a1 * a1 */
|
||||
"movq %%r11,%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d += a3 * a4 */
|
||||
"movq %%r13,%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* c += (d & M) * R */
|
||||
"movq %%rbx,%%rax\n"
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d >>= 52 (%%rbx only) */
|
||||
"shrdq $52,%%rcx,%%rbx\n"
|
||||
/* r[2] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq %%rax,16(%%rdi)\n"
|
||||
/* c >>= 52 */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
"xorq %%r9,%%r9\n"
|
||||
/* c += t3 */
|
||||
"addq %%r10,%%r8\n"
|
||||
/* c += d * R */
|
||||
"movq %%rbx,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* r[3] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq %%rax,24(%%rdi)\n"
|
||||
/* c >>= 52 (%%r8 only) */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
/* c += t4 (%%r8 only) */
|
||||
"addq %%rsi,%%r8\n"
|
||||
/* r[4] = c */
|
||||
"movq %%r8,32(%%rdi)\n"
|
||||
: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3)
|
||||
: "D"(r)
|
||||
: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */
|
||||
15
external/secp256k1/src/field_5x52_impl.h
vendored
15
external/secp256k1/src/field_5x52_impl.h
vendored
@@ -12,11 +12,7 @@
|
||||
#include "field.h"
|
||||
#include "modinv64_impl.h"
|
||||
|
||||
#if defined(USE_ASM_X86_64)
|
||||
#include "field_5x52_asm_impl.h"
|
||||
#else
|
||||
#include "field_5x52_int128_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef VERIFY
|
||||
static void secp256k1_fe_impl_verify(const secp256k1_fe *a) {
|
||||
@@ -216,13 +212,6 @@ SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) {
|
||||
return a->n[0] & 1;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) {
|
||||
int i;
|
||||
for (i=0; i<5; i++) {
|
||||
a->n[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
int i;
|
||||
for (i = 4; i >= 0; i--) {
|
||||
@@ -314,7 +303,7 @@ static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
|
||||
r[31] = a->n[0] & 0xFF;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
/* For all legal values of m (0..31), the following properties hold: */
|
||||
VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
|
||||
VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
|
||||
@@ -329,7 +318,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const sec
|
||||
r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4];
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) {
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) {
|
||||
r->n[0] *= a;
|
||||
r->n[1] *= a;
|
||||
r->n[2] *= a;
|
||||
|
||||
13
external/secp256k1/src/field_5x52_int128_impl.h
vendored
13
external/secp256k1/src/field_5x52_int128_impl.h
vendored
@@ -12,13 +12,8 @@
|
||||
#include "int128.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef VERIFY
|
||||
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
|
||||
#define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n)))
|
||||
#else
|
||||
#define VERIFY_BITS(x, n) do { } while(0)
|
||||
#define VERIFY_BITS_128(x, n) do { } while(0)
|
||||
#endif
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
|
||||
secp256k1_uint128 c, d;
|
||||
@@ -89,18 +84,18 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
|
||||
secp256k1_u128_accum_mul(&d, a2, b[3]);
|
||||
secp256k1_u128_accum_mul(&d, a3, b[2]);
|
||||
secp256k1_u128_accum_mul(&d, a4, b[1]);
|
||||
VERIFY_BITS_128(&d, 115);
|
||||
VERIFY_BITS_128(&d, 114);
|
||||
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
|
||||
VERIFY_BITS(u0, 52);
|
||||
VERIFY_BITS_128(&d, 63);
|
||||
VERIFY_BITS_128(&d, 62);
|
||||
/* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
/* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
u0 = (u0 << 4) | tx;
|
||||
VERIFY_BITS(u0, 56);
|
||||
/* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
secp256k1_u128_accum_mul(&c, u0, R >> 4);
|
||||
VERIFY_BITS_128(&c, 115);
|
||||
VERIFY_BITS_128(&c, 113);
|
||||
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
|
||||
VERIFY_BITS(r[0], 52);
|
||||
@@ -159,7 +154,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
|
||||
SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) {
|
||||
secp256k1_uint128 c, d;
|
||||
uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
|
||||
int64_t t3, t4, tx, u0;
|
||||
uint64_t t3, t4, tx, u0;
|
||||
const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
|
||||
|
||||
VERIFY_BITS(a[0], 56);
|
||||
|
||||
209
external/secp256k1/src/field_impl.h
vendored
209
external/secp256k1/src/field_impl.h
vendored
@@ -18,33 +18,23 @@
|
||||
#error "Please select wide multiplication implementation"
|
||||
#endif
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
|
||||
secp256k1_memclear(a, sizeof(secp256k1_fe));
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
secp256k1_fe na;
|
||||
#ifdef VERIFY
|
||||
secp256k1_fe_verify(a);
|
||||
secp256k1_fe_verify(b);
|
||||
VERIFY_CHECK(a->magnitude <= 1);
|
||||
VERIFY_CHECK(b->magnitude <= 31);
|
||||
#endif
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(b);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 1);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(b, 31);
|
||||
|
||||
secp256k1_fe_negate(&na, a, 1);
|
||||
secp256k1_fe_add(&na, b);
|
||||
return secp256k1_fe_normalizes_to_zero(&na);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
secp256k1_fe na;
|
||||
#ifdef VERIFY
|
||||
secp256k1_fe_verify(a);
|
||||
secp256k1_fe_verify(b);
|
||||
VERIFY_CHECK(a->magnitude <= 1);
|
||||
VERIFY_CHECK(b->magnitude <= 31);
|
||||
#endif
|
||||
secp256k1_fe_negate(&na, a, 1);
|
||||
secp256k1_fe_add(&na, b);
|
||||
return secp256k1_fe_normalizes_to_zero_var(&na);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a) {
|
||||
/** Given that p is congruent to 3 mod 4, we can compute the square root of
|
||||
* a mod p as the (p+1)/4'th power of a.
|
||||
*
|
||||
@@ -57,11 +47,9 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
|
||||
int j, ret;
|
||||
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(r != a);
|
||||
secp256k1_fe_verify(a);
|
||||
VERIFY_CHECK(a->magnitude <= 8);
|
||||
#endif
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 8);
|
||||
|
||||
/** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in
|
||||
* { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
|
||||
@@ -151,7 +139,7 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
if (!ret) {
|
||||
secp256k1_fe_negate(&t1, &t1, 1);
|
||||
secp256k1_fe_normalize_var(&t1);
|
||||
VERIFY_CHECK(secp256k1_fe_equal_var(&t1, a));
|
||||
VERIFY_CHECK(secp256k1_fe_equal(&t1, a));
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
@@ -159,104 +147,118 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
|
||||
#ifndef VERIFY
|
||||
static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; }
|
||||
static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) { (void)a; (void)m; }
|
||||
#else
|
||||
static void secp256k1_fe_impl_verify(const secp256k1_fe *a);
|
||||
static void secp256k1_fe_verify(const secp256k1_fe *a) {
|
||||
/* Magnitude between 0 and 32. */
|
||||
VERIFY_CHECK((a->magnitude >= 0) && (a->magnitude <= 32));
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 32);
|
||||
/* Normalized is 0 or 1. */
|
||||
VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1));
|
||||
/* If normalized, magnitude must be 0 or 1. */
|
||||
if (a->normalized) VERIFY_CHECK(a->magnitude <= 1);
|
||||
if (a->normalized) SECP256K1_FE_VERIFY_MAGNITUDE(a, 1);
|
||||
/* Invoke implementation-specific checks. */
|
||||
secp256k1_fe_impl_verify(a);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) {
|
||||
VERIFY_CHECK(m >= 0);
|
||||
VERIFY_CHECK(m <= 32);
|
||||
VERIFY_CHECK(a->magnitude <= m);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_normalize(secp256k1_fe *r);
|
||||
SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) {
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_normalize(r);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r);
|
||||
SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_normalize_weak(r);
|
||||
r->magnitude = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r);
|
||||
SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_normalize_var(r);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r);
|
||||
SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
return secp256k1_fe_impl_normalizes_to_zero(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r);
|
||||
SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
return secp256k1_fe_impl_normalizes_to_zero_var(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
|
||||
VERIFY_CHECK(0 <= a && a <= 0x7FFF);
|
||||
|
||||
secp256k1_fe_impl_set_int(r, a);
|
||||
r->magnitude = (a != 0);
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
|
||||
VERIFY_CHECK(0 <= a && a <= 0x7FFF);
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_add_int(r, a);
|
||||
r->magnitude += 1;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_clear(secp256k1_fe *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
|
||||
a->magnitude = 0;
|
||||
a->normalized = 1;
|
||||
secp256k1_fe_impl_clear(a);
|
||||
secp256k1_fe_verify(a);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
|
||||
secp256k1_fe_verify(a);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
||||
return secp256k1_fe_impl_is_zero(a);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
|
||||
secp256k1_fe_verify(a);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
||||
return secp256k1_fe_impl_is_odd(a);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
secp256k1_fe_verify(a);
|
||||
secp256k1_fe_verify(b);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(b);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
VERIFY_CHECK(b->normalized);
|
||||
|
||||
return secp256k1_fe_impl_cmp_var(a, b);
|
||||
}
|
||||
|
||||
@@ -265,7 +267,8 @@ SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const uns
|
||||
secp256k1_fe_impl_set_b32_mod(r, a);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
|
||||
@@ -273,7 +276,7 @@ SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const un
|
||||
if (secp256k1_fe_impl_set_b32_limit(r, a)) {
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
return 1;
|
||||
} else {
|
||||
/* Mark the output field element as invalid. */
|
||||
@@ -284,85 +287,97 @@ SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const un
|
||||
|
||||
static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
|
||||
secp256k1_fe_verify(a);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
||||
secp256k1_fe_impl_get_b32(r, a);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
|
||||
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
secp256k1_fe_verify(a);
|
||||
static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m);
|
||||
SECP256K1_INLINE static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(m >= 0 && m <= 31);
|
||||
VERIFY_CHECK(a->magnitude <= m);
|
||||
secp256k1_fe_impl_negate(r, a, m);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, m);
|
||||
|
||||
secp256k1_fe_impl_negate_unchecked(r, a, m);
|
||||
r->magnitude = m + 1;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
|
||||
secp256k1_fe_verify(r);
|
||||
static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a) {
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
VERIFY_CHECK(a >= 0 && a <= 32);
|
||||
VERIFY_CHECK(a*r->magnitude <= 32);
|
||||
secp256k1_fe_impl_mul_int(r, a);
|
||||
secp256k1_fe_impl_mul_int_unchecked(r, a);
|
||||
r->magnitude *= a;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
secp256k1_fe_verify(r);
|
||||
secp256k1_fe_verify(a);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(r->magnitude + a->magnitude <= 32);
|
||||
|
||||
secp256k1_fe_impl_add(r, a);
|
||||
r->magnitude += a->magnitude;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
|
||||
secp256k1_fe_verify(a);
|
||||
secp256k1_fe_verify(b);
|
||||
VERIFY_CHECK(a->magnitude <= 8);
|
||||
VERIFY_CHECK(b->magnitude <= 8);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(b);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 8);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(b, 8);
|
||||
VERIFY_CHECK(r != b);
|
||||
VERIFY_CHECK(a != b);
|
||||
|
||||
secp256k1_fe_impl_mul(r, a, b);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
secp256k1_fe_verify(a);
|
||||
VERIFY_CHECK(a->magnitude <= 8);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 8);
|
||||
|
||||
secp256k1_fe_impl_sqr(r, a);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
|
||||
SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
|
||||
VERIFY_CHECK(flag == 0 || flag == 1);
|
||||
secp256k1_fe_verify(a);
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_cmov(r, a, flag);
|
||||
if (flag) {
|
||||
r->magnitude = a->magnitude;
|
||||
r->normalized = a->normalized;
|
||||
}
|
||||
secp256k1_fe_verify(r);
|
||||
if (a->magnitude > r->magnitude) r->magnitude = a->magnitude;
|
||||
if (!a->normalized) r->normalized = 0;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
|
||||
secp256k1_fe_verify(a);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
||||
secp256k1_fe_impl_to_storage(r, a);
|
||||
}
|
||||
|
||||
@@ -371,36 +386,42 @@ SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const se
|
||||
secp256k1_fe_impl_from_storage(r, a);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x);
|
||||
SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
|
||||
int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
|
||||
secp256k1_fe_verify(x);
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
|
||||
secp256k1_fe_impl_inv(r, x);
|
||||
r->magnitude = x->magnitude > 0;
|
||||
r->normalized = 1;
|
||||
|
||||
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x);
|
||||
SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
|
||||
int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
|
||||
secp256k1_fe_verify(x);
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
|
||||
secp256k1_fe_impl_inv_var(r, x);
|
||||
r->magnitude = x->magnitude > 0;
|
||||
r->normalized = 1;
|
||||
|
||||
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x);
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
|
||||
int ret;
|
||||
secp256k1_fe tmp = *x, sqrt;
|
||||
secp256k1_fe_verify(x);
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
|
||||
ret = secp256k1_fe_impl_is_square_var(x);
|
||||
secp256k1_fe_normalize_weak(&tmp);
|
||||
VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp));
|
||||
@@ -411,20 +432,24 @@ static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m);
|
||||
SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) {
|
||||
VERIFY_CHECK(m >= 0);
|
||||
VERIFY_CHECK(m <= 32);
|
||||
|
||||
secp256k1_fe_impl_get_bounds(r, m);
|
||||
r->magnitude = m;
|
||||
r->normalized = (m == 0);
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_half(secp256k1_fe *r);
|
||||
SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) {
|
||||
secp256k1_fe_verify(r);
|
||||
VERIFY_CHECK(r->magnitude < 32);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(r, 31);
|
||||
|
||||
secp256k1_fe_impl_half(r);
|
||||
r->magnitude = (r->magnitude >> 1) + 1;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
#endif /* defined(VERIFY) */
|
||||
|
||||
41
external/secp256k1/src/group.h
vendored
41
external/secp256k1/src/group.h
vendored
@@ -44,6 +44,14 @@ typedef struct {
|
||||
|
||||
#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y)
|
||||
|
||||
/** Maximum allowed magnitudes for group element coordinates
|
||||
* in affine (x, y) and jacobian (x, y, z) representation. */
|
||||
#define SECP256K1_GE_X_MAGNITUDE_MAX 4
|
||||
#define SECP256K1_GE_Y_MAGNITUDE_MAX 3
|
||||
#define SECP256K1_GEJ_X_MAGNITUDE_MAX 4
|
||||
#define SECP256K1_GEJ_Y_MAGNITUDE_MAX 4
|
||||
#define SECP256K1_GEJ_Z_MAGNITUDE_MAX 1
|
||||
|
||||
/** Set a group element equal to the point with given X and Y coordinates */
|
||||
static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y);
|
||||
|
||||
@@ -51,6 +59,12 @@ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const se
|
||||
* for Y. Return value indicates whether the result is valid. */
|
||||
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd);
|
||||
|
||||
/** Determine whether x is a valid X coordinate on the curve. */
|
||||
static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x);
|
||||
|
||||
/** Determine whether fraction xn/xd is a valid X coordinate on the curve (xd != 0). */
|
||||
static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd);
|
||||
|
||||
/** Check whether a group element is the point at infinity. */
|
||||
static int secp256k1_ge_is_infinity(const secp256k1_ge *a);
|
||||
|
||||
@@ -88,6 +102,9 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
|
||||
*/
|
||||
static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr);
|
||||
|
||||
/** Check two group elements (affine) for equality in variable time. */
|
||||
static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b);
|
||||
|
||||
/** Set a group element (affine) equal to the point at infinity. */
|
||||
static void secp256k1_ge_set_infinity(secp256k1_ge *r);
|
||||
|
||||
@@ -100,7 +117,11 @@ static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a);
|
||||
/** Check two group elements (jacobian) for equality in variable time. */
|
||||
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b);
|
||||
|
||||
/** Compare the X coordinate of a group element (jacobian). */
|
||||
/** Check two group elements (jacobian and affine) for equality in variable time. */
|
||||
static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b);
|
||||
|
||||
/** Compare the X coordinate of a group element (jacobian).
|
||||
* The magnitude of the group element's X coordinate must not exceed 31. */
|
||||
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a);
|
||||
|
||||
/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */
|
||||
@@ -153,6 +174,22 @@ static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_g
|
||||
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */
|
||||
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
|
||||
|
||||
/** Convert a group element that is not infinity to a 64-byte array. The output
|
||||
* array is platform-dependent. */
|
||||
static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a);
|
||||
|
||||
/** Convert a 64-byte array into group element. This function assumes that the
|
||||
* provided buffer correctly encodes a group element. */
|
||||
static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf);
|
||||
|
||||
/** Convert a group element (that is allowed to be infinity) to a 64-byte
|
||||
* array. The output array is platform-dependent. */
|
||||
static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge);
|
||||
|
||||
/** Convert a 64-byte array into a group element. This function assumes that the
|
||||
* provided buffer is the output of secp256k1_ge_to_bytes_ext. */
|
||||
static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data);
|
||||
|
||||
/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve.
|
||||
*
|
||||
* In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the
|
||||
@@ -166,8 +203,10 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge);
|
||||
|
||||
/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */
|
||||
static void secp256k1_ge_verify(const secp256k1_ge *a);
|
||||
#define SECP256K1_GE_VERIFY(a) secp256k1_ge_verify(a)
|
||||
|
||||
/** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */
|
||||
static void secp256k1_gej_verify(const secp256k1_gej *a);
|
||||
#define SECP256K1_GEJ_VERIFY(a) secp256k1_gej_verify(a)
|
||||
|
||||
#endif /* SECP256K1_GROUP_H */
|
||||
|
||||
398
external/secp256k1/src/group_impl.h
vendored
398
external/secp256k1/src/group_impl.h
vendored
@@ -7,6 +7,8 @@
|
||||
#ifndef SECP256K1_GROUP_IMPL_H
|
||||
#define SECP256K1_GROUP_IMPL_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
#include "util.h"
|
||||
@@ -74,21 +76,22 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;
|
||||
/* End of section generated by sage/gen_exhaustive_groups.sage. */
|
||||
|
||||
static void secp256k1_ge_verify(const secp256k1_ge *a) {
|
||||
#ifdef VERIFY
|
||||
secp256k1_fe_verify(&a->x);
|
||||
secp256k1_fe_verify(&a->y);
|
||||
SECP256K1_FE_VERIFY(&a->x);
|
||||
SECP256K1_FE_VERIFY(&a->y);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GE_X_MAGNITUDE_MAX);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GE_Y_MAGNITUDE_MAX);
|
||||
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
|
||||
#endif
|
||||
(void)a;
|
||||
}
|
||||
|
||||
static void secp256k1_gej_verify(const secp256k1_gej *a) {
|
||||
#ifdef VERIFY
|
||||
secp256k1_fe_verify(&a->x);
|
||||
secp256k1_fe_verify(&a->y);
|
||||
secp256k1_fe_verify(&a->z);
|
||||
SECP256K1_FE_VERIFY(&a->x);
|
||||
SECP256K1_FE_VERIFY(&a->y);
|
||||
SECP256K1_FE_VERIFY(&a->z);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GEJ_X_MAGNITUDE_MAX);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(&a->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX);
|
||||
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
|
||||
#endif
|
||||
(void)a;
|
||||
}
|
||||
|
||||
@@ -96,57 +99,67 @@ static void secp256k1_gej_verify(const secp256k1_gej *a) {
|
||||
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
|
||||
secp256k1_fe zi2;
|
||||
secp256k1_fe zi3;
|
||||
secp256k1_gej_verify(a);
|
||||
secp256k1_fe_verify(zi);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(zi);
|
||||
VERIFY_CHECK(!a->infinity);
|
||||
|
||||
secp256k1_fe_sqr(&zi2, zi);
|
||||
secp256k1_fe_mul(&zi3, &zi2, zi);
|
||||
secp256k1_fe_mul(&r->x, &a->x, &zi2);
|
||||
secp256k1_fe_mul(&r->y, &a->y, &zi3);
|
||||
r->infinity = a->infinity;
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */
|
||||
static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, const secp256k1_fe *zi) {
|
||||
secp256k1_fe zi2;
|
||||
secp256k1_fe zi3;
|
||||
secp256k1_ge_verify(a);
|
||||
secp256k1_fe_verify(zi);
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(zi);
|
||||
VERIFY_CHECK(!a->infinity);
|
||||
|
||||
secp256k1_fe_sqr(&zi2, zi);
|
||||
secp256k1_fe_mul(&zi3, &zi2, zi);
|
||||
secp256k1_fe_mul(&r->x, &a->x, &zi2);
|
||||
secp256k1_fe_mul(&r->y, &a->y, &zi3);
|
||||
r->infinity = a->infinity;
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) {
|
||||
secp256k1_fe_verify(x);
|
||||
secp256k1_fe_verify(y);
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
SECP256K1_FE_VERIFY(y);
|
||||
|
||||
r->infinity = 0;
|
||||
r->x = *x;
|
||||
r->y = *y;
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_is_infinity(const secp256k1_ge *a) {
|
||||
secp256k1_ge_verify(a);
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
|
||||
return a->infinity;
|
||||
}
|
||||
|
||||
static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) {
|
||||
secp256k1_ge_verify(a);
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
|
||||
*r = *a;
|
||||
secp256k1_fe_normalize_weak(&r->y);
|
||||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
|
||||
secp256k1_fe z2, z3;
|
||||
secp256k1_gej_verify(a);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
r->infinity = a->infinity;
|
||||
secp256k1_fe_inv(&a->z, &a->z);
|
||||
secp256k1_fe_sqr(&z2, &a->z);
|
||||
@@ -156,12 +169,15 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
|
||||
secp256k1_fe_set_int(&a->z, 1);
|
||||
r->x = a->x;
|
||||
r->y = a->y;
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
|
||||
secp256k1_fe z2, z3;
|
||||
secp256k1_gej_verify(a);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
if (secp256k1_gej_is_infinity(a)) {
|
||||
secp256k1_ge_set_infinity(r);
|
||||
return;
|
||||
@@ -174,16 +190,22 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
|
||||
secp256k1_fe_mul(&a->y, &a->y, &z3);
|
||||
secp256k1_fe_set_int(&a->z, 1);
|
||||
secp256k1_ge_set_xy(r, &a->x, &a->y);
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) {
|
||||
secp256k1_fe u;
|
||||
size_t i;
|
||||
size_t last_i = SIZE_MAX;
|
||||
#ifdef VERIFY
|
||||
for (i = 0; i < len; i++) {
|
||||
SECP256K1_GEJ_VERIFY(&a[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
secp256k1_gej_verify(&a[i]);
|
||||
if (a[i].infinity) {
|
||||
secp256k1_ge_set_infinity(&r[i]);
|
||||
} else {
|
||||
@@ -217,70 +239,78 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
|
||||
if (!a[i].infinity) {
|
||||
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x);
|
||||
}
|
||||
secp256k1_ge_verify(&r[i]);
|
||||
}
|
||||
|
||||
#ifdef VERIFY
|
||||
for (i = 0; i < len; i++) {
|
||||
SECP256K1_GE_VERIFY(&r[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr) {
|
||||
size_t i = len - 1;
|
||||
size_t i;
|
||||
secp256k1_fe zs;
|
||||
#ifdef VERIFY
|
||||
for (i = 0; i < len; i++) {
|
||||
SECP256K1_GE_VERIFY(&a[i]);
|
||||
SECP256K1_FE_VERIFY(&zr[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len > 0) {
|
||||
/* Verify inputs a[len-1] and zr[len-1]. */
|
||||
secp256k1_ge_verify(&a[i]);
|
||||
secp256k1_fe_verify(&zr[i]);
|
||||
i = len - 1;
|
||||
/* Ensure all y values are in weak normal form for fast negation of points */
|
||||
secp256k1_fe_normalize_weak(&a[i].y);
|
||||
zs = zr[i];
|
||||
|
||||
/* Work our way backwards, using the z-ratios to scale the x/y values. */
|
||||
while (i > 0) {
|
||||
/* Verify all inputs a[i] and zr[i]. */
|
||||
secp256k1_fe_verify(&zr[i]);
|
||||
secp256k1_ge_verify(&a[i]);
|
||||
if (i != len - 1) {
|
||||
secp256k1_fe_mul(&zs, &zs, &zr[i]);
|
||||
}
|
||||
i--;
|
||||
secp256k1_ge_set_ge_zinv(&a[i], &a[i], &zs);
|
||||
/* Verify the output a[i]. */
|
||||
secp256k1_ge_verify(&a[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VERIFY
|
||||
for (i = 0; i < len; i++) {
|
||||
SECP256K1_GE_VERIFY(&a[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
|
||||
r->infinity = 1;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
secp256k1_fe_clear(&r->z);
|
||||
secp256k1_gej_verify(r);
|
||||
secp256k1_fe_set_int(&r->x, 0);
|
||||
secp256k1_fe_set_int(&r->y, 0);
|
||||
secp256k1_fe_set_int(&r->z, 0);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
|
||||
r->infinity = 1;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
secp256k1_ge_verify(r);
|
||||
secp256k1_fe_set_int(&r->x, 0);
|
||||
secp256k1_fe_set_int(&r->y, 0);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_clear(secp256k1_gej *r) {
|
||||
r->infinity = 0;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
secp256k1_fe_clear(&r->z);
|
||||
secp256k1_memclear(r, sizeof(secp256k1_gej));
|
||||
}
|
||||
|
||||
static void secp256k1_ge_clear(secp256k1_ge *r) {
|
||||
r->infinity = 0;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
secp256k1_memclear(r, sizeof(secp256k1_ge));
|
||||
}
|
||||
|
||||
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
|
||||
secp256k1_fe x2, x3;
|
||||
int ret;
|
||||
secp256k1_fe_verify(x);
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
|
||||
r->x = *x;
|
||||
secp256k1_fe_sqr(&x2, x);
|
||||
secp256k1_fe_mul(&x3, x, &x2);
|
||||
@@ -291,57 +321,94 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int o
|
||||
if (secp256k1_fe_is_odd(&r->y) != odd) {
|
||||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
}
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) {
|
||||
secp256k1_ge_verify(a);
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
|
||||
r->infinity = a->infinity;
|
||||
r->x = a->x;
|
||||
r->y = a->y;
|
||||
secp256k1_fe_set_int(&r->z, 1);
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) {
|
||||
secp256k1_gej tmp;
|
||||
secp256k1_gej_verify(b);
|
||||
secp256k1_gej_verify(a);
|
||||
SECP256K1_GEJ_VERIFY(b);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
secp256k1_gej_neg(&tmp, a);
|
||||
secp256k1_gej_add_var(&tmp, &tmp, b, NULL);
|
||||
return secp256k1_gej_is_infinity(&tmp);
|
||||
}
|
||||
|
||||
static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b) {
|
||||
secp256k1_gej tmp;
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(b);
|
||||
|
||||
secp256k1_gej_neg(&tmp, a);
|
||||
secp256k1_gej_add_ge_var(&tmp, &tmp, b, NULL);
|
||||
return secp256k1_gej_is_infinity(&tmp);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b) {
|
||||
secp256k1_fe tmp;
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(b);
|
||||
|
||||
if (a->infinity != b->infinity) return 0;
|
||||
if (a->infinity) return 1;
|
||||
|
||||
tmp = a->x;
|
||||
secp256k1_fe_normalize_weak(&tmp);
|
||||
if (!secp256k1_fe_equal(&tmp, &b->x)) return 0;
|
||||
|
||||
tmp = a->y;
|
||||
secp256k1_fe_normalize_weak(&tmp);
|
||||
if (!secp256k1_fe_equal(&tmp, &b->y)) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) {
|
||||
secp256k1_fe r, r2;
|
||||
secp256k1_fe_verify(x);
|
||||
secp256k1_gej_verify(a);
|
||||
secp256k1_fe r;
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
VERIFY_CHECK(!a->infinity);
|
||||
|
||||
secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x);
|
||||
r2 = a->x; secp256k1_fe_normalize_weak(&r2);
|
||||
return secp256k1_fe_equal_var(&r, &r2);
|
||||
return secp256k1_fe_equal(&r, &a->x);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) {
|
||||
secp256k1_gej_verify(a);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
r->infinity = a->infinity;
|
||||
r->x = a->x;
|
||||
r->y = a->y;
|
||||
r->z = a->z;
|
||||
secp256k1_fe_normalize_weak(&r->y);
|
||||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_gej_is_infinity(const secp256k1_gej *a) {
|
||||
secp256k1_gej_verify(a);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
return a->infinity;
|
||||
}
|
||||
|
||||
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
|
||||
secp256k1_fe y2, x3;
|
||||
secp256k1_ge_verify(a);
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
|
||||
if (a->infinity) {
|
||||
return 0;
|
||||
}
|
||||
@@ -349,15 +416,14 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
|
||||
secp256k1_fe_sqr(&y2, &a->y);
|
||||
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
|
||||
secp256k1_fe_add_int(&x3, SECP256K1_B);
|
||||
secp256k1_fe_normalize_weak(&x3);
|
||||
return secp256k1_fe_equal_var(&y2, &x3);
|
||||
return secp256k1_fe_equal(&y2, &x3);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) {
|
||||
/* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */
|
||||
secp256k1_fe l, s, t;
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
secp256k1_gej_verify(a);
|
||||
r->infinity = a->infinity;
|
||||
|
||||
/* Formula used:
|
||||
@@ -384,10 +450,13 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25
|
||||
secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */
|
||||
secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */
|
||||
secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
/** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
|
||||
* Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
|
||||
* y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
|
||||
@@ -398,7 +467,6 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
|
||||
* the infinity flag even though the point doubles to infinity, and the result
|
||||
* point will be gibberish (z = 0 but infinity = 0).
|
||||
*/
|
||||
secp256k1_gej_verify(a);
|
||||
if (a->infinity) {
|
||||
secp256k1_gej_set_infinity(r);
|
||||
if (rzr != NULL) {
|
||||
@@ -413,15 +481,16 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
|
||||
}
|
||||
|
||||
secp256k1_gej_double(r, a);
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
|
||||
/* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */
|
||||
secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t;
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GEJ_VERIFY(b);
|
||||
|
||||
secp256k1_gej_verify(a);
|
||||
secp256k1_gej_verify(b);
|
||||
if (a->infinity) {
|
||||
VERIFY_CHECK(rzr == NULL);
|
||||
*r = *b;
|
||||
@@ -476,14 +545,16 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons
|
||||
secp256k1_fe_mul(&r->y, &t, &i);
|
||||
secp256k1_fe_mul(&h3, &h3, &s1);
|
||||
secp256k1_fe_add(&r->y, &h3);
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) {
|
||||
/* 8 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */
|
||||
/* Operations: 8 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */
|
||||
secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t;
|
||||
secp256k1_gej_verify(a);
|
||||
secp256k1_ge_verify(b);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(b);
|
||||
|
||||
if (a->infinity) {
|
||||
VERIFY_CHECK(rzr == NULL);
|
||||
secp256k1_gej_set_ge(r, b);
|
||||
@@ -498,11 +569,11 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
|
||||
}
|
||||
|
||||
secp256k1_fe_sqr(&z12, &a->z);
|
||||
u1 = a->x; secp256k1_fe_normalize_weak(&u1);
|
||||
u1 = a->x;
|
||||
secp256k1_fe_mul(&u2, &b->x, &z12);
|
||||
s1 = a->y; secp256k1_fe_normalize_weak(&s1);
|
||||
s1 = a->y;
|
||||
secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
|
||||
secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
|
||||
secp256k1_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); secp256k1_fe_add(&h, &u2);
|
||||
secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1);
|
||||
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
|
||||
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
|
||||
@@ -536,16 +607,18 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
|
||||
secp256k1_fe_mul(&r->y, &t, &i);
|
||||
secp256k1_fe_mul(&h3, &h3, &s1);
|
||||
secp256k1_fe_add(&r->y, &h3);
|
||||
secp256k1_gej_verify(r);
|
||||
if (rzr != NULL) secp256k1_fe_verify(rzr);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
if (rzr != NULL) SECP256K1_FE_VERIFY(rzr);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) {
|
||||
/* 9 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */
|
||||
/* Operations: 9 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */
|
||||
secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t;
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(b);
|
||||
SECP256K1_FE_VERIFY(bzinv);
|
||||
|
||||
secp256k1_ge_verify(b);
|
||||
secp256k1_fe_verify(bzinv);
|
||||
if (a->infinity) {
|
||||
secp256k1_fe bzinv2, bzinv3;
|
||||
r->infinity = b->infinity;
|
||||
@@ -554,6 +627,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
|
||||
secp256k1_fe_mul(&r->x, &b->x, &bzinv2);
|
||||
secp256k1_fe_mul(&r->y, &b->y, &bzinv3);
|
||||
secp256k1_fe_set_int(&r->z, 1);
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
return;
|
||||
}
|
||||
if (b->infinity) {
|
||||
@@ -572,11 +646,11 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
|
||||
secp256k1_fe_mul(&az, &a->z, bzinv);
|
||||
|
||||
secp256k1_fe_sqr(&z12, &az);
|
||||
u1 = a->x; secp256k1_fe_normalize_weak(&u1);
|
||||
u1 = a->x;
|
||||
secp256k1_fe_mul(&u2, &b->x, &z12);
|
||||
s1 = a->y; secp256k1_fe_normalize_weak(&s1);
|
||||
s1 = a->y;
|
||||
secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az);
|
||||
secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
|
||||
secp256k1_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); secp256k1_fe_add(&h, &u2);
|
||||
secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1);
|
||||
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
|
||||
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
|
||||
@@ -604,19 +678,19 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
|
||||
secp256k1_fe_mul(&r->y, &t, &i);
|
||||
secp256k1_fe_mul(&h3, &h3, &s1);
|
||||
secp256k1_fe_add(&r->y, &h3);
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
|
||||
static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) {
|
||||
/* Operations: 7 mul, 5 sqr, 24 add/cmov/half/mul_int/negate/normalize_weak/normalizes_to_zero */
|
||||
/* Operations: 7 mul, 5 sqr, 21 add/cmov/half/mul_int/negate/normalizes_to_zero */
|
||||
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
|
||||
secp256k1_fe m_alt, rr_alt;
|
||||
int degenerate;
|
||||
secp256k1_gej_verify(a);
|
||||
secp256k1_ge_verify(b);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(b);
|
||||
VERIFY_CHECK(!b->infinity);
|
||||
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
|
||||
|
||||
/* In:
|
||||
* Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks.
|
||||
@@ -669,17 +743,17 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
|
||||
*/
|
||||
|
||||
secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */
|
||||
u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */
|
||||
u1 = a->x; /* u1 = U1 = X1*Z2^2 (GEJ_X_M) */
|
||||
secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */
|
||||
s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */
|
||||
s1 = a->y; /* s1 = S1 = Y1*Z2^3 (GEJ_Y_M) */
|
||||
secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */
|
||||
secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */
|
||||
t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */
|
||||
m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */
|
||||
t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (GEJ_X_M+1) */
|
||||
m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (GEJ_Y_M+1) */
|
||||
secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */
|
||||
secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */
|
||||
secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */
|
||||
secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */
|
||||
secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 (2) */
|
||||
secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (1) */
|
||||
secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (2) */
|
||||
/* If lambda = R/M = R/0 we have a problem (except in the "trivial"
|
||||
* case that Z = z1z2 = 0, and this is special-cased later on). */
|
||||
degenerate = secp256k1_fe_normalizes_to_zero(&m);
|
||||
@@ -689,24 +763,25 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
|
||||
* non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2),
|
||||
* so we set R/M equal to this. */
|
||||
rr_alt = s1;
|
||||
secp256k1_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */
|
||||
secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */
|
||||
secp256k1_fe_mul_int(&rr_alt, 2); /* rr_alt = Y1*Z2^3 - Y2*Z1^3 (GEJ_Y_M*2) */
|
||||
secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 (GEJ_X_M+2) */
|
||||
|
||||
secp256k1_fe_cmov(&rr_alt, &rr, !degenerate);
|
||||
secp256k1_fe_cmov(&m_alt, &m, !degenerate);
|
||||
secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); /* rr_alt (GEJ_Y_M*2) */
|
||||
secp256k1_fe_cmov(&m_alt, &m, !degenerate); /* m_alt (GEJ_X_M+2) */
|
||||
/* Now Ralt / Malt = lambda and is guaranteed not to be Ralt / 0.
|
||||
* From here on out Ralt and Malt represent the numerator
|
||||
* and denominator of lambda; R and M represent the explicit
|
||||
* expressions x1^2 + x2^2 + x1x2 and y1 + y2. */
|
||||
secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */
|
||||
secp256k1_fe_negate(&q, &t, 2); /* q = -T (3) */
|
||||
secp256k1_fe_negate(&q, &t,
|
||||
SECP256K1_GEJ_X_MAGNITUDE_MAX + 1); /* q = -T (GEJ_X_M+2) */
|
||||
secp256k1_fe_mul(&q, &q, &n); /* q = Q = -T*Malt^2 (1) */
|
||||
/* These two lines use the observation that either M == Malt or M == 0,
|
||||
* so M^3 * Malt is either Malt^4 (which is computed by squaring), or
|
||||
* zero (which is "computed" by cmov). So the cost is one squaring
|
||||
* versus two multiplications. */
|
||||
secp256k1_fe_sqr(&n, &n);
|
||||
secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */
|
||||
secp256k1_fe_sqr(&n, &n); /* n = Malt^4 (1) */
|
||||
secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (GEJ_Y_M+1) */
|
||||
secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */
|
||||
secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */
|
||||
secp256k1_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */
|
||||
@@ -714,9 +789,10 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
|
||||
secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */
|
||||
secp256k1_fe_add(&t, &q); /* t = 2*X3 + Q (5) */
|
||||
secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*X3 + Q) (1) */
|
||||
secp256k1_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (3) */
|
||||
secp256k1_fe_negate(&r->y, &t, 3); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (4) */
|
||||
secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 (3) */
|
||||
secp256k1_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (GEJ_Y_M+2) */
|
||||
secp256k1_fe_negate(&r->y, &t,
|
||||
SECP256K1_GEJ_Y_MAGNITUDE_MAX + 2); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (GEJ_Y_M+3) */
|
||||
secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 ((GEJ_Y_M+3)/2 + 1) */
|
||||
|
||||
/* In case a->infinity == 1, replace r with (b->x, b->y, 1). */
|
||||
secp256k1_fe_cmov(&r->x, &b->x, a->infinity);
|
||||
@@ -740,29 +816,31 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
|
||||
* We have degenerate = false, r->z = (y1 + y2) * Z.
|
||||
* Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */
|
||||
r->infinity = secp256k1_fe_normalizes_to_zero(&r->z);
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {
|
||||
/* Operations: 4 mul, 1 sqr */
|
||||
secp256k1_fe zz;
|
||||
secp256k1_gej_verify(r);
|
||||
secp256k1_fe_verify(s);
|
||||
#ifdef VERIFY
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
SECP256K1_FE_VERIFY(s);
|
||||
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(s));
|
||||
#endif
|
||||
|
||||
secp256k1_fe_sqr(&zz, s);
|
||||
secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */
|
||||
secp256k1_fe_mul(&r->y, &r->y, &zz);
|
||||
secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */
|
||||
secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) {
|
||||
secp256k1_fe x, y;
|
||||
secp256k1_ge_verify(a);
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
VERIFY_CHECK(!a->infinity);
|
||||
|
||||
x = a->x;
|
||||
secp256k1_fe_normalize(&x);
|
||||
y = a->y;
|
||||
@@ -775,18 +853,20 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag
|
||||
secp256k1_fe_from_storage(&r->x, &a->x);
|
||||
secp256k1_fe_from_storage(&r->y, &a->y);
|
||||
r->infinity = 0;
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) {
|
||||
secp256k1_gej_verify(r);
|
||||
secp256k1_gej_verify(a);
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
secp256k1_fe_cmov(&r->x, &a->x, flag);
|
||||
secp256k1_fe_cmov(&r->y, &a->y, flag);
|
||||
secp256k1_fe_cmov(&r->z, &a->z, flag);
|
||||
|
||||
r->infinity ^= (r->infinity ^ a->infinity) & flag;
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) {
|
||||
@@ -795,18 +875,20 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r,
|
||||
}
|
||||
|
||||
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
|
||||
*r = *a;
|
||||
secp256k1_ge_verify(a);
|
||||
secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta);
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
|
||||
#ifdef EXHAUSTIVE_TEST_ORDER
|
||||
secp256k1_gej out;
|
||||
int i;
|
||||
SECP256K1_GE_VERIFY(ge);
|
||||
|
||||
secp256k1_ge_verify(ge);
|
||||
/* A very simple EC multiplication ladder that avoids a dependency on ecmult. */
|
||||
secp256k1_gej_set_infinity(&out);
|
||||
for (i = 0; i < 32; ++i) {
|
||||
@@ -817,10 +899,76 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
|
||||
}
|
||||
return secp256k1_gej_is_infinity(&out);
|
||||
#else
|
||||
SECP256K1_GE_VERIFY(ge);
|
||||
|
||||
(void)ge;
|
||||
/* The real secp256k1 group has cofactor 1, so the subgroup is the entire curve. */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x) {
|
||||
secp256k1_fe c;
|
||||
secp256k1_fe_sqr(&c, x);
|
||||
secp256k1_fe_mul(&c, &c, x);
|
||||
secp256k1_fe_add_int(&c, SECP256K1_B);
|
||||
return secp256k1_fe_is_square_var(&c);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd) {
|
||||
/* We want to determine whether (xn/xd) is on the curve.
|
||||
*
|
||||
* (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square).
|
||||
*/
|
||||
secp256k1_fe r, t;
|
||||
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(xd));
|
||||
|
||||
secp256k1_fe_mul(&r, xd, xn); /* r = xd*xn */
|
||||
secp256k1_fe_sqr(&t, xn); /* t = xn^2 */
|
||||
secp256k1_fe_mul(&r, &r, &t); /* r = xd*xn^3 */
|
||||
secp256k1_fe_sqr(&t, xd); /* t = xd^2 */
|
||||
secp256k1_fe_sqr(&t, &t); /* t = xd^4 */
|
||||
VERIFY_CHECK(SECP256K1_B <= 31);
|
||||
secp256k1_fe_mul_int(&t, SECP256K1_B); /* t = 7*xd^4 */
|
||||
secp256k1_fe_add(&r, &t); /* r = xd*xn^3 + 7*xd^4 */
|
||||
return secp256k1_fe_is_square_var(&r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a) {
|
||||
secp256k1_ge_storage s;
|
||||
|
||||
/* We require that the secp256k1_ge_storage type is exactly 64 bytes.
|
||||
* This is formally not guaranteed by the C standard, but should hold on any
|
||||
* sane compiler in the real world. */
|
||||
STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64);
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(a));
|
||||
secp256k1_ge_to_storage(&s, a);
|
||||
memcpy(buf, &s, 64);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf) {
|
||||
secp256k1_ge_storage s;
|
||||
|
||||
STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64);
|
||||
memcpy(&s, buf, 64);
|
||||
secp256k1_ge_from_storage(r, &s);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge) {
|
||||
if (secp256k1_ge_is_infinity(ge)) {
|
||||
memset(data, 0, 64);
|
||||
} else {
|
||||
secp256k1_ge_to_bytes(data, ge);
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data) {
|
||||
static const unsigned char zeros[64] = { 0 };
|
||||
if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) {
|
||||
secp256k1_ge_set_infinity(ge);
|
||||
} else {
|
||||
secp256k1_ge_from_bytes(ge, data);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_GROUP_IMPL_H */
|
||||
|
||||
3
external/secp256k1/src/hash.h
vendored
3
external/secp256k1/src/hash.h
vendored
@@ -19,6 +19,7 @@ typedef struct {
|
||||
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);
|
||||
static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32);
|
||||
static void secp256k1_sha256_clear(secp256k1_sha256 *hash);
|
||||
|
||||
typedef struct {
|
||||
secp256k1_sha256 inner, outer;
|
||||
@@ -27,6 +28,7 @@ typedef struct {
|
||||
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size);
|
||||
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32);
|
||||
static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash);
|
||||
|
||||
typedef struct {
|
||||
unsigned char v[32];
|
||||
@@ -37,5 +39,6 @@ typedef struct {
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng);
|
||||
static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng);
|
||||
|
||||
#endif /* SECP256K1_HASH_H */
|
||||
|
||||
21
external/secp256k1/src/hash_impl.h
vendored
21
external/secp256k1/src/hash_impl.h
vendored
@@ -138,7 +138,7 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *
|
||||
}
|
||||
if (len) {
|
||||
/* Fill the buffer with what remains. */
|
||||
memcpy(((unsigned char*)hash->buf) + bufsize, data, len);
|
||||
memcpy(hash->buf + bufsize, data, len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,6 +171,10 @@ static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const uns
|
||||
secp256k1_sha256_write(hash, buf, 32);
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_clear(secp256k1_sha256 *hash) {
|
||||
secp256k1_memclear(hash, sizeof(*hash));
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) {
|
||||
size_t n;
|
||||
unsigned char rkey[64];
|
||||
@@ -196,7 +200,7 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const
|
||||
rkey[n] ^= 0x5c ^ 0x36;
|
||||
}
|
||||
secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey));
|
||||
memset(rkey, 0, sizeof(rkey));
|
||||
secp256k1_memclear(rkey, sizeof(rkey));
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) {
|
||||
@@ -207,10 +211,13 @@ static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned
|
||||
unsigned char temp[32];
|
||||
secp256k1_sha256_finalize(&hash->inner, temp);
|
||||
secp256k1_sha256_write(&hash->outer, temp, 32);
|
||||
memset(temp, 0, 32);
|
||||
secp256k1_memclear(temp, sizeof(temp));
|
||||
secp256k1_sha256_finalize(&hash->outer, out32);
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash) {
|
||||
secp256k1_memclear(hash, sizeof(*hash));
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) {
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
@@ -274,9 +281,11 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng) {
|
||||
memset(rng->k, 0, 32);
|
||||
memset(rng->v, 0, 32);
|
||||
rng->retry = 0;
|
||||
(void) rng;
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng) {
|
||||
secp256k1_memclear(rng, sizeof(*rng));
|
||||
}
|
||||
|
||||
#undef Round
|
||||
|
||||
33
external/secp256k1/src/hsort.h
vendored
Normal file
33
external/secp256k1/src/hsort.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2021 Russell O'Connor, Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_HSORT_H
|
||||
#define SECP256K1_HSORT_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/* In-place, iterative heapsort with an interface matching glibc's qsort_r. This
|
||||
* is preferred over standard library implementations because they generally
|
||||
* make no guarantee about being fast for malicious inputs.
|
||||
* Remember that heapsort is unstable.
|
||||
*
|
||||
* In/Out: ptr: pointer to the array to sort. The contents of the array are
|
||||
* sorted in ascending order according to the comparison function.
|
||||
* In: count: number of elements in the array.
|
||||
* size: size in bytes of each element.
|
||||
* cmp: pointer to a comparison function that is called with two
|
||||
* arguments that point to the objects being compared. The cmp_data
|
||||
* argument of secp256k1_hsort is passed as third argument. The
|
||||
* function must return an integer less than, equal to, or greater
|
||||
* than zero if the first argument is considered to be respectively
|
||||
* less than, equal to, or greater than the second.
|
||||
* cmp_data: pointer passed as third argument to cmp.
|
||||
*/
|
||||
static void secp256k1_hsort(void *ptr, size_t count, size_t size,
|
||||
int (*cmp)(const void *, const void *, void *),
|
||||
void *cmp_data);
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user