Showing preview only (457K chars total). Download the full file or copy to clipboard to get everything.
Repository: paritytech/libsecp256k1
Branch: master
Commit: f992b80dedc1
Files: 39
Total size: 440.1 KB
Directory structure:
gitextract_oew3p_ij/
├── .arcconfig
├── .editorconfig
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── audit.yml
│ ├── check-style.yml
│ ├── clippy.yml
│ ├── prepare_artifacts.sh
│ ├── rust-windows.yml
│ ├── rust.yml
│ └── sccache.sh
├── .gitignore
├── CHANGELOG.md
├── Cargo.toml
├── LICENSE
├── README.md
├── benches/
│ ├── public_key.rs
│ ├── sign.rs
│ └── signature.rs
├── build.rs
├── core/
│ ├── Cargo.toml
│ └── src/
│ ├── der.rs
│ ├── ecdh.rs
│ ├── ecdsa.rs
│ ├── ecmult.rs
│ ├── error.rs
│ ├── field.rs
│ ├── group.rs
│ ├── lib.rs
│ └── scalar.rs
├── gen/
│ ├── ecmult/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ └── genmult/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
├── res/
│ └── ecdsa_secp256k1_sha256_test.json
├── rustfmt.toml
├── src/
│ └── lib.rs
└── tests/
├── serde.rs
├── verify.rs
└── wycheproof.rs
================================================
FILE CONTENTS
================================================
================================================
FILE: .arcconfig
================================================
{
"phabricator.uri" : "https://source.that.world/"
}
================================================
FILE: .editorconfig
================================================
root = true
[*]
indent_style=space
indent_size=4
tab_width=4
end_of_line=lf
charset=utf-8
trim_trailing_whitespace=true
max_line_length=80
insert_final_newline=true
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: cargo
directory: "/"
labels: []
schedule:
interval: "daily"
rebase-strategy: disabled
open-pull-requests-limit: 2
- package-ecosystem: github-actions
directory: "/"
labels: []
schedule:
interval: "daily"
rebase-strategy: disabled
open-pull-requests-limit: 2
================================================
FILE: .github/workflows/audit.yml
================================================
name: Security audit
on:
pull_request:
paths: Cargo.lock
schedule:
- cron: '0 0 * * *'
jobs:
security_audit:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0
- name: Checkout sources
uses: actions/checkout@v3.1.0
with:
fetch-depth: 50
- name: Run cargo audit
uses: actions-rs/audit-check@v1.2.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/check-style.yml
================================================
name: Check style
on:
pull_request:
push:
branches:
- master
- stable
tags:
- v*
paths-ignore:
- 'README.md'
jobs:
check-style:
name: Check style
runs-on: ubuntu-latest
env:
RUST_BACKTRACE: full
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0
- name: Checkout sources & submodules
uses: actions/checkout@v3.1.0
with:
fetch-depth: 5
submodules: recursive
- name: Install toolchain
uses: actions-rs/toolchain@v1.0.7
with:
profile: minimal
toolchain: stable
components: clippy, rustfmt
override: true
- name: Checking style
uses: actions-rs/cargo@v1.0.3
with:
command: fmt
toolchain: stable
args: --all -- --check
================================================
FILE: .github/workflows/clippy.yml
================================================
name: Check clippy
on:
pull_request:
push:
branches:
- master
- stable
tags:
- v*
paths-ignore:
- 'README.md'
jobs:
check-clippy:
name: Check clippy
runs-on: ubuntu-latest
env:
RUST_BACKTRACE: full
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0
- name: Checkout sources & submodules
uses: actions/checkout@v3.1.0
with:
fetch-depth: 5
submodules: recursive
- name: Install toolchain
uses: actions-rs/toolchain@v1.0.7
with:
profile: minimal
toolchain: stable
components: clippy, rustfmt
override: true
- name: Checking clippy
uses: actions-rs/cargo@v1.0.3
with:
command: clippy
toolchain: stable
args: --all
- name: Checking clippy
uses: actions-rs/cargo@v1.0.3
with:
command: clippy
toolchain: stable
args: --all --no-default-features --features std,hmac,lazy-static-context
================================================
FILE: .github/workflows/prepare_artifacts.sh
================================================
#!/bin/bash
set -e # fail on any error
set -u # treat unset variables as error
# ARGUMENT $1 CARGO_TARGET
#Set additional dir path
if [ "${1}" == "" ]; then
dir=""
else
dir=".."
fi
mkdir -p ./artifacts/
cd ./target/$1/release/
ls -a
echo "_____ Find binary files in target _____"
find . -maxdepth 1 -type f ! -size 0 -exec grep -IL . "{}" \; | cut -c 3-
echo "_____ Move binaries to artifacts folder _____"
for binary in $(find . -maxdepth 1 -type f ! -size 0 -exec grep -IL . "{}" \; | cut -c 3- )
do
mv -v $binary ../$dir/../artifacts/$binary
done
cd ../$dir/..
echo "_____ Clean target dir _____"
find ./target/$1/{debug,release} -maxdepth 1 -type f -delete;
rm -f ./target/.rustc_info.json;
rm -rf ./target/$1/{debug,release}/{deps,.fingerprint}/
================================================
FILE: .github/workflows/rust-windows.yml
================================================
# almost a copy of .github/workflows/rust.yml made in https://github.com/paritytech/libsecp256k1/pull/84
# windows causes some troubles with sudo sccache and
# caching within GHA https://github.com/Swatinem/rust-cache/issues/31
name: Check, Test and Build on Windows
on:
pull_request:
push:
branches:
- master
- stable
tags:
- v*
paths-ignore:
- 'README.md'
jobs:
check:
name: Check
strategy:
matrix:
platform:
- windows-latest
toolchain:
- stable
- nightly
compiler:
- clang
- gcc
runs-on: ${{ matrix.platform }}
env:
RUST_BACKTRACE: full
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0
- name: Install sudo for windows #https://github.com/actions/virtual-environments/issues/572
if: matrix.platform == 'windows-latest'
run: choco install sudo
- name: Install LLVM for Windows
if: matrix.platform == 'windows-latest' && matrix.compiler == 'clang'
run: |
choco install llvm
echo "CC=clang-cl.exe --enable-64-bit" >> "$GITHUB_ENV"
echo "CXX=clang-cl.exe --enable-64-bit" >> "$GITHUB_ENV"
refreshenv
- name: Checkout sources & submodules
uses: actions/checkout@v3.1.0
with:
fetch-depth: 5
submodules: recursive
- name: Install toolchain
id: toolchain
uses: actions-rs/toolchain@v1.0.7
with:
profile: minimal
toolchain: ${{ matrix.toolchain }}
components: clippy, rustfmt
override: true
- name: Set cache_hash ENV and prepare cache dir
run: |
echo "cache_hash=${{ runner.os }}-${{ steps.toolchain.outputs.rustc_hash }}-${{ matrix.compiler }}-${{ hashFiles('**/Cargo.toml') }}" >> "$GITHUB_ENV"
mkdir -p $HOME/sccache
sudo chmod -R a+w $HOME/.cargo
shell: bash
- name: Cache cargo registry
uses: actions/cache@v3.0.11
with:
path: $HOME/.cargo/registry
key: cargo-registry-${{ env['cache_hash'] }}
- name: Cache cargo index
uses: actions/cache@v3.0.11
with:
path: $HOME/.cargo/git
key: cargo-git-${{ env['cache_hash'] }}
- name: Cache cargo build
uses: actions/cache@v3.0.11
with:
path: target
key: cargo-target-${{ env['cache_hash'] }}
- name: Checking ${{ matrix.platform }}-${{ matrix.toolchain }}
uses: actions-rs/cargo@v1.0.3
with:
command: check
toolchain: ${{ matrix.toolchain }}
args: --all --verbose
test:
name: Test
needs: [check]
strategy:
matrix:
platform:
- windows-latest
toolchain:
- stable
- nightly
compiler:
- clang
- gcc
runs-on: ${{ matrix.platform }}
env:
RUST_BACKTRACE: full
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0
- name: Set default compiler
if: matrix.compiler == 'clang' && matrix.platform != 'windows-latest'
run: |
echo "CC=clang" >> "$GITHUB_ENV"
echo "CXX=clang++" >> "$GITHUB_ENV"
- name: Install sudo for windows #https://github.com/actions/virtual-environments/issues/572
if: matrix.platform == 'windows-latest'
run: choco install sudo
- name: Install LLVM for Windows
if: matrix.platform == 'windows-latest' && matrix.compiler == 'clang'
run: |
choco install llvm
echo "CC=clang-cl.exe --enable-64-bit" >> "$GITHUB_ENV"
echo "CXX=clang-cl.exe --enable-64-bit" >> "$GITHUB_ENV"
refreshenv
- name: Checkout sources & submodules
uses: actions/checkout@v3.1.0
with:
fetch-depth: 5
submodules: recursive
- name: Install toolchain
id: toolchain
uses: actions-rs/toolchain@v1.0.7
with:
profile: minimal
toolchain: ${{ matrix.toolchain }}
components: clippy, rustfmt
override: true
- name: Set cache_hash ENV and prepare cache dir
run: |
echo "cache_hash=${{ runner.os }}-${{ steps.toolchain.outputs.rustc_hash }}-${{ matrix.compiler }}-${{ hashFiles('**/Cargo.toml') }}" >> "$GITHUB_ENV"
mkdir -p $HOME/sccache
sudo chmod -R a+w $HOME/.cargo
shell: bash
- name: Cache cargo registry
uses: actions/cache@v3.0.11
with:
path: $HOME/.cargo/registry
key: cargo-registry-${{ env['cache_hash'] }}
- name: Cache cargo index
uses: actions/cache@v3.0.11
with:
path: $HOME/.cargo/git
key: cargo-git-${{ env['cache_hash'] }}
- name: Cache cargo build
uses: actions/cache@v3.0.11
with:
path: target
key: cargo-target-${{ env['cache_hash'] }}
- name: Testing ${{ matrix.platform }}-${{ matrix.toolchain }} (debug build)
uses: actions-rs/cargo@v1.0.3
with:
command: test
toolchain: ${{ matrix.toolchain }}
args: --all --verbose
- name: Testing ${{ matrix.platform }}-${{ matrix.toolchain }} (release build)
uses: actions-rs/cargo@v1.0.3
with:
command: test
toolchain: ${{ matrix.toolchain }}
args: --all --release --verbose
build:
name: Build
needs: [check,test]
strategy:
matrix:
platform:
- windows-latest
toolchain:
- stable
- nightly
compiler:
- clang
- gcc
runs-on: ${{ matrix.platform }}
env:
RUST_BACKTRACE: full
# NOTE: Enables the aes-ni instructions for RustCrypto dependency.
# Strip binaries
# If you change this please remember to also update .cargo/config
RUSTFLAGS: "-C target-feature=+aes,+sse2,+ssse3 -C link-arg=-s"
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0
- name: Set default compiler
if: matrix.compiler == 'clang' && matrix.platform != 'windows-latest'
run: |
echo "CC=clang" >> "$GITHUB_ENV"
echo "CXX=clang++" >> "$GITHUB_ENV"
- name: Install sudo for windows #https://github.com/actions/virtual-environments/issues/572
if: matrix.platform == 'windows-latest'
run: choco install sudo
- name: Install LLVM for Windows
if: matrix.platform == 'windows-latest' && matrix.compiler == 'clang'
run: |
choco install llvm
echo "CC=clang-cl.exe --enable-64-bit" >> "$GITHUB_ENV"
echo "CXX=clang-cl.exe --enable-64-bit" >> "$GITHUB_ENV"
refreshenv
- name: Checkout sources & submodules
uses: actions/checkout@v3.1.0
with:
fetch-depth: 5
submodules: recursive
- name: Install toolchain
id: toolchain
uses: actions-rs/toolchain@v1.0.7
with:
profile: minimal
toolchain: ${{ matrix.toolchain }}
components: clippy, rustfmt
override: true
- name: Set cache_hash ENV and prepare cache dir
run: |
echo "cache_hash=${{ runner.os }}-${{ steps.toolchain.outputs.rustc_hash }}-${{ matrix.compiler }}-${{ hashFiles('**/Cargo.toml') }}" >> "$GITHUB_ENV"
mkdir -p $HOME/sccache
sudo chmod -R a+w $HOME/.cargo
shell: bash
- name: Cache cargo registry
uses: actions/cache@v3.0.11
with:
path: $HOME/.cargo/registry
key: cargo-registry-${{ env['cache_hash'] }}
- name: Cache cargo index
uses: actions/cache@v3.0.11
with:
path: $HOME/.cargo/git
key: cargo-git-${{ env['cache_hash'] }}
- name: Cache cargo build
uses: actions/cache@v3.0.11
with:
path: target
key: cargo-target-${{ env['cache_hash'] }}
- name: Building ${{ matrix.platform }}-${{ matrix.toolchain }}
uses: actions-rs/cargo@v1.0.3
with:
command: build
toolchain: ${{ matrix.toolchain }}
args: --all --verbose --release
- name: Building `no default` ${{ matrix.platform }}-${{ matrix.toolchain }}
uses: actions-rs/cargo@v1.0.3
with:
command: build
toolchain: ${{ matrix.toolchain }}
args: --verbose --no-default-features
- name: Building `hmac` ${{ matrix.platform }}-${{ matrix.toolchain }}
uses: actions-rs/cargo@v1.0.3
with:
command: build
toolchain: ${{ matrix.toolchain }}
args: --verbose --no-default-features --features hmac
- name: Building `static-context` ${{ matrix.platform }}-${{ matrix.toolchain }}
uses: actions-rs/cargo@v1.0.3
with:
command: build
toolchain: ${{ matrix.toolchain }}
args: --verbose --no-default-features --features static-context
- name: Building `lazy-static-context` ${{ matrix.platform }}-${{ matrix.toolchain }}
uses: actions-rs/cargo@v1.0.3
with:
command: build
toolchain: ${{ matrix.toolchain }}
args: --verbose --no-default-features --features lazy-static-context
- name: Prepare artifacts
run: .github/workflows/prepare_artifacts.sh ""
shell: bash
- name: Upload artifacts
uses: actions/upload-artifact@v3.1.0
with:
name: ${{ matrix.platform }}.${{ matrix.toolchain }}.${{ matrix.compiler }}.zip
path: artifacts/
================================================
FILE: .github/workflows/rust.yml
================================================
name: Check, Test and Build Suite
on:
pull_request:
push:
branches:
- master
- stable
tags:
- v*
paths-ignore:
- 'README.md'
jobs:
check:
name: Check
strategy:
matrix:
platform:
- ubuntu-latest
- macos-latest
toolchain:
- stable
- nightly
compiler:
- clang
- gcc
runs-on: ${{ matrix.platform }}
env:
RUST_BACKTRACE: full
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0
- name: Set default compiler
if: matrix.compiler == 'clang'
run: |
echo "CC=clang" >> "$GITHUB_ENV"
echo "CXX=clang++" >> "$GITHUB_ENV"
- name: Checkout sources & submodules
uses: actions/checkout@v3.1.0
with:
fetch-depth: 5
submodules: recursive
- name: Install toolchain
id: toolchain
uses: actions-rs/toolchain@v1.0.7
with:
profile: minimal
toolchain: ${{ matrix.toolchain }}
components: clippy, rustfmt
override: true
- uses: Swatinem/rust-cache@22c9328bcba27aa81a32b1bef27c7e3c78052531 # v2.0.1
- name: Cache sccache
uses: actions/cache@v3.0.11
with:
path: "$HOME/sccache"
key: sccache-${{ env['cache_hash'] }}
- name: Install & start sccache for ${{ matrix.platform }}
shell: bash
run: .github/workflows/sccache.sh ${{ runner.os}}
- name: Sccache statistics
run: sccache --show-stats
# here comes different part
- name: Checking ${{ matrix.platform }}-${{ matrix.toolchain }}
uses: actions-rs/cargo@v1.0.3
with:
command: check
toolchain: ${{ matrix.toolchain }}
args: --all --verbose
- name: Stop sccache
if: always()
run: sccache --stop-server
test:
name: Test
needs: [check]
strategy:
matrix:
platform:
- ubuntu-latest
- macos-latest
toolchain:
- stable
- nightly
compiler:
- clang
- gcc
runs-on: ${{ matrix.platform }}
env:
RUST_BACKTRACE: full
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0
- name: Set default compiler
if: matrix.compiler == 'clang'
run: |
echo "CC=clang" >> "$GITHUB_ENV"
echo "CXX=clang++" >> "$GITHUB_ENV"
- name: Checkout sources & submodules
uses: actions/checkout@v3.1.0
with:
fetch-depth: 5
submodules: recursive
- name: Install toolchain
id: toolchain
uses: actions-rs/toolchain@v1.0.7
with:
profile: minimal
toolchain: ${{ matrix.toolchain }}
components: clippy, rustfmt
override: true
- uses: Swatinem/rust-cache@22c9328bcba27aa81a32b1bef27c7e3c78052531 # v2.0.1
- name: Cache sccache
uses: actions/cache@v3.0.11
with:
path: "$HOME/sccache"
key: sccache-${{ env['cache_hash'] }}
- name: Install & start sccache for ${{ matrix.platform }}
shell: bash
run: .github/workflows/sccache.sh ${{ runner.os}}
- name: Sccache statistics
run: sccache --show-stats
# here comes different part
- name: Testing ${{ matrix.platform }}-${{ matrix.toolchain }} (debug build)
uses: actions-rs/cargo@v1.0.3
with:
command: test
toolchain: ${{ matrix.toolchain }}
args: --all --verbose
- name: Testing ${{ matrix.platform }}-${{ matrix.toolchain }} (release build)
uses: actions-rs/cargo@v1.0.3
with:
command: test
toolchain: ${{ matrix.toolchain }}
args: --all --release --verbose
- name: Stop sccache
if: always()
run: sccache --stop-server
build:
name: Build
needs: [check,test]
strategy:
matrix:
platform:
- ubuntu-latest
- macos-latest
toolchain:
- stable
- nightly
compiler:
- clang
- gcc
runs-on: ${{ matrix.platform }}
env:
RUST_BACKTRACE: full
# NOTE: Enables the aes-ni instructions for RustCrypto dependency.
# Strip binaries
# If you change this please remember to also update .cargo/config
RUSTFLAGS: "-C target-feature=+aes,+sse2,+ssse3 -C link-arg=-s"
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0
- name: Set default compiler
if: matrix.compiler == 'clang'
run: |
echo "CC=clang" >> "$GITHUB_ENV"
echo "CXX=clang++" >> "$GITHUB_ENV"
- name: Checkout sources & submodules
uses: actions/checkout@v3.1.0
with:
fetch-depth: 5
submodules: recursive
- name: Install toolchain
id: toolchain
uses: actions-rs/toolchain@v1.0.7
with:
profile: minimal
toolchain: ${{ matrix.toolchain }}
components: clippy, rustfmt
override: true
- uses: Swatinem/rust-cache@22c9328bcba27aa81a32b1bef27c7e3c78052531 # v2.0.1
- name: Cache sccache
uses: actions/cache@v3.0.11
with:
path: "$HOME/sccache"
key: sccache-${{ env['cache_hash'] }}
- name: Install & start sccache for ${{ matrix.platform }}
shell: bash
run: .github/workflows/sccache.sh ${{ runner.os}}
- name: Sccache statistics
run: sccache --show-stats
# here comes different part
- name: Building ${{ matrix.platform }}-${{ matrix.toolchain }}
uses: actions-rs/cargo@v1.0.3
with:
command: build
toolchain: ${{ matrix.toolchain }}
args: --all --verbose --release
- name: Building `no default` ${{ matrix.platform }}-${{ matrix.toolchain }}
uses: actions-rs/cargo@v1.0.3
with:
command: build
toolchain: ${{ matrix.toolchain }}
args: --verbose --no-default-features
- name: Building `hmac` ${{ matrix.platform }}-${{ matrix.toolchain }}
uses: actions-rs/cargo@v1.0.3
with:
command: build
toolchain: ${{ matrix.toolchain }}
args: --verbose --no-default-features --features hmac
- name: Building `static-context` ${{ matrix.platform }}-${{ matrix.toolchain }}
uses: actions-rs/cargo@v1.0.3
with:
command: build
toolchain: ${{ matrix.toolchain }}
args: --verbose --no-default-features --features static-context
- name: Building `lazy-static-context` ${{ matrix.platform }}-${{ matrix.toolchain }}
uses: actions-rs/cargo@v1.0.3
with:
command: build
toolchain: ${{ matrix.toolchain }}
args: --verbose --no-default-features --features lazy-static-context
- name: Stop sccache
if: always()
run: sccache --stop-server
- name: Prepare artifacts
run: .github/workflows/prepare_artifacts.sh ""
shell: bash
- name: Upload artifacts
uses: actions/upload-artifact@v3.1.0
with:
name: ${{ matrix.platform }}.${{ matrix.toolchain }}.${{ matrix.compiler }}.zip
path: artifacts/
================================================
FILE: .github/workflows/sccache.sh
================================================
#!/bin/bash
set -ex
export SCCACHE_CACHE_SIZE="1G"
export SCCACHE_IDLE_TIMEOUT=0
export SCCACHE_DIR="$HOME/sccache"
OS=$1
VERSION="0.2.13"
echo "Current OS: $OS"
case $OS in
"macOS")
PLATFORM="x86_64-apple-darwin"
;;
"Linux")
PLATFORM="x86_64-unknown-linux-musl"
;;
"Windows")
PLATFORM="x86_64-pc-windows-msvc"
VERSION="0.2.14"
;;
esac
echo "Target arch: " $PLATFORM
BASENAME="sccache-$VERSION-$PLATFORM"
URL="https://github.com/mozilla/sccache/releases/download/$VERSION/$BASENAME.tar.gz"
echo "Download sccache from " "$URL"
curl -LO "$URL"
tar -xzvf "$BASENAME.tar.gz"
ls $BASENAME/
echo "$(pwd)/$BASENAME" >> "$GITHUB_PATH"
echo "RUSTC_WRAPPER=sccache" >> "$GITHUB_ENV"
./$BASENAME/sccache --start-server
================================================
FILE: .gitignore
================================================
/target/
**/*.rs.bk
Cargo.lock
*.swp
/.idea
/shell.nix
================================================
FILE: CHANGELOG.md
================================================
# Changelog
The format is based on [Keep a Changelog].
[Keep a Changelog]: http://keepachangelog.com/en/1.0.0/
## [0.5.0] - 2021-05-18
- Add standard non-overflowing signature parsing `Signature::parse_standard`. The previous behavior `Signature::parse` is considered non-standard and renamed to `Signature::parse_overflowing`. Unless you have a specific need, you should switch to use the new `Signature::parse_standard` function. (PR #67)
## [0.3.5] - 2020-02-06
- Implement `std::error::Error` and `Display` for `Error`. (PR #29)
- Fix the PartialEq impl of Field. (PR #30)
- Add `LowerHex` implementation for `SecretKey` and `Scalar`. (PR #32)
- Put signing behind feature flag. (PR #33)
================================================
FILE: Cargo.toml
================================================
[package]
name = "libsecp256k1"
description = "Pure Rust secp256k1 implementation."
license = "Apache-2.0"
version = "0.7.2"
authors = ["Wei Tang <hi@that.world>"]
repository = "https://github.com/paritytech/libsecp256k1"
keywords = ["crypto", "ECDSA", "secp256k1", "bitcoin", "no_std"]
edition = "2018"
resolver = "2"
[dependencies]
libsecp256k1-core = { version = "0.3.0", path = "core", default-features = false }
arrayref = "0.3"
rand = { version = "0.8", default-features = false }
digest = "0.9"
base64 = { version = "0.22", default-features = false }
hmac-drbg = { version = "0.3", optional = true }
sha2 = { version = "0.9", optional = true, default-features = false }
typenum = { version = "1.12", optional = true }
serde = { version = "1.0.104", features = ["derive"], default-features = false }
lazy_static = { version = "1.4.0", optional = true }
[dev-dependencies]
secp256k1-test = { package = "secp256k1", version = "0.20.3", features = ["rand-std", "recovery"] }
clear_on_drop = "0.2"
serde_json = "1.0"
hex = "0.4"
hex-literal = "0.3.3"
bincode = "1.3.3"
[build-dependencies]
libsecp256k1-gen-ecmult = { version = "0.3.0", path = "gen/ecmult" }
libsecp256k1-gen-genmult = { version = "0.3.0", path = "gen/genmult" }
[features]
default = ["std", "hmac", "static-context"]
std = ["libsecp256k1-core/std", "sha2/std", "rand/std", "serde/std", "base64/std"]
hmac = ["hmac-drbg", "sha2", "typenum"]
static-context = []
lazy-static-context = ["static-context", "lazy_static", "std"]
[workspace]
members = [
"./gen/ecmult",
"./gen/genmult",
]
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
_Please note that this repository is no longer maintained. You can use [k256](https://crates.io/crates/k256) instead._
# SECP256K1 implementation in pure Rust
* [Cargo](https://crates.io/crates/libsecp256k1)
* [Documentation](https://docs.rs/libsecp256k1)
SECP256K1 implementation with `no_std` support. Currently we have implementation for:
* Convert a private key to a public key.
* Sign messages.
* Signature verification.
* Public key recovery from signed messages.
* Shared secrets.
## Feature flags
* `std`: If disabled, works in `no_std` environment. Enabled by default.
* `hmac`: Add certain features that requires the HMAC-DRBG. This includes
signing. Enabled by default.
* `static-context`: To speed up computation, the library uses a pre-computed
table context for many `ecmult` operations. This feature flag puts the context
directly as static variables. If disabled, the context must be created from
heap manually. Increases binary size, enabled by default.
* `lazy-static-context`: Instead of storing the pre-computed table context as
static variables, store it as a variable that dynamically allocates the
context in heap via `lazy_static`. It overwrites `static-context`. Impact
bootstrap performance and only available in `std`, disabled by default.
## Development workflow
### Branch
This repository uses `develop` branch for development. Changes are periodically
merged to `master` branch.
### Pull request
All changes (except new releases) are handled through pull requests. Please open
your PR against `develop` branch.
### Versioning
`libsecp256k1` follows [Semantic Versioning](https://semver.org/). An unreleased crate
in the repository will have the `-dev` suffix in the end, and we do rolling
releases.
When you make a pull request against this repository, please also update the
affected crates' versions, using the following rules. Note that the rules should
be applied recursively -- if a change modifies any upper crate's dependency
(even just the `Cargo.toml` file), then the upper crate will also need to apply
those rules.
Additionally, if your change is notable, then you should also modify the
corresponding `CHANGELOG.md` file, in the "Unreleased" section.
If the affected crate already has `-dev` suffix:
* If your change is a patch, then you do not have to update any versions.
* If your change introduces a new feature, please check if the local version
already had its minor version bumped, if not, bump it.
* If your change modifies the current interface, please check if the local
version already had its major version bumped, if not, bump it.
If the affected crate does not yet have `-dev` suffix:
* If your change is a patch, then bump the patch version, and add `-dev` suffix.
* If your change introduces a new feature, then bump the minor version, and add
`-dev` suffix.
* If your change modifies the current interface, then bump the major version,
and add `-dev` suffix.
If your pull request introduces a new crate, please set its version to
`1.0.0-dev`.
================================================
FILE: benches/public_key.rs
================================================
#![feature(test)]
extern crate test;
use libsecp256k1::PublicKey;
use secp256k1_test::{rand::thread_rng, Secp256k1};
use test::Bencher;
#[bench]
fn bench_public_key_parse(b: &mut Bencher) {
let secp256k1 = Secp256k1::new();
let (_, secp_pubkey) = secp256k1.generate_keypair(&mut thread_rng());
let pubkey_arr = secp_pubkey.serialize_uncompressed();
assert!(pubkey_arr.len() == 65);
let mut pubkey_a = [0u8; 65];
pubkey_a[0..65].copy_from_slice(&pubkey_arr[0..65]);
b.iter(|| {
let _pubkey = PublicKey::parse(&pubkey_a).unwrap();
});
}
#[bench]
fn bench_public_key_serialize(b: &mut Bencher) {
let secp256k1 = Secp256k1::new();
let (_, secp_pubkey) = secp256k1.generate_keypair(&mut thread_rng());
let pubkey_arr = secp_pubkey.serialize_uncompressed();
assert!(pubkey_arr.len() == 65);
let mut pubkey_a = [0u8; 65];
pubkey_a[0..65].copy_from_slice(&pubkey_arr[0..65]);
let pubkey = PublicKey::parse(&pubkey_a).unwrap();
b.iter(|| {
let _serialized = pubkey.serialize();
});
}
#[bench]
fn bench_public_key_serialize_compressed(b: &mut Bencher) {
let secp256k1 = Secp256k1::new();
let (_, secp_pubkey) = secp256k1.generate_keypair(&mut thread_rng());
let pubkey_arr = secp_pubkey.serialize_uncompressed();
assert!(pubkey_arr.len() == 65);
let mut pubkey_a = [0u8; 65];
pubkey_a[0..65].copy_from_slice(&pubkey_arr[0..65]);
let pubkey = PublicKey::parse(&pubkey_a).unwrap();
b.iter(|| {
let _serialized = pubkey.serialize_compressed();
});
}
================================================
FILE: benches/sign.rs
================================================
#![feature(test)]
extern crate test;
use arrayref::array_ref;
use libsecp256k1::{sign, Message, SecretKey};
use secp256k1_test::{rand::thread_rng, Secp256k1};
use test::Bencher;
#[bench]
fn bench_sign_message(b: &mut Bencher) {
let secp256k1 = Secp256k1::new();
let message = Message::parse(&[5u8; 32]);
let (secp_privkey, _) = secp256k1.generate_keypair(&mut thread_rng());
let seckey = SecretKey::parse(array_ref!(secp_privkey, 0, 32)).unwrap();
b.iter(|| {
let _ = sign(&message, &seckey);
});
}
================================================
FILE: benches/signature.rs
================================================
#![feature(test)]
extern crate test;
use libsecp256k1::Signature;
use secp256k1_test::{rand::thread_rng, Message as SecpMessage, Secp256k1};
use test::Bencher;
#[bench]
fn bench_signature_parse(b: &mut Bencher) {
let secp256k1 = Secp256k1::new();
let message_arr = [5u8; 32];
let (privkey, _) = secp256k1.generate_keypair(&mut thread_rng());
let message = SecpMessage::from_slice(&message_arr).unwrap();
let signature = secp256k1.sign(&message, &privkey);
let signature_arr = signature.serialize_compact();
assert!(signature_arr.len() == 64);
let mut signature_a = [0u8; 64];
signature_a.copy_from_slice(&signature_arr[0..64]);
b.iter(|| {
let _signature = Signature::parse_standard_slice(&signature_a);
});
}
#[bench]
fn bench_signature_serialize(b: &mut Bencher) {
let secp256k1 = Secp256k1::new();
let message_arr = [5u8; 32];
let (privkey, _) = secp256k1.generate_keypair(&mut thread_rng());
let message = SecpMessage::from_slice(&message_arr).unwrap();
let signature = secp256k1.sign(&message, &privkey);
let signature_arr = signature.serialize_compact();
assert!(signature_arr.len() == 64);
let mut signature_a = [0u8; 64];
signature_a.copy_from_slice(&signature_arr[0..64]);
let signature = Signature::parse_standard_slice(&signature_a).expect("parsed signature");
b.iter(|| {
let _serialized = signature.serialize();
});
}
================================================
FILE: build.rs
================================================
use std::{env, fs::File, io::Write, path::Path};
fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let const_path = Path::new(&out_dir).join("const.rs");
let mut const_file = File::create(&const_path).expect("Create const.rs file failed");
libsecp256k1_gen_ecmult::generate_to(&mut const_file).expect("Write const.rs file failed");
const_file.flush().expect("Flush const.rs file failed");
let gen_path = Path::new(&out_dir).join("const_gen.rs");
let mut gen_file = File::create(&gen_path).expect("Create const_gen.rs file failed");
libsecp256k1_gen_genmult::generate_to(&mut gen_file).expect("Write const_gen.rs file failed");
gen_file.flush().expect("Flush const_gen.rs file failed");
}
================================================
FILE: core/Cargo.toml
================================================
[package]
name = "libsecp256k1-core"
description = "Core functions for pure Rust secp256k1 implementation."
license = "Apache-2.0"
version = "0.3.0"
authors = ["Wei Tang <hi@that.world>"]
repository = "https://github.com/paritytech/libsecp256k1"
keywords = ["crypto", "ECDSA", "secp256k1", "bitcoin", "no_std"]
edition = "2018"
[dependencies]
subtle = { version = "2.2", default-features = false }
crunchy = "0.2"
digest = "0.9"
[features]
default = ["std"]
std = ["subtle/std"]
================================================
FILE: core/src/der.rs
================================================
use core::{
convert::{AsMut, AsRef},
mem,
};
use crate::{error::Error, scalar::Scalar};
pub struct SignatureArray([u8; 6 + 33 + 33], usize);
impl SignatureArray {
pub fn new(size: usize) -> Self {
SignatureArray([0u8; 6 + 33 + 33], size)
}
pub fn len(&self) -> usize {
self.1
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl AsRef<[u8]> for SignatureArray {
fn as_ref(&self) -> &[u8] {
&self.0[..self.1]
}
}
impl AsMut<[u8]> for SignatureArray {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0[..self.1]
}
}
pub struct Decoder<'a>(&'a [u8], usize);
impl<'a> Decoder<'a> {
pub fn new(arr: &'a [u8]) -> Self {
Decoder(arr, 0)
}
pub fn remaining_len(&self) -> usize {
self.0.len() - self.1
}
pub fn read(&mut self) -> Result<u8, Error> {
if self.1 >= self.0.len() {
Err(Error::InvalidSignature)
} else {
let v = self.0[self.1];
self.1 += 1;
Ok(v)
}
}
pub fn peek(&self, forward: usize) -> Result<u8, Error> {
if self.1 + forward >= self.0.len() {
Err(Error::InvalidSignature)
} else {
let v = self.0[self.1 + forward];
Ok(v)
}
}
pub fn peek_slice(&self, len: usize) -> Result<&[u8], Error> {
if (len == 0 && self.1 >= self.0.len()) || self.1 + len > self.0.len() {
Err(Error::InvalidSignature)
} else {
let v = &self.0[self.1..(self.1 + len)];
Ok(v)
}
}
pub fn skip(&mut self, len: usize) -> Result<(), Error> {
if (len == 0 && self.1 >= self.0.len()) || self.1 + len > self.0.len() {
Err(Error::InvalidSignature)
} else {
self.1 += len;
Ok(())
}
}
pub fn read_constructed_sequence(&mut self) -> Result<(), Error> {
let v = self.read()?;
if v == 0x30 {
Ok(())
} else {
Err(Error::InvalidSignature)
}
}
pub fn read_len(&mut self) -> Result<usize, Error> {
let b1 = self.read()?;
if b1 == 0xff {
return Err(Error::InvalidSignature);
}
// Short form
if b1 & 0x80 == 0 {
return Ok(b1 as usize);
}
// Infinite length is not allowed
if b1 == 0x80 {
return Err(Error::InvalidSignature);
}
let mut lenleft = (b1 & 0x7f) as usize;
if lenleft > self.remaining_len() {
return Err(Error::InvalidSignature);
}
if self.peek(0)? == 0 {
// Not the shortest possible length encoding
return Err(Error::InvalidSignature);
}
if lenleft > mem::size_of::<usize>() {
return Err(Error::InvalidSignature);
}
let mut ret = 0;
while lenleft > 0 {
ret = (ret << 8) | (self.read()? as usize);
if ret + lenleft > self.remaining_len() {
return Err(Error::InvalidSignature);
}
lenleft -= 1;
}
if ret < 128 {
// Not the shortest possible length encoding
return Err(Error::InvalidSignature);
}
Ok(ret)
}
pub fn read_integer(&mut self) -> Result<Scalar, Error> {
if self.read()? != 0x02 {
return Err(Error::InvalidSignature);
}
let mut rlen = self.read_len()?;
if rlen == 0 || rlen > self.remaining_len() {
return Err(Error::InvalidSignature);
}
if self.peek(0)? == 0x00 && rlen > 1 && (self.peek(1)? & 0x80) == 0x00 {
return Err(Error::InvalidSignature);
}
if self.peek(0)? == 0xff && rlen > 1 && (self.peek(1)? & 0x80) == 0x00 {
return Err(Error::InvalidSignature);
}
let mut overflow = false;
if self.peek(0)? & 0x80 == 0x80 {
overflow |= true;
}
// Skip leading zero bytes
while rlen > 0 && self.peek(0)? == 0 {
rlen -= 1;
self.read()?;
}
if rlen > 32 {
overflow |= true;
}
let mut int = Scalar::default();
if !overflow {
let mut b32 = [0u8; 32];
b32[32 - rlen..].copy_from_slice(self.peek_slice(rlen)?);
self.skip(rlen)?;
overflow |= bool::from(int.set_b32(&b32));
}
if overflow {
int = Scalar::default();
}
Ok(int)
}
pub fn read_seq_len_lax(&mut self) -> Result<usize, Error> {
let mut len = self.read()?;
if len & 0x80 != 0x00 {
len -= 0x80;
if len as usize > self.remaining_len() {
return Err(Error::InvalidSignature);
}
self.skip(len as usize)?;
}
Ok(len as usize)
}
pub fn read_len_lax(&mut self) -> Result<usize, Error> {
let mut ret = 0usize;
let mut len = self.read()?;
if len & 0x80 != 0x00 {
len -= 0x80;
if len as usize > self.remaining_len() {
return Err(Error::InvalidSignature);
}
while len > 0 && self.peek(0)? == 0 {
self.skip(1)?;
len -= 1;
}
if (len as usize) >= mem::size_of::<usize>() {
return Err(Error::InvalidSignature);
}
while len > 0 {
ret = (ret << 8) + (self.read()? as usize);
len -= 1;
}
} else {
ret = len as usize;
}
if ret > self.remaining_len() {
return Err(Error::InvalidSignature);
}
Ok(ret)
}
pub fn read_integer_lax(&mut self) -> Result<Scalar, Error> {
// Integer tag byte.
if self.read()? != 0x02 {
return Err(Error::InvalidSignature);
}
let mut len = self.read_len_lax()?;
// Ignore leading zeroes.
while len > 0 && self.peek(0)? == 0 {
len -= 1;
self.skip(1)?;
}
let mut overflow = false;
// Copy value
if len > 32 {
overflow |= true;
}
let mut int = Scalar::default();
if !overflow {
let mut b32 = [0u8; 32];
b32[32 - len..].copy_from_slice(&self.peek_slice(len)?);
self.skip(len)?;
overflow |= bool::from(int.set_b32(&b32));
}
if overflow {
int = Scalar::default();
}
Ok(int)
}
}
================================================
FILE: core/src/ecdh.rs
================================================
use crate::{
ecmult::ECMultContext,
group::{Affine, Jacobian},
scalar::Scalar,
};
use digest::{generic_array::GenericArray, Digest};
impl ECMultContext {
pub fn ecdh_raw<D: Digest + Default>(
&self,
point: &Affine,
scalar: &Scalar,
) -> Option<GenericArray<u8, D::OutputSize>> {
let mut digest: D = Default::default();
let mut pt = *point;
let s = *scalar;
if s.is_zero() {
return None;
}
let mut res = Jacobian::default();
self.ecmult_const(&mut res, &pt, &s);
pt.set_gej(&res);
pt.x.normalize();
pt.y.normalize();
let x = pt.x.b32();
let y = 0x02 | (if pt.y.is_odd() { 1 } else { 0 });
digest.update(&[y]);
digest.update(&x);
Some(digest.finalize_reset())
}
}
================================================
FILE: core/src/ecdsa.rs
================================================
use crate::{
ecmult::{ECMultContext, ECMultGenContext},
field::Field,
group::{Affine, Jacobian},
scalar::Scalar,
Error,
};
const P_MINUS_ORDER: Field = Field::new(0, 0, 0, 1, 0x45512319, 0x50B75FC4, 0x402DA172, 0x2FC9BAEE);
const ORDER_AS_FE: Field = Field::new(
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xBAAEDCE6, 0xAF48A03B, 0xBFD25E8C, 0xD0364141,
);
impl ECMultContext {
pub fn verify_raw(
&self,
sigr: &Scalar,
sigs: &Scalar,
pubkey: &Affine,
message: &Scalar,
) -> bool {
let c;
let (sn, u1, u2): (Scalar, Scalar, Scalar);
if sigr.is_zero() || sigs.is_zero() {
return false;
}
sn = sigs.inv_var();
u1 = &sn * message;
u2 = &sn * sigr;
let mut pubkeyj: Jacobian = Jacobian::default();
pubkeyj.set_ge(pubkey);
let mut pr: Jacobian = Jacobian::default();
self.ecmult(&mut pr, &pubkeyj, &u2, &u1);
if pr.is_infinity() {
return false;
}
c = sigr.b32();
let mut xr: Field = Default::default();
let _ = xr.set_b32(&c);
if pr.eq_x_var(&xr) {
return true;
}
if xr >= P_MINUS_ORDER {
return false;
}
xr += ORDER_AS_FE;
if pr.eq_x_var(&xr) {
return true;
}
false
}
pub fn recover_raw(
&self,
sigr: &Scalar,
sigs: &Scalar,
rec_id: u8,
message: &Scalar,
) -> Result<Affine, Error> {
debug_assert!(rec_id < 4);
if sigr.is_zero() || sigs.is_zero() {
return Err(Error::InvalidSignature);
}
let brx = sigr.b32();
let mut fx = Field::default();
let overflow = fx.set_b32(&brx);
debug_assert!(overflow);
if rec_id & 2 > 0 {
if fx >= P_MINUS_ORDER {
return Err(Error::InvalidSignature);
}
fx += ORDER_AS_FE;
}
let mut x = Affine::default();
if !x.set_xo_var(&fx, rec_id & 1 > 0) {
return Err(Error::InvalidSignature);
}
let mut xj = Jacobian::default();
xj.set_ge(&x);
let rn = sigr.inv();
let mut u1 = &rn * message;
u1 = -u1;
let u2 = &rn * sigs;
let mut qj = Jacobian::default();
self.ecmult(&mut qj, &xj, &u2, &u1);
let mut pubkey = Affine::default();
pubkey.set_gej_var(&qj);
if pubkey.is_infinity() {
Err(Error::InvalidSignature)
} else {
Ok(pubkey)
}
}
}
impl ECMultGenContext {
pub fn sign_raw(
&self,
seckey: &Scalar,
message: &Scalar,
nonce: &Scalar,
) -> Result<(Scalar, Scalar, u8), Error> {
let mut rp = Jacobian::default();
self.ecmult_gen(&mut rp, nonce);
let mut r = Affine::default();
r.set_gej(&rp);
r.x.normalize();
r.y.normalize();
let b = r.x.b32();
let mut sigr = Scalar::default();
let overflow = bool::from(sigr.set_b32(&b));
debug_assert!(!sigr.is_zero());
debug_assert!(!overflow);
let mut recid = (if overflow { 2 } else { 0 }) | (if r.y.is_odd() { 1 } else { 0 });
let mut n = &sigr * seckey;
n += message;
let mut sigs = nonce.inv();
sigs *= &n;
n.clear();
rp.clear();
r.clear();
if sigs.is_zero() {
return Err(Error::InvalidMessage);
}
if sigs.is_high() {
sigs = -sigs;
recid ^= 1;
}
Ok((sigr, sigs, recid))
}
}
================================================
FILE: core/src/ecmult.rs
================================================
use crate::{
field::Field,
group::{globalz_set_table_gej, set_table_gej_var, Affine, AffineStorage, Jacobian, AFFINE_G},
scalar::Scalar,
};
use alloc::{
alloc::{alloc, Layout},
boxed::Box,
vec,
vec::Vec,
};
use subtle::Choice;
pub const WINDOW_A: usize = 5;
pub const WINDOW_G: usize = 16;
pub const ECMULT_TABLE_SIZE_A: usize = 1 << (WINDOW_A - 2);
pub const ECMULT_TABLE_SIZE_G: usize = 1 << (WINDOW_G - 2);
pub const WNAF_BITS: usize = 256;
fn odd_multiples_table_storage_var(pre: &mut [AffineStorage], a: &Jacobian) {
let mut prej: Vec<Jacobian> = Vec::with_capacity(pre.len());
for _ in 0..pre.len() {
prej.push(Jacobian::default());
}
let mut prea: Vec<Affine> = Vec::with_capacity(pre.len());
for _ in 0..pre.len() {
prea.push(Affine::default());
}
let mut zr: Vec<Field> = Vec::with_capacity(pre.len());
for _ in 0..pre.len() {
zr.push(Field::default());
}
odd_multiples_table(&mut prej, &mut zr, a);
set_table_gej_var(&mut prea, &prej, &zr);
for i in 0..pre.len() {
pre[i] = prea[i].into();
}
}
/// Context for accelerating the computation of a*P + b*G.
pub struct ECMultContext {
pre_g: [AffineStorage; ECMULT_TABLE_SIZE_G],
}
impl ECMultContext {
/// Create a new `ECMultContext` from raw values.
///
/// # Safety
/// The function is unsafe because incorrect value of `pre_g` can lead to
/// crypto logic failure. You most likely do not want to use this function,
/// but `ECMultContext::new_boxed`.
pub const unsafe fn new_from_raw(pre_g: [AffineStorage; ECMULT_TABLE_SIZE_G]) -> Self {
Self { pre_g }
}
/// Inspect raw values of `ECMultContext`.
pub fn inspect_raw(&self) -> &[AffineStorage; ECMULT_TABLE_SIZE_G] {
&self.pre_g
}
/// Generate a new `ECMultContext` on the heap. Note that this function is expensive.
pub fn new_boxed() -> Box<Self> {
// This unsafe block allocates a new, unitialized `ECMultContext` and
// then fills in the value. This is to avoid allocating it on stack
// because the struct is big. All values in `ECMultContext` are manually
// initialized after allocation.
let mut this = unsafe {
let ptr = alloc(Layout::new::<ECMultContext>()) as *mut ECMultContext;
let mut this = Box::from_raw(ptr);
for i in 0..ECMULT_TABLE_SIZE_G {
this.pre_g[i] = AffineStorage::default();
}
this
};
let mut gj = Jacobian::default();
gj.set_ge(&AFFINE_G);
odd_multiples_table_storage_var(&mut this.pre_g, &gj);
this
}
}
/// Set a batch of group elements equal to the inputs given in jacobian
/// coordinates. Not constant time.
pub fn set_all_gej_var(a: &[Jacobian]) -> Vec<Affine> {
let mut az: Vec<Field> = Vec::with_capacity(a.len());
for point in a {
if !point.is_infinity() {
az.push(point.z);
}
}
let azi: Vec<Field> = inv_all_var(&az);
let mut ret = vec![Affine::default(); a.len()];
let mut count = 0;
for i in 0..a.len() {
ret[i].infinity = a[i].infinity;
if !a[i].is_infinity() {
ret[i].set_gej_zinv(&a[i], &azi[count]);
count += 1;
}
}
ret
}
/// Calculate the (modular) inverses of a batch of field
/// elements. Requires the inputs' magnitudes to be at most 8. The
/// output magnitudes are 1 (but not guaranteed to be
/// normalized).
pub fn inv_all_var(fields: &[Field]) -> Vec<Field> {
if fields.is_empty() {
return Vec::new();
}
let mut ret = Vec::with_capacity(fields.len());
ret.push(fields[0]);
for i in 1..fields.len() {
ret.push(Field::default());
ret[i] = ret[i - 1] * fields[i];
}
let mut u = ret[fields.len() - 1].inv_var();
for i in (1..fields.len()).rev() {
let j = i;
let i = i - 1;
ret[j] = ret[i] * u;
u *= fields[j];
}
ret[0] = u;
ret
}
const GEN_BLIND: Scalar = Scalar([
2217680822, 850875797, 1046150361, 1330484644, 4015777837, 2466086288, 2052467175, 2084507480,
]);
const GEN_INITIAL: Jacobian = Jacobian {
x: Field::new_raw(
586608, 43357028, 207667908, 262670128, 142222828, 38529388, 267186148, 45417712,
115291924, 13447464,
),
y: Field::new_raw(
12696548, 208302564, 112025180, 191752716, 143238548, 145482948, 228906000, 69755164,
243572800, 210897016,
),
z: Field::new_raw(
3685368, 75404844, 20246216, 5748944, 73206666, 107661790, 110806176, 73488774, 5707384,
104448710,
),
infinity: false,
};
/// Context for accelerating the computation of a*G.
pub struct ECMultGenContext {
prec: [[AffineStorage; 16]; 64],
blind: Scalar,
initial: Jacobian,
}
impl ECMultGenContext {
/// Create a new `ECMultGenContext` from raw values.
///
/// # Safety
/// The function is unsafe because incorrect value of `pre_g` can lead to
/// crypto logic failure. You most likely do not want to use this function,
/// but `ECMultGenContext::new_boxed`.
pub const unsafe fn new_from_raw(prec: [[AffineStorage; 16]; 64]) -> Self {
Self {
prec,
blind: GEN_BLIND,
initial: GEN_INITIAL,
}
}
/// Inspect `ECMultGenContext` values.
pub fn inspect_raw(&self) -> &[[AffineStorage; 16]; 64] {
&self.prec
}
/// Generate a new `ECMultGenContext` on the heap. Note that this function is expensive.
pub fn new_boxed() -> Box<Self> {
// This unsafe block allocates a new, unitialized `ECMultGenContext` and
// then fills in the value. This is to avoid allocating it on stack
// because the struct is big. All values in `ECMultGenContext` are
// manually initialized after allocation.
let mut this = unsafe {
let ptr = alloc(Layout::new::<ECMultGenContext>()) as *mut ECMultGenContext;
let mut this = Box::from_raw(ptr);
for j in 0..64 {
for i in 0..16 {
this.prec[j][i] = AffineStorage::default();
}
}
this.blind = GEN_BLIND;
this.initial = GEN_INITIAL;
this
};
let mut gj = Jacobian::default();
gj.set_ge(&AFFINE_G);
// Construct a group element with no known corresponding scalar (nothing up my sleeve).
let mut nums_32 = [0u8; 32];
debug_assert!(b"The scalar for this x is unknown".len() == 32);
for (i, v) in b"The scalar for this x is unknown".iter().enumerate() {
nums_32[i] = *v;
}
let mut nums_x = Field::default();
assert!(nums_x.set_b32(&nums_32));
let mut nums_ge = Affine::default();
assert!(nums_ge.set_xo_var(&nums_x, false));
let mut nums_gej = Jacobian::default();
nums_gej.set_ge(&nums_ge);
nums_gej = nums_gej.add_ge_var(&AFFINE_G, None);
// Compute prec.
let mut precj: Vec<Jacobian> = Vec::with_capacity(1024);
for _ in 0..1024 {
precj.push(Jacobian::default());
}
let mut gbase = gj;
let mut numsbase = nums_gej;
for j in 0..64 {
precj[j * 16] = numsbase;
for i in 1..16 {
precj[j * 16 + i] = precj[j * 16 + i - 1].add_var(&gbase, None);
}
for _ in 0..4 {
gbase = gbase.double_var(None);
}
numsbase = numsbase.double_var(None);
if j == 62 {
numsbase = numsbase.neg();
numsbase = numsbase.add_var(&nums_gej, None);
}
}
let prec = set_all_gej_var(&precj);
for j in 0..64 {
for i in 0..16 {
let pg: AffineStorage = prec[j * 16 + i].into();
this.prec[j][i] = pg;
}
}
this
}
}
pub fn odd_multiples_table(prej: &mut [Jacobian], zr: &mut [Field], a: &Jacobian) {
debug_assert!(prej.len() == zr.len());
debug_assert!(!prej.is_empty());
debug_assert!(!a.is_infinity());
let d = a.double_var(None);
let d_ge = Affine {
x: d.x,
y: d.y,
infinity: false,
};
let mut a_ge = Affine::default();
a_ge.set_gej_zinv(a, &d.z);
prej[0].x = a_ge.x;
prej[0].y = a_ge.y;
prej[0].z = a.z;
prej[0].infinity = false;
zr[0] = d.z;
for i in 1..prej.len() {
prej[i] = prej[i - 1].add_ge_var(&d_ge, Some(&mut zr[i]));
}
let l = prej.last().unwrap().z * d.z;
prej.last_mut().unwrap().z = l;
}
fn odd_multiples_table_globalz_windowa(
pre: &mut [Affine; ECMULT_TABLE_SIZE_A],
globalz: &mut Field,
a: &Jacobian,
) {
let mut prej: [Jacobian; ECMULT_TABLE_SIZE_A] = Default::default();
let mut zr: [Field; ECMULT_TABLE_SIZE_A] = Default::default();
odd_multiples_table(&mut prej, &mut zr, a);
globalz_set_table_gej(pre, globalz, &prej, &zr);
}
fn table_get_ge(r: &mut Affine, pre: &[Affine], n: i32, w: usize) {
debug_assert!(n & 1 == 1);
debug_assert!(n >= -((1 << (w - 1)) - 1));
debug_assert!(n <= ((1 << (w - 1)) - 1));
if n > 0 {
*r = pre[((n - 1) / 2) as usize];
} else {
*r = pre[((-n - 1) / 2) as usize].neg();
}
}
fn table_get_ge_const(r: &mut Affine, pre: &[Affine], n: i32, w: usize) {
let abs_n = n * (if n > 0 { 1 } else { 0 } * 2 - 1);
let idx_n = abs_n / 2;
debug_assert!(n & 1 == 1);
debug_assert!(n >= -((1 << (w - 1)) - 1));
debug_assert!(n <= ((1 << (w - 1)) - 1));
for m in 0..pre.len() {
let flag = m == idx_n as usize;
r.x.cmov(&pre[m].x, flag);
r.y.cmov(&pre[m].y, flag);
}
r.infinity = false;
let neg_y = r.y.neg(1);
r.y.cmov(&neg_y, n != abs_n);
}
fn table_get_ge_storage(r: &mut Affine, pre: &[AffineStorage], n: i32, w: usize) {
debug_assert!(n & 1 == 1);
debug_assert!(n >= -((1 << (w - 1)) - 1));
debug_assert!(n <= ((1 << (w - 1)) - 1));
if n > 0 {
*r = pre[((n - 1) / 2) as usize].into();
} else {
*r = pre[((-n - 1) / 2) as usize].into();
*r = r.neg();
}
}
pub fn ecmult_wnaf(wnaf: &mut [i32], a: &Scalar, w: usize) -> i32 {
let mut s = *a;
let mut last_set_bit: i32 = -1;
let mut bit = 0;
let mut sign = 1;
let mut carry = 0;
debug_assert!(wnaf.len() <= 256);
debug_assert!(w >= 2 && w <= 31);
for i in 0..wnaf.len() {
wnaf[i] = 0;
}
if s.bits(255, 1) > 0 {
s = -s;
sign = -1;
}
while bit < wnaf.len() {
let mut now;
let mut word;
if s.bits(bit, 1) == carry as u32 {
bit += 1;
continue;
}
now = w;
if now > wnaf.len() - bit {
now = wnaf.len() - bit;
}
word = (s.bits_var(bit, now) as i32) + carry;
carry = (word >> (w - 1)) & 1;
word -= carry << w;
wnaf[bit] = sign * word;
last_set_bit = bit as i32;
bit += now;
}
debug_assert!(carry == 0);
debug_assert!({
let mut t = true;
while bit < 256 {
t = t && (s.bits(bit, 1) == 0);
bit += 1;
}
t
});
last_set_bit + 1
}
pub fn ecmult_wnaf_const(wnaf: &mut [i32], a: &Scalar, w: usize) -> i32 {
let mut s = *a;
let mut word = 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 technique from Section
* 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for
* even) or 2 (for odd) to the number we are encoding, returning a
* skew value indicating this, and having the caller compensate
* after doing the multiplication. */
/* Negative numbers will be negated to keep their bit
* representation below the maximum width */
let flip = s.is_high();
/* We add 1 to even numbers, 2 to odd ones, noting that negation
* flips parity */
let bit = flip ^ !s.is_even();
/* We add 1 to even numbers, 2 to odd ones, noting that negation
* flips parity */
let neg_s = -s;
let not_neg_one = !neg_s.is_one();
s.cadd_bit(if bit { 1 } else { 0 }, not_neg_one);
/* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so
* caller expects that we added two to it and flipped it. In fact
* for -1 these operations are identical. We only flipped, but
* since skewing is required (in the sense that the skew must be 1
* or 2, never zero) and flipping is not, we need to change our
* flags to claim that we only skewed. */
let mut global_sign = if flip { -1 } else { 1 };
s.cond_neg_assign(Choice::from(flip as u8));
global_sign *= if not_neg_one { 1 } else { 0 } * 2 - 1;
let skew = 1 << (if bit { 1 } else { 0 });
let mut u_last: i32 = s.shr_int(w) as i32;
let mut u: i32 = 0;
while word * w < WNAF_BITS {
u = s.shr_int(w) as i32;
let even = (u & 1) == 0;
let sign = 2 * (if u_last > 0 { 1 } else { 0 }) - 1;
u += sign * if even { 1 } else { 0 };
u_last -= sign * if even { 1 } else { 0 } * (1 << w);
wnaf[word] = (u_last as i32 * global_sign as i32) as i32;
word += 1;
u_last = u;
}
wnaf[word] = u * global_sign as i32;
debug_assert!(s.is_zero());
let wnaf_size = (WNAF_BITS + w - 1) / w;
debug_assert!(word == wnaf_size);
skew
}
impl ECMultContext {
pub fn ecmult(&self, r: &mut Jacobian, a: &Jacobian, na: &Scalar, ng: &Scalar) {
let mut tmpa = Affine::default();
let mut pre_a: [Affine; ECMULT_TABLE_SIZE_A] = Default::default();
let mut z = Field::default();
let mut wnaf_na = [0i32; 256];
let mut wnaf_ng = [0i32; 256];
let bits_na = ecmult_wnaf(&mut wnaf_na, na, WINDOW_A);
let mut bits = bits_na;
odd_multiples_table_globalz_windowa(&mut pre_a, &mut z, a);
let bits_ng = ecmult_wnaf(&mut wnaf_ng, &ng, WINDOW_G);
if bits_ng > bits {
bits = bits_ng;
}
r.set_infinity();
for i in (0..bits).rev() {
let mut n;
*r = r.double_var(None);
n = wnaf_na[i as usize];
if i < bits_na && n != 0 {
table_get_ge(&mut tmpa, &pre_a, n, WINDOW_A);
*r = r.add_ge_var(&tmpa, None);
}
n = wnaf_ng[i as usize];
if i < bits_ng && n != 0 {
table_get_ge_storage(&mut tmpa, &self.pre_g, n, WINDOW_G);
*r = r.add_zinv_var(&tmpa, &z);
}
}
if !r.is_infinity() {
r.z *= &z;
}
}
pub fn ecmult_const(&self, r: &mut Jacobian, a: &Affine, scalar: &Scalar) {
const WNAF_SIZE: usize = (WNAF_BITS + (WINDOW_A - 1) - 1) / (WINDOW_A - 1);
let mut tmpa = Affine::default();
let mut pre_a: [Affine; ECMULT_TABLE_SIZE_A] = Default::default();
let mut z = Field::default();
let mut wnaf_1 = [0i32; 1 + WNAF_SIZE];
let sc = *scalar;
let skew_1 = ecmult_wnaf_const(&mut wnaf_1, &sc, WINDOW_A - 1);
/* Calculate odd multiples of a. All multiples are brought to
* the same Z 'denominator', which is stored in 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.
*/
r.set_ge(a);
odd_multiples_table_globalz_windowa(&mut pre_a, &mut z, r);
for i in 0..ECMULT_TABLE_SIZE_A {
pre_a[i].y.normalize_weak();
}
/* 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) */
let i = wnaf_1[WNAF_SIZE];
debug_assert!(i != 0);
table_get_ge_const(&mut tmpa, &pre_a, i, WINDOW_A);
r.set_ge(&tmpa);
/* remaining loop iterations */
for i in (0..WNAF_SIZE).rev() {
for _ in 0..(WINDOW_A - 1) {
let r2 = *r;
r.double_nonzero_in_place(&r2, None);
}
let n = wnaf_1[i];
table_get_ge_const(&mut tmpa, &pre_a, n, WINDOW_A);
debug_assert!(n != 0);
*r = r.add_ge(&tmpa);
}
r.z *= &z;
/* Correct for wNAF skew */
let mut correction = *a;
let mut correction_1_stor: AffineStorage;
let a2_stor: AffineStorage;
let mut tmpj = Jacobian::default();
tmpj.set_ge(&correction);
tmpj = tmpj.double_var(None);
correction.set_gej(&tmpj);
correction_1_stor = (*a).into();
a2_stor = correction.into();
/* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
correction_1_stor.cmov(&a2_stor, skew_1 == 2);
/* Apply the correction */
correction = correction_1_stor.into();
correction = correction.neg();
*r = r.add_ge(&correction)
}
}
impl ECMultGenContext {
pub fn ecmult_gen(&self, r: &mut Jacobian, gn: &Scalar) {
let mut adds = AffineStorage::default();
*r = self.initial;
let mut gnb = gn + &self.blind;
let mut add = Affine::default();
add.infinity = false;
for j in 0..64 {
let mut bits = gnb.bits(j * 4, 4);
for i in 0..16 {
adds.cmov(&self.prec[j][i], i as u32 == bits);
}
add = adds.into();
*r = r.add_ge(&add);
#[allow(unused_assignments)]
{
bits = 0;
}
}
add.clear();
gnb.clear();
}
}
================================================
FILE: core/src/error.rs
================================================
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Error {
InvalidSignature,
InvalidPublicKey,
InvalidSecretKey,
InvalidRecoveryId,
InvalidMessage,
InvalidInputLength,
TweakOutOfRange,
InvalidAffine,
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Error::InvalidSignature => write!(f, "Invalid signature"),
Error::InvalidPublicKey => write!(f, "Invalid public key"),
Error::InvalidSecretKey => write!(f, "Invalid secret key"),
Error::InvalidRecoveryId => write!(f, "Invalid recovery ID"),
Error::InvalidMessage => write!(f, "Invalid message"),
Error::InvalidInputLength => write!(f, "Invalid input length"),
Error::TweakOutOfRange => write!(f, "Tweak out of range"),
Error::InvalidAffine => write!(f, "Invalid Affine"),
}
}
}
================================================
FILE: core/src/field.rs
================================================
use core::{
cmp::Ordering,
ops::{Add, AddAssign, Mul, MulAssign},
};
macro_rules! debug_assert_bits {
($x: expr, $n: expr) => {
debug_assert!($x >> $n == 0);
};
}
#[derive(Debug, Clone, Copy)]
/// Field element for secp256k1.
pub struct Field {
/// Store representation of X.
/// X = sum(i=0..9, n[i]*2^(i*26)) mod p
/// where p = 2^256 - 0x1000003D1
///
/// The least signifiant byte is in the front.
n: [u32; 10],
magnitude: u32,
normalized: bool,
}
impl Field {
pub const fn new_raw(
d9: u32,
d8: u32,
d7: u32,
d6: u32,
d5: u32,
d4: u32,
d3: u32,
d2: u32,
d1: u32,
d0: u32,
) -> Self {
Self {
n: [d0, d1, d2, d3, d4, d5, d6, d7, d8, d9],
magnitude: 1,
normalized: false,
}
}
pub const fn new(
d7: u32,
d6: u32,
d5: u32,
d4: u32,
d3: u32,
d2: u32,
d1: u32,
d0: u32,
) -> Self {
Self {
n: [
d0 & 0x3ffffff,
(d0 >> 26) | ((d1 & 0xfffff) << 6),
(d1 >> 20) | ((d2 & 0x3fff) << 12),
(d2 >> 14) | ((d3 & 0xff) << 18),
(d3 >> 8) | ((d4 & 0x3) << 24),
(d4 >> 2) & 0x3ffffff,
(d4 >> 28) | ((d5 & 0x3fffff) << 4),
(d5 >> 22) | ((d6 & 0xffff) << 10),
(d6 >> 16) | ((d7 & 0x3ff) << 16),
(d7 >> 10),
],
magnitude: 1,
normalized: true,
}
}
pub fn from_int(a: u32) -> Field {
let mut f = Field::default();
f.set_int(a);
f
}
fn verify(&self) -> bool {
let m = if self.normalized { 1 } else { 2 } * self.magnitude;
let mut r = true;
r = r && (self.n[0] <= 0x3ffffff * m);
r = r && (self.n[1] <= 0x3ffffff * m);
r = r && (self.n[2] <= 0x3ffffff * m);
r = r && (self.n[3] <= 0x3ffffff * m);
r = r && (self.n[4] <= 0x3ffffff * m);
r = r && (self.n[5] <= 0x3ffffff * m);
r = r && (self.n[6] <= 0x3ffffff * m);
r = r && (self.n[7] <= 0x3ffffff * m);
r = r && (self.n[8] <= 0x3ffffff * m);
r = r && (self.n[9] <= 0x03fffff * m);
r = r && (self.magnitude <= 32);
if self.normalized {
r = r && self.magnitude <= 1;
if r && (self.n[9] == 0x03fffff) {
let mid = self.n[8]
& self.n[7]
& self.n[6]
& self.n[5]
& self.n[4]
& self.n[3]
& self.n[2];
if mid == 0x3ffffff {
r = r && ((self.n[1] + 0x40 + ((self.n[0] + 0x3d1) >> 26)) <= 0x3ffffff)
}
}
}
r
}
/// Normalize a field element.
pub fn normalize(&mut self) {
let mut t0 = self.n[0];
let mut t1 = self.n[1];
let mut t2 = self.n[2];
let mut t3 = self.n[3];
let mut t4 = self.n[4];
let mut t5 = self.n[5];
let mut t6 = self.n[6];
let mut t7 = self.n[7];
let mut t8 = self.n[8];
let mut t9 = self.n[9];
let mut m: u32;
let mut x = t9 >> 22;
t9 &= 0x03fffff;
t0 += x * 0x3d1;
t1 += x << 6;
t1 += t0 >> 26;
t0 &= 0x3ffffff;
t2 += t1 >> 26;
t1 &= 0x3ffffff;
t3 += t2 >> 26;
t2 &= 0x3ffffff;
m = t2;
t4 += t3 >> 26;
t3 &= 0x3ffffff;
m &= t3;
t5 += t4 >> 26;
t4 &= 0x3ffffff;
m &= t4;
t6 += t5 >> 26;
t5 &= 0x3ffffff;
m &= t5;
t7 += t6 >> 26;
t6 &= 0x3ffffff;
m &= t6;
t8 += t7 >> 26;
t7 &= 0x3ffffff;
m &= t7;
t9 += t8 >> 26;
t8 &= 0x3ffffff;
m &= t8;
debug_assert!(t9 >> 23 == 0);
x = (t9 >> 22)
| (if t9 == 0x03fffff { 1 } else { 0 }
& if m == 0x3ffffff { 1 } else { 0 }
& (if (t1 + 0x40 + ((t0 + 0x3d1) >> 26)) > 0x3ffffff {
1
} else {
0
}));
t0 += x * 0x3d1;
t1 += x << 6;
t1 += t0 >> 26;
t0 &= 0x3ffffff;
t2 += t1 >> 26;
t1 &= 0x3ffffff;
t3 += t2 >> 26;
t2 &= 0x3ffffff;
t4 += t3 >> 26;
t3 &= 0x3ffffff;
t5 += t4 >> 26;
t4 &= 0x3ffffff;
t6 += t5 >> 26;
t5 &= 0x3ffffff;
t7 += t6 >> 26;
t6 &= 0x3ffffff;
t8 += t7 >> 26;
t7 &= 0x3ffffff;
t9 += t8 >> 26;
t8 &= 0x3ffffff;
debug_assert!(t9 >> 22 == x);
t9 &= 0x03fffff;
self.n = [t0, t1, t2, t3, t4, t5, t6, t7, t8, t9];
self.magnitude = 1;
self.normalized = true;
debug_assert!(self.verify());
}
/// Weakly normalize a field element: reduce it magnitude to 1,
/// but don't fully normalize.
pub fn normalize_weak(&mut self) {
let mut t0 = self.n[0];
let mut t1 = self.n[1];
let mut t2 = self.n[2];
let mut t3 = self.n[3];
let mut t4 = self.n[4];
let mut t5 = self.n[5];
let mut t6 = self.n[6];
let mut t7 = self.n[7];
let mut t8 = self.n[8];
let mut t9 = self.n[9];
let x = t9 >> 22;
t9 &= 0x03fffff;
t0 += x * 0x3d1;
t1 += x << 6;
t1 += t0 >> 26;
t0 &= 0x3ffffff;
t2 += t1 >> 26;
t1 &= 0x3ffffff;
t3 += t2 >> 26;
t2 &= 0x3ffffff;
t4 += t3 >> 26;
t3 &= 0x3ffffff;
t5 += t4 >> 26;
t4 &= 0x3ffffff;
t6 += t5 >> 26;
t5 &= 0x3ffffff;
t7 += t6 >> 26;
t6 &= 0x3ffffff;
t8 += t7 >> 26;
t7 &= 0x3ffffff;
t9 += t8 >> 26;
t8 &= 0x3ffffff;
debug_assert!(t9 >> 23 == 0);
self.n = [t0, t1, t2, t3, t4, t5, t6, t7, t8, t9];
self.magnitude = 1;
debug_assert!(self.verify());
}
/// Normalize a field element, without constant-time guarantee.
pub fn normalize_var(&mut self) {
let mut t0 = self.n[0];
let mut t1 = self.n[1];
let mut t2 = self.n[2];
let mut t3 = self.n[3];
let mut t4 = self.n[4];
let mut t5 = self.n[5];
let mut t6 = self.n[6];
let mut t7 = self.n[7];
let mut t8 = self.n[8];
let mut t9 = self.n[9];
let mut m: u32;
let mut x = t9 >> 22;
t9 &= 0x03fffff;
t0 += x * 0x3d1;
t1 += x << 6;
t1 += t0 >> 26;
t0 &= 0x3ffffff;
t2 += t1 >> 26;
t1 &= 0x3ffffff;
t3 += t2 >> 26;
t2 &= 0x3ffffff;
m = t2;
t4 += t3 >> 26;
t3 &= 0x3ffffff;
m &= t3;
t5 += t4 >> 26;
t4 &= 0x3ffffff;
m &= t4;
t6 += t5 >> 26;
t5 &= 0x3ffffff;
m &= t5;
t7 += t6 >> 26;
t6 &= 0x3ffffff;
m &= t6;
t8 += t7 >> 26;
t7 &= 0x3ffffff;
m &= t7;
t9 += t8 >> 26;
t8 &= 0x3ffffff;
m &= t8;
debug_assert!(t9 >> 23 == 0);
x = (t9 >> 22)
| (if t9 == 0x03fffff { 1 } else { 0 }
& if m == 0x3ffffff { 1 } else { 0 }
& (if (t1 + 0x40 + ((t0 + 0x3d1) >> 26)) > 0x3ffffff {
1
} else {
0
}));
if x > 0 {
t0 += 0x3d1;
t1 += x << 6;
t1 += t0 >> 26;
t0 &= 0x3ffffff;
t2 += t1 >> 26;
t1 &= 0x3ffffff;
t3 += t2 >> 26;
t2 &= 0x3ffffff;
t4 += t3 >> 26;
t3 &= 0x3ffffff;
t5 += t4 >> 26;
t4 &= 0x3ffffff;
t6 += t5 >> 26;
t5 &= 0x3ffffff;
t7 += t6 >> 26;
t6 &= 0x3ffffff;
t8 += t7 >> 26;
t7 &= 0x3ffffff;
t9 += t8 >> 26;
t8 &= 0x3ffffff;
debug_assert!(t9 >> 22 == x);
t9 &= 0x03fffff;
}
self.n = [t0, t1, t2, t3, t4, t5, t6, t7, t8, t9];
self.magnitude = 1;
self.normalized = true;
debug_assert!(self.verify());
}
/// Verify whether a field element represents zero i.e. would
/// normalize to a zero value. The field implementation may
/// optionally normalize the input, but this should not be relied
/// upon.
pub fn normalizes_to_zero(&self) -> bool {
let mut t0 = self.n[0];
let mut t1 = self.n[1];
let mut t2 = self.n[2];
let mut t3 = self.n[3];
let mut t4 = self.n[4];
let mut t5 = self.n[5];
let mut t6 = self.n[6];
let mut t7 = self.n[7];
let mut t8 = self.n[8];
let mut t9 = self.n[9];
let mut z0: u32;
let mut z1: u32;
let x = t9 >> 22;
t9 &= 0x03fffff;
t0 += x * 0x3d1;
t1 += x << 6;
t1 += t0 >> 26;
t0 &= 0x3ffffff;
z0 = t0;
z1 = t0 ^ 0x3d0;
t2 += t1 >> 26;
t1 &= 0x3ffffff;
z0 |= t1;
z1 &= t1 ^ 0x40;
t3 += t2 >> 26;
t2 &= 0x3ffffff;
z0 |= t2;
z1 &= t2;
t4 += t3 >> 26;
t3 &= 0x3ffffff;
z0 |= t3;
z1 &= t3;
t5 += t4 >> 26;
t4 &= 0x3ffffff;
z0 |= t4;
z1 &= t4;
t6 += t5 >> 26;
t5 &= 0x3ffffff;
z0 |= t5;
z1 &= t5;
t7 += t6 >> 26;
t6 &= 0x3ffffff;
z0 |= t6;
z1 &= t6;
t8 += t7 >> 26;
t7 &= 0x3ffffff;
z0 |= t7;
z1 &= t7;
t9 += t8 >> 26;
t8 &= 0x3ffffff;
z0 |= t8;
z1 &= t8;
z0 |= t9;
z1 &= t9 ^ 0x3c00000;
debug_assert!(t9 >> 23 == 0);
z0 == 0 || z1 == 0x3ffffff
}
/// Verify whether a field element represents zero i.e. would
/// normalize to a zero value. The field implementation may
/// optionally normalize the input, but this should not be relied
/// upon.
pub fn normalizes_to_zero_var(&self) -> bool {
let mut t0: u32;
let mut t1: u32;
let mut t2: u32;
let mut t3: u32;
let mut t4: u32;
let mut t5: u32;
let mut t6: u32;
let mut t7: u32;
let mut t8: u32;
let mut t9: u32;
let mut z0: u32;
let mut z1: u32;
let x: u32;
t0 = self.n[0];
t9 = self.n[9];
x = t9 >> 22;
t0 += x * 0x3d1;
z0 = t0 & 0x3ffffff;
z1 = z0 ^ 0x3d0;
if z0 != 0 && z1 != 0x3ffffff {
return false;
}
t1 = self.n[1];
t2 = self.n[2];
t3 = self.n[3];
t4 = self.n[4];
t5 = self.n[5];
t6 = self.n[6];
t7 = self.n[7];
t8 = self.n[8];
t9 &= 0x03fffff;
t1 += x << 6;
t1 += t0 >> 26;
t2 += t1 >> 26;
t1 &= 0x3ffffff;
z0 |= t1;
z1 &= t1 ^ 0x40;
t3 += t2 >> 26;
t2 &= 0x3ffffff;
z0 |= t2;
z1 &= t2;
t4 += t3 >> 26;
t3 &= 0x3ffffff;
z0 |= t3;
z1 &= t3;
t5 += t4 >> 26;
t4 &= 0x3ffffff;
z0 |= t4;
z1 &= t4;
t6 += t5 >> 26;
t5 &= 0x3ffffff;
z0 |= t5;
z1 &= t5;
t7 += t6 >> 26;
t6 &= 0x3ffffff;
z0 |= t6;
z1 &= t6;
t8 += t7 >> 26;
t7 &= 0x3ffffff;
z0 |= t7;
z1 &= t7;
t9 += t8 >> 26;
t8 &= 0x3ffffff;
z0 |= t8;
z1 &= t8;
z0 |= t9;
z1 &= t9 ^ 0x3c00000;
debug_assert!(t9 >> 23 == 0);
z0 == 0 || z1 == 0x3ffffff
}
/// Set a field element equal to a small integer. Resulting field
/// element is normalized.
pub fn set_int(&mut self, a: u32) {
self.n = [a, 0, 0, 0, 0, 0, 0, 0, 0, 0];
self.magnitude = 1;
self.normalized = true;
debug_assert!(self.verify());
}
/// Verify whether a field element is zero. Requires the input to
/// be normalized.
pub fn is_zero(&self) -> bool {
debug_assert!(self.normalized);
debug_assert!(self.verify());
(self.n[0]
| self.n[1]
| self.n[2]
| self.n[3]
| self.n[4]
| self.n[5]
| self.n[6]
| self.n[7]
| self.n[8]
| self.n[9])
== 0
}
/// Check the "oddness" of a field element. Requires the input to
/// be normalized.
pub fn is_odd(&self) -> bool {
debug_assert!(self.normalized);
debug_assert!(self.verify());
self.n[0] & 1 != 0
}
/// Sets a field element equal to zero, initializing all fields.
pub fn clear(&mut self) {
self.magnitude = 0;
self.normalized = true;
self.n = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
}
/// Set a field element equal to 32-byte big endian value. If
/// successful, the resulting field element is normalized.
#[must_use]
pub fn set_b32(&mut self, a: &[u8; 32]) -> bool {
self.n[0] = (a[31] as u32)
| ((a[30] as u32) << 8)
| ((a[29] as u32) << 16)
| (((a[28] & 0x3) as u32) << 24);
self.n[1] = (((a[28] >> 2) & 0x3f) as u32)
| ((a[27] as u32) << 6)
| ((a[26] as u32) << 14)
| (((a[25] & 0xf) as u32) << 22);
self.n[2] = (((a[25] >> 4) & 0xf) as u32)
| ((a[24] as u32) << 4)
| ((a[23] as u32) << 12)
| (((a[22] as u32) & 0x3f) << 20);
self.n[3] = (((a[22] >> 6) & 0x3) as u32)
| ((a[21] as u32) << 2)
| ((a[20] as u32) << 10)
| ((a[19] as u32) << 18);
self.n[4] = (a[18] as u32)
| ((a[17] as u32) << 8)
| ((a[16] as u32) << 16)
| (((a[15] & 0x3) as u32) << 24);
self.n[5] = (((a[15] >> 2) & 0x3f) as u32)
| ((a[14] as u32) << 6)
| ((a[13] as u32) << 14)
| (((a[12] as u32) & 0xf) << 22);
self.n[6] = (((a[12] >> 4) & 0xf) as u32)
| ((a[11] as u32) << 4)
| ((a[10] as u32) << 12)
| (((a[9] & 0x3f) as u32) << 20);
self.n[7] = (((a[9] >> 6) & 0x3) as u32)
| ((a[8] as u32) << 2)
| ((a[7] as u32) << 10)
| ((a[6] as u32) << 18);
self.n[8] = (a[5] as u32)
| ((a[4] as u32) << 8)
| ((a[3] as u32) << 16)
| (((a[2] & 0x3) as u32) << 24);
self.n[9] = (((a[2] >> 2) & 0x3f) as u32) | ((a[1] as u32) << 6) | ((a[0] as u32) << 14);
if self.n[9] == 0x03fffff
&& (self.n[8] & self.n[7] & self.n[6] & self.n[5] & self.n[4] & self.n[3] & self.n[2])
== 0x3ffffff
&& (self.n[1] + 0x40 + ((self.n[0] + 0x3d1) >> 26)) > 0x3ffffff
{
return false;
}
self.magnitude = 1;
self.normalized = true;
debug_assert!(self.verify());
true
}
pub fn fill_b32(&self, r: &mut [u8; 32]) {
debug_assert!(self.normalized);
debug_assert!(self.verify());
r[0] = ((self.n[9] >> 14) & 0xff) as u8;
r[1] = ((self.n[9] >> 6) & 0xff) as u8;
r[2] = (((self.n[9] & 0x3f) << 2) | ((self.n[8] >> 24) & 0x3)) as u8;
r[3] = ((self.n[8] >> 16) & 0xff) as u8;
r[4] = ((self.n[8] >> 8) & 0xff) as u8;
r[5] = (self.n[8] & 0xff) as u8;
r[6] = ((self.n[7] >> 18) & 0xff) as u8;
r[7] = ((self.n[7] >> 10) & 0xff) as u8;
r[8] = ((self.n[7] >> 2) & 0xff) as u8;
r[9] = (((self.n[7] & 0x3) << 6) | ((self.n[6] >> 20) & 0x3f)) as u8;
r[10] = ((self.n[6] >> 12) & 0xff) as u8;
r[11] = ((self.n[6] >> 4) & 0xff) as u8;
r[12] = (((self.n[6] & 0xf) << 4) | ((self.n[5] >> 22) & 0xf)) as u8;
r[13] = ((self.n[5] >> 14) & 0xff) as u8;
r[14] = ((self.n[5] >> 6) & 0xff) as u8;
r[15] = (((self.n[5] & 0x3f) << 2) | ((self.n[4] >> 24) & 0x3)) as u8;
r[16] = ((self.n[4] >> 16) & 0xff) as u8;
r[17] = ((self.n[4] >> 8) & 0xff) as u8;
r[18] = (self.n[4] & 0xff) as u8;
r[19] = ((self.n[3] >> 18) & 0xff) as u8;
r[20] = ((self.n[3] >> 10) & 0xff) as u8;
r[21] = ((self.n[3] >> 2) & 0xff) as u8;
r[22] = (((self.n[3] & 0x3) << 6) | ((self.n[2] >> 20) & 0x3f)) as u8;
r[23] = ((self.n[2] >> 12) & 0xff) as u8;
r[24] = ((self.n[2] >> 4) & 0xff) as u8;
r[25] = (((self.n[2] & 0xf) << 4) | ((self.n[1] >> 22) & 0xf)) as u8;
r[26] = ((self.n[1] >> 14) & 0xff) as u8;
r[27] = ((self.n[1] >> 6) & 0xff) as u8;
r[28] = (((self.n[1] & 0x3f) << 2) | ((self.n[0] >> 24) & 0x3)) as u8;
r[29] = ((self.n[0] >> 16) & 0xff) as u8;
r[30] = ((self.n[0] >> 8) & 0xff) as u8;
r[31] = (self.n[0] & 0xff) as u8;
}
/// Convert a field element to a 32-byte big endian
/// value. Requires the input to be normalized.
pub fn b32(&self) -> [u8; 32] {
let mut r = [0u8; 32];
self.fill_b32(&mut r);
r
}
/// Set a field element equal to the additive inverse of
/// another. Takes a maximum magnitude of the input as an
/// argument. The magnitude of the output is one higher.
pub fn neg_in_place(&mut self, other: &Field, m: u32) {
debug_assert!(other.magnitude <= m);
debug_assert!(other.verify());
self.n[0] = 0x3fffc2f * 2 * (m + 1) - other.n[0];
self.n[1] = 0x3ffffbf * 2 * (m + 1) - other.n[1];
self.n[2] = 0x3ffffff * 2 * (m + 1) - other.n[2];
self.n[3] = 0x3ffffff * 2 * (m + 1) - other.n[3];
self.n[4] = 0x3ffffff * 2 * (m + 1) - other.n[4];
self.n[5] = 0x3ffffff * 2 * (m + 1) - other.n[5];
self.n[6] = 0x3ffffff * 2 * (m + 1) - other.n[6];
self.n[7] = 0x3ffffff * 2 * (m + 1) - other.n[7];
self.n[8] = 0x3ffffff * 2 * (m + 1) - other.n[8];
self.n[9] = 0x03fffff * 2 * (m + 1) - other.n[9];
self.magnitude = m + 1;
self.normalized = false;
debug_assert!(self.verify());
}
/// Compute the additive inverse of this element. Takes the maximum
/// expected magnitude of this element as an argument.
pub fn neg(&self, m: u32) -> Field {
let mut ret = Field::default();
ret.neg_in_place(self, m);
ret
}
/// Multiplies the passed field element with a small integer
/// constant. Multiplies the magnitude by that small integer.
pub fn mul_int(&mut self, a: u32) {
self.n[0] *= a;
self.n[1] *= a;
self.n[2] *= a;
self.n[3] *= a;
self.n[4] *= a;
self.n[5] *= a;
self.n[6] *= a;
self.n[7] *= a;
self.n[8] *= a;
self.n[9] *= a;
self.magnitude *= a;
self.normalized = false;
debug_assert!(self.verify());
}
/// Compare two field elements. Requires both inputs to be
/// normalized.
pub fn cmp_var(&self, other: &Field) -> Ordering {
// Variable time compare implementation.
debug_assert!(self.normalized);
debug_assert!(other.normalized);
debug_assert!(self.verify());
debug_assert!(other.verify());
for i in (0..10).rev() {
if self.n[i] > other.n[i] {
return Ordering::Greater;
}
if self.n[i] < other.n[i] {
return Ordering::Less;
}
}
Ordering::Equal
}
pub fn eq_var(&self, other: &Field) -> bool {
let mut na = self.neg(1);
na += other;
na.normalizes_to_zero_var()
}
fn mul_inner(&mut self, a: &Field, b: &Field) {
const M: u64 = 0x3ffffff;
const R0: u64 = 0x3d10;
const R1: u64 = 0x400;
let (mut c, mut d): (u64, u64);
let (v0, v1, v2, v3, v4, v5, v6, v7, v8): (u64, u64, u64, u64, u64, u64, u64, u64, u64);
let (t9, t1, t0, t2, t3, t4, t5, t6, t7): (u32, u32, u32, u32, u32, u32, u32, u32, u32);
debug_assert_bits!(a.n[0], 30);
debug_assert_bits!(a.n[1], 30);
debug_assert_bits!(a.n[2], 30);
debug_assert_bits!(a.n[3], 30);
debug_assert_bits!(a.n[4], 30);
debug_assert_bits!(a.n[5], 30);
debug_assert_bits!(a.n[6], 30);
debug_assert_bits!(a.n[7], 30);
debug_assert_bits!(a.n[8], 30);
debug_assert_bits!(a.n[9], 26);
debug_assert_bits!(b.n[0], 30);
debug_assert_bits!(b.n[1], 30);
debug_assert_bits!(b.n[2], 30);
debug_assert_bits!(b.n[3], 30);
debug_assert_bits!(b.n[4], 30);
debug_assert_bits!(b.n[5], 30);
debug_assert_bits!(b.n[6], 30);
debug_assert_bits!(b.n[7], 30);
debug_assert_bits!(b.n[8], 30);
debug_assert_bits!(b.n[9], 26);
// [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n.
// px is a shorthand for sum(a[i]*b[x-i], i=0..x).
// Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0].
d = ((a.n[0] as u64) * (b.n[9] as u64))
.wrapping_add((a.n[1] as u64) * (b.n[8] as u64))
.wrapping_add((a.n[2] as u64) * (b.n[7] as u64))
.wrapping_add((a.n[3] as u64) * (b.n[6] as u64))
.wrapping_add((a.n[4] as u64) * (b.n[5] as u64))
.wrapping_add((a.n[5] as u64) * (b.n[4] as u64))
.wrapping_add((a.n[6] as u64) * (b.n[3] as u64))
.wrapping_add((a.n[7] as u64) * (b.n[2] as u64))
.wrapping_add((a.n[8] as u64) * (b.n[1] as u64))
.wrapping_add((a.n[9] as u64) * (b.n[0] as u64));
// debug_assert_bits!(d, 64);
/* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */
t9 = (d & M) as u32;
d >>= 26;
debug_assert_bits!(t9, 26);
debug_assert_bits!(d, 38);
/* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */
c = (a.n[0] as u64) * (b.n[0] as u64);
debug_assert_bits!(c, 60);
/* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */
d = d
.wrapping_add((a.n[1] as u64) * (b.n[9] as u64))
.wrapping_add((a.n[2] as u64) * (b.n[8] as u64))
.wrapping_add((a.n[3] as u64) * (b.n[7] as u64))
.wrapping_add((a.n[4] as u64) * (b.n[6] as u64))
.wrapping_add((a.n[5] as u64) * (b.n[5] as u64))
.wrapping_add((a.n[6] as u64) * (b.n[4] as u64))
.wrapping_add((a.n[7] as u64) * (b.n[3] as u64))
.wrapping_add((a.n[8] as u64) * (b.n[2] as u64))
.wrapping_add((a.n[9] as u64) * (b.n[1] as u64));
debug_assert_bits!(d, 63);
/* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
v0 = d & M;
d >>= 26;
c += v0 * R0;
debug_assert_bits!(v0, 26);
debug_assert_bits!(d, 37);
debug_assert_bits!(c, 61);
/* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
t0 = (c & M) as u32;
c >>= 26;
c += v0 * R1;
debug_assert_bits!(t0, 26);
debug_assert_bits!(c, 37);
/* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
/* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
c = c
.wrapping_add((a.n[0] as u64) * (b.n[1] as u64))
.wrapping_add((a.n[1] as u64) * (b.n[0] as u64));
debug_assert_bits!(c, 62);
/* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */
d = d
.wrapping_add((a.n[2] as u64) * (b.n[9] as u64))
.wrapping_add((a.n[3] as u64) * (b.n[8] as u64))
.wrapping_add((a.n[4] as u64) * (b.n[7] as u64))
.wrapping_add((a.n[5] as u64) * (b.n[6] as u64))
.wrapping_add((a.n[6] as u64) * (b.n[5] as u64))
.wrapping_add((a.n[7] as u64) * (b.n[4] as u64))
.wrapping_add((a.n[8] as u64) * (b.n[3] as u64))
.wrapping_add((a.n[9] as u64) * (b.n[2] as u64));
debug_assert_bits!(d, 63);
/* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
v1 = d & M;
d >>= 26;
c += v1 * R0;
debug_assert_bits!(v1, 26);
debug_assert_bits!(d, 37);
debug_assert_bits!(c, 63);
/* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
t1 = (c & M) as u32;
c >>= 26;
c += v1 * R1;
debug_assert_bits!(t1, 26);
debug_assert_bits!(c, 38);
/* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
/* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
c = c
.wrapping_add((a.n[0] as u64) * (b.n[2] as u64))
.wrapping_add((a.n[1] as u64) * (b.n[1] as u64))
.wrapping_add((a.n[2] as u64) * (b.n[0] as u64));
debug_assert_bits!(c, 62);
/* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
d = d
.wrapping_add((a.n[3] as u64) * (b.n[9] as u64))
.wrapping_add((a.n[4] as u64) * (b.n[8] as u64))
.wrapping_add((a.n[5] as u64) * (b.n[7] as u64))
.wrapping_add((a.n[6] as u64) * (b.n[6] as u64))
.wrapping_add((a.n[7] as u64) * (b.n[5] as u64))
.wrapping_add((a.n[8] as u64) * (b.n[4] as u64))
.wrapping_add((a.n[9] as u64) * (b.n[3] as u64));
debug_assert_bits!(d, 63);
/* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
v2 = d & M;
d >>= 26;
c += v2 * R0;
debug_assert_bits!(v2, 26);
debug_assert_bits!(d, 37);
debug_assert_bits!(c, 63);
/* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
t2 = (c & M) as u32;
c >>= 26;
c += v2 * R1;
debug_assert_bits!(t2, 26);
debug_assert_bits!(c, 38);
/* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
/* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
c = c
.wrapping_add((a.n[0] as u64) * (b.n[3] as u64))
.wrapping_add((a.n[1] as u64) * (b.n[2] as u64))
.wrapping_add((a.n[2] as u64) * (b.n[1] as u64))
.wrapping_add((a.n[3] as u64) * (b.n[0] as u64));
debug_assert_bits!(c, 63);
/* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
d = d
.wrapping_add((a.n[4] as u64) * (b.n[9] as u64))
.wrapping_add((a.n[5] as u64) * (b.n[8] as u64))
.wrapping_add((a.n[6] as u64) * (b.n[7] as u64))
.wrapping_add((a.n[7] as u64) * (b.n[6] as u64))
.wrapping_add((a.n[8] as u64) * (b.n[5] as u64))
.wrapping_add((a.n[9] as u64) * (b.n[4] as u64));
debug_assert_bits!(d, 63);
/* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
v3 = d & M;
d >>= 26;
c += v3 * R0;
debug_assert_bits!(v3, 26);
debug_assert_bits!(d, 37);
// debug_assert_bits!(c, 64);
/* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
t3 = (c & M) as u32;
c >>= 26;
c += v3 * R1;
debug_assert_bits!(t3, 26);
debug_assert_bits!(c, 39);
/* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
/* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
c = c
.wrapping_add((a.n[0] as u64) * (b.n[4] as u64))
.wrapping_add((a.n[1] as u64) * (b.n[3] as u64))
.wrapping_add((a.n[2] as u64) * (b.n[2] as u64))
.wrapping_add((a.n[3] as u64) * (b.n[1] as u64))
.wrapping_add((a.n[4] as u64) * (b.n[0] as u64));
debug_assert_bits!(c, 63);
/* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
d = d
.wrapping_add((a.n[5] as u64) * (b.n[9] as u64))
.wrapping_add((a.n[6] as u64) * (b.n[8] as u64))
.wrapping_add((a.n[7] as u64) * (b.n[7] as u64))
.wrapping_add((a.n[8] as u64) * (b.n[6] as u64))
.wrapping_add((a.n[9] as u64) * (b.n[5] as u64));
debug_assert_bits!(d, 62);
/* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
v4 = d & M;
d >>= 26;
c += v4 * R0;
debug_assert_bits!(v4, 26);
debug_assert_bits!(d, 36);
// debug_assert_bits!(c, 64);
/* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
t4 = (c & M) as u32;
c >>= 26;
c += v4 * R1;
debug_assert_bits!(t4, 26);
debug_assert_bits!(c, 39);
/* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
/* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
c = c
.wrapping_add((a.n[0] as u64) * (b.n[5] as u64))
.wrapping_add((a.n[1] as u64) * (b.n[4] as u64))
.wrapping_add((a.n[2] as u64) * (b.n[3] as u64))
.wrapping_add((a.n[3] as u64) * (b.n[2] as u64))
.wrapping_add((a.n[4] as u64) * (b.n[1] as u64))
.wrapping_add((a.n[5] as u64) * (b.n[0] as u64));
debug_assert_bits!(c, 63);
/* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
d = d
.wrapping_add((a.n[6] as u64) * (b.n[9] as u64))
.wrapping_add((a.n[7] as u64) * (b.n[8] as u64))
.wrapping_add((a.n[8] as u64) * (b.n[7] as u64))
.wrapping_add((a.n[9] as u64) * (b.n[6] as u64));
debug_assert_bits!(d, 62);
/* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
v5 = d & M;
d >>= 26;
c += v5 * R0;
debug_assert_bits!(v5, 26);
debug_assert_bits!(d, 36);
// debug_assert_bits!(c, 64);
/* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
t5 = (c & M) as u32;
c >>= 26;
c += v5 * R1;
debug_assert_bits!(t5, 26);
debug_assert_bits!(c, 39);
/* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
/* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
c = c
.wrapping_add((a.n[0] as u64) * (b.n[6] as u64))
.wrapping_add((a.n[1] as u64) * (b.n[5] as u64))
.wrapping_add((a.n[2] as u64) * (b.n[4] as u64))
.wrapping_add((a.n[3] as u64) * (b.n[3] as u64))
.wrapping_add((a.n[4] as u64) * (b.n[2] as u64))
.wrapping_add((a.n[5] as u64) * (b.n[1] as u64))
.wrapping_add((a.n[6] as u64) * (b.n[0] as u64));
debug_assert_bits!(c, 63);
/* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
d = d
.wrapping_add((a.n[7] as u64) * (b.n[9] as u64))
.wrapping_add((a.n[8] as u64) * (b.n[8] as u64))
.wrapping_add((a.n[9] as u64) * (b.n[7] as u64));
debug_assert_bits!(d, 61);
/* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
v6 = d & M;
d >>= 26;
c += v6 * R0;
debug_assert_bits!(v6, 26);
debug_assert_bits!(d, 35);
// debug_assert_bits!(c, 64);
/* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
t6 = (c & M) as u32;
c >>= 26;
c += v6 * R1;
debug_assert_bits!(t6, 26);
debug_assert_bits!(c, 39);
/* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
/* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
c = c
.wrapping_add((a.n[0] as u64) * (b.n[7] as u64))
.wrapping_add((a.n[1] as u64) * (b.n[6] as u64))
.wrapping_add((a.n[2] as u64) * (b.n[5] as u64))
.wrapping_add((a.n[3] as u64) * (b.n[4] as u64))
.wrapping_add((a.n[4] as u64) * (b.n[3] as u64))
.wrapping_add((a.n[5] as u64) * (b.n[2] as u64))
.wrapping_add((a.n[6] as u64) * (b.n[1] as u64))
.wrapping_add((a.n[7] as u64) * (b.n[0] as u64));
// debug_assert_bits!(c, 64);
debug_assert!(c <= 0x8000007c00000007);
/* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
d = d
.wrapping_add((a.n[8] as u64) * (b.n[9] as u64))
.wrapping_add((a.n[9] as u64) * (b.n[8] as u64));
debug_assert_bits!(d, 58);
/* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
v7 = d & M;
d >>= 26;
c += v7 * R0;
debug_assert_bits!(v7, 26);
debug_assert_bits!(d, 32);
// debug_assert_bits!(c, 64);
debug_assert!(c <= 0x800001703fffc2f7);
/* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
t7 = (c & M) as u32;
c >>= 26;
c += v7 * R1;
debug_assert_bits!(t7, 26);
debug_assert_bits!(c, 38);
/* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
/* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
c = c
.wrapping_add((a.n[0] as u64) * (b.n[8] as u64))
.wrapping_add((a.n[1] as u64) * (b.n[7] as u64))
.wrapping_add((a.n[2] as u64) * (b.n[6] as u64))
.wrapping_add((a.n[3] as u64) * (b.n[5] as u64))
.wrapping_add((a.n[4] as u64) * (b.n[4] as u64))
.wrapping_add((a.n[5] as u64) * (b.n[3] as u64))
.wrapping_add((a.n[6] as u64) * (b.n[2] as u64))
.wrapping_add((a.n[7] as u64) * (b.n[1] as u64))
.wrapping_add((a.n[8] as u64) * (b.n[0] as u64));
// debug_assert_bits!(c, 64);
debug_assert!(c <= 0x9000007b80000008);
/* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
d = d.wrapping_add((a.n[9] as u64) * (b.n[9] as u64));
debug_assert_bits!(d, 57);
/* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
v8 = d & M;
d >>= 26;
c += v8 * R0;
debug_assert_bits!(v8, 26);
debug_assert_bits!(d, 31);
// debug_assert_bits!(c, 64);
debug_assert!(c <= 0x9000016fbfffc2f8);
/* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[3] = t3;
debug_assert_bits!(self.n[3], 26);
/* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[4] = t4;
debug_assert_bits!(self.n[4], 26);
/* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[5] = t5;
debug_assert_bits!(self.n[5], 26);
/* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[6] = t6;
debug_assert_bits!(self.n[6], 26);
/* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[7] = t7;
debug_assert_bits!(self.n[7], 26);
/* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[8] = (c & M) as u32;
c >>= 26;
c += v8 * R1;
debug_assert_bits!(self.n[8], 26);
debug_assert_bits!(c, 39);
/* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
/* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += d * R0 + t9 as u64;
debug_assert_bits!(c, 45);
/* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[9] = (c & (M >> 4)) as u32;
c >>= 22;
c += d * (R1 << 4);
debug_assert_bits!(self.n[9], 22);
debug_assert_bits!(c, 46);
/* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
/* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
/* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
d = c * (R0 >> 4) + t0 as u64;
debug_assert_bits!(d, 56);
/* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[0] = (d & M) as u32;
d >>= 26;
debug_assert_bits!(self.n[0], 26);
debug_assert_bits!(d, 30);
/* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
d += c * (R1 >> 4) + t1 as u64;
debug_assert_bits!(d, 53);
debug_assert!(d <= 0x10000003ffffbf);
/* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
/* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[1] = (d & M) as u32;
d >>= 26;
debug_assert_bits!(self.n[1], 26);
debug_assert_bits!(d, 27);
debug_assert!(d <= 0x4000000);
/* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
d += t2 as u64;
debug_assert_bits!(d, 27);
/* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[2] = d as u32;
debug_assert_bits!(self.n[2], 27);
/* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}
fn sqr_inner(&mut self, a: &Field) {
const M: u64 = 0x3ffffff;
const R0: u64 = 0x3d10;
const R1: u64 = 0x400;
let (mut c, mut d): (u64, u64);
let (v0, v1, v2, v3, v4, v5, v6, v7, v8): (u64, u64, u64, u64, u64, u64, u64, u64, u64);
let (t9, t0, t1, t2, t3, t4, t5, t6, t7): (u32, u32, u32, u32, u32, u32, u32, u32, u32);
debug_assert_bits!(a.n[0], 30);
debug_assert_bits!(a.n[1], 30);
debug_assert_bits!(a.n[2], 30);
debug_assert_bits!(a.n[3], 30);
debug_assert_bits!(a.n[4], 30);
debug_assert_bits!(a.n[5], 30);
debug_assert_bits!(a.n[6], 30);
debug_assert_bits!(a.n[7], 30);
debug_assert_bits!(a.n[8], 30);
debug_assert_bits!(a.n[9], 26);
// [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n.
// px is a shorthand for sum(a.n[i]*a.n[x-i], i=0..x).
// Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0].
d = (((a.n[0] * 2) as u64) * (a.n[9] as u64))
.wrapping_add(((a.n[1] * 2) as u64) * (a.n[8] as u64))
.wrapping_add(((a.n[2] * 2) as u64) * (a.n[7] as u64))
.wrapping_add(((a.n[3] * 2) as u64) * (a.n[6] as u64))
.wrapping_add(((a.n[4] * 2) as u64) * (a.n[5] as u64));
// debug_assert_bits!(d, 64);
/* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */
t9 = (d & M) as u32;
d >>= 26;
debug_assert_bits!(t9, 26);
debug_assert_bits!(d, 38);
/* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */
c = (a.n[0] as u64) * (a.n[0] as u64);
debug_assert_bits!(c, 60);
/* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */
d = d
.wrapping_add(((a.n[1] * 2) as u64) * (a.n[9] as u64))
.wrapping_add(((a.n[2] * 2) as u64) * (a.n[8] as u64))
.wrapping_add(((a.n[3] * 2) as u64) * (a.n[7] as u64))
.wrapping_add(((a.n[4] * 2) as u64) * (a.n[6] as u64))
.wrapping_add((a.n[5] as u64) * (a.n[5] as u64));
debug_assert_bits!(d, 63);
/* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
v0 = d & M;
d >>= 26;
c += v0 * R0;
debug_assert_bits!(v0, 26);
debug_assert_bits!(d, 37);
debug_assert_bits!(c, 61);
/* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
t0 = (c & M) as u32;
c >>= 26;
c += v0 * R1;
debug_assert_bits!(t0, 26);
debug_assert_bits!(c, 37);
/* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
/* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */
c = c.wrapping_add(((a.n[0] * 2) as u64) * (a.n[1] as u64));
debug_assert_bits!(c, 62);
/* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */
d = d
.wrapping_add(((a.n[2] * 2) as u64) * (a.n[9] as u64))
.wrapping_add(((a.n[3] * 2) as u64) * (a.n[8] as u64))
.wrapping_add(((a.n[4] * 2) as u64) * (a.n[7] as u64))
.wrapping_add(((a.n[5] * 2) as u64) * (a.n[6] as u64));
debug_assert_bits!(d, 63);
/* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
v1 = d & M;
d >>= 26;
c += v1 * R0;
debug_assert_bits!(v1, 26);
debug_assert_bits!(d, 37);
debug_assert_bits!(c, 63);
/* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
t1 = (c & M) as u32;
c >>= 26;
c += v1 * R1;
debug_assert_bits!(t1, 26);
debug_assert_bits!(c, 38);
/* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
/* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */
c = c
.wrapping_add(((a.n[0] * 2) as u64) * (a.n[2] as u64))
.wrapping_add((a.n[1] as u64) * (a.n[1] as u64));
debug_assert_bits!(c, 62);
/* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
d = d
.wrapping_add(((a.n[3] * 2) as u64) * (a.n[9] as u64))
.wrapping_add(((a.n[4] * 2) as u64) * (a.n[8] as u64))
.wrapping_add(((a.n[5] * 2) as u64) * (a.n[7] as u64))
.wrapping_add((a.n[6] as u64) * (a.n[6] as u64));
debug_assert_bits!(d, 63);
/* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
v2 = d & M;
d >>= 26;
c += v2 * R0;
debug_assert_bits!(v2, 26);
debug_assert_bits!(d, 37);
debug_assert_bits!(c, 63);
/* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
t2 = (c & M) as u32;
c >>= 26;
c += v2 * R1;
debug_assert_bits!(t2, 26);
debug_assert_bits!(c, 38);
/* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
/* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */
c = c
.wrapping_add(((a.n[0] * 2) as u64) * (a.n[3] as u64))
.wrapping_add(((a.n[1] * 2) as u64) * (a.n[2] as u64));
debug_assert_bits!(c, 63);
/* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
d = d
.wrapping_add(((a.n[4] * 2) as u64) * (a.n[9] as u64))
.wrapping_add(((a.n[5] * 2) as u64) * (a.n[8] as u64))
.wrapping_add(((a.n[6] * 2) as u64) * (a.n[7] as u64));
debug_assert_bits!(d, 63);
/* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
v3 = d & M;
d >>= 26;
c += v3 * R0;
debug_assert_bits!(v3, 26);
debug_assert_bits!(d, 37);
// debug_assert_bits!(c, 64);
/* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
t3 = (c & M) as u32;
c >>= 26;
c += v3 * R1;
debug_assert_bits!(t3, 26);
debug_assert_bits!(c, 39);
/* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
/* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */
c = c
.wrapping_add(((a.n[0] * 2) as u64) * (a.n[4] as u64))
.wrapping_add(((a.n[1] * 2) as u64) * (a.n[3] as u64))
.wrapping_add((a.n[2] as u64) * (a.n[2] as u64));
debug_assert_bits!(c, 63);
/* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
d = d
.wrapping_add(((a.n[5] * 2) as u64) * (a.n[9] as u64))
.wrapping_add(((a.n[6] * 2) as u64) * (a.n[8] as u64))
.wrapping_add((a.n[7] as u64) * (a.n[7] as u64));
debug_assert_bits!(d, 62);
/* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
v4 = d & M;
d >>= 26;
c += v4 * R0;
debug_assert_bits!(v4, 26);
debug_assert_bits!(d, 36);
// debug_assert_bits!(c, 64);
/* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
t4 = (c & M) as u32;
c >>= 26;
c += v4 * R1;
debug_assert_bits!(t4, 26);
debug_assert_bits!(c, 39);
/* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
/* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */
c = c
.wrapping_add(((a.n[0] * 2) as u64) * (a.n[5] as u64))
.wrapping_add(((a.n[1] * 2) as u64) * (a.n[4] as u64))
.wrapping_add(((a.n[2] * 2) as u64) * (a.n[3] as u64));
debug_assert_bits!(c, 63);
/* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
d = d
.wrapping_add(((a.n[6] * 2) as u64) * (a.n[9] as u64))
.wrapping_add(((a.n[7] * 2) as u64) * (a.n[8] as u64));
debug_assert_bits!(d, 62);
/* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
v5 = d & M;
d >>= 26;
c += v5 * R0;
debug_assert_bits!(v5, 26);
debug_assert_bits!(d, 36);
// debug_assert_bits!(c, 64);
/* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
t5 = (c & M) as u32;
c >>= 26;
c += v5 * R1;
debug_assert_bits!(t5, 26);
debug_assert_bits!(c, 39);
/* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
/* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */
c = c
.wrapping_add(((a.n[0] * 2) as u64) * (a.n[6] as u64))
.wrapping_add(((a.n[1] * 2) as u64) * (a.n[5] as u64))
.wrapping_add(((a.n[2] * 2) as u64) * (a.n[4] as u64))
.wrapping_add((a.n[3] as u64) * (a.n[3] as u64));
debug_assert_bits!(c, 63);
/* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
d = d
.wrapping_add(((a.n[7] * 2) as u64) * (a.n[9] as u64))
.wrapping_add((a.n[8] as u64) * (a.n[8] as u64));
debug_assert_bits!(d, 61);
/* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
v6 = d & M;
d >>= 26;
c += v6 * R0;
debug_assert_bits!(v6, 26);
debug_assert_bits!(d, 35);
// debug_assert_bits!(c, 64);
/* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
t6 = (c & M) as u32;
c >>= 26;
c += v6 * R1;
debug_assert_bits!(t6, 26);
debug_assert_bits!(c, 39);
/* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
/* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */
c = c
.wrapping_add(((a.n[0] * 2) as u64) * (a.n[7] as u64))
.wrapping_add(((a.n[1] * 2) as u64) * (a.n[6] as u64))
.wrapping_add(((a.n[2] * 2) as u64) * (a.n[5] as u64))
.wrapping_add(((a.n[3] * 2) as u64) * (a.n[4] as u64));
// debug_assert_bits!(c, 64);
debug_assert!(c <= 0x8000007C00000007);
/* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
d = d.wrapping_add(((a.n[8] * 2) as u64) * (a.n[9] as u64));
debug_assert_bits!(d, 58);
/* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
v7 = d & M;
d >>= 26;
c += v7 * R0;
debug_assert_bits!(v7, 26);
debug_assert_bits!(d, 32);
/* debug_assert_bits!(c, 64); */
debug_assert!(c <= 0x800001703FFFC2F7);
/* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
t7 = (c & M) as u32;
c >>= 26;
c += v7 * R1;
debug_assert_bits!(t7, 26);
debug_assert_bits!(c, 38);
/* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
/* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */
c = c
.wrapping_add(((a.n[0] * 2) as u64) * (a.n[8] as u64))
.wrapping_add(((a.n[1] * 2) as u64) * (a.n[7] as u64))
.wrapping_add(((a.n[2] * 2) as u64) * (a.n[6] as u64))
.wrapping_add(((a.n[3] * 2) as u64) * (a.n[5] as u64))
.wrapping_add((a.n[4] as u64) * (a.n[4] as u64));
// debug_assert_bits!(c, 64);
debug_assert!(c <= 0x9000007B80000008);
/* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
d = d.wrapping_add((a.n[9] as u64) * (a.n[9] as u64));
debug_assert_bits!(d, 57);
/* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
v8 = d & M;
d >>= 26;
c += v8 * R0;
debug_assert_bits!(v8, 26);
debug_assert_bits!(d, 31);
/* debug_assert_bits!(c, 64); */
debug_assert!(c <= 0x9000016FBFFFC2F8);
/* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[3] = t3;
debug_assert_bits!(self.n[3], 26);
/* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[4] = t4;
debug_assert_bits!(self.n[4], 26);
/* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[5] = t5;
debug_assert_bits!(self.n[5], 26);
/* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[6] = t6;
debug_assert_bits!(self.n[6], 26);
/* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[7] = t7;
debug_assert_bits!(self.n[7], 26);
/* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[8] = (c & M) as u32;
c >>= 26;
c += v8 * R1;
debug_assert_bits!(self.n[8], 26);
debug_assert_bits!(c, 39);
/* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
/* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += d * R0 + t9 as u64;
debug_assert_bits!(c, 45);
/* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[9] = (c & (M >> 4)) as u32;
c >>= 22;
c += d * (R1 << 4);
debug_assert_bits!(self.n[9], 22);
debug_assert_bits!(c, 46);
/* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
/* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
/* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
d = c * (R0 >> 4) + t0 as u64;
debug_assert_bits!(d, 56);
/* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[0] = (d & M) as u32;
d >>= 26;
debug_assert_bits!(self.n[0], 26);
debug_assert_bits!(d, 30);
/* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
d += c * (R1 >> 4) + t1 as u64;
debug_assert_bits!(d, 53);
debug_assert!(d <= 0x10000003FFFFBF);
/* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
/* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[1] = (d & M) as u32;
d >>= 26;
debug_assert_bits!(self.n[1], 26);
debug_assert_bits!(d, 27);
debug_assert!(d <= 0x4000000);
/* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
d += t2 as u64;
debug_assert_bits!(d, 27);
/* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
self.n[2] = d as u32;
debug_assert_bits!(self.n[2], 27);
/* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}
/// Sets a field element to be the product of two others. Requires
/// the inputs' magnitudes to be at most 8. The output magnitude
/// is 1 (but not guaranteed to be normalized).
pub fn mul_in_place(&mut self, a: &Field, b: &Field) {
debug_assert!(a.magnitude <= 8);
debug_assert!(b.magnitude <= 8);
debug_assert!(a.verify());
debug_assert!(b.verify());
self.mul_inner(a, b);
self.magnitude = 1;
self.normalized = false;
debug_assert!(self.verify());
}
/// Sets a field element to be the square of another. Requires the
/// input's magnitude to be at most 8. The output magnitude is 1
/// (but not guaranteed to be normalized).
pub fn sqr_in_place(&mut self, a: &Field) {
debug_assert!(a.magnitude <= 8);
debug_assert!(a.verify());
self.sqr_inner(a);
self.magnitude = 1;
self.normalized = false;
debug_assert!(a.verify());
}
pub fn sqr(&self) -> Field {
let mut ret = Field::default();
ret.sqr_in_place(self);
ret
}
/// If a has a square root, it is computed in r and 1 is
/// returned. If a does not have a square root, the root of its
/// negation is computed and 0 is returned. The input's magnitude
/// can be at most 8. The output magnitude is 1 (but not
/// guaranteed to be normalized). The result in r will always be a
/// square itself.
pub fn sqrt(&self) -> (Field, bool) {
let mut x2 = self.sqr();
x2 *= self;
let mut x3 = x2.sqr();
x3 *= self;
let mut x6 = x3;
for _ in 0..3 {
x6 = x6.sqr();
}
x6 *= &x3;
let mut x9 = x6;
for _ in 0..3 {
x9 = x9.sqr();
}
x9 *= &x3;
let mut x11 = x9;
for _ in 0..2 {
x11 = x11.sqr();
}
x11 *= &x2;
let mut x22 = x11;
for _ in 0..11 {
x22 = x22.sqr();
}
x22 *= &x11;
let mut x44 = x22;
for _ in 0..22 {
x44 = x44.sqr();
}
x44 *= &x22;
let mut x88 = x44;
for _ in 0..44 {
x88 = x88.sqr();
}
x88 *= &x44;
let mut x176 = x88;
for _ in 0..88 {
x176 = x176.sqr();
}
x176 *= &x88;
let mut x220 = x176;
for _ in 0..44 {
x220 = x220.sqr();
}
x220 *= &x44;
let mut x223 = x220;
for _ in 0..3 {
x223 = x223.sqr();
}
x223 *= &x3;
let mut t1 = x223;
for _ in 0..23 {
t1 = t1.sqr();
}
t1 *= &x22;
for _ in 0..6 {
t1 = t1.sqr();
}
t1 *= &x2;
t1 = t1.sqr();
let r = t1.sqr();
t1 = r.sqr();
(r, &t1 == self)
}
/// Sets a field element to be the (modular) inverse of
/// another. Requires the input's magnitude to be at most 8. The
/// output magnitude is 1 (but not guaranteed to be normalized).
pub fn inv(&self) -> Field {
let mut x2 = self.sqr();
x2 *= self;
let mut x3 = x2.sqr();
x3 *= self;
let mut x6 = x3;
for _ in 0..3 {
x6 = x6.sqr();
}
x6 *= &x3;
let mut x9 = x6;
for _ in 0..3 {
x9 = x9.sqr();
}
x9 *= &x3;
let mut x11 = x9;
for _ in 0..2 {
x11 = x11.sqr();
}
x11 *= &x2;
let mut x22 = x11;
for _ in 0..11 {
x22 = x22.sqr();
}
x22 *= &x11;
let mut x44 = x22;
for _ in 0..22 {
x44 = x44.sqr();
}
x44 *= &x22;
let mut x88 = x44;
for _ in 0..44 {
x88 = x88.sqr();
}
x88 *= &x44;
let mut x176 = x88;
for _ in 0..88 {
x176 = x176.sqr();
}
x176 *= &x88;
let mut x220 = x176;
for _ in 0..44 {
x220 = x220.sqr();
}
x220 *= &x44;
let mut x223 = x220;
for _ in 0..3 {
x223 = x223.sqr();
}
x223 *= &x3;
let mut t1 = x223;
for _ in 0..23 {
t1 = t1.sqr();
}
t1 *= &x22;
for _ in 0..5 {
t1 = t1.sqr();
}
t1 *= self;
for _ in 0..3 {
t1 = t1.sqr();
}
t1 *= &x2;
for _ in 0..2 {
t1 = t1.sqr();
}
self * &t1
}
/// Potentially faster version of secp256k1_fe_inv, without
/// constant-time guarantee.
pub fn inv_var(&self) -> Field {
self.inv()
}
/// Checks whether a field element is a quadratic residue.
pub fn is_quad_var(&self) -> bool {
let (_, ret) = self.sqrt();
ret
}
/// If flag is true, set *r equal to *a; otherwise leave
/// it. Constant-time.
pub fn cmov(&mut self, other: &Field, flag: bool) {
self.n[0] = if flag { other.n[0] } else { self.n[0] };
self.n[1] = if flag { other.n[1] } else { self.n[1] };
self.n[2] = if flag { other.n[2] } else { self.n[2] };
self.n[3] = if flag { other.n[3] } else { self.n[3] };
self.n[4] = if flag { other.n[4] } else { self.n[4] };
self.n[5] = if flag { other.n[5] } else { self.n[5] };
self.n[6] = if flag { other.n[6] } else { self.n[6] };
self.n[7] = if flag { other.n[7] } else { self.n[7] };
self.n[8] = if flag { other.n[8] } else { self.n[8] };
self.n[9] = if flag { other.n[9] } else { self.n[9] };
self.magnitude = if flag {
other.magnitude
} else {
self.magnitude
};
self.normalized = if flag {
other.normalized
} else {
self.normalized
};
}
}
impl Default for Field {
fn default() -> Field {
Self {
n: [0u32; 10],
magnitude: 0,
normalized: true,
}
}
}
impl Add<Field> for Field {
type Output = Field;
fn add(self, other: Field) -> Field {
let mut ret = self;
ret.add_assign(&other);
ret
}
}
impl<'a, 'b> Add<&'a Field> for &'b Field {
type Output = Field;
fn add(self, other: &'a Field) -> Field {
let mut ret = *self;
ret.add_assign(other);
ret
}
}
impl<'a> AddAssign<&'a Field> for Field {
fn add_assign(&mut self, other: &'a Field) {
self.n[0] += other.n[0];
self.n[1] += other.n[1];
self.n[2] += other.n[2];
self.n[3] += other.n[3];
self.n[4] += other.n[4];
self.n[5] += other.n[5];
self.n[6] += other.n[6];
self.n[7] += other.n[7];
self.n[8] += other.n[8];
self.n[9] += other.n[9];
self.magnitude += other.magnitude;
self.normalized = false;
debug_assert!(self.verify());
}
}
impl AddAssign<Field> for Field {
fn add_assign(&mut self, other: Field) {
self.add_assign(&other)
}
}
impl Mul<Field> for Field {
type Output = Field;
fn mul(self, other: Field) -> Field {
let mut ret = Field::default();
ret.mul_in_place(&self, &other);
ret
}
}
impl<'a, 'b> Mul<&'a Field> for &'b Field {
type Output = Field;
fn mul(self, other: &'a Field) -> Field {
let mut ret = Field::default();
ret.mul_in_place(self, other);
ret
}
}
impl<'a> MulAssign<&'a Field> for Field {
fn mul_assign(&mut self, other: &'a Field) {
let mut ret = Field::default();
ret.mul_in_place(self, other);
*self = ret;
}
}
impl MulAssign<Field> for Field {
fn mul_assign(&mut self, other: Field) {
self.mul_assign(&other)
}
}
impl PartialEq for Field {
fn eq(&self, other: &Field) -> bool {
let mut na = self.neg(self.magnitude);
na += other;
na.normalizes_to_zero()
}
}
impl Eq for Field {}
impl Ord for Field {
fn cmp(&self, other: &Field) -> Ordering {
self.cmp_var(other)
}
}
impl PartialOrd for Field {
fn partial_cmp(&self, other: &Field) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// Compact field element storage.
pub struct FieldStorage(pub [u32; 8]);
impl Default for FieldStorage {
fn default() -> FieldStorage {
FieldStorage([0; 8])
}
}
impl FieldStorage {
pub const fn new(
d7: u32,
d6: u32,
d5: u32,
d4: u32,
d3: u32,
d2: u32,
d1: u32,
d0: u32,
) -> Self {
Self([d0, d1, d2, d3, d4, d5, d6, d7])
}
pub fn cmov(&mut self, other: &FieldStorage, flag: bool) {
self.0[0] = if flag { other.0[0] } else { self.0[0] };
self.0[1] = if flag { other.0[1] } else { self.0[1] };
self.0[2] = if flag { other.0[2] } else { self.0[2] };
self.0[3] = if flag { other.0[3] } else { self.0[3] };
self.0[4] = if flag { other.0[4] } else { self.0[4] };
self.0[5] = if flag { other.0[5] } else { self.0[5] };
self.0[6] = if flag { other.0[6] } else { self.0[6] };
self.0[7] = if flag { other.0[7] } else { self.0[7] };
}
}
impl From<FieldStorage> for Field {
fn from(a: FieldStorage) -> Field {
let mut r = Field::default();
r.n[0] = a.0[0] & 0x3FFFFFF;
r.n[1] = a.0[0] >> 26 | ((a.0[1] << 6) & 0x3FFFFFF);
r.n[2] = a.0[1] >> 20 | ((a.0[2] << 12) & 0x3FFFFFF);
r.n[3] = a.0[2] >> 14 | ((a.0[3] << 18) & 0x3FFFFFF);
r.n[4] = a.0[3] >> 8 | ((a.0[4] << 24) & 0x3FFFFFF);
r.n[5] = (a.0[4] >> 2) & 0x3FFFFFF;
r.n[6] = a.0[4] >> 28 | ((a.0[5] << 4) & 0x3FFFFFF);
r.n[7] = a.0[5] >> 22 | ((a.0[6] << 10) & 0x3FFFFFF);
r.n[8] = a.0[6] >> 16 | ((a.0[7] << 16) & 0x3FFFFFF);
r.n[9] = a.0[7] >> 10;
r.magnitude = 1;
r.normalized = true;
r
}
}
impl Into<FieldStorage> for Field {
fn into(self) -> FieldStorage {
debug_assert!(self.normalized);
let mut r = FieldStorage::default();
r.0[0] = self.n[0] | self.n[1] << 26;
r.0[1] = self.n[1] >> 6 | self.n[2] << 20;
r.0[2] = self.n[2] >> 12 | self.n[3] << 14;
r.0[3] = self.n[3] >> 18 | self.n[4] << 8;
r.0[4] = self.n[4] >> 24 | self.n[5] << 2 | self.n[6] << 28;
r.0[5] = self.n[6] >> 4 | self.n[7] << 22;
r.0[6] = self.n[7] >> 10 | self.n[8] << 16;
r.0[7] = self.n[8] >> 16 | self.n[9] << 10;
r
}
}
================================================
FILE: core/src/group.rs
================================================
use crate::field::{Field, FieldStorage};
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// A group element of the secp256k1 curve, in affine coordinates.
pub struct Affine {
pub x: Field,
pub y: Field,
pub infinity: bool,
}
#[derive(Debug, Clone, Copy)]
/// A group element of the secp256k1 curve, in jacobian coordinates.
pub struct Jacobian {
pub x: Field,
pub y: Field,
pub z: Field,
pub infinity: bool,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// Affine coordinate group element compact storage.
pub struct AffineStorage {
pub x: FieldStorage,
pub y: FieldStorage,
}
impl Default for Affine {
fn default() -> Affine {
Affine {
x: Field::default(),
y: Field::default(),
infinity: false,
}
}
}
impl Default for Jacobian {
fn default() -> Jacobian {
Jacobian {
x: Field::default(),
y: Field::default(),
z: Field::default(),
infinity: false,
}
}
}
impl Default for AffineStorage {
fn default() -> AffineStorage {
AffineStorage {
x: FieldStorage::default(),
y: FieldStorage::default(),
}
}
}
pub static AFFINE_INFINITY: Affine = Affine {
x: Field::new(0, 0, 0, 0, 0, 0, 0, 0),
y: Field::new(0, 0, 0, 0, 0, 0, 0, 0),
infinity: true,
};
pub static JACOBIAN_INFINITY: Jacobian = Jacobian {
x: Field::new(0, 0, 0, 0, 0, 0, 0, 0),
y: Field::new(0, 0, 0, 0, 0, 0, 0, 0),
z: Field::new(0, 0, 0, 0, 0, 0, 0, 0),
infinity: true,
};
pub static AFFINE_G: Affine = Affine::new(
Field::new(
0x79BE667E, 0xF9DCBBAC, 0x55A06295, 0xCE870B07, 0x029BFCDB, 0x2DCE28D9, 0x59F2815B,
0x16F81798,
),
Field::new(
0x483ADA77, 0x26A3C465, 0x5DA4FBFC, 0x0E1108A8, 0xFD17B448, 0xA6855419, 0x9C47D08F,
0xFB10D4B8,
),
);
pub const CURVE_B: u32 = 7;
impl Affine {
/// Create a new affine.
pub const fn new(x: Field, y: Field) -> Self {
Self {
x,
y,
infinity: false,
}
}
/// Set a group element equal to the point with given X and Y
/// coordinates.
pub fn set_xy(&mut self, x: &Field, y: &Field) {
self.infinity = false;
self.x = *x;
self.y = *y;
}
/// Set a group element (affine) equal to the point with the given
/// X coordinate and a Y coordinate that is a quadratic residue
/// modulo p. The return value is true iff a coordinate with the
/// given X coordinate exists.
pub fn set_xquad(&mut self, x: &Field) -> bool {
self.x = *x;
let x2 = x.sqr();
let x3 = *x * x2;
self.infinity = false;
let mut c = Field::default();
c.set_int(CURVE_B);
c += x3;
let (v, ret) = c.sqrt();
self.y = v;
ret
}
/// Set a group element (affine) equal to the point with the given
/// X coordinate, and given oddness for Y. Return value indicates
/// whether the result is valid.
pub fn set_xo_var(&mut self, x: &Field, odd: bool) -> bool {
if !self.set_xquad(x) {
return false;
}
self.y.normalize_var();
if self.y.is_odd() != odd {
self.y = self.y.neg(1);
}
true
}
/// Check whether a group element is the point at infinity.
pub fn is_infinity(&self) -> bool {
self.infinity
}
/// Check whether a group element is valid (i.e., on the curve).
pub fn is_valid_var(&self) -> bool {
if self.is_infinity() {
return false;
}
let y2 = self.y.sqr();
let mut x3 = self.x.sqr();
x3 *= &self.x;
let mut c = Field::default();
c.set_int(CURVE_B);
x3 += &c;
x3.normalize_weak();
y2.eq_var(&x3)
}
pub fn neg_in_place(&mut self, other: &Affine) {
*self = *other;
self.y.normalize_weak();
self.y = self.y.neg(1);
}
pub fn neg(&self) -> Affine {
let mut ret = Affine::default();
ret.neg_in_place(self);
ret
}
/// Set a group element equal to another which is given in
/// jacobian coordinates.
pub fn set_gej(&mut self, a: &Jacobian) {
self.infinity = a.infinity;
let mut a = *a;
a.z = a.z.inv();
let z2 = a.z.sqr();
let z3 = a.z * z2;
a.x *= z2;
a.y *= z3;
a.z.set_int(1);
self.x = a.x;
self.y = a.y;
}
pub fn from_gej(a: &Jacobian) -> Self {
let mut ge = Self::default();
ge.set_gej(a);
ge
}
pub fn set_gej_var(&mut self, a: &Jacobian) {
let mut a = *a;
self.infinity = a.infinity;
if a.is_infinity() {
return;
}
a.z = a.z.inv_var();
let z2 = a.z.sqr();
let z3 = a.z * z2;
a.x *= &z2;
a.y *= &z3;
a.z.set_int(1);
self.x = a.x;
self.y = a.y;
}
pub fn set_gej_zinv(&mut self, a: &Jacobian, zi: &Field) {
let zi2 = zi.sqr();
let zi3 = zi2 * *zi;
self.x = a.x * zi2;
self.y = a.y * zi3;
self.infinity = a.infinity;
}
/// Clear a secp256k1_ge to prevent leaking sensitive information.
pub fn clear(&mut self) {
self.infinity = false;
self.x.clear();
self.y.clear();
}
}
pub fn set_table_gej_var(r: &mut [Affine], a: &[Jacobian], zr: &[Field]) {
debug_assert!(r.len() == a.len());
let mut i = r.len() - 1;
let mut zi: Field;
if !r.is_empty() {
zi = a[i].z.inv();
r[i].set_gej_zinv(&a[i], &zi);
while i > 0 {
zi *= &zr[i];
i -= 1;
r[i].set_gej_zinv(&a[i], &zi);
}
}
}
pub fn globalz_set_table_gej(r: &mut [Affine], globalz: &mut Field, a: &[Jacobian], zr: &[Field]) {
debug_assert!(r.len() == a.len() && a.len() == zr.len());
let mut i = r.len() - 1;
let mut zs: Field;
if !r.is_empty() {
r[i].x = a[i].x;
r[i].y = a[i].y;
*globalz = a[i].z;
r[i].infinity = false;
zs = zr[i];
while i > 0 {
if i != r.len() - 1 {
zs *= zr[i];
}
i -= 1;
r[i].set_gej_zinv(&a[i], &zs);
}
}
}
impl Jacobian {
/// Create a new jacobian.
pub const fn new(x: Field, y: Field) -> Self {
Self {
x,
y,
infinity: false,
z: Field::new(0, 0, 0, 0, 0, 0, 0, 1),
}
}
/// Set a group element (jacobian) equal to the point at infinity.
pub fn set_infinity(&mut self) {
self.infinity = true;
self.x.clear();
self.y.clear();
self.z.clear();
}
/// Set a group element (jacobian) equal to another which is given
/// in affine coordinates.
pub fn set_ge(&mut self, a: &Affine) {
self.infinity = a.infinity;
self.x = a.x;
self.y = a.y;
self.z.set_int(1);
}
pub fn from_ge(a: &Affine) -> Self {
let mut gej = Self::default();
gej.set_ge(a);
gej
}
/// Compare the X coordinate of a group element (jacobian).
pub fn eq_x_var(&self, x: &Field) -> bool {
debug_assert!(!self.is_infinity());
let mut r = self.z.sqr();
r *= x;
let mut r2 = self.x;
r2.normalize_weak();
r.eq_var(&r2)
}
/// Set r equal to the inverse of a (i.e., mirrored around the X
/// axis).
pub fn neg_in_place(&mut self, a: &Jacobian) {
self.infinity = a.infinity;
self.x = a.x;
self.y = a.y;
self.z = a.z;
self.y.normalize_weak();
self.y = self.y.neg(1);
}
pub fn neg(&self) -> Jacobian {
let mut ret = Jacobian::default();
ret.neg_in_place(self);
ret
}
/// Check whether a group element is the point at infinity.
pub fn is_infinity(&self) -> bool {
self.infinity
}
/// Check whether a group element's y coordinate is a quadratic residue.
pub fn has_quad_y_var(&self) -> bool {
if self.infinity {
return false;
}
let yz = self.y * self.z;
yz.is_quad_var()
}
/// Set r equal to the double of a. If rzr is not-NULL, r->z =
/// a->z * *rzr (where infinity means an implicit z = 0). a may
/// not be zero. Constant time.
pub fn double_nonzero_in_place(&mut self, a: &Jacobian, rzr: Option<&mut Field>) {
debug_assert!(!self.is_infinity());
self.double_var_in_place(a, rzr);
}
/// Set r equal to the double of a. If rzr is not-NULL, r->z =
/// a->z * *rzr (where infinity means an implicit z = 0).
pub fn double_var_in_place(&mut self, a: &Jacobian, rzr: Option<&mut Field>) {
self.infinity = a.infinity;
if self.infinity {
if let Some(rzr) = rzr {
rzr.set_int(1);
}
return;
}
if let Some(rzr) = rzr {
*rzr = a.y;
rzr.normalize_weak();
rzr.mul_int(2);
}
self.z = a.z * a.y;
self.z.mul_int(2);
let mut t1 = a.x.sqr();
t1.mul_int(3);
let mut t2 = t1.sqr();
let mut t3 = a.y.sqr();
t3.mul_int(2);
let mut t4 = t3.sqr();
t4.mul_int(2);
t3 *= &a.x;
self.x = t3;
self.x.mul_int(4);
self.x = self.x.neg(4);
self.x += &t2;
t2 = t2.neg(1);
t3.mul_int(6);
t3 += &t2;
self.y = t1 * t3;
t2 = t4.neg(2);
self.y += t2;
}
pub fn double_var(&self, rzr: Option<&mut Field>) -> Jacobian {
let mut ret = Jacobian::default();
ret.double_var_in_place(&self, rzr);
ret
}
/// Set r equal to the sum of a and b. If rzr is non-NULL, r->z =
/// a->z * *rzr (a cannot be infinity in that case).
pub fn add_var_in_place(&mut self, a: &Jacobian, b: &Jacobian, rzr: Option<&mut Field>) {
if a.is_infinity() {
debug_assert!(rzr.is_none());
*self = *b;
return;
}
if b.is_infinity() {
if let Some(rzr) = rzr {
rzr.set_int(1);
}
*self = *a;
return;
}
self.infinity = false;
let z22 = b.z.sqr();
let z12 = a.z.sqr();
let u1 = a.x * z22;
let u2 = b.x * z12;
let mut s1 = a.y * z22;
s1 *= b.z;
let mut s2 = b.y * z12;
s2 *= a.z;
let mut h = u1.neg(1);
h += u2;
let mut i = s1.neg(1);
i += s2;
if h.normalizes_to_zero_var() {
if i.normalizes_to_zero_var() {
self.double_var_in_place(a, rzr);
} else {
if let Some(rzr) = rzr {
rzr.set_int(0);
}
self.infinity = true;
}
return;
}
let i2 = i.sqr();
let h2 = h.sqr();
let mut h3 = h * h2;
h *= b.z;
if let Some(rzr) = rzr {
*rzr = h;
}
self.z = a.z * h;
let t = u1 * h2;
self.x = t;
self.x.mul_int(2);
self.x += h3;
self.x = self.x.neg(3);
self.x += i2;
self.y = self.x.neg(5);
self.y += t;
self.y *= i;
h3 *= s1;
h3 = h3.neg(1);
self.y += h3;
}
pub fn add_var(&self, b: &Jacobian, rzr: Option<&mut Field>) -> Jacobian {
let mut ret = Jacobian::default();
ret.add_var_in_place(self, b, rzr);
ret
}
/// Set r equal to the sum of a and b (with b given in affine
/// coordinates, and not infinity).
pub fn add_ge_in_place(&mut self, a: &Jacobian, b: &Affine) {
const FE1: Field = Field::new(0, 0, 0, 0, 0, 0, 0, 1);
debug_assert!(!b.infinity);
let zz = a.z.sqr();
let mut u1 = a.x;
u1.normalize_weak();
let u2 = b.x * zz;
let mut s1 = a.y;
s1.normalize_weak();
let mut s2 = b.y * zz;
s2 *= a.z;
let mut t = u1;
t += u2;
let mut m = s1;
m += s2;
let mut rr = t.sqr();
let mut m_alt = u2.neg(1);
let tt = u1 * m_alt;
rr += tt;
let degenerate = m.normalizes_to_zero() && rr.normalizes_to_zero();
let mut rr_alt = s1;
rr_alt.mul_int(2);
m_alt += u1;
rr_alt.cmov(&rr, !degenerate);
m_alt.cmov(&m, !degenerate);
let mut n = m_alt.sqr();
let mut q = n * t;
n = n.sqr();
n.cmov(&m, degenerate);
t = rr_alt.sqr();
self.z = a.z * m_alt;
let infinity = {
let p = self.z.normalizes_to_zero();
let q = a.infinity;
match (p, q) {
(true, true) => false,
(true, false) => true,
(false, true) => false,
(false, false) => false,
}
};
self.z.mul_int(2);
q = q.neg(1);
t += q;
t.normalize_weak();
self.x = t;
t.mul_int(2);
t += q;
t *= rr_alt;
t += n;
self.y = t.neg(3);
self.y.normalize_weak();
self.x.mul_int(4);
self.y.mul_int(4);
self.x.cmov(&b.x, a.infinity);
self.y.cmov(&b.y, a.infinity);
self.z.cmov(&FE1, a.infinity);
self.infinity = infinity;
}
pub fn add_ge(&self, b: &Affine) -> Jacobian {
let mut ret = Jacobian::default();
ret.add_ge_in_place(self, b);
ret
}
/// Set r equal to the sum of a and b (with b given in affine
/// coordinates). This is more efficient than
/// secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge
/// but without constant-time guarantee, and b is allowed to be
/// infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be
/// infinity in that case).
pub fn add_ge_var_in_place(&mut self, a: &Jacobian, b: &Affine, rzr: Option<&mut Field>) {
if a.is_infinity() {
debug_assert!(rzr.is_none());
self.set_ge(b);
return;
}
if b.is_infinity() {
if let Some(rzr) = rzr {
rzr.set_int(1);
}
*self = *a;
return;
}
self.infinity = false;
let z12 = a.z.sqr();
let mut u1 = a.x;
u1.normalize_weak();
let u2 = b.x * z12;
let mut s1 = a.y;
s1.normalize_weak();
let mut s2 = b.y * z12;
s2 *= a.z;
let mut h = u1.neg(1);
h += u2;
let mut i = s1.neg(1);
i += s2;
if h.normalizes_to_zero_var() {
if i.normalizes_to_zero_var() {
self.double_var_in_place(a, rzr);
} else {
if let Some(rzr) = rzr {
rzr.set_int(0);
}
self.infinity = true;
}
return;
}
let i2 = i.sqr();
let h2 = h.sqr();
let mut h3 = h * h2;
if let Some(rzr) = rzr {
*rzr = h;
}
self.z = a.z * h;
let t = u1 * h2;
self.x = t;
self.x.mul_int(2);
self.x += h3;
self.x = self.x.neg(3);
self.x += i2;
self.y = self.x.neg(5);
self.y += t;
self.y *= i;
h3 *= s1;
h3 = h3.neg(1);
self.y += h3;
}
pub fn add_ge_var(&self, b: &Affine, rzr: Option<&mut Field>) -> Jacobian {
let mut ret = Jacobian::default();
ret.add_ge_var_in_place(&self, b, rzr);
ret
}
/// Set r equal to the sum of a and b (with the inverse of b's Z
/// coordinate passed as bzinv).
pub fn add_zinv_var_in_place(&mut self, a: &Jacobian, b: &Affine, bzinv: &Field) {
if b.is_infinity() {
*self = *a;
return;
}
if a.is_infinity() {
self.infinity = b.infinity;
let bzinv2 = bzinv.sqr();
let bzinv3 = &bzinv2 * bzinv;
self.x = b.x * bzinv2;
self.y = b.y * bzinv3;
self.z.set_int(1);
return;
}
self.infinity = false;
let az = a.z * *bzinv;
let z12 = az.sqr();
let mut u1 = a.x;
u1.normalize_weak();
let u2 = b.x * z12;
let mut s1 = a.y;
s1.normalize_weak();
let mut s2 = b.y * z12;
s2 *= &az;
let mut h = u1.neg(1);
h += &u2;
let mut i = s1.neg(1);
i += &s2;
if h.normalizes_to_zero_var() {
if i.normalizes_to_zero_var() {
self.double_var_in_place(a, None);
} else {
self.infinity = true;
}
return;
}
let i2 = i.sqr();
let h2 = h.sqr();
let mut h3 = h * h2;
self.z = a.z;
self.z *= h;
let t = u1 * h2;
self.x = t;
self.x.mul_int(2);
self.x += h3;
self.x = self.x.neg(3);
self.x += i2;
self.y = self.x.neg(5);
self.y += t;
self.y *= i;
h3 *= s1;
h3 = h3.neg(1);
self.y += h3;
}
pub fn add_zinv_var(&mut self, b: &Affine, bzinv: &Field) -> Jacobian {
let mut ret = Jacobian::default();
ret.add_zinv_var_in_place(&self, b, bzinv);
ret
}
/// Clear a secp256k1_gej to prevent leaking sensitive
/// information.
pub fn clear(&mut self) {
self.infinity = false;
self.x.clear();
self.y.clear();
self.z.clear();
}
/// Rescale a jacobian point by b which must be
/// non-zero. Constant-time.
pub fn rescale(&mut self, s: &Field) {
debug_assert!(!s.is_zero());
let zz = s.sqr();
self.x *= &zz;
self.y *= &zz;
self.y *= s;
self.z *= s;
}
}
impl From<AffineStorage> for Affine {
fn from(a: AffineStorage) -> Affine {
Affine::new(a.x.into(), a.y.into())
}
}
impl Into<AffineStorage> for Affine {
fn into(mut self) -> AffineStorage {
debug_assert!(!self.is_infinity());
self.x.normalize();
self.y.normalize();
AffineStorage::new(self.x.into(), self.y.into())
}
}
impl AffineStorage {
/// Create a new affine storage.
pub const fn new(x: FieldStorage, y: FieldStorage) -> Self {
Self { x, y }
}
/// If flag is true, set *r equal to *a; otherwise leave
/// it. Constant-time.
pub fn cmov(&mut self, a: &AffineStorage, flag: bool) {
self.x.cmov(&a.x, flag);
self.y.cmov(&a.y, flag);
}
}
================================================
FILE: core/src/lib.rs
================================================
//! Core libraries for libsecp256k1.
#![allow(
clippy::cast_ptr_alignment,
clippy::identity_op,
clippy::many_single_char_names,
clippy::needless_range_loop,
clippy::suspicious_op_assign_impl,
clippy::too_many_arguments,
clippy::type_complexity
)]
#![deny(
unused_import_braces,
unused_imports,
unused_comparisons,
unused_must_use,
unused_variables,
non_shorthand_field_patterns,
unreachable_code,
unused_parens
)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
#[macro_use]
mod field;
#[macro_use]
mod group;
mod der;
mod ecdh;
mod ecdsa;
mod ecmult;
mod error;
mod scalar;
pub use crate::error::Error;
/// Curve related structs.
pub mod curve {
pub use crate::{
field::{Field, FieldStorage},
group::{Affine, AffineStorage, Jacobian, AFFINE_G, CURVE_B},
scalar::Scalar,
};
pub use crate::ecmult::{ECMultContext, ECMultGenContext};
}
/// Utilities to manipulate the secp256k1 curve parameters.
pub mod util {
pub const TAG_PUBKEY_EVEN: u8 = 0x02;
pub const TAG_PUBKEY_ODD: u8 = 0x03;
pub const TAG_PUBKEY_FULL: u8 = 0x04;
pub const TAG_PUBKEY_HYBRID_EVEN: u8 = 0x06;
pub const TAG_PUBKEY_HYBRID_ODD: u8 = 0x07;
pub const MESSAGE_SIZE: usize = 32;
pub const SECRET_KEY_SIZE: usize = 32;
pub const RAW_PUBLIC_KEY_SIZE: usize = 64;
pub const FULL_PUBLIC_KEY_SIZE: usize = 65;
pub const COMPRESSED_PUBLIC_KEY_SIZE: usize = 33;
pub const SIGNATURE_SIZE: usize = 64;
pub const DER_MAX_SIGNATURE_SIZE: usize = 72;
pub use crate::{
ecmult::{
odd_multiples_table, ECMULT_TABLE_SIZE_A, ECMULT_TABLE_SIZE_G, WINDOW_A, WINDOW_G,
},
group::{globalz_set_table_gej, set_table_gej_var, AFFINE_INFINITY, JACOBIAN_INFINITY},
};
pub use crate::der::{Decoder, SignatureArray};
}
================================================
FILE: core/src/scalar.rs
================================================
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg};
use crunchy::unroll;
use subtle::Choice;
const SECP256K1_N: [u32; 8] = [
0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
];
const SECP256K1_N_C_0: u32 = !SECP256K1_N[0] + 1;
const SECP256K1_N_C_1: u32 = !SECP256K1_N[1];
const SECP256K1_N_C_2: u32 = !SECP256K1_N[2];
const SECP256K1_N_C_3: u32 = !SECP256K1_N[3];
const SECP256K1_N_C_4: u32 = 1;
const SECP256K1_N_H_0: u32 = 0x681B20A0;
const SECP256K1_N_H_1: u32 = 0xDFE92F46;
const SECP256K1_N_H_2: u32 = 0x57A4501D;
const SECP256K1_N_H_3: u32 = 0x5D576E73;
const SECP256K1_N_H_4: u32 = 0xFFFFFFFF;
const SECP256K1_N_H_5: u32 = 0xFFFFFFFF;
const SECP256K1_N_H_6: u32 = 0xFFFFFFFF;
const SECP256K1_N_H_7: u32 = 0x7FFFFFFF;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// A 256-bit scalar value.
pub struct Scalar(pub [u32; 8]);
impl Scalar {
/// Clear a scalar to prevent the leak of sensitive data.
pub fn clear(&mut self) {
unsafe {
core::ptr::write_volatile(&mut self.0, [0u32; 8]);
}
}
/// Set a scalar to an unsigned integer.
pub fn set_int(&mut self, v: u32) {
self.0 = [v, 0, 0, 0, 0, 0, 0, 0];
}
/// Create a scalar from an unsigned integer.
pub fn from_int(v: u32) -> Self {
let mut scalar = Self::default();
scalar.set_int(v);
scalar
}
/// Access bits from a scalar. All requested bits must belong to
/// the same 32-bit limb.
pub fn bits(&self, offset: usize, count: usize) -> u32 {
debug_assert!((offset + count - 1) >> 5 == offset >> 5);
(self.0[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1)
}
/// Access bits from a scalar. Not constant time.
pub fn bits_var(&self, offset: usize, count: usize) -> u32 {
debug_assert!(count < 32);
debug_assert!(offset + count <= 256);
if (offset + count - 1) >> 5 == offset >> 5 {
self.bits(offset, count)
} else {
debug_assert!((offset >> 5) + 1 < 8);
((self.0[offset >> 5] >> (offset & 0x1f))
| (self.0[(offset >> 5) + 1] << (32 - (offset & 0x1f))))
& ((1 << count) - 1)
}
}
#[must_use]
fn check_overflow(&self) -> Choice {
let mut yes: Choice = 0.into();
let mut no: Choice = 0.into();
no |= Choice::from((self.0[7] < SECP256K1_N[7]) as u8); /* No need for a > check. */
no |= Choice::from((self.0[6] < SECP256K1_N[6]) as u8); /* No need for a > check. */
no |= Choice::from((self.0[5] < SECP256K1_N[5]) as u8); /* No need for a > check. */
no |= Choice::from((self.0[4] < SECP256K1_N[4]) as u8);
yes |= Choice::from((self.0[4] > SECP256K1_N[4]) as u8) & !no;
no |= Choice::from((self.0[3] < SECP256K1_N[3]) as u8) & !yes;
yes |= Choice::from((self.0[3] > SECP256K1_N[3]) as u8) & !no;
no |= Choice::from((self.0[2] < SECP256K1_N[2]) as u8) & !yes;
yes |= Choice::from((self.0[2] > SECP256K1_N[2]) as u8) & !no;
no |= Choice::from((self.0[1] < SECP256K1_N[1]) as u8) & !yes;
yes |= Choice::from((self.0[1] > SECP256K1_N[1]) as u8) & !no;
yes |= Choice::from((self.0[0] >= SECP256K1_N[0]) as u8) & !no;
yes
}
fn reduce(&mut self, overflow: Choice) {
let o = overflow.unwrap_u8() as u64;
let mut t: u64;
t = (self.0[0] as u64) + o * (SECP256K1_N_C_0 as u64);
self.0[0] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[1] as u64) + o * (SECP256K1_N_C_1 as u64);
self.0[1] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[2] as u64) + o * (SECP256K1_N_C_2 as u64);
self.0[2] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[3] as u64) + o * (SECP256K1_N_C_3 as u64);
self.0[3] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[4] as u64) + o * (SECP256K1_N_C_4 as u64);
self.0[4] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += self.0[5] as u64;
self.0[5] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += self.0[6] as u64;
self.0[6] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += self.0[7] as u64;
self.0[7] = (t & 0xFFFFFFFF) as u32;
}
/// Conditionally add a power of two to a scalar. The result is
/// not allowed to overflow.
pub fn cadd_bit(&mut self, mut bit: usize, flag: bool) {
let mut t: u64;
debug_assert!(bit < 256);
bit += if flag { 0 } else { usize::max_value() } & 0x100;
t = (self.0[0] as u64) + ((if (bit >> 5) == 0 { 1 } else { 0 }) << (bit & 0x1F));
self.0[0] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[1] as u64) + ((if (bit >> 5) == 1 { 1 } else { 0 }) << (bit & 0x1F));
self.0[1] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[2] as u64) + ((if (bit >> 5) == 2 { 1 } else { 0 }) << (bit & 0x1F));
self.0[2] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[3] as u64) + ((if (bit >> 5) == 3 { 1 } else { 0 }) << (bit & 0x1F));
self.0[3] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[4] as u64) + ((if (bit >> 5) == 4 { 1 } else { 0 }) << (bit & 0x1F));
self.0[4] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[5] as u64) + ((if (bit >> 5) == 5 { 1 } else { 0 }) << (bit & 0x1F));
self.0[5] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[6] as u64) + ((if (bit >> 5) == 6 { 1 } else { 0 }) << (bit & 0x1F));
self.0[6] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
t += (self.0[7] as u64) + ((if (bit >> 5) == 7 { 1 } else { 0 }) << (bit & 0x1F));
self.0[7] = (t & 0xFFFFFFFF) as u32;
debug_assert!((t >> 32) == 0);
debug_assert!(!bool::from(self.check_overflow()));
}
/// Set a scalar from a big endian byte array, return whether it overflowed.
#[must_use]
pub fn set_b32(&mut self, b32: &[u8; 32]) -> Choice {
self.0[0] = (b32[31] as u32)
| ((b32[30] as u32) << 8)
| ((b32[29] as u32) << 16)
| ((b32[28] as u32) << 24);
self.0[1] = (b32[27] as u32)
| ((b32[26] as u32) << 8)
| ((b32[25] as u32) << 16)
| ((b32[24] as u32) << 24);
self.0[2] = (b32[23] as u32)
| ((b32[22] as u32) << 8)
| ((b32[21] as u32) << 16)
| ((b32[20] as u32) << 24);
self.0[3] = (b32[19] as u32)
| ((b32[18] as u32) << 8)
| ((b32[17] as u32) << 16)
| ((b32[16] as u32) << 24);
self.0[4] = (b32[15] as u32)
| ((b32[14] as u32) << 8)
| ((b32[13] as u32) << 16)
| ((b32[12] as u32) << 24);
self.0[5] = (b32[11] as u32)
| ((b32[10] as u32) << 8)
| ((b32[9] as u32) << 16)
| ((b32[8] as u32) << 24);
self.0[6] = (b32[7] as u32)
| ((b32[6] as u32) << 8)
| ((b32[5] as u32) << 16)
| ((b32[4] as u32) << 24);
self.0[7] = (b32[3] as u32)
| ((b32[2] as u32) << 8)
| ((b32[1] as u32) << 16)
| ((b32[0] as u32) << 24);
let overflow = self.check_overflow();
self.reduce(overflow);
overflow
}
/// Convert a scalar to a byte array.
pub fn b32(&self) -> [u8; 32] {
let mut bin = [0u8; 32];
self.fill_b32(&mut bin);
bin
}
/// Convert a scalar to a byte array.
pub fn fill_b32(&self, bin: &mut [u8; 32]) {
bin[0] = (self.0[7] >> 24) as u8;
bin[1] = (self.0[7] >> 16) as u8;
bin[2] = (self.0[7] >> 8) as u8;
bin[3] = (self.0[7]) as u8;
bin[4] = (self.0[6] >> 24) as u8;
bin[5] = (self.0[6] >> 16) as u8;
bin[6] = (self.0[6] >> 8) as u8;
bin[7] = (self.0[6]) as u8;
bin[8] = (self.0[5] >> 24) as u8;
bin[9] = (self.0[5] >> 16) as u8;
bin[10] = (self.0[5] >> 8) as u8;
bin[11] = (self.0[5]) as u8;
bin[12] = (self.0[4] >> 24) as u8;
bin[13] = (self.0[4] >> 16) as u8;
bin[14] = (self.0[4] >> 8) as u8;
bin[15] = (self.0[4]) as u8;
bin[16] = (self.0[3] >> 24) as u8;
bin[17] = (self.0[3] >> 16) as u8;
bin[18] = (self.0[3] >> 8) as u8;
bin[19] = (self.0[3]) as u8;
bin[20] = (self.0[2] >> 24) as u8;
bin[21] = (self.0[2] >> 16) as u8;
bin[22] = (self.0[2] >> 8) as u8;
bin[23] = (self.0[2]) as u8;
bin[24] = (self.0[1] >> 24) as u8;
bin[25] = (self.0[1] >> 16) as u8;
bin[26] = (self.0[1] >> 8) as u8;
bin[27] = (self.0[1]) as u8;
bin[28] = (self.0[0] >> 24) as u8;
bin[29] = (self.0[0] >> 16) as u8;
bin[30] = (self.0[0] >> 8) as u8;
bin[31] = (self.0[0]) as u8;
}
/// Check whether a scalar equals zero.
pub fn is_zero(&self) -> bool {
(self.0[0]
| self.0[1]
| self.0[2]
| self.0[3]
| self.0[4]
| self.0[5]
| self.0[6]
| self.0[7])
== 0
}
/// Check whether a scalar equals one.
pub fn is_one(&self) -> bool {
((self.0[0] ^ 1)
| self.0[1]
| self.0[2]
| self.0[3]
| self.0[4]
| self.0[5]
| self.0[6]
| self.0[7])
== 0
}
/// Check whether a scalar is higher than the group order divided
/// by 2.
pub fn is_high(&self) -> bool {
let mut yes: Choice = 0.into();
let mut no: Choice = 0.into();
no |= Choice::from((self.0[7] < SECP256K1_N_H_7) as u8);
yes |= Choice::from((self.0[7] > SECP256K1_N_H_7) as u8) & !no;
no |= Choice::from((self.0[6] < SECP256K1_N_H_6) as u8) & !yes; /* No need for a > check. */
no |= Choice::from((self.0[5] < SECP256K1_N_H_5) as u8) & !yes; /* No need for a > check. */
no |= Choice::from((self.0[4] < SECP256K1_N_H_4) as u8) & !yes; /* No need for a > check. */
no |= Choice::from((self.0[3] < SECP256K1_N_H_3) as u8) & !yes;
yes |= Choice::from((self.0[3] > SECP256K1_N_H_3) as u8) & !no;
no |= Choice::from((self.0[2] < SECP256K1_N_H_2) as u8) & !yes;
yes |= Choice::from((self.0[2] > SECP256K1_N_H_2) as u8) & !no;
no |= Choice::from((self.0[1] < SECP256K1_N_H_1) as u8) & !yes;
yes |= Choice::from((self.0[1] > SECP256K1_N_H_1) as u8) & !no;
yes |= Choice::from((self.0[0] >= SECP256K1_N_H_0) as u8) & !no;
yes.into()
}
/// Conditionally negate a number, in constant time.
pub fn cond_neg_assign(&mut self, flag: Choice) {
let mask = u32::max_value() * flag.unwrap_u8() as u32;
let nonzero = 0xFFFFFFFFu64 * !self.is_zero() as u64;
let mut t = 1u64 * flag.unwrap_u8() as u64;
unroll! {
for i in 0..8 {
t += (self.0[i] ^ mask) as u64 + (SECP256K1_N[i] & mask) as u64;
self.0[i] = (t & nonzero) as u32;
t >>= 32;
}
}
let _ = t;
}
}
macro_rules! define_ops {
($c0: ident, $c1: ident, $c2: ident) => {
#[allow(unused_macros)]
macro_rules! muladd {
($a: expr, $b: expr) => {
let a = $a;
let b = $b;
let t = (a as u64) * (b as u64);
let mut th = (t >> 32) as u32;
let tl = t as u32;
$c0 = $c0.wrapping_add(tl);
th = th.wrapping_add(if $c0 < tl { 1 } else { 0 });
$c1 = $c1.wrapping_add(th);
$c2 = $c2.wrapping_add(if $c1 < th { 1 } else { 0 });
debug_assert!($c1 >= th || $c2 != 0);
};
}
#[allow(unused_macros)]
macro_rules! muladd_fast {
($a: expr, $b: expr) => {
let a = $a;
let b = $b;
let t = (a as u64) * (b as u64);
let mut th = (t >> 32) as u32;
let tl = t as u32;
$c0 = $c0.wrapping_add(tl);
th = th.wrapping_add(if $c0 < tl { 1 } else { 0 });
$c1 = $c1.wrapping_add(th);
debug_assert!($c1 >= th);
};
}
#[allow(unused_macros)]
macro_rules! muladd2 {
($a: expr, $b: expr) => {
let a = $a;
let b = $b;
let t = (a as u64) * (b as u64);
let th = (t >> 32) as u32;
let tl = t as u32;
let mut th2 = th.wrapping_add(th);
$c2 = $c2.wrapping_add(if th2 < th { 1 } else { 0 });
debug_assert!(th2 >= th || $c2 != 0);
let tl2 = tl.wrapping_add(tl);
th2 = th2.wrapping_add(if tl2 < tl { 1 } else { 0 });
$c0 = $c0.wrapping_add(tl2);
th2 = th2.wrapping_add(if $c0 < tl2 { 1 } else { 0 });
$c2 = $c2.wrapping_add(if $c0 < tl2 && th2 == 0 { 1 } else { 0 });
debug_assert!($c0 >= tl2 || th2 != 0 || $c2 != 0);
$c1 = $c1.wrapping_add(th2);
$c2 = $c2.wrapping_add(if $c1 < th2 { 1 } else { 0 });
debug_assert!($c1 >= th2 || $c2 != 0);
};
}
#[allow(unused_macros)]
macro_rules! sumadd {
($a: expr) => {
let a = $a;
$c0 = $c0.wrapping_add(a);
let over = if $c0 < a { 1 } else { 0 };
$c1 = $c1.wrapping_add(over);
$c2 = $c2.wrapping_add(if $c1 < over { 1 } else { 0 });
};
}
#[allow(unused_macros)]
macro_rules! sumadd_fast {
($a: expr) => {
let a = $a;
$c0 = $c0.wrapping_add(a);
$c1 = $c1.wrapping_add(if $c0 < a { 1 } else { 0 });
debug_assert!($c1 != 0 || $c0 >= a);
debug_assert!($c2 == 0);
};
}
#[allow(unused_macros)]
macro_rules! extract {
() => {{
#[allow(unused_assignments)]
{
let n = $c0;
$c0 = $c1;
$c1 = $c2;
$c2 = 0;
n
}
}};
}
#[allow(unused_macros)]
macro_rules! extract_fast {
() => {{
#[allow(unused_assignments)]
{
let n = $c0;
$c0 = $c1;
$c1 = 0;
debug_assert!($c2 == 0);
n
}
}};
}
};
}
impl Scalar {
fn reduce_512(&mut self, l: &[u32; 16]) {
let (mut c0, mut c1, mut c2): (u32, u32, u32);
define_ops!(c0, c1, c2);
let mut c: u64;
let (n0, n1, n2, n3, n4, n5, n6, n7) =
(l[8], l[9], l[10], l[11], l[12], l[13], l[14], l[15]);
let (m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12): (
u32,
u32,
u32,
u32,
u32,
u32,
u32,
u32,
u32,
u32,
u32,
u32,
u32,
);
let (p0, p1, p2, p3, p4, p5, p6, p7, p8): (u32, u32, u32, u32, u32, u32, u32, u32, u32);
c0 = l[0];
c1 = 0;
c2 = 0;
muladd_fast!(n0, SECP256K1_N_C_0);
m0 = extract_fast!();
sumadd_fast!(l[1]);
muladd!(n1, SECP256K1_N_C_0);
muladd!(n0, SECP256K1_N_C_1);
m1 = extract!();
sumadd!(l[2]);
muladd!(n2, SECP256K1_N_C_0);
muladd!(n1, SECP256K1_N_C_1);
muladd!(n0, SECP256K1_N_C_2);
m2 = extract!();
sumadd!(l[3]);
muladd!(n3, SECP256K1_N_C_0);
muladd!(n2, SECP256K1_N_C_1);
muladd!(n1, SECP256K1_N_C_2);
muladd!(n0, SECP256K1_N_C_3);
m3 = extract!();
sumadd!(l[4]);
muladd!(n4, SECP256K1_N_C_0);
muladd!(n3, SECP256K1_N_C_1);
muladd!(n2, SECP256K1_N_C_2);
muladd!(n1, SECP256K1_N_C_3);
sumadd!(n0);
m4 = extract!();
sumadd!(l[5]);
muladd!(n5, SECP256K1_N_C_0);
muladd!(n4, SECP256K1_N_C_1);
muladd!(n3, SECP256K1_N_C_2);
muladd!(n2, SECP256K1_N_C_3);
sumadd!(n1);
m5 = extract!();
sumadd!(l[6]);
muladd!(n6, SECP256K1_N_C_0);
muladd!(n5, SECP256K1_N_C_1);
muladd!(n4, SECP256K1_N_C_2);
muladd!(n3, SECP256K1_N_C_3);
sumadd!(n2);
m6 = extract!();
sumadd!(l[7]);
muladd!(n7, SECP256K1_N_C_0);
muladd!(n6, SECP256K1_N_C_1);
muladd!(n5, SECP256K1_N_C_2);
muladd!(n4, SECP256K1_N_C_3);
sumadd!(n3);
m7 = extract!();
muladd!(n7, SECP256K1_N_C_1);
muladd!(n6, SECP256K1_N_C_2);
muladd!(n5, SECP256K1_N_C_3);
sumadd!(n4);
m8 = extract!();
muladd!(n7, SECP256K1_N_C_2);
muladd!(n6, SECP256K1_N_C_3);
sumadd!(n5);
m9 = extract!();
muladd!(n7, SECP256K1_N_C_3);
sumadd!(n6);
m10 = extract!();
sumadd_fast!(n7);
m11 = extract_fast!();
debug_assert!(c0 <= 1);
m12 = c0;
/* Reduce 385 bits into 258. */
/* p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. */
c0 = m0;
c1 = 0;
c2 = 0;
muladd_fast!(m8, SECP256K1_N_C_0);
p0 = extract_fast!();
sumadd_fast!(m1);
muladd!(m9, SECP256K1_N_C_0);
muladd!(m8, SECP256K1_N_C_1);
p1 = extract!();
sumadd!(m2);
muladd!(m10, SECP256K1_N_C_0);
muladd!(m9, SECP256K1_N_C_1);
muladd!(m8, SECP256K1_N_C_2);
p2 = extract!();
sumadd!(m3);
muladd!(m11, SECP256K1_N_C_0);
muladd!(m10, SECP256K1_N_C_1);
muladd!(m9, SECP256K1_N_C_2);
muladd!(m8, SECP256K1_N_C_3);
p3 = extract!();
sumadd!(m4);
muladd!(m12, SECP256K1_N_C_0);
muladd!(m11, SECP256K1_N_C_1);
muladd!(m10, SECP256K1_N_C_2);
muladd!(m9, SECP256K1_N_C_3);
sumadd!(m8);
p4 = extract!();
sumadd!(m5);
muladd!(m12, SECP256K1_N_C_1);
muladd!(m11, SECP256K1_N_C_2);
muladd!(m10, SECP256K1_N_C_3);
sumadd!(m9);
p5 = extract!();
sumadd!(m6);
muladd!(m12, SECP256K1_N_C_2);
muladd!(m11, SECP256K1_N_C_3);
sumadd!(m10);
p6 = extract!();
sumadd_fast!(m7);
muladd_fast!(m12, SECP256K1_N_C_3);
sumadd_fast!(m11);
p7 = extract_fast!();
p8 = c0 + m12;
debug_assert!(p8 <= 2);
/* Reduce 258 bits into 256. */
/* r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. */
c = p0 as u64 + SECP256K1_N_C_0 as u64 * p8 as u64;
self.0[0] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p1 as u64 + SECP256K1_N_C_1 as u64 * p8 as u64;
self.0[1] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p2 as u64 + SECP256K1_N_C_2 as u64 * p8 as u64;
self.0[2] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p3 as u64 + SECP256K1_N_C_3 as u64 * p8 as u64;
self.0[3] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p4 as u64 + p8 as u64;
self.0[4] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p5 as u64;
self.0[5] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p6 as u64;
self.0[6] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
c += p7 as u64;
self.0[7] = (c & 0xFFFFFFFF) as u32;
c >>= 32;
let overflow = self.check_overflow();
self.reduce(Choice::from(c as u8) | overflow);
}
fn mul_512(&self, b: &Scalar, l: &mut [u32; 16]) {
let (mut c0, mut c1, mut c2): (u32, u32, u32) = (0, 0, 0);
define_ops!(c0, c1, c2);
/* l[0..15] = a[0..7] * b[0..7]. */
muladd_fast!(self.0[0], b.0[0]);
l[0] = extract_fast!();
muladd!(self.0[0], b.0[1]);
muladd!(self.0[1], b.0[0]);
l[1] = extract!();
muladd!(self.0[0], b.0[2]);
muladd!(self.0[1], b.0[1]);
muladd!(self.0[2], b.0[0]);
l[2] = extract!();
muladd!(self.0[0], b.0[3]);
muladd!(self.0[1], b.0[2]);
muladd!(self.0[2], b.0[1]);
muladd!(self.0[3], b.0[0]);
l[3] = extract!();
muladd!(self.0[0], b.0[4]);
muladd!(self.0[1], b.0[3]);
muladd!(self.0[2], b.0[2]);
muladd!(self.0[3], b.0[1]);
muladd!(self.0[4], b.0[0]);
l[4] = extract!();
muladd!(self.0[0], b.0[5]);
muladd!(self.0[1], b.0[4]);
muladd!(self.0[2], b.0[3]);
muladd!(self.0[3], b.0[2]);
muladd!(self.0[4], b.0[1]);
muladd!(self.0[5], b.0[0]);
l[5] = extract!();
muladd!(self.0[0], b.0[6]);
muladd!(self.0[1], b.0[5]);
muladd!(self.0[2], b.0[4]);
muladd!(self.0[3], b.0[3]);
muladd!(self.0[4], b.0[2]);
muladd!(self.0[5], b.0[1]);
muladd!(self.0[6], b.0[0]);
l[6] = extract!();
muladd!(self.0[0], b.0[7]);
muladd!(self.0[1], b.0[6]);
muladd!(self.0[2], b.0[5]);
muladd!(self.0[3], b.0[4]);
muladd!(self.0[4], b.0[3]);
muladd!(self.0[5], b.0[2]);
muladd!(self.0[6], b.0[1]);
muladd!(self.0[7], b.0[0]);
l[7] = extract!();
muladd!(self.0[1], b.0[7]);
muladd!(self.0[2], b.0[6]);
muladd!(self.0[3], b.0[5]);
muladd!(self.0[4], b.0[4]);
muladd!(self.0[5], b.0[3]);
muladd!(self.0[6], b.0[2]);
muladd!(self.0[7], b.0[1]);
l[8] = extract!();
muladd!(self.0[2], b.0[7]);
muladd!(self.0[3], b.0[6]);
muladd!(self.0[4], b.0[5]);
muladd!(self.0[5], b.0[4]);
muladd!(self.0[6], b.0[3]);
muladd!(self.0[7], b.0[2]);
l[9] = extract!();
muladd!(self.0[3], b.0[7]);
muladd!(self.0[4], b.0[6]);
muladd!(self.0[5], b.0[5]);
muladd!(self.0[6], b.0[4]);
muladd!(self.0[7], b.0[3]);
l[10] = extract!();
muladd!(self.0[4], b.0[7]);
muladd!(self.0[5], b.0[6]);
muladd!(self.0[6], b.0[5]);
muladd!(self.0[7], b.0[4]);
l[11] = extract!();
muladd!(self.0[5], b.0[7]);
muladd!(self.0[6], b.0[6]);
muladd!(self.0[7], b.0[5]);
l[12] = extract!();
muladd!(self.0[6], b.0[7]);
muladd!(self.0[7], b.0[6]);
l[13] = extract!();
muladd_fast!(self.0[7], b.0[7]);
l[14] = extract_fast!();
debug_assert!(c1 == 0);
l[15] = c0;
}
fn sqr_512(&self, l: &mut [u32; 16]) {
let (mut c0, mut c1, mut c2): (u32, u32, u32) = (0, 0, 0);
define_ops!(c0, c1, c2);
/* l[0..15] = a[0..7]^2. */
muladd_fast!(self.0[0], self.0[0]);
l[0] = extract_fast!();
muladd2!(self.0[0], self.0[1]);
l[1] = extract!();
muladd2!(self.0[0], self.0[2]);
muladd!(self.0[1], self.0[1]);
l[2] = extract!();
muladd2!(self.0[0], self.0[3]);
muladd2!(self.0[1], self.0[2]);
l[3] = extract!();
muladd2!(self.0[0], self.0[4]);
muladd2!(self.0[1], self.0[3]);
muladd!(self.0[2], self.0[2]);
l[4] = extract!();
muladd2!(self.0[0], self.0[5]);
muladd2!(self.0[1], self.0[4]);
muladd2!(self.0[2], self.0[3]);
l[5] = extract!();
muladd2!(self.0[0], self.0[6]);
muladd2!(self.0[1], self.0[5]);
muladd2!(self.0[2], self.0[4]);
muladd!(self.0[3], self.0[3]);
l[6] = extract!();
muladd2!(self.0[0], self.0[7]);
muladd2!(self.0[1], self.0[6]);
muladd2!(self.0[2], self.0[5]);
muladd2!(self.0[3], self.0[4]);
l[7] = extract!();
muladd2!(self.0[1], self.0[7]);
muladd2!(self.0[2], self.0[6]);
muladd2!(self.0[3], self.0[5]);
muladd!(self.0[4], self.0[4]);
l[8] = extract!();
muladd2!(self.0[2], self.0[7]);
muladd2!(self.0[3], self.0[6]);
muladd2!(self.0[4], self.0[5]);
l[9] = extract!();
muladd2!(self.0[3], self.0[7]);
muladd2!(self.0[4], self.0[6]);
muladd!(self.0[5], self.0[5]);
l[10] = extract!();
muladd2!(self.0[4], self.0[7]);
muladd2!(self.0[5], self.0[6]);
l[11] = extract!();
muladd2!(self.0[5], self.0[7]);
muladd!(self.0[6], self.0[6]);
l[12] = extract!();
muladd2!(self.0[6], self.0[7]);
l[13] = extract!();
muladd_fast!(self.0[7], self.0[7]);
l[14] = extract_fast!();
debug_assert!(c1 == 0);
l[15] = c0;
}
pub fn mul_in_place(&mut self, a: &Scalar, b: &Scalar) {
let mut l = [0u32; 16];
a.mul_512(b, &mut l);
self.reduce_512(&l);
}
/// Shift a scalar right by some amount strictly between 0 and 16,
/// returning the low bits that were shifted off.
pub fn shr_int(&mut self, n: usize) -> u32 {
let ret: u32;
debug_assert!(n > 0);
debug_assert!(n < 16);
ret = self.0[0] & ((1 << n) - 1);
self.0[0] = (self.0[0] >> n) + (self.0[1] << (32 - n));
self.0[1] = (self.0[1] >> n) + (self.0[2] << (32 - n));
self.0[2] = (self.0[2] >> n) + (self.0[3] << (32 - n));
self.0[3] = (self.0[3] >> n) + (self.0[4] << (32 - n));
self.0[4] = (self.0[4] >> n) + (self.0[5] << (32 - n));
self.0[5] = (self.0[5] >> n) + (self.0[6] << (32 - n));
self.0[6] = (self.0[6] >> n) + (self.0[7] << (32 - n));
self.0[7] >>= n;
ret
}
pub fn sqr_in_place(&mut self, a: &Scalar) {
let mut l = [0u32; 16];
a.sqr_512(&mut l);
self.reduce_512(&l);
}
pub fn sqr(&self) -> Scalar {
let mut ret = Scalar::default();
ret.sqr_in_place(self);
ret
}
pub fn inv_in_place(&mut self, x: &Scalar) {
let u2 = x.sqr();
let x2 = u2 * *x;
let u5 = u2 * x2;
let x3 = u5 * u2;
let u9 = x3 * u2;
let u11 = u9 * u2;
let u13 = u11 * u2;
let mut x6 = u13.sqr();
x6 = x6.sqr();
x6 *= &u11;
let mut x8 = x6.sqr();
x8 = x8.sqr();
x8 *= &x2;
let mut x14 = x8.sqr();
for _ in 0..5 {
x14 = x14.sqr();
}
x14 *= &x6;
let mut x28 = x14.sqr();
for _ in 0..13 {
x28 = x28.sqr();
}
x28 *= &x14;
let mut x56 = x28.sqr();
for _ in 0..27 {
x56 = x56.sqr();
}
x56 *= &x28;
let mut x112 = x56.sqr();
for _ in 0..55 {
x112 = x112.sqr();
}
x112 *= &x56;
let mut x126 = x112.sqr();
for _ in 0..13 {
x126 = x126.sqr();
}
x126 *= &x14;
let mut t = x126;
for _ in 0..3 {
t = t.sqr();
}
t *= &u5;
for _ in 0..4 {
t = t.sqr();
}
t *= &x3;
for _ in 0..4 {
t = t.sqr();
}
t *= &u5;
for _ in 0..5 {
t = t.sqr();
}
t *= &u11;
for _ in 0..4 {
t = t.sqr();
}
t *= &u11;
for _ in 0..4 {
t = t.sqr();
}
t *= &x3;
for _ in 0..5 {
t = t.sqr();
}
t *= &x3;
for _ in 0..6 {
t = t.sqr();
}
t *= &u13;
for _ in 0..4 {
t = t.sqr();
}
t *= &u5;
for _ in 0..3 {
t = t.sqr();
}
t *= &x3;
for _ in 0..5 {
t = t.sqr();
}
t *= &u9;
for _ in 0..6 {
t = t.sqr();
}
t *= &u5;
for _ in 0..10 {
t = t.sqr();
}
t *= &x3;
for _ in 0..4 {
t = t.sqr();
}
t *= &x3;
for _ in 0..9 {
t = t.sqr();
}
t *= &x8;
for _ in 0..5 {
t = t.sqr();
}
t *= &u9;
for _ in 0..6 {
t = t.sqr();
}
t *= &u11;
for _ in 0..4 {
t = t.sqr();
}
t *= &u13;
for _ in 0..5 {
t = t.sqr();
}
t *= &x2;
for _ in 0..6 {
t = t.sqr();
}
t *= &u13;
for _ in 0..10 {
t = t.sqr();
}
t *= &u13;
for _ in 0..4 {
t = t.sqr();
}
t *= &u9;
for _ in 0..6 {
t = t.sqr();
}
t *= x;
for _ in 0..8 {
t = t.sqr();
}
*self = t * x6;
}
pub fn inv(&self) -> Scalar {
let mut ret = Scalar::default();
ret.inv_in_place(self);
ret
}
pub fn inv_var(&self) -> Scalar {
self.inv()
}
pub fn is_even(&self) -> bool {
self.0[0] & 1 == 0
}
}
impl Default for Scalar {
fn default() -> Scalar {
Scalar([0u32; 8])
}
}
impl Add<Scalar> for Scalar {
type Output = Scalar;
fn add(mut self, other: Scalar) -> Scalar {
self.add_assign(&other);
self
}
}
impl<'a, 'b> Add<&'a Scalar> for &'b Scalar {
type Output = Scalar;
fn add(self, other: &'a Scalar) -> Scalar {
let mut ret = *self;
ret.add_assign(other);
ret
}
}
impl<'a> AddAssign<&'a Scalar> for Scalar {
fn add_assign(&mut self, other: &'a Scalar) {
let mut t = 0u64;
unroll! {
for i in 0..8 {
t += (self.0[i] as u64) + (other.0[i] as u64);
self.0[i] = (t & 0xFFFFFFFF) as u32;
t >>= 32;
}
}
let overflow = self.check_overflow();
self.reduce(Choice::from(t as u8) | overflow);
}
}
impl AddAssign<Scalar> for Scalar {
fn add_assign(&mut self, other: Scalar) {
self.add_assign(&other)
}
}
impl Mul<Scalar> for Scalar {
type Output = Scalar;
fn mul(self, other: Scalar) -> Scalar {
let mut ret = Scalar::default();
ret.mul_in_place(&self, &other);
ret
}
}
impl<'a, 'b> Mul<&'a Scalar> for &'b Scalar {
type Output = Scalar;
fn mul(self, other: &'a Scalar) -> Scalar {
let mut ret = Scalar::default();
ret.mul_in_place(self, other);
ret
}
}
impl<'a> MulAssign<&'a Scalar> for Scalar {
fn mul_assign(&mut self, other: &'a Scalar) {
let mut ret = Scalar::default();
ret.mul_in_place(self, other);
*self = ret;
}
}
impl MulAssign<Scalar> for Scalar {
fn mul_assign(&mut self, other: Scalar) {
self.mul_assign(&other)
}
}
impl Neg for Scalar {
type Output = Scalar;
fn neg(mut self) -> Scalar {
self.cond_neg_assign(1.into());
gitextract_oew3p_ij/
├── .arcconfig
├── .editorconfig
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── audit.yml
│ ├── check-style.yml
│ ├── clippy.yml
│ ├── prepare_artifacts.sh
│ ├── rust-windows.yml
│ ├── rust.yml
│ └── sccache.sh
├── .gitignore
├── CHANGELOG.md
├── Cargo.toml
├── LICENSE
├── README.md
├── benches/
│ ├── public_key.rs
│ ├── sign.rs
│ └── signature.rs
├── build.rs
├── core/
│ ├── Cargo.toml
│ └── src/
│ ├── der.rs
│ ├── ecdh.rs
│ ├── ecdsa.rs
│ ├── ecmult.rs
│ ├── error.rs
│ ├── field.rs
│ ├── group.rs
│ ├── lib.rs
│ └── scalar.rs
├── gen/
│ ├── ecmult/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ └── genmult/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
├── res/
│ └── ecdsa_secp256k1_sha256_test.json
├── rustfmt.toml
├── src/
│ └── lib.rs
└── tests/
├── serde.rs
├── verify.rs
└── wycheproof.rs
SYMBOL INDEX (341 symbols across 19 files)
FILE: benches/public_key.rs
function bench_public_key_parse (line 10) | fn bench_public_key_parse(b: &mut Bencher) {
function bench_public_key_serialize (line 23) | fn bench_public_key_serialize(b: &mut Bencher) {
function bench_public_key_serialize_compressed (line 37) | fn bench_public_key_serialize_compressed(b: &mut Bencher) {
FILE: benches/sign.rs
function bench_sign_message (line 11) | fn bench_sign_message(b: &mut Bencher) {
FILE: benches/signature.rs
function bench_signature_parse (line 10) | fn bench_signature_parse(b: &mut Bencher) {
function bench_signature_serialize (line 27) | fn bench_signature_serialize(b: &mut Bencher) {
FILE: build.rs
function main (line 3) | fn main() {
FILE: core/src/der.rs
type SignatureArray (line 8) | pub struct SignatureArray([u8; 6 + 33 + 33], usize);
method new (line 11) | pub fn new(size: usize) -> Self {
method len (line 15) | pub fn len(&self) -> usize {
method is_empty (line 19) | pub fn is_empty(&self) -> bool {
method as_ref (line 25) | fn as_ref(&self) -> &[u8] {
method as_mut (line 31) | fn as_mut(&mut self) -> &mut [u8] {
type Decoder (line 36) | pub struct Decoder<'a>(&'a [u8], usize);
function new (line 39) | pub fn new(arr: &'a [u8]) -> Self {
function remaining_len (line 43) | pub fn remaining_len(&self) -> usize {
function read (line 47) | pub fn read(&mut self) -> Result<u8, Error> {
function peek (line 57) | pub fn peek(&self, forward: usize) -> Result<u8, Error> {
function peek_slice (line 66) | pub fn peek_slice(&self, len: usize) -> Result<&[u8], Error> {
function skip (line 75) | pub fn skip(&mut self, len: usize) -> Result<(), Error> {
function read_constructed_sequence (line 84) | pub fn read_constructed_sequence(&mut self) -> Result<(), Error> {
function read_len (line 93) | pub fn read_len(&mut self) -> Result<usize, Error> {
function read_integer (line 140) | pub fn read_integer(&mut self) -> Result<Scalar, Error> {
function read_seq_len_lax (line 190) | pub fn read_seq_len_lax(&mut self) -> Result<usize, Error> {
function read_len_lax (line 203) | pub fn read_len_lax(&mut self) -> Result<usize, Error> {
function read_integer_lax (line 232) | pub fn read_integer_lax(&mut self) -> Result<Scalar, Error> {
FILE: core/src/ecdh.rs
method ecdh_raw (line 9) | pub fn ecdh_raw<D: Digest + Default>(
FILE: core/src/ecdsa.rs
constant P_MINUS_ORDER (line 9) | const P_MINUS_ORDER: Field = Field::new(0, 0, 0, 1, 0x45512319, 0x50B75F...
constant ORDER_AS_FE (line 11) | const ORDER_AS_FE: Field = Field::new(
method verify_raw (line 16) | pub fn verify_raw(
method recover_raw (line 58) | pub fn recover_raw(
method sign_raw (line 107) | pub fn sign_raw(
FILE: core/src/ecmult.rs
constant WINDOW_A (line 14) | pub const WINDOW_A: usize = 5;
constant WINDOW_G (line 15) | pub const WINDOW_G: usize = 16;
constant ECMULT_TABLE_SIZE_A (line 16) | pub const ECMULT_TABLE_SIZE_A: usize = 1 << (WINDOW_A - 2);
constant ECMULT_TABLE_SIZE_G (line 17) | pub const ECMULT_TABLE_SIZE_G: usize = 1 << (WINDOW_G - 2);
constant WNAF_BITS (line 18) | pub const WNAF_BITS: usize = 256;
function odd_multiples_table_storage_var (line 20) | fn odd_multiples_table_storage_var(pre: &mut [AffineStorage], a: &Jacobi...
type ECMultContext (line 43) | pub struct ECMultContext {
method new_from_raw (line 54) | pub const unsafe fn new_from_raw(pre_g: [AffineStorage; ECMULT_TABLE_S...
method inspect_raw (line 59) | pub fn inspect_raw(&self) -> &[AffineStorage; ECMULT_TABLE_SIZE_G] {
method new_boxed (line 64) | pub fn new_boxed() -> Box<Self> {
method ecmult (line 454) | pub fn ecmult(&self, r: &mut Jacobian, a: &Jacobian, na: &Scalar, ng: ...
method ecmult_const (line 491) | pub fn ecmult_const(&self, r: &mut Jacobian, a: &Affine, scalar: &Scal...
function set_all_gej_var (line 90) | pub fn set_all_gej_var(a: &[Jacobian]) -> Vec<Affine> {
function inv_all_var (line 116) | pub fn inv_all_var(fields: &[Field]) -> Vec<Field> {
constant GEN_BLIND (line 142) | const GEN_BLIND: Scalar = Scalar([
constant GEN_INITIAL (line 145) | const GEN_INITIAL: Jacobian = Jacobian {
type ECMultGenContext (line 162) | pub struct ECMultGenContext {
method new_from_raw (line 175) | pub const unsafe fn new_from_raw(prec: [[AffineStorage; 16]; 64]) -> S...
method inspect_raw (line 184) | pub fn inspect_raw(&self) -> &[[AffineStorage; 16]; 64] {
method new_boxed (line 189) | pub fn new_boxed() -> Box<Self> {
method ecmult_gen (line 560) | pub fn ecmult_gen(&self, r: &mut Jacobian, gn: &Scalar) {
function odd_multiples_table (line 261) | pub fn odd_multiples_table(prej: &mut [Jacobian], zr: &mut [Field], a: &...
function odd_multiples_table_globalz_windowa (line 289) | fn odd_multiples_table_globalz_windowa(
function table_get_ge (line 301) | fn table_get_ge(r: &mut Affine, pre: &[Affine], n: i32, w: usize) {
function table_get_ge_const (line 312) | fn table_get_ge_const(r: &mut Affine, pre: &[Affine], n: i32, w: usize) {
function table_get_ge_storage (line 328) | fn table_get_ge_storage(r: &mut Affine, pre: &[AffineStorage], n: i32, w...
function ecmult_wnaf (line 340) | pub fn ecmult_wnaf(wnaf: &mut [i32], a: &Scalar, w: usize) -> i32 {
function ecmult_wnaf_const (line 394) | pub fn ecmult_wnaf_const(wnaf: &mut [i32], a: &Scalar, w: usize) -> i32 {
FILE: core/src/error.rs
type Error (line 2) | pub enum Error {
method fmt (line 17) | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
FILE: core/src/field.rs
type Field (line 14) | pub struct Field {
method new_raw (line 26) | pub const fn new_raw(
method new (line 45) | pub const fn new(
method from_int (line 73) | pub fn from_int(a: u32) -> Field {
method verify (line 79) | fn verify(&self) -> bool {
method normalize (line 112) | pub fn normalize(&mut self) {
method normalize_weak (line 200) | pub fn normalize_weak(&mut self) {
method normalize_var (line 244) | pub fn normalize_var(&mut self) {
method normalizes_to_zero (line 336) | pub fn normalizes_to_zero(&self) -> bool {
method normalizes_to_zero_var (line 404) | pub fn normalizes_to_zero_var(&self) -> bool {
method set_int (line 487) | pub fn set_int(&mut self, a: u32) {
method is_zero (line 496) | pub fn is_zero(&self) -> bool {
method is_odd (line 514) | pub fn is_odd(&self) -> bool {
method clear (line 521) | pub fn clear(&mut self) {
method set_b32 (line 530) | pub fn set_b32(&mut self, a: &[u8; 32]) -> bool {
method fill_b32 (line 584) | pub fn fill_b32(&self, r: &mut [u8; 32]) {
method b32 (line 624) | pub fn b32(&self) -> [u8; 32] {
method neg_in_place (line 633) | pub fn neg_in_place(&mut self, other: &Field, m: u32) {
method neg (line 655) | pub fn neg(&self, m: u32) -> Field {
method mul_int (line 663) | pub fn mul_int(&mut self, a: u32) {
method cmp_var (line 682) | pub fn cmp_var(&self, other: &Field) -> Ordering {
method eq_var (line 700) | pub fn eq_var(&self, other: &Field) -> bool {
method mul_inner (line 706) | fn mul_inner(&mut self, a: &Field, b: &Field) {
method sqr_inner (line 1097) | fn sqr_inner(&mut self, a: &Field) {
method mul_in_place (line 1431) | pub fn mul_in_place(&mut self, a: &Field, b: &Field) {
method sqr_in_place (line 1445) | pub fn sqr_in_place(&mut self, a: &Field) {
method sqr (line 1454) | pub fn sqr(&self) -> Field {
method sqrt (line 1466) | pub fn sqrt(&self) -> (Field, bool) {
method inv (line 1546) | pub fn inv(&self) -> Field {
method inv_var (line 1628) | pub fn inv_var(&self) -> Field {
method is_quad_var (line 1633) | pub fn is_quad_var(&self) -> bool {
method cmov (line 1640) | pub fn cmov(&mut self, other: &Field, flag: bool) {
type Output (line 1675) | type Output = Field;
method add (line 1676) | fn add(self, other: Field) -> Field {
method add_assign (line 1693) | fn add_assign(&mut self, other: &'a Field) {
method add_assign (line 1712) | fn add_assign(&mut self, other: Field) {
type Output (line 1718) | type Output = Field;
method mul (line 1719) | fn mul(self, other: Field) -> Field {
method mul_assign (line 1736) | fn mul_assign(&mut self, other: &'a Field) {
method mul_assign (line 1744) | fn mul_assign(&mut self, other: Field) {
method from (line 1808) | fn from(a: FieldStorage) -> Field {
method into (line 1830) | fn into(self) -> FieldStorage {
method default (line 1665) | fn default() -> Field {
type Output (line 1684) | type Output = Field;
function add (line 1685) | fn add(self, other: &'a Field) -> Field {
type Output (line 1727) | type Output = Field;
function mul (line 1728) | fn mul(self, other: &'a Field) -> Field {
method eq (line 1750) | fn eq(&self, other: &Field) -> bool {
method cmp (line 1760) | fn cmp(&self, other: &Field) -> Ordering {
method partial_cmp (line 1766) | fn partial_cmp(&self, other: &Field) -> Option<Ordering> {
type FieldStorage (line 1773) | pub struct FieldStorage(pub [u32; 8]);
method new (line 1782) | pub const fn new(
method cmov (line 1795) | pub fn cmov(&mut self, other: &FieldStorage, flag: bool) {
method default (line 1776) | fn default() -> FieldStorage {
FILE: core/src/group.rs
type Affine (line 5) | pub struct Affine {
method new (line 85) | pub const fn new(x: Field, y: Field) -> Self {
method set_xy (line 95) | pub fn set_xy(&mut self, x: &Field, y: &Field) {
method set_xquad (line 105) | pub fn set_xquad(&mut self, x: &Field) -> bool {
method set_xo_var (line 121) | pub fn set_xo_var(&mut self, x: &Field, odd: bool) -> bool {
method is_infinity (line 133) | pub fn is_infinity(&self) -> bool {
method is_valid_var (line 138) | pub fn is_valid_var(&self) -> bool {
method neg_in_place (line 152) | pub fn neg_in_place(&mut self, other: &Affine) {
method neg (line 158) | pub fn neg(&self) -> Affine {
method set_gej (line 166) | pub fn set_gej(&mut self, a: &Jacobian) {
method from_gej (line 179) | pub fn from_gej(a: &Jacobian) -> Self {
method set_gej_var (line 185) | pub fn set_gej_var(&mut self, a: &Jacobian) {
method set_gej_zinv (line 201) | pub fn set_gej_zinv(&mut self, a: &Jacobian, zi: &Field) {
method clear (line 210) | pub fn clear(&mut self) {
method from (line 687) | fn from(a: AffineStorage) -> Affine {
method into (line 693) | fn into(mut self) -> AffineStorage {
type Jacobian (line 13) | pub struct Jacobian {
method new (line 260) | pub const fn new(x: Field, y: Field) -> Self {
method set_infinity (line 270) | pub fn set_infinity(&mut self) {
method set_ge (line 279) | pub fn set_ge(&mut self, a: &Affine) {
method from_ge (line 286) | pub fn from_ge(a: &Affine) -> Self {
method eq_x_var (line 293) | pub fn eq_x_var(&self, x: &Field) -> bool {
method neg_in_place (line 304) | pub fn neg_in_place(&mut self, a: &Jacobian) {
method neg (line 313) | pub fn neg(&self) -> Jacobian {
method is_infinity (line 320) | pub fn is_infinity(&self) -> bool {
method has_quad_y_var (line 325) | pub fn has_quad_y_var(&self) -> bool {
method double_nonzero_in_place (line 337) | pub fn double_nonzero_in_place(&mut self, a: &Jacobian, rzr: Option<&m...
method double_var_in_place (line 344) | pub fn double_var_in_place(&mut self, a: &Jacobian, rzr: Option<&mut F...
method double_var (line 381) | pub fn double_var(&self, rzr: Option<&mut Field>) -> Jacobian {
method add_var_in_place (line 389) | pub fn add_var_in_place(&mut self, a: &Jacobian, b: &Jacobian, rzr: Op...
method add_var (line 449) | pub fn add_var(&self, b: &Jacobian, rzr: Option<&mut Field>) -> Jacobi...
method add_ge_in_place (line 457) | pub fn add_ge_in_place(&mut self, a: &Jacobian, b: &Affine) {
method add_ge (line 524) | pub fn add_ge(&self, b: &Affine) -> Jacobian {
method add_ge_var_in_place (line 536) | pub fn add_ge_var_in_place(&mut self, a: &Jacobian, b: &Affine, rzr: O...
method add_ge_var (line 595) | pub fn add_ge_var(&self, b: &Affine, rzr: Option<&mut Field>) -> Jacob...
method add_zinv_var_in_place (line 603) | pub fn add_zinv_var_in_place(&mut self, a: &Jacobian, b: &Affine, bzin...
method add_zinv_var (line 659) | pub fn add_zinv_var(&mut self, b: &Affine, bzinv: &Field) -> Jacobian {
method clear (line 667) | pub fn clear(&mut self) {
method rescale (line 676) | pub fn rescale(&mut self, s: &Field) {
type AffineStorage (line 22) | pub struct AffineStorage {
method new (line 703) | pub const fn new(x: FieldStorage, y: FieldStorage) -> Self {
method cmov (line 709) | pub fn cmov(&mut self, a: &AffineStorage, flag: bool) {
method default (line 28) | fn default() -> Affine {
method default (line 38) | fn default() -> Jacobian {
method default (line 49) | fn default() -> AffineStorage {
constant CURVE_B (line 81) | pub const CURVE_B: u32 = 7;
function set_table_gej_var (line 217) | pub fn set_table_gej_var(r: &mut [Affine], a: &[Jacobian], zr: &[Field]) {
function globalz_set_table_gej (line 235) | pub fn globalz_set_table_gej(r: &mut [Affine], globalz: &mut Field, a: &...
FILE: core/src/lib.rs
constant TAG_PUBKEY_EVEN (line 51) | pub const TAG_PUBKEY_EVEN: u8 = 0x02;
constant TAG_PUBKEY_ODD (line 52) | pub const TAG_PUBKEY_ODD: u8 = 0x03;
constant TAG_PUBKEY_FULL (line 53) | pub const TAG_PUBKEY_FULL: u8 = 0x04;
constant TAG_PUBKEY_HYBRID_EVEN (line 54) | pub const TAG_PUBKEY_HYBRID_EVEN: u8 = 0x06;
constant TAG_PUBKEY_HYBRID_ODD (line 55) | pub const TAG_PUBKEY_HYBRID_ODD: u8 = 0x07;
constant MESSAGE_SIZE (line 57) | pub const MESSAGE_SIZE: usize = 32;
constant SECRET_KEY_SIZE (line 58) | pub const SECRET_KEY_SIZE: usize = 32;
constant RAW_PUBLIC_KEY_SIZE (line 59) | pub const RAW_PUBLIC_KEY_SIZE: usize = 64;
constant FULL_PUBLIC_KEY_SIZE (line 60) | pub const FULL_PUBLIC_KEY_SIZE: usize = 65;
constant COMPRESSED_PUBLIC_KEY_SIZE (line 61) | pub const COMPRESSED_PUBLIC_KEY_SIZE: usize = 33;
constant SIGNATURE_SIZE (line 62) | pub const SIGNATURE_SIZE: usize = 64;
constant DER_MAX_SIGNATURE_SIZE (line 63) | pub const DER_MAX_SIGNATURE_SIZE: usize = 72;
FILE: core/src/scalar.rs
constant SECP256K1_N (line 5) | const SECP256K1_N: [u32; 8] = [
constant SECP256K1_N_C_0 (line 9) | const SECP256K1_N_C_0: u32 = !SECP256K1_N[0] + 1;
constant SECP256K1_N_C_1 (line 10) | const SECP256K1_N_C_1: u32 = !SECP256K1_N[1];
constant SECP256K1_N_C_2 (line 11) | const SECP256K1_N_C_2: u32 = !SECP256K1_N[2];
constant SECP256K1_N_C_3 (line 12) | const SECP256K1_N_C_3: u32 = !SECP256K1_N[3];
constant SECP256K1_N_C_4 (line 13) | const SECP256K1_N_C_4: u32 = 1;
constant SECP256K1_N_H_0 (line 15) | const SECP256K1_N_H_0: u32 = 0x681B20A0;
constant SECP256K1_N_H_1 (line 16) | const SECP256K1_N_H_1: u32 = 0xDFE92F46;
constant SECP256K1_N_H_2 (line 17) | const SECP256K1_N_H_2: u32 = 0x57A4501D;
constant SECP256K1_N_H_3 (line 18) | const SECP256K1_N_H_3: u32 = 0x5D576E73;
constant SECP256K1_N_H_4 (line 19) | const SECP256K1_N_H_4: u32 = 0xFFFFFFFF;
constant SECP256K1_N_H_5 (line 20) | const SECP256K1_N_H_5: u32 = 0xFFFFFFFF;
constant SECP256K1_N_H_6 (line 21) | const SECP256K1_N_H_6: u32 = 0xFFFFFFFF;
constant SECP256K1_N_H_7 (line 22) | const SECP256K1_N_H_7: u32 = 0x7FFFFFFF;
type Scalar (line 26) | pub struct Scalar(pub [u32; 8]);
method clear (line 30) | pub fn clear(&mut self) {
method set_int (line 37) | pub fn set_int(&mut self, v: u32) {
method from_int (line 42) | pub fn from_int(v: u32) -> Self {
method bits (line 50) | pub fn bits(&self, offset: usize, count: usize) -> u32 {
method bits_var (line 56) | pub fn bits_var(&self, offset: usize, count: usize) -> u32 {
method check_overflow (line 70) | fn check_overflow(&self) -> Choice {
method reduce (line 89) | fn reduce(&mut self, overflow: Choice) {
method cadd_bit (line 127) | pub fn cadd_bit(&mut self, mut bit: usize, flag: bool) {
method set_b32 (line 160) | pub fn set_b32(&mut self, b32: &[u8; 32]) -> Choice {
method b32 (line 201) | pub fn b32(&self) -> [u8; 32] {
method fill_b32 (line 208) | pub fn fill_b32(&self, bin: &mut [u8; 32]) {
method is_zero (line 244) | pub fn is_zero(&self) -> bool {
method is_one (line 257) | pub fn is_one(&self) -> bool {
method is_high (line 271) | pub fn is_high(&self) -> bool {
method cond_neg_assign (line 290) | pub fn cond_neg_assign(&mut self, flag: Choice) {
method reduce_512 (line 417) | fn reduce_512(&mut self, l: &[u32; 16]) {
method mul_512 (line 584) | fn mul_512(&self, b: &Scalar, l: &mut [u32; 16]) {
method sqr_512 (line 672) | fn sqr_512(&self, l: &mut [u32; 16]) {
method mul_in_place (line 732) | pub fn mul_in_place(&mut self, a: &Scalar, b: &Scalar) {
method shr_int (line 740) | pub fn shr_int(&mut self, n: usize) -> u32 {
method sqr_in_place (line 756) | pub fn sqr_in_place(&mut self, a: &Scalar) {
method sqr (line 762) | pub fn sqr(&self) -> Scalar {
method inv_in_place (line 768) | pub fn inv_in_place(&mut self, x: &Scalar) {
method inv (line 914) | pub fn inv(&self) -> Scalar {
method inv_var (line 920) | pub fn inv_var(&self) -> Scalar {
method is_even (line 924) | pub fn is_even(&self) -> bool {
type Output (line 936) | type Output = Scalar;
method add (line 937) | fn add(mut self, other: Scalar) -> Scalar {
method add_assign (line 953) | fn add_assign(&mut self, other: &'a Scalar) {
method add_assign (line 970) | fn add_assign(&mut self, other: Scalar) {
type Output (line 976) | type Output = Scalar;
method mul (line 977) | fn mul(self, other: Scalar) -> Scalar {
method mul_assign (line 994) | fn mul_assign(&mut self, other: &'a Scalar) {
method mul_assign (line 1002) | fn mul_assign(&mut self, other: Scalar) {
method fmt (line 1024) | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
method default (line 930) | fn default() -> Scalar {
type Output (line 944) | type Output = Scalar;
function add (line 945) | fn add(self, other: &'a Scalar) -> Scalar {
type Output (line 985) | type Output = Scalar;
function mul (line 986) | fn mul(self, other: &'a Scalar) -> Scalar {
type Output (line 1008) | type Output = Scalar;
method neg (line 1009) | fn neg(mut self) -> Scalar {
type Output (line 1016) | type Output = Scalar;
method neg (line 1017) | fn neg(self) -> Scalar {
FILE: gen/ecmult/src/lib.rs
function generate_to (line 7) | pub fn generate_to(file: &mut File) -> Result<(), Error> {
FILE: gen/genmult/src/lib.rs
function generate_to (line 9) | pub fn generate_to(file: &mut File) -> Result<(), Error> {
FILE: src/lib.rs
type PublicKey (line 64) | pub struct PublicKey(Affine);
method from_secret_key_with_context (line 107) | pub fn from_secret_key_with_context(
method from_secret_key (line 119) | pub fn from_secret_key(seckey: &SecretKey) -> PublicKey {
method parse_slice (line 123) | pub fn parse_slice(p: &[u8], format: Option<PublicKeyFormat>) -> Resul...
method parse (line 158) | pub fn parse(p: &[u8; util::FULL_PUBLIC_KEY_SIZE]) -> Result<PublicKey...
method parse_compressed (line 192) | pub fn parse_compressed(
method serialize (line 216) | pub fn serialize(&self) -> [u8; util::FULL_PUBLIC_KEY_SIZE] {
method serialize_compressed (line 233) | pub fn serialize_compressed(&self) -> [u8; util::COMPRESSED_PUBLIC_KEY...
method tweak_add_assign_with_context (line 253) | pub fn tweak_add_assign_with_context(
method tweak_add_assign (line 272) | pub fn tweak_add_assign(&mut self, tweak: &SecretKey) -> Result<(), Er...
method tweak_mul_assign_with_context (line 276) | pub fn tweak_mul_assign_with_context(
method tweak_mul_assign (line 295) | pub fn tweak_mul_assign(&mut self, tweak: &SecretKey) -> Result<(), Er...
method combine (line 299) | pub fn combine(keys: &[PublicKey]) -> Result<Self, Error> {
method into (line 317) | fn into(self) -> Affine {
type Error (line 323) | type Error = Error;
method try_from (line 325) | fn try_from(value: Affine) -> Result<Self, Self::Error> {
method deserialize (line 399) | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
type SecretKey (line 68) | pub struct SecretKey(Scalar);
method parse (line 412) | pub fn parse(p: &[u8; util::SECRET_KEY_SIZE]) -> Result<SecretKey, Err...
method parse_slice (line 421) | pub fn parse_slice(p: &[u8]) -> Result<SecretKey, Error> {
method random (line 431) | pub fn random<R: Rng>(rng: &mut R) -> SecretKey {
method serialize (line 442) | pub fn serialize(&self) -> [u8; util::SECRET_KEY_SIZE] {
method tweak_add_assign (line 446) | pub fn tweak_add_assign(&mut self, tweak: &SecretKey) -> Result<(), Er...
method tweak_mul_assign (line 455) | pub fn tweak_mul_assign(&mut self, tweak: &SecretKey) -> Result<(), Er...
method inv (line 464) | pub fn inv(&self) -> Self {
method clear (line 468) | pub fn clear(&mut self) {
method is_zero (line 472) | pub fn is_zero(&self) -> bool {
method into (line 492) | fn into(self) -> Scalar {
type Error (line 498) | type Error = Error;
method try_from (line 500) | fn try_from(scalar: Scalar) -> Result<Self, Error> {
method fmt (line 510) | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
type Signature (line 72) | pub struct Signature {
method parse_overflowing (line 528) | pub fn parse_overflowing(p: &[u8; util::SIGNATURE_SIZE]) -> Signature {
method parse_standard (line 541) | pub fn parse_standard(p: &[u8; util::SIGNATURE_SIZE]) -> Result<Signat...
method parse_overflowing_slice (line 561) | pub fn parse_overflowing_slice(p: &[u8]) -> Result<Signature, Error> {
method parse_standard_slice (line 572) | pub fn parse_standard_slice(p: &[u8]) -> Result<Signature, Error> {
method parse_der (line 583) | pub fn parse_der(p: &[u8]) -> Result<Signature, Error> {
method parse_der_lax (line 607) | pub fn parse_der_lax(p: &[u8]) -> Result<Signature, Error> {
method normalize_s (line 636) | pub fn normalize_s(&mut self) {
method serialize (line 644) | pub fn serialize(&self) -> [u8; util::SIGNATURE_SIZE] {
method serialize_der (line 653) | pub fn serialize_der(&self) -> SignatureArray {
type RecoveryId (line 79) | pub struct RecoveryId(u8);
method parse (line 718) | pub fn parse(p: u8) -> Result<RecoveryId, Error> {
method parse_rpc (line 727) | pub fn parse_rpc(p: u8) -> Result<RecoveryId, Error> {
method serialize (line 735) | pub fn serialize(&self) -> u8 {
method into (line 741) | fn into(self) -> u8 {
method into (line 747) | fn into(self) -> i32 {
type Message (line 83) | pub struct Message(pub Scalar);
method parse (line 692) | pub fn parse(p: &[u8; util::MESSAGE_SIZE]) -> Message {
method parse_slice (line 701) | pub fn parse_slice(p: &[u8]) -> Result<Message, Error> {
method serialize (line 711) | pub fn serialize(&self) -> [u8; util::MESSAGE_SIZE] {
type SharedSecret (line 87) | pub struct SharedSecret<D: Digest>(GenericArray<u8, D::OutputSize>);
type PublicKeyFormat (line 97) | pub enum PublicKeyFormat {
method serialize (line 336) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
type PublicKeyStrVisitor (line 349) | struct PublicKeyStrVisitor;
type Value (line 353) | type Value = PublicKey;
method expecting (line 355) | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
method visit_str (line 360) | fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
type PublicKeyBytesVisitor (line 377) | struct PublicKeyBytesVisitor;
type Value (line 381) | type Value = PublicKey;
method expecting (line 383) | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
method visit_bytes (line 389) | fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
method default (line 478) | fn default() -> SecretKey {
function new_with_context (line 753) | pub fn new_with_context(
function new (line 767) | pub fn new(pubkey: &PublicKey, seckey: &SecretKey) -> Result<SharedSecre...
function as_ref (line 773) | fn as_ref(&self) -> &[u8] {
function verify_with_context (line 779) | pub fn verify_with_context(
function verify (line 790) | pub fn verify(message: &Message, signature: &Signature, pubkey: &PublicK...
function recover_with_context (line 795) | pub fn recover_with_context(
function recover (line 808) | pub fn recover(
function sign_with_context (line 818) | pub fn sign_with_context(
function sign (line 857) | pub fn sign(message: &Message, seckey: &SecretKey) -> (Signature, Recove...
function secret_key_inverse_is_sane (line 867) | fn secret_key_inverse_is_sane() {
function secret_key_clear_is_correct (line 883) | fn secret_key_clear_is_correct() {
FILE: tests/serde.rs
constant DEBUG_SECRET_KEY (line 5) | const DEBUG_SECRET_KEY: [u8; 32] = [1u8; 32];
constant SERIALIZED_DEBUG_PUBLIC_KEY (line 7) | const SERIALIZED_DEBUG_PUBLIC_KEY: &str =
function debug_public_key (line 10) | fn debug_public_key() -> PublicKey {
function test_serialize_public_key (line 16) | fn test_serialize_public_key() {
function test_deserialize_public_key (line 23) | fn test_deserialize_public_key() {
function test_public_key_bincode_serde (line 29) | fn test_public_key_bincode_serde() {
FILE: tests/verify.rs
function genkey (line 21) | fn genkey(
function test_signature_der (line 38) | fn test_signature_der() {
function test_sign_verify (line 59) | fn test_sign_verify() {
function test_failing_sign_verify (line 110) | fn test_failing_sign_verify() {
function test_shared_secret (line 133) | fn test_shared_secret() {
function test_verify (line 158) | fn test_verify() {
function secret_clear_on_drop (line 199) | fn secret_clear_on_drop() {
function test_recover (line 208) | fn test_recover() {
function from_hex (line 238) | fn from_hex(hex: &str, target: &mut [u8]) -> Result<usize, ()> {
function test_signature_der_lax (line 271) | fn test_signature_der_lax() {
function test_low_s (line 289) | fn test_low_s() {
function test_convert_key1 (line 324) | fn test_convert_key1() {
function test_convert_key2 (line 345) | fn test_convert_key2() {
function test_convert_anykey (line 366) | fn test_convert_anykey() {
function test_pubkey_combine (line 394) | fn test_pubkey_combine() {
function test_pubkey_equality (line 421) | fn test_pubkey_equality() {
FILE: tests/wycheproof.rs
type TestCollection (line 8) | struct TestCollection {
type TestGroup (line 21) | struct TestGroup {
type TestKey (line 34) | struct TestKey {
type TestUnit (line 47) | struct TestUnit {
type TestResult (line 58) | enum TestResult {
type TestError (line 64) | enum TestError {
function test_unit (line 70) | fn test_unit(test: &TestUnit, key: &libsecp256k1::PublicKey) -> Result<(...
function test_wycheproof (line 90) | fn test_wycheproof() {
Condensed preview — 39 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (476K chars).
[
{
"path": ".arcconfig",
"chars": 54,
"preview": "{\n \"phabricator.uri\" : \"https://source.that.world/\"\n}"
},
{
"path": ".editorconfig",
"chars": 165,
"preview": "root = true\n[*]\nindent_style=space\nindent_size=4\ntab_width=4\nend_of_line=lf\ncharset=utf-8\ntrim_trailing_whitespace=true\n"
},
{
"path": ".github/dependabot.yml",
"chars": 356,
"preview": "version: 2\nupdates:\n - package-ecosystem: cargo\n directory: \"/\"\n labels: []\n schedule:\n interval: \"daily\""
},
{
"path": ".github/workflows/audit.yml",
"chars": 595,
"preview": "name: Security audit\non:\n pull_request:\n paths: Cargo.lock\n schedule:\n - cron: '0 0 * * *'\njobs:\n security_audi"
},
{
"path": ".github/workflows/check-style.yml",
"chars": 1060,
"preview": "name: Check style\n\non:\n pull_request:\n push:\n branches:\n - master\n - stable\n tags:\n "
},
{
"path": ".github/workflows/clippy.yml",
"chars": 1308,
"preview": "name: Check clippy\n\non:\n pull_request:\n push:\n branches:\n - master\n - stable\n tags:\n "
},
{
"path": ".github/workflows/prepare_artifacts.sh",
"chars": 759,
"preview": "#!/bin/bash\nset -e # fail on any error\nset -u # treat unset variables as error\n\n# ARGUMENT $1 CARGO_TARGET\n#Set addition"
},
{
"path": ".github/workflows/rust-windows.yml",
"chars": 11145,
"preview": "# almost a copy of .github/workflows/rust.yml made in https://github.com/paritytech/libsecp256k1/pull/84\n# windows cause"
},
{
"path": ".github/workflows/rust.yml",
"chars": 8684,
"preview": "name: Check, Test and Build Suite\n\non:\n pull_request:\n push:\n branches:\n - master\n - sta"
},
{
"path": ".github/workflows/sccache.sh",
"chars": 726,
"preview": "#!/bin/bash\n\nset -ex\n\nexport SCCACHE_CACHE_SIZE=\"1G\"\nexport SCCACHE_IDLE_TIMEOUT=0\nexport SCCACHE_DIR=\"$HOME/sccache\"\nOS"
},
{
"path": ".gitignore",
"chars": 55,
"preview": "/target/\n**/*.rs.bk\nCargo.lock\n*.swp\n/.idea\n/shell.nix\n"
},
{
"path": "CHANGELOG.md",
"chars": 696,
"preview": "# Changelog\n\nThe format is based on [Keep a Changelog].\n\n[Keep a Changelog]: http://keepachangelog.com/en/1.0.0/\n\n## [0."
},
{
"path": "Cargo.toml",
"chars": 1561,
"preview": "[package]\nname = \"libsecp256k1\"\ndescription = \"Pure Rust secp256k1 implementation.\"\nlicense = \"Apache-2.0\"\nversion = \"0."
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 3044,
"preview": "_Please note that this repository is no longer maintained. You can use [k256](https://crates.io/crates/k256) instead._\n\n"
},
{
"path": "benches/public_key.rs",
"chars": 1570,
"preview": "#![feature(test)]\n\nextern crate test;\n\nuse libsecp256k1::PublicKey;\nuse secp256k1_test::{rand::thread_rng, Secp256k1};\nu"
},
{
"path": "benches/sign.rs",
"chars": 535,
"preview": "#![feature(test)]\n\nextern crate test;\n\nuse arrayref::array_ref;\nuse libsecp256k1::{sign, Message, SecretKey};\nuse secp25"
},
{
"path": "benches/signature.rs",
"chars": 1445,
"preview": "#![feature(test)]\n\nextern crate test;\n\nuse libsecp256k1::Signature;\nuse secp256k1_test::{rand::thread_rng, Message as Se"
},
{
"path": "build.rs",
"chars": 736,
"preview": "use std::{env, fs::File, io::Write, path::Path};\n\nfn main() {\n let out_dir = env::var_os(\"OUT_DIR\").unwrap();\n\n le"
},
{
"path": "core/Cargo.toml",
"chars": 481,
"preview": "[package]\nname = \"libsecp256k1-core\"\ndescription = \"Core functions for pure Rust secp256k1 implementation.\"\nlicense = \"A"
},
{
"path": "core/src/der.rs",
"chars": 6679,
"preview": "use core::{\n convert::{AsMut, AsRef},\n mem,\n};\n\nuse crate::{error::Error, scalar::Scalar};\n\npub struct SignatureAr"
},
{
"path": "core/src/ecdh.rs",
"chars": 849,
"preview": "use crate::{\n ecmult::ECMultContext,\n group::{Affine, Jacobian},\n scalar::Scalar,\n};\nuse digest::{generic_array"
},
{
"path": "core/src/ecdsa.rs",
"chars": 3703,
"preview": "use crate::{\n ecmult::{ECMultContext, ECMultGenContext},\n field::Field,\n group::{Affine, Jacobian},\n scalar:"
},
{
"path": "core/src/ecmult.rs",
"chars": 18215,
"preview": "use crate::{\n field::Field,\n group::{globalz_set_table_gej, set_table_gej_var, Affine, AffineStorage, Jacobian, AF"
},
{
"path": "core/src/error.rs",
"chars": 1017,
"preview": "#[derive(Debug, Clone, Copy, Eq, PartialEq)]\npub enum Error {\n InvalidSignature,\n InvalidPublicKey,\n InvalidSec"
},
{
"path": "core/src/field.rs",
"chars": 67350,
"preview": "use core::{\n cmp::Ordering,\n ops::{Add, AddAssign, Mul, MulAssign},\n};\n\nmacro_rules! debug_assert_bits {\n ($x: "
},
{
"path": "core/src/group.rs",
"chars": 18882,
"preview": "use crate::field::{Field, FieldStorage};\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\n/// A group element of the secp25"
},
{
"path": "core/src/lib.rs",
"chars": 1875,
"preview": "//! Core libraries for libsecp256k1.\n\n#![allow(\n clippy::cast_ptr_alignment,\n clippy::identity_op,\n clippy::man"
},
{
"path": "core/src/scalar.rs",
"chars": 31902,
"preview": "use core::ops::{Add, AddAssign, Mul, MulAssign, Neg};\nuse crunchy::unroll;\nuse subtle::Choice;\n\nconst SECP256K1_N: [u32;"
},
{
"path": "gen/ecmult/Cargo.toml",
"chars": 408,
"preview": "[package]\nname = \"libsecp256k1-gen-ecmult\"\ndescription = \"Generator function of const_gen for libsecp256k1.\"\nlicense = \""
},
{
"path": "gen/ecmult/src/lib.rs",
"chars": 844,
"preview": "use libsecp256k1_core::curve::ECMultContext;\nuse std::{\n fs::File,\n io::{Error, Write},\n};\n\npub fn generate_to(fil"
},
{
"path": "gen/genmult/Cargo.toml",
"chars": 405,
"preview": "[package]\nname = \"libsecp256k1-gen-genmult\"\ndescription = \"Generator function of const for libsecp256k1.\"\nlicense = \"Apa"
},
{
"path": "gen/genmult/src/lib.rs",
"chars": 1039,
"preview": "#![allow(clippy::needless_range_loop)]\n\nuse libsecp256k1_core::curve::ECMultGenContext;\nuse std::{\n fs::File,\n io:"
},
{
"path": "res/ecdsa_secp256k1_sha256_test.json",
"chars": 203551,
"preview": "{\n \"algorithm\" : \"ECDSA\",\n \"generatorVersion\" : \"0.8r12\",\n \"numberOfTests\" : 380,\n \"header\" : [\n \"Test vectors of"
},
{
"path": "rustfmt.toml",
"chars": 0,
"preview": ""
},
{
"path": "src/lib.rs",
"chars": 26926,
"preview": "//! Pure Rust implementation of the secp256k1 curve and fast ECDSA\n//! signatures. The secp256k1 curve is used extensive"
},
{
"path": "tests/serde.rs",
"chars": 1039,
"preview": "#![cfg(feature = \"std\")]\n\nuse libsecp256k1::*;\n\nconst DEBUG_SECRET_KEY: [u8; 32] = [1u8; 32];\n// Public key for debug se"
},
{
"path": "tests/verify.rs",
"chars": 16336,
"preview": "use libsecp256k1::*;\nuse secp256k1_test::{\n key, rand::thread_rng, Error as SecpError, Message as SecpMessage, Secp25"
},
{
"path": "tests/wycheproof.rs",
"chars": 3290,
"preview": "use serde::Deserialize;\nuse sha2::Digest;\nuse std::collections::HashMap;\n\n#[derive(Deserialize)]\n#[serde(rename_all = \"c"
}
]
About this extraction
This page contains the full source code of the paritytech/libsecp256k1 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 39 files (440.1 KB), approximately 163.4k tokens, and a symbol index with 341 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.