├── .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 /.arcconfig: -------------------------------------------------------------------------------- 1 | { 2 | "phabricator.uri" : "https://source.that.world/" 3 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | indent_style=space 4 | indent_size=4 5 | tab_width=4 6 | end_of_line=lf 7 | charset=utf-8 8 | trim_trailing_whitespace=true 9 | max_line_length=80 10 | insert_final_newline=true 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | labels: [] 6 | schedule: 7 | interval: "daily" 8 | rebase-strategy: disabled 9 | open-pull-requests-limit: 2 10 | 11 | - package-ecosystem: github-actions 12 | directory: "/" 13 | labels: [] 14 | schedule: 15 | interval: "daily" 16 | rebase-strategy: disabled 17 | open-pull-requests-limit: 2 18 | -------------------------------------------------------------------------------- /.github/workflows/audit.yml: -------------------------------------------------------------------------------- 1 | name: Security audit 2 | on: 3 | pull_request: 4 | paths: Cargo.lock 5 | schedule: 6 | - cron: '0 0 * * *' 7 | jobs: 8 | security_audit: 9 | runs-on: ubuntu-latest 10 | steps: 11 | 12 | - name: Cancel Previous Runs 13 | uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0 14 | 15 | - name: Checkout sources 16 | uses: actions/checkout@v3.1.0 17 | with: 18 | fetch-depth: 50 19 | 20 | - name: Run cargo audit 21 | uses: actions-rs/audit-check@v1.2.0 22 | with: 23 | token: ${{ secrets.GITHUB_TOKEN }} 24 | -------------------------------------------------------------------------------- /.github/workflows/check-style.yml: -------------------------------------------------------------------------------- 1 | name: Check style 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | - stable 9 | tags: 10 | - v* 11 | paths-ignore: 12 | - 'README.md' 13 | jobs: 14 | check-style: 15 | name: Check style 16 | runs-on: ubuntu-latest 17 | env: 18 | RUST_BACKTRACE: full 19 | steps: 20 | - name: Cancel Previous Runs 21 | uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0 22 | 23 | - name: Checkout sources & submodules 24 | uses: actions/checkout@v3.1.0 25 | with: 26 | fetch-depth: 5 27 | submodules: recursive 28 | 29 | - name: Install toolchain 30 | uses: actions-rs/toolchain@v1.0.7 31 | with: 32 | profile: minimal 33 | toolchain: stable 34 | components: clippy, rustfmt 35 | override: true 36 | 37 | - name: Checking style 38 | uses: actions-rs/cargo@v1.0.3 39 | with: 40 | command: fmt 41 | toolchain: stable 42 | args: --all -- --check 43 | -------------------------------------------------------------------------------- /.github/workflows/clippy.yml: -------------------------------------------------------------------------------- 1 | name: Check clippy 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | - stable 9 | tags: 10 | - v* 11 | paths-ignore: 12 | - 'README.md' 13 | jobs: 14 | check-clippy: 15 | name: Check clippy 16 | runs-on: ubuntu-latest 17 | env: 18 | RUST_BACKTRACE: full 19 | steps: 20 | - name: Cancel Previous Runs 21 | uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0 22 | 23 | - name: Checkout sources & submodules 24 | uses: actions/checkout@v3.1.0 25 | with: 26 | fetch-depth: 5 27 | submodules: recursive 28 | 29 | - name: Install toolchain 30 | uses: actions-rs/toolchain@v1.0.7 31 | with: 32 | profile: minimal 33 | toolchain: stable 34 | components: clippy, rustfmt 35 | override: true 36 | 37 | - name: Checking clippy 38 | uses: actions-rs/cargo@v1.0.3 39 | with: 40 | command: clippy 41 | toolchain: stable 42 | args: --all 43 | 44 | - name: Checking clippy 45 | uses: actions-rs/cargo@v1.0.3 46 | with: 47 | command: clippy 48 | toolchain: stable 49 | args: --all --no-default-features --features std,hmac,lazy-static-context 50 | -------------------------------------------------------------------------------- /.github/workflows/prepare_artifacts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e # fail on any error 3 | set -u # treat unset variables as error 4 | 5 | # ARGUMENT $1 CARGO_TARGET 6 | #Set additional dir path 7 | if [ "${1}" == "" ]; then 8 | dir="" 9 | else 10 | dir=".." 11 | fi 12 | mkdir -p ./artifacts/ 13 | cd ./target/$1/release/ 14 | ls -a 15 | echo "_____ Find binary files in target _____" 16 | find . -maxdepth 1 -type f ! -size 0 -exec grep -IL . "{}" \; | cut -c 3- 17 | echo "_____ Move binaries to artifacts folder _____" 18 | for binary in $(find . -maxdepth 1 -type f ! -size 0 -exec grep -IL . "{}" \; | cut -c 3- ) 19 | do 20 | mv -v $binary ../$dir/../artifacts/$binary 21 | done 22 | cd ../$dir/.. 23 | echo "_____ Clean target dir _____" 24 | find ./target/$1/{debug,release} -maxdepth 1 -type f -delete; 25 | rm -f ./target/.rustc_info.json; 26 | rm -rf ./target/$1/{debug,release}/{deps,.fingerprint}/ 27 | -------------------------------------------------------------------------------- /.github/workflows/rust-windows.yml: -------------------------------------------------------------------------------- 1 | # almost a copy of .github/workflows/rust.yml made in https://github.com/paritytech/libsecp256k1/pull/84 2 | # windows causes some troubles with sudo sccache and 3 | # caching within GHA https://github.com/Swatinem/rust-cache/issues/31 4 | name: Check, Test and Build on Windows 5 | 6 | on: 7 | pull_request: 8 | push: 9 | branches: 10 | - master 11 | - stable 12 | tags: 13 | - v* 14 | paths-ignore: 15 | - 'README.md' 16 | 17 | jobs: 18 | check: 19 | name: Check 20 | strategy: 21 | matrix: 22 | platform: 23 | - windows-latest 24 | toolchain: 25 | - stable 26 | - nightly 27 | compiler: 28 | - clang 29 | - gcc 30 | runs-on: ${{ matrix.platform }} 31 | env: 32 | RUST_BACKTRACE: full 33 | steps: 34 | 35 | - name: Cancel Previous Runs 36 | uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0 37 | 38 | - name: Install sudo for windows #https://github.com/actions/virtual-environments/issues/572 39 | if: matrix.platform == 'windows-latest' 40 | run: choco install sudo 41 | 42 | - name: Install LLVM for Windows 43 | if: matrix.platform == 'windows-latest' && matrix.compiler == 'clang' 44 | run: | 45 | choco install llvm 46 | echo "CC=clang-cl.exe --enable-64-bit" >> "$GITHUB_ENV" 47 | echo "CXX=clang-cl.exe --enable-64-bit" >> "$GITHUB_ENV" 48 | refreshenv 49 | 50 | - name: Checkout sources & submodules 51 | uses: actions/checkout@v3.1.0 52 | with: 53 | fetch-depth: 5 54 | submodules: recursive 55 | 56 | - name: Install toolchain 57 | id: toolchain 58 | uses: actions-rs/toolchain@v1.0.7 59 | with: 60 | profile: minimal 61 | toolchain: ${{ matrix.toolchain }} 62 | components: clippy, rustfmt 63 | override: true 64 | 65 | - name: Set cache_hash ENV and prepare cache dir 66 | run: | 67 | echo "cache_hash=${{ runner.os }}-${{ steps.toolchain.outputs.rustc_hash }}-${{ matrix.compiler }}-${{ hashFiles('**/Cargo.toml') }}" >> "$GITHUB_ENV" 68 | mkdir -p $HOME/sccache 69 | sudo chmod -R a+w $HOME/.cargo 70 | shell: bash 71 | 72 | - name: Cache cargo registry 73 | uses: actions/cache@v3.0.11 74 | with: 75 | path: $HOME/.cargo/registry 76 | key: cargo-registry-${{ env['cache_hash'] }} 77 | 78 | - name: Cache cargo index 79 | uses: actions/cache@v3.0.11 80 | with: 81 | path: $HOME/.cargo/git 82 | key: cargo-git-${{ env['cache_hash'] }} 83 | 84 | - name: Cache cargo build 85 | uses: actions/cache@v3.0.11 86 | with: 87 | path: target 88 | key: cargo-target-${{ env['cache_hash'] }} 89 | 90 | - name: Checking ${{ matrix.platform }}-${{ matrix.toolchain }} 91 | uses: actions-rs/cargo@v1.0.3 92 | with: 93 | command: check 94 | toolchain: ${{ matrix.toolchain }} 95 | args: --all --verbose 96 | 97 | test: 98 | name: Test 99 | needs: [check] 100 | strategy: 101 | matrix: 102 | platform: 103 | - windows-latest 104 | toolchain: 105 | - stable 106 | - nightly 107 | compiler: 108 | - clang 109 | - gcc 110 | runs-on: ${{ matrix.platform }} 111 | env: 112 | RUST_BACKTRACE: full 113 | steps: 114 | 115 | - name: Cancel Previous Runs 116 | uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0 117 | 118 | - name: Set default compiler 119 | if: matrix.compiler == 'clang' && matrix.platform != 'windows-latest' 120 | run: | 121 | echo "CC=clang" >> "$GITHUB_ENV" 122 | echo "CXX=clang++" >> "$GITHUB_ENV" 123 | 124 | - name: Install sudo for windows #https://github.com/actions/virtual-environments/issues/572 125 | if: matrix.platform == 'windows-latest' 126 | run: choco install sudo 127 | 128 | - name: Install LLVM for Windows 129 | if: matrix.platform == 'windows-latest' && matrix.compiler == 'clang' 130 | run: | 131 | choco install llvm 132 | echo "CC=clang-cl.exe --enable-64-bit" >> "$GITHUB_ENV" 133 | echo "CXX=clang-cl.exe --enable-64-bit" >> "$GITHUB_ENV" 134 | refreshenv 135 | 136 | - name: Checkout sources & submodules 137 | uses: actions/checkout@v3.1.0 138 | with: 139 | fetch-depth: 5 140 | submodules: recursive 141 | 142 | - name: Install toolchain 143 | id: toolchain 144 | uses: actions-rs/toolchain@v1.0.7 145 | with: 146 | profile: minimal 147 | toolchain: ${{ matrix.toolchain }} 148 | components: clippy, rustfmt 149 | override: true 150 | 151 | - name: Set cache_hash ENV and prepare cache dir 152 | run: | 153 | echo "cache_hash=${{ runner.os }}-${{ steps.toolchain.outputs.rustc_hash }}-${{ matrix.compiler }}-${{ hashFiles('**/Cargo.toml') }}" >> "$GITHUB_ENV" 154 | mkdir -p $HOME/sccache 155 | sudo chmod -R a+w $HOME/.cargo 156 | shell: bash 157 | 158 | - name: Cache cargo registry 159 | uses: actions/cache@v3.0.11 160 | with: 161 | path: $HOME/.cargo/registry 162 | key: cargo-registry-${{ env['cache_hash'] }} 163 | 164 | - name: Cache cargo index 165 | uses: actions/cache@v3.0.11 166 | with: 167 | path: $HOME/.cargo/git 168 | key: cargo-git-${{ env['cache_hash'] }} 169 | 170 | - name: Cache cargo build 171 | uses: actions/cache@v3.0.11 172 | with: 173 | path: target 174 | key: cargo-target-${{ env['cache_hash'] }} 175 | 176 | - name: Testing ${{ matrix.platform }}-${{ matrix.toolchain }} (debug build) 177 | uses: actions-rs/cargo@v1.0.3 178 | with: 179 | command: test 180 | toolchain: ${{ matrix.toolchain }} 181 | args: --all --verbose 182 | 183 | - name: Testing ${{ matrix.platform }}-${{ matrix.toolchain }} (release build) 184 | uses: actions-rs/cargo@v1.0.3 185 | with: 186 | command: test 187 | toolchain: ${{ matrix.toolchain }} 188 | args: --all --release --verbose 189 | 190 | build: 191 | name: Build 192 | needs: [check,test] 193 | strategy: 194 | matrix: 195 | platform: 196 | - windows-latest 197 | toolchain: 198 | - stable 199 | - nightly 200 | compiler: 201 | - clang 202 | - gcc 203 | runs-on: ${{ matrix.platform }} 204 | env: 205 | RUST_BACKTRACE: full 206 | # NOTE: Enables the aes-ni instructions for RustCrypto dependency. 207 | # Strip binaries 208 | # If you change this please remember to also update .cargo/config 209 | RUSTFLAGS: "-C target-feature=+aes,+sse2,+ssse3 -C link-arg=-s" 210 | steps: 211 | 212 | - name: Cancel Previous Runs 213 | uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0 214 | 215 | - name: Set default compiler 216 | if: matrix.compiler == 'clang' && matrix.platform != 'windows-latest' 217 | run: | 218 | echo "CC=clang" >> "$GITHUB_ENV" 219 | echo "CXX=clang++" >> "$GITHUB_ENV" 220 | 221 | - name: Install sudo for windows #https://github.com/actions/virtual-environments/issues/572 222 | if: matrix.platform == 'windows-latest' 223 | run: choco install sudo 224 | 225 | - name: Install LLVM for Windows 226 | if: matrix.platform == 'windows-latest' && matrix.compiler == 'clang' 227 | run: | 228 | choco install llvm 229 | echo "CC=clang-cl.exe --enable-64-bit" >> "$GITHUB_ENV" 230 | echo "CXX=clang-cl.exe --enable-64-bit" >> "$GITHUB_ENV" 231 | refreshenv 232 | 233 | - name: Checkout sources & submodules 234 | uses: actions/checkout@v3.1.0 235 | with: 236 | fetch-depth: 5 237 | submodules: recursive 238 | 239 | - name: Install toolchain 240 | id: toolchain 241 | uses: actions-rs/toolchain@v1.0.7 242 | with: 243 | profile: minimal 244 | toolchain: ${{ matrix.toolchain }} 245 | components: clippy, rustfmt 246 | override: true 247 | 248 | - name: Set cache_hash ENV and prepare cache dir 249 | run: | 250 | echo "cache_hash=${{ runner.os }}-${{ steps.toolchain.outputs.rustc_hash }}-${{ matrix.compiler }}-${{ hashFiles('**/Cargo.toml') }}" >> "$GITHUB_ENV" 251 | mkdir -p $HOME/sccache 252 | sudo chmod -R a+w $HOME/.cargo 253 | shell: bash 254 | 255 | - name: Cache cargo registry 256 | uses: actions/cache@v3.0.11 257 | with: 258 | path: $HOME/.cargo/registry 259 | key: cargo-registry-${{ env['cache_hash'] }} 260 | 261 | - name: Cache cargo index 262 | uses: actions/cache@v3.0.11 263 | with: 264 | path: $HOME/.cargo/git 265 | key: cargo-git-${{ env['cache_hash'] }} 266 | 267 | - name: Cache cargo build 268 | uses: actions/cache@v3.0.11 269 | with: 270 | path: target 271 | key: cargo-target-${{ env['cache_hash'] }} 272 | 273 | - name: Building ${{ matrix.platform }}-${{ matrix.toolchain }} 274 | uses: actions-rs/cargo@v1.0.3 275 | with: 276 | command: build 277 | toolchain: ${{ matrix.toolchain }} 278 | args: --all --verbose --release 279 | 280 | - name: Building `no default` ${{ matrix.platform }}-${{ matrix.toolchain }} 281 | uses: actions-rs/cargo@v1.0.3 282 | with: 283 | command: build 284 | toolchain: ${{ matrix.toolchain }} 285 | args: --verbose --no-default-features 286 | 287 | - name: Building `hmac` ${{ matrix.platform }}-${{ matrix.toolchain }} 288 | uses: actions-rs/cargo@v1.0.3 289 | with: 290 | command: build 291 | toolchain: ${{ matrix.toolchain }} 292 | args: --verbose --no-default-features --features hmac 293 | 294 | - name: Building `static-context` ${{ matrix.platform }}-${{ matrix.toolchain }} 295 | uses: actions-rs/cargo@v1.0.3 296 | with: 297 | command: build 298 | toolchain: ${{ matrix.toolchain }} 299 | args: --verbose --no-default-features --features static-context 300 | 301 | - name: Building `lazy-static-context` ${{ matrix.platform }}-${{ matrix.toolchain }} 302 | uses: actions-rs/cargo@v1.0.3 303 | with: 304 | command: build 305 | toolchain: ${{ matrix.toolchain }} 306 | args: --verbose --no-default-features --features lazy-static-context 307 | 308 | - name: Prepare artifacts 309 | run: .github/workflows/prepare_artifacts.sh "" 310 | shell: bash 311 | 312 | - name: Upload artifacts 313 | uses: actions/upload-artifact@v3.1.0 314 | with: 315 | name: ${{ matrix.platform }}.${{ matrix.toolchain }}.${{ matrix.compiler }}.zip 316 | path: artifacts/ 317 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Check, Test and Build Suite 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | - stable 9 | tags: 10 | - v* 11 | paths-ignore: 12 | - 'README.md' 13 | 14 | jobs: 15 | check: 16 | name: Check 17 | strategy: 18 | matrix: 19 | platform: 20 | - ubuntu-latest 21 | - macos-latest 22 | toolchain: 23 | - stable 24 | - nightly 25 | compiler: 26 | - clang 27 | - gcc 28 | runs-on: ${{ matrix.platform }} 29 | env: 30 | RUST_BACKTRACE: full 31 | steps: 32 | 33 | - name: Cancel Previous Runs 34 | uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0 35 | 36 | - name: Set default compiler 37 | if: matrix.compiler == 'clang' 38 | run: | 39 | echo "CC=clang" >> "$GITHUB_ENV" 40 | echo "CXX=clang++" >> "$GITHUB_ENV" 41 | 42 | - name: Checkout sources & submodules 43 | uses: actions/checkout@v3.1.0 44 | with: 45 | fetch-depth: 5 46 | submodules: recursive 47 | 48 | - name: Install toolchain 49 | id: toolchain 50 | uses: actions-rs/toolchain@v1.0.7 51 | with: 52 | profile: minimal 53 | toolchain: ${{ matrix.toolchain }} 54 | components: clippy, rustfmt 55 | override: true 56 | 57 | - uses: Swatinem/rust-cache@22c9328bcba27aa81a32b1bef27c7e3c78052531 # v2.0.1 58 | 59 | - name: Cache sccache 60 | uses: actions/cache@v3.0.11 61 | with: 62 | path: "$HOME/sccache" 63 | key: sccache-${{ env['cache_hash'] }} 64 | 65 | - name: Install & start sccache for ${{ matrix.platform }} 66 | shell: bash 67 | run: .github/workflows/sccache.sh ${{ runner.os}} 68 | 69 | - name: Sccache statistics 70 | run: sccache --show-stats 71 | 72 | # here comes different part 73 | - name: Checking ${{ matrix.platform }}-${{ matrix.toolchain }} 74 | uses: actions-rs/cargo@v1.0.3 75 | with: 76 | command: check 77 | toolchain: ${{ matrix.toolchain }} 78 | args: --all --verbose 79 | 80 | - name: Stop sccache 81 | if: always() 82 | run: sccache --stop-server 83 | 84 | test: 85 | name: Test 86 | needs: [check] 87 | strategy: 88 | matrix: 89 | platform: 90 | - ubuntu-latest 91 | - macos-latest 92 | toolchain: 93 | - stable 94 | - nightly 95 | compiler: 96 | - clang 97 | - gcc 98 | runs-on: ${{ matrix.platform }} 99 | env: 100 | RUST_BACKTRACE: full 101 | steps: 102 | 103 | - name: Cancel Previous Runs 104 | uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0 105 | 106 | - name: Set default compiler 107 | if: matrix.compiler == 'clang' 108 | run: | 109 | echo "CC=clang" >> "$GITHUB_ENV" 110 | echo "CXX=clang++" >> "$GITHUB_ENV" 111 | 112 | - name: Checkout sources & submodules 113 | uses: actions/checkout@v3.1.0 114 | with: 115 | fetch-depth: 5 116 | submodules: recursive 117 | 118 | - name: Install toolchain 119 | id: toolchain 120 | uses: actions-rs/toolchain@v1.0.7 121 | with: 122 | profile: minimal 123 | toolchain: ${{ matrix.toolchain }} 124 | components: clippy, rustfmt 125 | override: true 126 | 127 | - uses: Swatinem/rust-cache@22c9328bcba27aa81a32b1bef27c7e3c78052531 # v2.0.1 128 | 129 | - name: Cache sccache 130 | uses: actions/cache@v3.0.11 131 | with: 132 | path: "$HOME/sccache" 133 | key: sccache-${{ env['cache_hash'] }} 134 | 135 | - name: Install & start sccache for ${{ matrix.platform }} 136 | shell: bash 137 | run: .github/workflows/sccache.sh ${{ runner.os}} 138 | 139 | - name: Sccache statistics 140 | run: sccache --show-stats 141 | 142 | # here comes different part 143 | - name: Testing ${{ matrix.platform }}-${{ matrix.toolchain }} (debug build) 144 | uses: actions-rs/cargo@v1.0.3 145 | with: 146 | command: test 147 | toolchain: ${{ matrix.toolchain }} 148 | args: --all --verbose 149 | 150 | - name: Testing ${{ matrix.platform }}-${{ matrix.toolchain }} (release build) 151 | uses: actions-rs/cargo@v1.0.3 152 | with: 153 | command: test 154 | toolchain: ${{ matrix.toolchain }} 155 | args: --all --release --verbose 156 | 157 | - name: Stop sccache 158 | if: always() 159 | run: sccache --stop-server 160 | 161 | build: 162 | name: Build 163 | needs: [check,test] 164 | strategy: 165 | matrix: 166 | platform: 167 | - ubuntu-latest 168 | - macos-latest 169 | toolchain: 170 | - stable 171 | - nightly 172 | compiler: 173 | - clang 174 | - gcc 175 | runs-on: ${{ matrix.platform }} 176 | env: 177 | RUST_BACKTRACE: full 178 | # NOTE: Enables the aes-ni instructions for RustCrypto dependency. 179 | # Strip binaries 180 | # If you change this please remember to also update .cargo/config 181 | RUSTFLAGS: "-C target-feature=+aes,+sse2,+ssse3 -C link-arg=-s" 182 | steps: 183 | 184 | - name: Cancel Previous Runs 185 | uses: styfle/cancel-workflow-action@b173b6ec0100793626c2d9e6b90435061f4fc3e5 # 0.11.0 186 | 187 | - name: Set default compiler 188 | if: matrix.compiler == 'clang' 189 | run: | 190 | echo "CC=clang" >> "$GITHUB_ENV" 191 | echo "CXX=clang++" >> "$GITHUB_ENV" 192 | 193 | - name: Checkout sources & submodules 194 | uses: actions/checkout@v3.1.0 195 | with: 196 | fetch-depth: 5 197 | submodules: recursive 198 | 199 | - name: Install toolchain 200 | id: toolchain 201 | uses: actions-rs/toolchain@v1.0.7 202 | with: 203 | profile: minimal 204 | toolchain: ${{ matrix.toolchain }} 205 | components: clippy, rustfmt 206 | override: true 207 | 208 | - uses: Swatinem/rust-cache@22c9328bcba27aa81a32b1bef27c7e3c78052531 # v2.0.1 209 | 210 | - name: Cache sccache 211 | uses: actions/cache@v3.0.11 212 | with: 213 | path: "$HOME/sccache" 214 | key: sccache-${{ env['cache_hash'] }} 215 | 216 | - name: Install & start sccache for ${{ matrix.platform }} 217 | shell: bash 218 | run: .github/workflows/sccache.sh ${{ runner.os}} 219 | 220 | - name: Sccache statistics 221 | run: sccache --show-stats 222 | 223 | # here comes different part 224 | - name: Building ${{ matrix.platform }}-${{ matrix.toolchain }} 225 | uses: actions-rs/cargo@v1.0.3 226 | with: 227 | command: build 228 | toolchain: ${{ matrix.toolchain }} 229 | args: --all --verbose --release 230 | 231 | - name: Building `no default` ${{ matrix.platform }}-${{ matrix.toolchain }} 232 | uses: actions-rs/cargo@v1.0.3 233 | with: 234 | command: build 235 | toolchain: ${{ matrix.toolchain }} 236 | args: --verbose --no-default-features 237 | 238 | - name: Building `hmac` ${{ matrix.platform }}-${{ matrix.toolchain }} 239 | uses: actions-rs/cargo@v1.0.3 240 | with: 241 | command: build 242 | toolchain: ${{ matrix.toolchain }} 243 | args: --verbose --no-default-features --features hmac 244 | 245 | - name: Building `static-context` ${{ matrix.platform }}-${{ matrix.toolchain }} 246 | uses: actions-rs/cargo@v1.0.3 247 | with: 248 | command: build 249 | toolchain: ${{ matrix.toolchain }} 250 | args: --verbose --no-default-features --features static-context 251 | 252 | - name: Building `lazy-static-context` ${{ matrix.platform }}-${{ matrix.toolchain }} 253 | uses: actions-rs/cargo@v1.0.3 254 | with: 255 | command: build 256 | toolchain: ${{ matrix.toolchain }} 257 | args: --verbose --no-default-features --features lazy-static-context 258 | 259 | - name: Stop sccache 260 | if: always() 261 | run: sccache --stop-server 262 | 263 | - name: Prepare artifacts 264 | run: .github/workflows/prepare_artifacts.sh "" 265 | shell: bash 266 | 267 | - name: Upload artifacts 268 | uses: actions/upload-artifact@v3.1.0 269 | with: 270 | name: ${{ matrix.platform }}.${{ matrix.toolchain }}.${{ matrix.compiler }}.zip 271 | path: artifacts/ 272 | -------------------------------------------------------------------------------- /.github/workflows/sccache.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | export SCCACHE_CACHE_SIZE="1G" 6 | export SCCACHE_IDLE_TIMEOUT=0 7 | export SCCACHE_DIR="$HOME/sccache" 8 | OS=$1 9 | VERSION="0.2.13" 10 | 11 | echo "Current OS: $OS" 12 | case $OS in 13 | "macOS") 14 | PLATFORM="x86_64-apple-darwin" 15 | ;; 16 | "Linux") 17 | PLATFORM="x86_64-unknown-linux-musl" 18 | ;; 19 | "Windows") 20 | PLATFORM="x86_64-pc-windows-msvc" 21 | VERSION="0.2.14" 22 | ;; 23 | esac 24 | echo "Target arch: " $PLATFORM 25 | BASENAME="sccache-$VERSION-$PLATFORM" 26 | URL="https://github.com/mozilla/sccache/releases/download/$VERSION/$BASENAME.tar.gz" 27 | echo "Download sccache from " "$URL" 28 | curl -LO "$URL" 29 | tar -xzvf "$BASENAME.tar.gz" 30 | ls $BASENAME/ 31 | echo "$(pwd)/$BASENAME" >> "$GITHUB_PATH" 32 | echo "RUSTC_WRAPPER=sccache" >> "$GITHUB_ENV" 33 | ./$BASENAME/sccache --start-server 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | *.swp 5 | /.idea 6 | /shell.nix 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | The format is based on [Keep a Changelog]. 4 | 5 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 6 | 7 | ## [0.5.0] - 2021-05-18 8 | - 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) 9 | 10 | ## [0.3.5] - 2020-02-06 11 | - Implement `std::error::Error` and `Display` for `Error`. (PR #29) 12 | - Fix the PartialEq impl of Field. (PR #30) 13 | - Add `LowerHex` implementation for `SecretKey` and `Scalar`. (PR #32) 14 | - Put signing behind feature flag. (PR #33) 15 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libsecp256k1" 3 | description = "Pure Rust secp256k1 implementation." 4 | license = "Apache-2.0" 5 | version = "0.7.2" 6 | authors = ["Wei Tang "] 7 | repository = "https://github.com/paritytech/libsecp256k1" 8 | keywords = ["crypto", "ECDSA", "secp256k1", "bitcoin", "no_std"] 9 | edition = "2018" 10 | resolver = "2" 11 | 12 | [dependencies] 13 | libsecp256k1-core = { version = "0.3.0", path = "core", default-features = false } 14 | arrayref = "0.3" 15 | rand = { version = "0.8", default-features = false } 16 | digest = "0.9" 17 | base64 = { version = "0.22", default-features = false } 18 | hmac-drbg = { version = "0.3", optional = true } 19 | sha2 = { version = "0.9", optional = true, default-features = false } 20 | typenum = { version = "1.12", optional = true } 21 | serde = { version = "1.0.104", features = ["derive"], default-features = false } 22 | lazy_static = { version = "1.4.0", optional = true } 23 | 24 | [dev-dependencies] 25 | secp256k1-test = { package = "secp256k1", version = "0.20.3", features = ["rand-std", "recovery"] } 26 | clear_on_drop = "0.2" 27 | serde_json = "1.0" 28 | hex = "0.4" 29 | hex-literal = "0.3.3" 30 | bincode = "1.3.3" 31 | 32 | [build-dependencies] 33 | libsecp256k1-gen-ecmult = { version = "0.3.0", path = "gen/ecmult" } 34 | libsecp256k1-gen-genmult = { version = "0.3.0", path = "gen/genmult" } 35 | 36 | [features] 37 | default = ["std", "hmac", "static-context"] 38 | std = ["libsecp256k1-core/std", "sha2/std", "rand/std", "serde/std", "base64/std"] 39 | hmac = ["hmac-drbg", "sha2", "typenum"] 40 | static-context = [] 41 | lazy-static-context = ["static-context", "lazy_static", "std"] 42 | 43 | [workspace] 44 | members = [ 45 | "./gen/ecmult", 46 | "./gen/genmult", 47 | ] 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | _Please note that this repository is no longer maintained. You can use [k256](https://crates.io/crates/k256) instead._ 2 | 3 | # SECP256K1 implementation in pure Rust 4 | 5 | * [Cargo](https://crates.io/crates/libsecp256k1) 6 | * [Documentation](https://docs.rs/libsecp256k1) 7 | 8 | SECP256K1 implementation with `no_std` support. Currently we have implementation for: 9 | 10 | * Convert a private key to a public key. 11 | * Sign messages. 12 | * Signature verification. 13 | * Public key recovery from signed messages. 14 | * Shared secrets. 15 | 16 | ## Feature flags 17 | 18 | * `std`: If disabled, works in `no_std` environment. Enabled by default. 19 | * `hmac`: Add certain features that requires the HMAC-DRBG. This includes 20 | signing. Enabled by default. 21 | * `static-context`: To speed up computation, the library uses a pre-computed 22 | table context for many `ecmult` operations. This feature flag puts the context 23 | directly as static variables. If disabled, the context must be created from 24 | heap manually. Increases binary size, enabled by default. 25 | * `lazy-static-context`: Instead of storing the pre-computed table context as 26 | static variables, store it as a variable that dynamically allocates the 27 | context in heap via `lazy_static`. It overwrites `static-context`. Impact 28 | bootstrap performance and only available in `std`, disabled by default. 29 | 30 | ## Development workflow 31 | 32 | ### Branch 33 | 34 | This repository uses `develop` branch for development. Changes are periodically 35 | merged to `master` branch. 36 | 37 | ### Pull request 38 | 39 | All changes (except new releases) are handled through pull requests. Please open 40 | your PR against `develop` branch. 41 | 42 | ### Versioning 43 | 44 | `libsecp256k1` follows [Semantic Versioning](https://semver.org/). An unreleased crate 45 | in the repository will have the `-dev` suffix in the end, and we do rolling 46 | releases. 47 | 48 | When you make a pull request against this repository, please also update the 49 | affected crates' versions, using the following rules. Note that the rules should 50 | be applied recursively -- if a change modifies any upper crate's dependency 51 | (even just the `Cargo.toml` file), then the upper crate will also need to apply 52 | those rules. 53 | 54 | Additionally, if your change is notable, then you should also modify the 55 | corresponding `CHANGELOG.md` file, in the "Unreleased" section. 56 | 57 | If the affected crate already has `-dev` suffix: 58 | 59 | * If your change is a patch, then you do not have to update any versions. 60 | * If your change introduces a new feature, please check if the local version 61 | already had its minor version bumped, if not, bump it. 62 | * If your change modifies the current interface, please check if the local 63 | version already had its major version bumped, if not, bump it. 64 | 65 | If the affected crate does not yet have `-dev` suffix: 66 | 67 | * If your change is a patch, then bump the patch version, and add `-dev` suffix. 68 | * If your change introduces a new feature, then bump the minor version, and add 69 | `-dev` suffix. 70 | * If your change modifies the current interface, then bump the major version, 71 | and add `-dev` suffix. 72 | 73 | If your pull request introduces a new crate, please set its version to 74 | `1.0.0-dev`. 75 | -------------------------------------------------------------------------------- /benches/public_key.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate test; 4 | 5 | use libsecp256k1::PublicKey; 6 | use secp256k1_test::{rand::thread_rng, Secp256k1}; 7 | use test::Bencher; 8 | 9 | #[bench] 10 | fn bench_public_key_parse(b: &mut Bencher) { 11 | let secp256k1 = Secp256k1::new(); 12 | let (_, secp_pubkey) = secp256k1.generate_keypair(&mut thread_rng()); 13 | let pubkey_arr = secp_pubkey.serialize_uncompressed(); 14 | assert!(pubkey_arr.len() == 65); 15 | let mut pubkey_a = [0u8; 65]; 16 | pubkey_a[0..65].copy_from_slice(&pubkey_arr[0..65]); 17 | b.iter(|| { 18 | let _pubkey = PublicKey::parse(&pubkey_a).unwrap(); 19 | }); 20 | } 21 | 22 | #[bench] 23 | fn bench_public_key_serialize(b: &mut Bencher) { 24 | let secp256k1 = Secp256k1::new(); 25 | let (_, secp_pubkey) = secp256k1.generate_keypair(&mut thread_rng()); 26 | let pubkey_arr = secp_pubkey.serialize_uncompressed(); 27 | assert!(pubkey_arr.len() == 65); 28 | let mut pubkey_a = [0u8; 65]; 29 | pubkey_a[0..65].copy_from_slice(&pubkey_arr[0..65]); 30 | let pubkey = PublicKey::parse(&pubkey_a).unwrap(); 31 | b.iter(|| { 32 | let _serialized = pubkey.serialize(); 33 | }); 34 | } 35 | 36 | #[bench] 37 | fn bench_public_key_serialize_compressed(b: &mut Bencher) { 38 | let secp256k1 = Secp256k1::new(); 39 | let (_, secp_pubkey) = secp256k1.generate_keypair(&mut thread_rng()); 40 | let pubkey_arr = secp_pubkey.serialize_uncompressed(); 41 | assert!(pubkey_arr.len() == 65); 42 | let mut pubkey_a = [0u8; 65]; 43 | pubkey_a[0..65].copy_from_slice(&pubkey_arr[0..65]); 44 | let pubkey = PublicKey::parse(&pubkey_a).unwrap(); 45 | b.iter(|| { 46 | let _serialized = pubkey.serialize_compressed(); 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /benches/sign.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate test; 4 | 5 | use arrayref::array_ref; 6 | use libsecp256k1::{sign, Message, SecretKey}; 7 | use secp256k1_test::{rand::thread_rng, Secp256k1}; 8 | use test::Bencher; 9 | 10 | #[bench] 11 | fn bench_sign_message(b: &mut Bencher) { 12 | let secp256k1 = Secp256k1::new(); 13 | let message = Message::parse(&[5u8; 32]); 14 | let (secp_privkey, _) = secp256k1.generate_keypair(&mut thread_rng()); 15 | let seckey = SecretKey::parse(array_ref!(secp_privkey, 0, 32)).unwrap(); 16 | 17 | b.iter(|| { 18 | let _ = sign(&message, &seckey); 19 | }); 20 | } 21 | -------------------------------------------------------------------------------- /benches/signature.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate test; 4 | 5 | use libsecp256k1::Signature; 6 | use secp256k1_test::{rand::thread_rng, Message as SecpMessage, Secp256k1}; 7 | use test::Bencher; 8 | 9 | #[bench] 10 | fn bench_signature_parse(b: &mut Bencher) { 11 | let secp256k1 = Secp256k1::new(); 12 | let message_arr = [5u8; 32]; 13 | let (privkey, _) = secp256k1.generate_keypair(&mut thread_rng()); 14 | let message = SecpMessage::from_slice(&message_arr).unwrap(); 15 | let signature = secp256k1.sign(&message, &privkey); 16 | let signature_arr = signature.serialize_compact(); 17 | assert!(signature_arr.len() == 64); 18 | let mut signature_a = [0u8; 64]; 19 | signature_a.copy_from_slice(&signature_arr[0..64]); 20 | 21 | b.iter(|| { 22 | let _signature = Signature::parse_standard_slice(&signature_a); 23 | }); 24 | } 25 | 26 | #[bench] 27 | fn bench_signature_serialize(b: &mut Bencher) { 28 | let secp256k1 = Secp256k1::new(); 29 | let message_arr = [5u8; 32]; 30 | let (privkey, _) = secp256k1.generate_keypair(&mut thread_rng()); 31 | let message = SecpMessage::from_slice(&message_arr).unwrap(); 32 | let signature = secp256k1.sign(&message, &privkey); 33 | let signature_arr = signature.serialize_compact(); 34 | assert!(signature_arr.len() == 64); 35 | let mut signature_a = [0u8; 64]; 36 | signature_a.copy_from_slice(&signature_arr[0..64]); 37 | let signature = Signature::parse_standard_slice(&signature_a).expect("parsed signature"); 38 | 39 | b.iter(|| { 40 | let _serialized = signature.serialize(); 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::{env, fs::File, io::Write, path::Path}; 2 | 3 | fn main() { 4 | let out_dir = env::var_os("OUT_DIR").unwrap(); 5 | 6 | let const_path = Path::new(&out_dir).join("const.rs"); 7 | let mut const_file = File::create(&const_path).expect("Create const.rs file failed"); 8 | libsecp256k1_gen_ecmult::generate_to(&mut const_file).expect("Write const.rs file failed"); 9 | const_file.flush().expect("Flush const.rs file failed"); 10 | 11 | let gen_path = Path::new(&out_dir).join("const_gen.rs"); 12 | let mut gen_file = File::create(&gen_path).expect("Create const_gen.rs file failed"); 13 | libsecp256k1_gen_genmult::generate_to(&mut gen_file).expect("Write const_gen.rs file failed"); 14 | gen_file.flush().expect("Flush const_gen.rs file failed"); 15 | } 16 | -------------------------------------------------------------------------------- /core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libsecp256k1-core" 3 | description = "Core functions for pure Rust secp256k1 implementation." 4 | license = "Apache-2.0" 5 | version = "0.3.0" 6 | authors = ["Wei Tang "] 7 | repository = "https://github.com/paritytech/libsecp256k1" 8 | keywords = ["crypto", "ECDSA", "secp256k1", "bitcoin", "no_std"] 9 | edition = "2018" 10 | 11 | [dependencies] 12 | subtle = { version = "2.2", default-features = false } 13 | crunchy = "0.2" 14 | digest = "0.9" 15 | 16 | [features] 17 | default = ["std"] 18 | std = ["subtle/std"] 19 | -------------------------------------------------------------------------------- /core/src/der.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | convert::{AsMut, AsRef}, 3 | mem, 4 | }; 5 | 6 | use crate::{error::Error, scalar::Scalar}; 7 | 8 | pub struct SignatureArray([u8; 6 + 33 + 33], usize); 9 | 10 | impl SignatureArray { 11 | pub fn new(size: usize) -> Self { 12 | SignatureArray([0u8; 6 + 33 + 33], size) 13 | } 14 | 15 | pub fn len(&self) -> usize { 16 | self.1 17 | } 18 | 19 | pub fn is_empty(&self) -> bool { 20 | self.len() == 0 21 | } 22 | } 23 | 24 | impl AsRef<[u8]> for SignatureArray { 25 | fn as_ref(&self) -> &[u8] { 26 | &self.0[..self.1] 27 | } 28 | } 29 | 30 | impl AsMut<[u8]> for SignatureArray { 31 | fn as_mut(&mut self) -> &mut [u8] { 32 | &mut self.0[..self.1] 33 | } 34 | } 35 | 36 | pub struct Decoder<'a>(&'a [u8], usize); 37 | 38 | impl<'a> Decoder<'a> { 39 | pub fn new(arr: &'a [u8]) -> Self { 40 | Decoder(arr, 0) 41 | } 42 | 43 | pub fn remaining_len(&self) -> usize { 44 | self.0.len() - self.1 45 | } 46 | 47 | pub fn read(&mut self) -> Result { 48 | if self.1 >= self.0.len() { 49 | Err(Error::InvalidSignature) 50 | } else { 51 | let v = self.0[self.1]; 52 | self.1 += 1; 53 | Ok(v) 54 | } 55 | } 56 | 57 | pub fn peek(&self, forward: usize) -> Result { 58 | if self.1 + forward >= self.0.len() { 59 | Err(Error::InvalidSignature) 60 | } else { 61 | let v = self.0[self.1 + forward]; 62 | Ok(v) 63 | } 64 | } 65 | 66 | pub fn peek_slice(&self, len: usize) -> Result<&[u8], Error> { 67 | if (len == 0 && self.1 >= self.0.len()) || self.1 + len > self.0.len() { 68 | Err(Error::InvalidSignature) 69 | } else { 70 | let v = &self.0[self.1..(self.1 + len)]; 71 | Ok(v) 72 | } 73 | } 74 | 75 | pub fn skip(&mut self, len: usize) -> Result<(), Error> { 76 | if (len == 0 && self.1 >= self.0.len()) || self.1 + len > self.0.len() { 77 | Err(Error::InvalidSignature) 78 | } else { 79 | self.1 += len; 80 | Ok(()) 81 | } 82 | } 83 | 84 | pub fn read_constructed_sequence(&mut self) -> Result<(), Error> { 85 | let v = self.read()?; 86 | if v == 0x30 { 87 | Ok(()) 88 | } else { 89 | Err(Error::InvalidSignature) 90 | } 91 | } 92 | 93 | pub fn read_len(&mut self) -> Result { 94 | let b1 = self.read()?; 95 | if b1 == 0xff { 96 | return Err(Error::InvalidSignature); 97 | } 98 | 99 | // Short form 100 | if b1 & 0x80 == 0 { 101 | return Ok(b1 as usize); 102 | } 103 | 104 | // Infinite length is not allowed 105 | if b1 == 0x80 { 106 | return Err(Error::InvalidSignature); 107 | } 108 | 109 | let mut lenleft = (b1 & 0x7f) as usize; 110 | if lenleft > self.remaining_len() { 111 | return Err(Error::InvalidSignature); 112 | } 113 | 114 | if self.peek(0)? == 0 { 115 | // Not the shortest possible length encoding 116 | return Err(Error::InvalidSignature); 117 | } 118 | 119 | if lenleft > mem::size_of::() { 120 | return Err(Error::InvalidSignature); 121 | } 122 | 123 | let mut ret = 0; 124 | while lenleft > 0 { 125 | ret = (ret << 8) | (self.read()? as usize); 126 | if ret + lenleft > self.remaining_len() { 127 | return Err(Error::InvalidSignature); 128 | } 129 | lenleft -= 1; 130 | } 131 | 132 | if ret < 128 { 133 | // Not the shortest possible length encoding 134 | return Err(Error::InvalidSignature); 135 | } 136 | 137 | Ok(ret) 138 | } 139 | 140 | pub fn read_integer(&mut self) -> Result { 141 | if self.read()? != 0x02 { 142 | return Err(Error::InvalidSignature); 143 | } 144 | 145 | let mut rlen = self.read_len()?; 146 | if rlen == 0 || rlen > self.remaining_len() { 147 | return Err(Error::InvalidSignature); 148 | } 149 | 150 | if self.peek(0)? == 0x00 && rlen > 1 && (self.peek(1)? & 0x80) == 0x00 { 151 | return Err(Error::InvalidSignature); 152 | } 153 | 154 | if self.peek(0)? == 0xff && rlen > 1 && (self.peek(1)? & 0x80) == 0x00 { 155 | return Err(Error::InvalidSignature); 156 | } 157 | 158 | let mut overflow = false; 159 | if self.peek(0)? & 0x80 == 0x80 { 160 | overflow |= true; 161 | } 162 | 163 | // Skip leading zero bytes 164 | while rlen > 0 && self.peek(0)? == 0 { 165 | rlen -= 1; 166 | self.read()?; 167 | } 168 | 169 | if rlen > 32 { 170 | overflow |= true; 171 | } 172 | 173 | let mut int = Scalar::default(); 174 | 175 | if !overflow { 176 | let mut b32 = [0u8; 32]; 177 | b32[32 - rlen..].copy_from_slice(self.peek_slice(rlen)?); 178 | self.skip(rlen)?; 179 | 180 | overflow |= bool::from(int.set_b32(&b32)); 181 | } 182 | 183 | if overflow { 184 | int = Scalar::default(); 185 | } 186 | 187 | Ok(int) 188 | } 189 | 190 | pub fn read_seq_len_lax(&mut self) -> Result { 191 | let mut len = self.read()?; 192 | if len & 0x80 != 0x00 { 193 | len -= 0x80; 194 | if len as usize > self.remaining_len() { 195 | return Err(Error::InvalidSignature); 196 | } 197 | self.skip(len as usize)?; 198 | } 199 | 200 | Ok(len as usize) 201 | } 202 | 203 | pub fn read_len_lax(&mut self) -> Result { 204 | let mut ret = 0usize; 205 | let mut len = self.read()?; 206 | if len & 0x80 != 0x00 { 207 | len -= 0x80; 208 | if len as usize > self.remaining_len() { 209 | return Err(Error::InvalidSignature); 210 | } 211 | while len > 0 && self.peek(0)? == 0 { 212 | self.skip(1)?; 213 | len -= 1; 214 | } 215 | if (len as usize) >= mem::size_of::() { 216 | return Err(Error::InvalidSignature); 217 | } 218 | while len > 0 { 219 | ret = (ret << 8) + (self.read()? as usize); 220 | len -= 1; 221 | } 222 | } else { 223 | ret = len as usize; 224 | } 225 | if ret > self.remaining_len() { 226 | return Err(Error::InvalidSignature); 227 | } 228 | 229 | Ok(ret) 230 | } 231 | 232 | pub fn read_integer_lax(&mut self) -> Result { 233 | // Integer tag byte. 234 | if self.read()? != 0x02 { 235 | return Err(Error::InvalidSignature); 236 | } 237 | 238 | let mut len = self.read_len_lax()?; 239 | 240 | // Ignore leading zeroes. 241 | while len > 0 && self.peek(0)? == 0 { 242 | len -= 1; 243 | self.skip(1)?; 244 | } 245 | 246 | let mut overflow = false; 247 | // Copy value 248 | if len > 32 { 249 | overflow |= true; 250 | } 251 | 252 | let mut int = Scalar::default(); 253 | 254 | if !overflow { 255 | let mut b32 = [0u8; 32]; 256 | b32[32 - len..].copy_from_slice(&self.peek_slice(len)?); 257 | self.skip(len)?; 258 | 259 | overflow |= bool::from(int.set_b32(&b32)); 260 | } 261 | 262 | if overflow { 263 | int = Scalar::default(); 264 | } 265 | 266 | Ok(int) 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /core/src/ecdh.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | ecmult::ECMultContext, 3 | group::{Affine, Jacobian}, 4 | scalar::Scalar, 5 | }; 6 | use digest::{generic_array::GenericArray, Digest}; 7 | 8 | impl ECMultContext { 9 | pub fn ecdh_raw( 10 | &self, 11 | point: &Affine, 12 | scalar: &Scalar, 13 | ) -> Option> { 14 | let mut digest: D = Default::default(); 15 | 16 | let mut pt = *point; 17 | let s = *scalar; 18 | 19 | if s.is_zero() { 20 | return None; 21 | } 22 | 23 | let mut res = Jacobian::default(); 24 | self.ecmult_const(&mut res, &pt, &s); 25 | pt.set_gej(&res); 26 | 27 | pt.x.normalize(); 28 | pt.y.normalize(); 29 | 30 | let x = pt.x.b32(); 31 | let y = 0x02 | (if pt.y.is_odd() { 1 } else { 0 }); 32 | 33 | digest.update(&[y]); 34 | digest.update(&x); 35 | Some(digest.finalize_reset()) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/src/ecdsa.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | ecmult::{ECMultContext, ECMultGenContext}, 3 | field::Field, 4 | group::{Affine, Jacobian}, 5 | scalar::Scalar, 6 | Error, 7 | }; 8 | 9 | const P_MINUS_ORDER: Field = Field::new(0, 0, 0, 1, 0x45512319, 0x50B75FC4, 0x402DA172, 0x2FC9BAEE); 10 | 11 | const ORDER_AS_FE: Field = Field::new( 12 | 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xBAAEDCE6, 0xAF48A03B, 0xBFD25E8C, 0xD0364141, 13 | ); 14 | 15 | impl ECMultContext { 16 | pub fn verify_raw( 17 | &self, 18 | sigr: &Scalar, 19 | sigs: &Scalar, 20 | pubkey: &Affine, 21 | message: &Scalar, 22 | ) -> bool { 23 | let c; 24 | let (sn, u1, u2): (Scalar, Scalar, Scalar); 25 | 26 | if sigr.is_zero() || sigs.is_zero() { 27 | return false; 28 | } 29 | 30 | sn = sigs.inv_var(); 31 | u1 = &sn * message; 32 | u2 = &sn * sigr; 33 | let mut pubkeyj: Jacobian = Jacobian::default(); 34 | pubkeyj.set_ge(pubkey); 35 | let mut pr: Jacobian = Jacobian::default(); 36 | self.ecmult(&mut pr, &pubkeyj, &u2, &u1); 37 | if pr.is_infinity() { 38 | return false; 39 | } 40 | 41 | c = sigr.b32(); 42 | let mut xr: Field = Default::default(); 43 | let _ = xr.set_b32(&c); 44 | 45 | if pr.eq_x_var(&xr) { 46 | return true; 47 | } 48 | if xr >= P_MINUS_ORDER { 49 | return false; 50 | } 51 | xr += ORDER_AS_FE; 52 | if pr.eq_x_var(&xr) { 53 | return true; 54 | } 55 | false 56 | } 57 | 58 | pub fn recover_raw( 59 | &self, 60 | sigr: &Scalar, 61 | sigs: &Scalar, 62 | rec_id: u8, 63 | message: &Scalar, 64 | ) -> Result { 65 | debug_assert!(rec_id < 4); 66 | 67 | if sigr.is_zero() || sigs.is_zero() { 68 | return Err(Error::InvalidSignature); 69 | } 70 | 71 | let brx = sigr.b32(); 72 | let mut fx = Field::default(); 73 | let overflow = fx.set_b32(&brx); 74 | debug_assert!(overflow); 75 | 76 | if rec_id & 2 > 0 { 77 | if fx >= P_MINUS_ORDER { 78 | return Err(Error::InvalidSignature); 79 | } 80 | fx += ORDER_AS_FE; 81 | } 82 | let mut x = Affine::default(); 83 | if !x.set_xo_var(&fx, rec_id & 1 > 0) { 84 | return Err(Error::InvalidSignature); 85 | } 86 | let mut xj = Jacobian::default(); 87 | xj.set_ge(&x); 88 | let rn = sigr.inv(); 89 | let mut u1 = &rn * message; 90 | u1 = -u1; 91 | let u2 = &rn * sigs; 92 | let mut qj = Jacobian::default(); 93 | self.ecmult(&mut qj, &xj, &u2, &u1); 94 | 95 | let mut pubkey = Affine::default(); 96 | pubkey.set_gej_var(&qj); 97 | 98 | if pubkey.is_infinity() { 99 | Err(Error::InvalidSignature) 100 | } else { 101 | Ok(pubkey) 102 | } 103 | } 104 | } 105 | 106 | impl ECMultGenContext { 107 | pub fn sign_raw( 108 | &self, 109 | seckey: &Scalar, 110 | message: &Scalar, 111 | nonce: &Scalar, 112 | ) -> Result<(Scalar, Scalar, u8), Error> { 113 | let mut rp = Jacobian::default(); 114 | self.ecmult_gen(&mut rp, nonce); 115 | let mut r = Affine::default(); 116 | r.set_gej(&rp); 117 | r.x.normalize(); 118 | r.y.normalize(); 119 | let b = r.x.b32(); 120 | let mut sigr = Scalar::default(); 121 | let overflow = bool::from(sigr.set_b32(&b)); 122 | debug_assert!(!sigr.is_zero()); 123 | debug_assert!(!overflow); 124 | 125 | let mut recid = (if overflow { 2 } else { 0 }) | (if r.y.is_odd() { 1 } else { 0 }); 126 | let mut n = &sigr * seckey; 127 | n += message; 128 | let mut sigs = nonce.inv(); 129 | sigs *= &n; 130 | n.clear(); 131 | rp.clear(); 132 | r.clear(); 133 | if sigs.is_zero() { 134 | return Err(Error::InvalidMessage); 135 | } 136 | if sigs.is_high() { 137 | sigs = -sigs; 138 | recid ^= 1; 139 | } 140 | Ok((sigr, sigs, recid)) 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /core/src/ecmult.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | field::Field, 3 | group::{globalz_set_table_gej, set_table_gej_var, Affine, AffineStorage, Jacobian, AFFINE_G}, 4 | scalar::Scalar, 5 | }; 6 | use alloc::{ 7 | alloc::{alloc, Layout}, 8 | boxed::Box, 9 | vec, 10 | vec::Vec, 11 | }; 12 | use subtle::Choice; 13 | 14 | pub const WINDOW_A: usize = 5; 15 | pub const WINDOW_G: usize = 16; 16 | pub const ECMULT_TABLE_SIZE_A: usize = 1 << (WINDOW_A - 2); 17 | pub const ECMULT_TABLE_SIZE_G: usize = 1 << (WINDOW_G - 2); 18 | pub const WNAF_BITS: usize = 256; 19 | 20 | fn odd_multiples_table_storage_var(pre: &mut [AffineStorage], a: &Jacobian) { 21 | let mut prej: Vec = Vec::with_capacity(pre.len()); 22 | for _ in 0..pre.len() { 23 | prej.push(Jacobian::default()); 24 | } 25 | let mut prea: Vec = Vec::with_capacity(pre.len()); 26 | for _ in 0..pre.len() { 27 | prea.push(Affine::default()); 28 | } 29 | let mut zr: Vec = Vec::with_capacity(pre.len()); 30 | for _ in 0..pre.len() { 31 | zr.push(Field::default()); 32 | } 33 | 34 | odd_multiples_table(&mut prej, &mut zr, a); 35 | set_table_gej_var(&mut prea, &prej, &zr); 36 | 37 | for i in 0..pre.len() { 38 | pre[i] = prea[i].into(); 39 | } 40 | } 41 | 42 | /// Context for accelerating the computation of a*P + b*G. 43 | pub struct ECMultContext { 44 | pre_g: [AffineStorage; ECMULT_TABLE_SIZE_G], 45 | } 46 | 47 | impl ECMultContext { 48 | /// Create a new `ECMultContext` from raw values. 49 | /// 50 | /// # Safety 51 | /// The function is unsafe because incorrect value of `pre_g` can lead to 52 | /// crypto logic failure. You most likely do not want to use this function, 53 | /// but `ECMultContext::new_boxed`. 54 | pub const unsafe fn new_from_raw(pre_g: [AffineStorage; ECMULT_TABLE_SIZE_G]) -> Self { 55 | Self { pre_g } 56 | } 57 | 58 | /// Inspect raw values of `ECMultContext`. 59 | pub fn inspect_raw(&self) -> &[AffineStorage; ECMULT_TABLE_SIZE_G] { 60 | &self.pre_g 61 | } 62 | 63 | /// Generate a new `ECMultContext` on the heap. Note that this function is expensive. 64 | pub fn new_boxed() -> Box { 65 | // This unsafe block allocates a new, unitialized `ECMultContext` and 66 | // then fills in the value. This is to avoid allocating it on stack 67 | // because the struct is big. All values in `ECMultContext` are manually 68 | // initialized after allocation. 69 | let mut this = unsafe { 70 | let ptr = alloc(Layout::new::()) as *mut ECMultContext; 71 | let mut this = Box::from_raw(ptr); 72 | 73 | for i in 0..ECMULT_TABLE_SIZE_G { 74 | this.pre_g[i] = AffineStorage::default(); 75 | } 76 | 77 | this 78 | }; 79 | 80 | let mut gj = Jacobian::default(); 81 | gj.set_ge(&AFFINE_G); 82 | odd_multiples_table_storage_var(&mut this.pre_g, &gj); 83 | 84 | this 85 | } 86 | } 87 | 88 | /// Set a batch of group elements equal to the inputs given in jacobian 89 | /// coordinates. Not constant time. 90 | pub fn set_all_gej_var(a: &[Jacobian]) -> Vec { 91 | let mut az: Vec = Vec::with_capacity(a.len()); 92 | for point in a { 93 | if !point.is_infinity() { 94 | az.push(point.z); 95 | } 96 | } 97 | let azi: Vec = inv_all_var(&az); 98 | 99 | let mut ret = vec![Affine::default(); a.len()]; 100 | 101 | let mut count = 0; 102 | for i in 0..a.len() { 103 | ret[i].infinity = a[i].infinity; 104 | if !a[i].is_infinity() { 105 | ret[i].set_gej_zinv(&a[i], &azi[count]); 106 | count += 1; 107 | } 108 | } 109 | ret 110 | } 111 | 112 | /// Calculate the (modular) inverses of a batch of field 113 | /// elements. Requires the inputs' magnitudes to be at most 8. The 114 | /// output magnitudes are 1 (but not guaranteed to be 115 | /// normalized). 116 | pub fn inv_all_var(fields: &[Field]) -> Vec { 117 | if fields.is_empty() { 118 | return Vec::new(); 119 | } 120 | 121 | let mut ret = Vec::with_capacity(fields.len()); 122 | ret.push(fields[0]); 123 | 124 | for i in 1..fields.len() { 125 | ret.push(Field::default()); 126 | ret[i] = ret[i - 1] * fields[i]; 127 | } 128 | 129 | let mut u = ret[fields.len() - 1].inv_var(); 130 | 131 | for i in (1..fields.len()).rev() { 132 | let j = i; 133 | let i = i - 1; 134 | ret[j] = ret[i] * u; 135 | u *= fields[j]; 136 | } 137 | 138 | ret[0] = u; 139 | ret 140 | } 141 | 142 | const GEN_BLIND: Scalar = Scalar([ 143 | 2217680822, 850875797, 1046150361, 1330484644, 4015777837, 2466086288, 2052467175, 2084507480, 144 | ]); 145 | const GEN_INITIAL: Jacobian = Jacobian { 146 | x: Field::new_raw( 147 | 586608, 43357028, 207667908, 262670128, 142222828, 38529388, 267186148, 45417712, 148 | 115291924, 13447464, 149 | ), 150 | y: Field::new_raw( 151 | 12696548, 208302564, 112025180, 191752716, 143238548, 145482948, 228906000, 69755164, 152 | 243572800, 210897016, 153 | ), 154 | z: Field::new_raw( 155 | 3685368, 75404844, 20246216, 5748944, 73206666, 107661790, 110806176, 73488774, 5707384, 156 | 104448710, 157 | ), 158 | infinity: false, 159 | }; 160 | 161 | /// Context for accelerating the computation of a*G. 162 | pub struct ECMultGenContext { 163 | prec: [[AffineStorage; 16]; 64], 164 | blind: Scalar, 165 | initial: Jacobian, 166 | } 167 | 168 | impl ECMultGenContext { 169 | /// Create a new `ECMultGenContext` from raw values. 170 | /// 171 | /// # Safety 172 | /// The function is unsafe because incorrect value of `pre_g` can lead to 173 | /// crypto logic failure. You most likely do not want to use this function, 174 | /// but `ECMultGenContext::new_boxed`. 175 | pub const unsafe fn new_from_raw(prec: [[AffineStorage; 16]; 64]) -> Self { 176 | Self { 177 | prec, 178 | blind: GEN_BLIND, 179 | initial: GEN_INITIAL, 180 | } 181 | } 182 | 183 | /// Inspect `ECMultGenContext` values. 184 | pub fn inspect_raw(&self) -> &[[AffineStorage; 16]; 64] { 185 | &self.prec 186 | } 187 | 188 | /// Generate a new `ECMultGenContext` on the heap. Note that this function is expensive. 189 | pub fn new_boxed() -> Box { 190 | // This unsafe block allocates a new, unitialized `ECMultGenContext` and 191 | // then fills in the value. This is to avoid allocating it on stack 192 | // because the struct is big. All values in `ECMultGenContext` are 193 | // manually initialized after allocation. 194 | let mut this = unsafe { 195 | let ptr = alloc(Layout::new::()) as *mut ECMultGenContext; 196 | let mut this = Box::from_raw(ptr); 197 | 198 | for j in 0..64 { 199 | for i in 0..16 { 200 | this.prec[j][i] = AffineStorage::default(); 201 | } 202 | } 203 | 204 | this.blind = GEN_BLIND; 205 | this.initial = GEN_INITIAL; 206 | 207 | this 208 | }; 209 | 210 | let mut gj = Jacobian::default(); 211 | gj.set_ge(&AFFINE_G); 212 | 213 | // Construct a group element with no known corresponding scalar (nothing up my sleeve). 214 | let mut nums_32 = [0u8; 32]; 215 | debug_assert!(b"The scalar for this x is unknown".len() == 32); 216 | for (i, v) in b"The scalar for this x is unknown".iter().enumerate() { 217 | nums_32[i] = *v; 218 | } 219 | let mut nums_x = Field::default(); 220 | assert!(nums_x.set_b32(&nums_32)); 221 | let mut nums_ge = Affine::default(); 222 | assert!(nums_ge.set_xo_var(&nums_x, false)); 223 | let mut nums_gej = Jacobian::default(); 224 | nums_gej.set_ge(&nums_ge); 225 | nums_gej = nums_gej.add_ge_var(&AFFINE_G, None); 226 | 227 | // Compute prec. 228 | let mut precj: Vec = Vec::with_capacity(1024); 229 | for _ in 0..1024 { 230 | precj.push(Jacobian::default()); 231 | } 232 | let mut gbase = gj; 233 | let mut numsbase = nums_gej; 234 | for j in 0..64 { 235 | precj[j * 16] = numsbase; 236 | for i in 1..16 { 237 | precj[j * 16 + i] = precj[j * 16 + i - 1].add_var(&gbase, None); 238 | } 239 | for _ in 0..4 { 240 | gbase = gbase.double_var(None); 241 | } 242 | numsbase = numsbase.double_var(None); 243 | if j == 62 { 244 | numsbase = numsbase.neg(); 245 | numsbase = numsbase.add_var(&nums_gej, None); 246 | } 247 | } 248 | let prec = set_all_gej_var(&precj); 249 | 250 | for j in 0..64 { 251 | for i in 0..16 { 252 | let pg: AffineStorage = prec[j * 16 + i].into(); 253 | this.prec[j][i] = pg; 254 | } 255 | } 256 | 257 | this 258 | } 259 | } 260 | 261 | pub fn odd_multiples_table(prej: &mut [Jacobian], zr: &mut [Field], a: &Jacobian) { 262 | debug_assert!(prej.len() == zr.len()); 263 | debug_assert!(!prej.is_empty()); 264 | debug_assert!(!a.is_infinity()); 265 | 266 | let d = a.double_var(None); 267 | let d_ge = Affine { 268 | x: d.x, 269 | y: d.y, 270 | infinity: false, 271 | }; 272 | 273 | let mut a_ge = Affine::default(); 274 | a_ge.set_gej_zinv(a, &d.z); 275 | prej[0].x = a_ge.x; 276 | prej[0].y = a_ge.y; 277 | prej[0].z = a.z; 278 | prej[0].infinity = false; 279 | 280 | zr[0] = d.z; 281 | for i in 1..prej.len() { 282 | prej[i] = prej[i - 1].add_ge_var(&d_ge, Some(&mut zr[i])); 283 | } 284 | 285 | let l = prej.last().unwrap().z * d.z; 286 | prej.last_mut().unwrap().z = l; 287 | } 288 | 289 | fn odd_multiples_table_globalz_windowa( 290 | pre: &mut [Affine; ECMULT_TABLE_SIZE_A], 291 | globalz: &mut Field, 292 | a: &Jacobian, 293 | ) { 294 | let mut prej: [Jacobian; ECMULT_TABLE_SIZE_A] = Default::default(); 295 | let mut zr: [Field; ECMULT_TABLE_SIZE_A] = Default::default(); 296 | 297 | odd_multiples_table(&mut prej, &mut zr, a); 298 | globalz_set_table_gej(pre, globalz, &prej, &zr); 299 | } 300 | 301 | fn table_get_ge(r: &mut Affine, pre: &[Affine], n: i32, w: usize) { 302 | debug_assert!(n & 1 == 1); 303 | debug_assert!(n >= -((1 << (w - 1)) - 1)); 304 | debug_assert!(n <= ((1 << (w - 1)) - 1)); 305 | if n > 0 { 306 | *r = pre[((n - 1) / 2) as usize]; 307 | } else { 308 | *r = pre[((-n - 1) / 2) as usize].neg(); 309 | } 310 | } 311 | 312 | fn table_get_ge_const(r: &mut Affine, pre: &[Affine], n: i32, w: usize) { 313 | let abs_n = n * (if n > 0 { 1 } else { 0 } * 2 - 1); 314 | let idx_n = abs_n / 2; 315 | debug_assert!(n & 1 == 1); 316 | debug_assert!(n >= -((1 << (w - 1)) - 1)); 317 | debug_assert!(n <= ((1 << (w - 1)) - 1)); 318 | for m in 0..pre.len() { 319 | let flag = m == idx_n as usize; 320 | r.x.cmov(&pre[m].x, flag); 321 | r.y.cmov(&pre[m].y, flag); 322 | } 323 | r.infinity = false; 324 | let neg_y = r.y.neg(1); 325 | r.y.cmov(&neg_y, n != abs_n); 326 | } 327 | 328 | fn table_get_ge_storage(r: &mut Affine, pre: &[AffineStorage], n: i32, w: usize) { 329 | debug_assert!(n & 1 == 1); 330 | debug_assert!(n >= -((1 << (w - 1)) - 1)); 331 | debug_assert!(n <= ((1 << (w - 1)) - 1)); 332 | if n > 0 { 333 | *r = pre[((n - 1) / 2) as usize].into(); 334 | } else { 335 | *r = pre[((-n - 1) / 2) as usize].into(); 336 | *r = r.neg(); 337 | } 338 | } 339 | 340 | pub fn ecmult_wnaf(wnaf: &mut [i32], a: &Scalar, w: usize) -> i32 { 341 | let mut s = *a; 342 | let mut last_set_bit: i32 = -1; 343 | let mut bit = 0; 344 | let mut sign = 1; 345 | let mut carry = 0; 346 | 347 | debug_assert!(wnaf.len() <= 256); 348 | debug_assert!(w >= 2 && w <= 31); 349 | 350 | for i in 0..wnaf.len() { 351 | wnaf[i] = 0; 352 | } 353 | 354 | if s.bits(255, 1) > 0 { 355 | s = -s; 356 | sign = -1; 357 | } 358 | 359 | while bit < wnaf.len() { 360 | let mut now; 361 | let mut word; 362 | if s.bits(bit, 1) == carry as u32 { 363 | bit += 1; 364 | continue; 365 | } 366 | 367 | now = w; 368 | if now > wnaf.len() - bit { 369 | now = wnaf.len() - bit; 370 | } 371 | 372 | word = (s.bits_var(bit, now) as i32) + carry; 373 | 374 | carry = (word >> (w - 1)) & 1; 375 | word -= carry << w; 376 | 377 | wnaf[bit] = sign * word; 378 | last_set_bit = bit as i32; 379 | 380 | bit += now; 381 | } 382 | debug_assert!(carry == 0); 383 | debug_assert!({ 384 | let mut t = true; 385 | while bit < 256 { 386 | t = t && (s.bits(bit, 1) == 0); 387 | bit += 1; 388 | } 389 | t 390 | }); 391 | last_set_bit + 1 392 | } 393 | 394 | pub fn ecmult_wnaf_const(wnaf: &mut [i32], a: &Scalar, w: usize) -> i32 { 395 | let mut s = *a; 396 | let mut word = 0; 397 | 398 | /* Note that we cannot handle even numbers by negating them to be 399 | * odd, as is done in other implementations, since if our scalars 400 | * were specified to have width < 256 for performance reasons, 401 | * their negations would have width 256 and we'd lose any 402 | * performance benefit. Instead, we use a technique from Section 403 | * 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for 404 | * even) or 2 (for odd) to the number we are encoding, returning a 405 | * skew value indicating this, and having the caller compensate 406 | * after doing the multiplication. */ 407 | 408 | /* Negative numbers will be negated to keep their bit 409 | * representation below the maximum width */ 410 | let flip = s.is_high(); 411 | /* We add 1 to even numbers, 2 to odd ones, noting that negation 412 | * flips parity */ 413 | let bit = flip ^ !s.is_even(); 414 | /* We add 1 to even numbers, 2 to odd ones, noting that negation 415 | * flips parity */ 416 | let neg_s = -s; 417 | let not_neg_one = !neg_s.is_one(); 418 | s.cadd_bit(if bit { 1 } else { 0 }, not_neg_one); 419 | /* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so 420 | * caller expects that we added two to it and flipped it. In fact 421 | * for -1 these operations are identical. We only flipped, but 422 | * since skewing is required (in the sense that the skew must be 1 423 | * or 2, never zero) and flipping is not, we need to change our 424 | * flags to claim that we only skewed. */ 425 | let mut global_sign = if flip { -1 } else { 1 }; 426 | s.cond_neg_assign(Choice::from(flip as u8)); 427 | global_sign *= if not_neg_one { 1 } else { 0 } * 2 - 1; 428 | let skew = 1 << (if bit { 1 } else { 0 }); 429 | 430 | let mut u_last: i32 = s.shr_int(w) as i32; 431 | let mut u: i32 = 0; 432 | while word * w < WNAF_BITS { 433 | u = s.shr_int(w) as i32; 434 | let even = (u & 1) == 0; 435 | let sign = 2 * (if u_last > 0 { 1 } else { 0 }) - 1; 436 | u += sign * if even { 1 } else { 0 }; 437 | u_last -= sign * if even { 1 } else { 0 } * (1 << w); 438 | 439 | wnaf[word] = (u_last as i32 * global_sign as i32) as i32; 440 | word += 1; 441 | 442 | u_last = u; 443 | } 444 | wnaf[word] = u * global_sign as i32; 445 | 446 | debug_assert!(s.is_zero()); 447 | let wnaf_size = (WNAF_BITS + w - 1) / w; 448 | debug_assert!(word == wnaf_size); 449 | 450 | skew 451 | } 452 | 453 | impl ECMultContext { 454 | pub fn ecmult(&self, r: &mut Jacobian, a: &Jacobian, na: &Scalar, ng: &Scalar) { 455 | let mut tmpa = Affine::default(); 456 | let mut pre_a: [Affine; ECMULT_TABLE_SIZE_A] = Default::default(); 457 | let mut z = Field::default(); 458 | let mut wnaf_na = [0i32; 256]; 459 | let mut wnaf_ng = [0i32; 256]; 460 | let bits_na = ecmult_wnaf(&mut wnaf_na, na, WINDOW_A); 461 | let mut bits = bits_na; 462 | odd_multiples_table_globalz_windowa(&mut pre_a, &mut z, a); 463 | 464 | let bits_ng = ecmult_wnaf(&mut wnaf_ng, &ng, WINDOW_G); 465 | if bits_ng > bits { 466 | bits = bits_ng; 467 | } 468 | 469 | r.set_infinity(); 470 | for i in (0..bits).rev() { 471 | let mut n; 472 | *r = r.double_var(None); 473 | 474 | n = wnaf_na[i as usize]; 475 | if i < bits_na && n != 0 { 476 | table_get_ge(&mut tmpa, &pre_a, n, WINDOW_A); 477 | *r = r.add_ge_var(&tmpa, None); 478 | } 479 | n = wnaf_ng[i as usize]; 480 | if i < bits_ng && n != 0 { 481 | table_get_ge_storage(&mut tmpa, &self.pre_g, n, WINDOW_G); 482 | *r = r.add_zinv_var(&tmpa, &z); 483 | } 484 | } 485 | 486 | if !r.is_infinity() { 487 | r.z *= &z; 488 | } 489 | } 490 | 491 | pub fn ecmult_const(&self, r: &mut Jacobian, a: &Affine, scalar: &Scalar) { 492 | const WNAF_SIZE: usize = (WNAF_BITS + (WINDOW_A - 1) - 1) / (WINDOW_A - 1); 493 | 494 | let mut tmpa = Affine::default(); 495 | let mut pre_a: [Affine; ECMULT_TABLE_SIZE_A] = Default::default(); 496 | let mut z = Field::default(); 497 | 498 | let mut wnaf_1 = [0i32; 1 + WNAF_SIZE]; 499 | 500 | let sc = *scalar; 501 | let skew_1 = ecmult_wnaf_const(&mut wnaf_1, &sc, WINDOW_A - 1); 502 | 503 | /* Calculate odd multiples of a. All multiples are brought to 504 | * the same Z 'denominator', which is stored in Z. Due to 505 | * secp256k1' isomorphism we can do all operations pretending 506 | * that the Z coordinate was 1, use affine addition formulae, 507 | * and correct the Z coordinate of the result once at the end. 508 | */ 509 | r.set_ge(a); 510 | odd_multiples_table_globalz_windowa(&mut pre_a, &mut z, r); 511 | for i in 0..ECMULT_TABLE_SIZE_A { 512 | pre_a[i].y.normalize_weak(); 513 | } 514 | 515 | /* first loop iteration (separated out so we can directly set 516 | * r, rather than having it start at infinity, get doubled 517 | * several times, then have its new value added to it) */ 518 | let i = wnaf_1[WNAF_SIZE]; 519 | debug_assert!(i != 0); 520 | table_get_ge_const(&mut tmpa, &pre_a, i, WINDOW_A); 521 | r.set_ge(&tmpa); 522 | 523 | /* remaining loop iterations */ 524 | for i in (0..WNAF_SIZE).rev() { 525 | for _ in 0..(WINDOW_A - 1) { 526 | let r2 = *r; 527 | r.double_nonzero_in_place(&r2, None); 528 | } 529 | 530 | let n = wnaf_1[i]; 531 | table_get_ge_const(&mut tmpa, &pre_a, n, WINDOW_A); 532 | debug_assert!(n != 0); 533 | *r = r.add_ge(&tmpa); 534 | } 535 | 536 | r.z *= &z; 537 | 538 | /* Correct for wNAF skew */ 539 | let mut correction = *a; 540 | let mut correction_1_stor: AffineStorage; 541 | let a2_stor: AffineStorage; 542 | let mut tmpj = Jacobian::default(); 543 | tmpj.set_ge(&correction); 544 | tmpj = tmpj.double_var(None); 545 | correction.set_gej(&tmpj); 546 | correction_1_stor = (*a).into(); 547 | a2_stor = correction.into(); 548 | 549 | /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */ 550 | correction_1_stor.cmov(&a2_stor, skew_1 == 2); 551 | 552 | /* Apply the correction */ 553 | correction = correction_1_stor.into(); 554 | correction = correction.neg(); 555 | *r = r.add_ge(&correction) 556 | } 557 | } 558 | 559 | impl ECMultGenContext { 560 | pub fn ecmult_gen(&self, r: &mut Jacobian, gn: &Scalar) { 561 | let mut adds = AffineStorage::default(); 562 | *r = self.initial; 563 | 564 | let mut gnb = gn + &self.blind; 565 | let mut add = Affine::default(); 566 | add.infinity = false; 567 | 568 | for j in 0..64 { 569 | let mut bits = gnb.bits(j * 4, 4); 570 | for i in 0..16 { 571 | adds.cmov(&self.prec[j][i], i as u32 == bits); 572 | } 573 | add = adds.into(); 574 | *r = r.add_ge(&add); 575 | #[allow(unused_assignments)] 576 | { 577 | bits = 0; 578 | } 579 | } 580 | add.clear(); 581 | gnb.clear(); 582 | } 583 | } 584 | -------------------------------------------------------------------------------- /core/src/error.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 2 | pub enum Error { 3 | InvalidSignature, 4 | InvalidPublicKey, 5 | InvalidSecretKey, 6 | InvalidRecoveryId, 7 | InvalidMessage, 8 | InvalidInputLength, 9 | TweakOutOfRange, 10 | InvalidAffine, 11 | } 12 | 13 | #[cfg(feature = "std")] 14 | impl std::error::Error for Error {} 15 | 16 | impl core::fmt::Display for Error { 17 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 18 | match self { 19 | Error::InvalidSignature => write!(f, "Invalid signature"), 20 | Error::InvalidPublicKey => write!(f, "Invalid public key"), 21 | Error::InvalidSecretKey => write!(f, "Invalid secret key"), 22 | Error::InvalidRecoveryId => write!(f, "Invalid recovery ID"), 23 | Error::InvalidMessage => write!(f, "Invalid message"), 24 | Error::InvalidInputLength => write!(f, "Invalid input length"), 25 | Error::TweakOutOfRange => write!(f, "Tweak out of range"), 26 | Error::InvalidAffine => write!(f, "Invalid Affine"), 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/group.rs: -------------------------------------------------------------------------------- 1 | use crate::field::{Field, FieldStorage}; 2 | 3 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 4 | /// A group element of the secp256k1 curve, in affine coordinates. 5 | pub struct Affine { 6 | pub x: Field, 7 | pub y: Field, 8 | pub infinity: bool, 9 | } 10 | 11 | #[derive(Debug, Clone, Copy)] 12 | /// A group element of the secp256k1 curve, in jacobian coordinates. 13 | pub struct Jacobian { 14 | pub x: Field, 15 | pub y: Field, 16 | pub z: Field, 17 | pub infinity: bool, 18 | } 19 | 20 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 21 | /// Affine coordinate group element compact storage. 22 | pub struct AffineStorage { 23 | pub x: FieldStorage, 24 | pub y: FieldStorage, 25 | } 26 | 27 | impl Default for Affine { 28 | fn default() -> Affine { 29 | Affine { 30 | x: Field::default(), 31 | y: Field::default(), 32 | infinity: false, 33 | } 34 | } 35 | } 36 | 37 | impl Default for Jacobian { 38 | fn default() -> Jacobian { 39 | Jacobian { 40 | x: Field::default(), 41 | y: Field::default(), 42 | z: Field::default(), 43 | infinity: false, 44 | } 45 | } 46 | } 47 | 48 | impl Default for AffineStorage { 49 | fn default() -> AffineStorage { 50 | AffineStorage { 51 | x: FieldStorage::default(), 52 | y: FieldStorage::default(), 53 | } 54 | } 55 | } 56 | 57 | pub static AFFINE_INFINITY: Affine = Affine { 58 | x: Field::new(0, 0, 0, 0, 0, 0, 0, 0), 59 | y: Field::new(0, 0, 0, 0, 0, 0, 0, 0), 60 | infinity: true, 61 | }; 62 | 63 | pub static JACOBIAN_INFINITY: Jacobian = Jacobian { 64 | x: Field::new(0, 0, 0, 0, 0, 0, 0, 0), 65 | y: Field::new(0, 0, 0, 0, 0, 0, 0, 0), 66 | z: Field::new(0, 0, 0, 0, 0, 0, 0, 0), 67 | infinity: true, 68 | }; 69 | 70 | pub static AFFINE_G: Affine = Affine::new( 71 | Field::new( 72 | 0x79BE667E, 0xF9DCBBAC, 0x55A06295, 0xCE870B07, 0x029BFCDB, 0x2DCE28D9, 0x59F2815B, 73 | 0x16F81798, 74 | ), 75 | Field::new( 76 | 0x483ADA77, 0x26A3C465, 0x5DA4FBFC, 0x0E1108A8, 0xFD17B448, 0xA6855419, 0x9C47D08F, 77 | 0xFB10D4B8, 78 | ), 79 | ); 80 | 81 | pub const CURVE_B: u32 = 7; 82 | 83 | impl Affine { 84 | /// Create a new affine. 85 | pub const fn new(x: Field, y: Field) -> Self { 86 | Self { 87 | x, 88 | y, 89 | infinity: false, 90 | } 91 | } 92 | 93 | /// Set a group element equal to the point with given X and Y 94 | /// coordinates. 95 | pub fn set_xy(&mut self, x: &Field, y: &Field) { 96 | self.infinity = false; 97 | self.x = *x; 98 | self.y = *y; 99 | } 100 | 101 | /// Set a group element (affine) equal to the point with the given 102 | /// X coordinate and a Y coordinate that is a quadratic residue 103 | /// modulo p. The return value is true iff a coordinate with the 104 | /// given X coordinate exists. 105 | pub fn set_xquad(&mut self, x: &Field) -> bool { 106 | self.x = *x; 107 | let x2 = x.sqr(); 108 | let x3 = *x * x2; 109 | self.infinity = false; 110 | let mut c = Field::default(); 111 | c.set_int(CURVE_B); 112 | c += x3; 113 | let (v, ret) = c.sqrt(); 114 | self.y = v; 115 | ret 116 | } 117 | 118 | /// Set a group element (affine) equal to the point with the given 119 | /// X coordinate, and given oddness for Y. Return value indicates 120 | /// whether the result is valid. 121 | pub fn set_xo_var(&mut self, x: &Field, odd: bool) -> bool { 122 | if !self.set_xquad(x) { 123 | return false; 124 | } 125 | self.y.normalize_var(); 126 | if self.y.is_odd() != odd { 127 | self.y = self.y.neg(1); 128 | } 129 | true 130 | } 131 | 132 | /// Check whether a group element is the point at infinity. 133 | pub fn is_infinity(&self) -> bool { 134 | self.infinity 135 | } 136 | 137 | /// Check whether a group element is valid (i.e., on the curve). 138 | pub fn is_valid_var(&self) -> bool { 139 | if self.is_infinity() { 140 | return false; 141 | } 142 | let y2 = self.y.sqr(); 143 | let mut x3 = self.x.sqr(); 144 | x3 *= &self.x; 145 | let mut c = Field::default(); 146 | c.set_int(CURVE_B); 147 | x3 += &c; 148 | x3.normalize_weak(); 149 | y2.eq_var(&x3) 150 | } 151 | 152 | pub fn neg_in_place(&mut self, other: &Affine) { 153 | *self = *other; 154 | self.y.normalize_weak(); 155 | self.y = self.y.neg(1); 156 | } 157 | 158 | pub fn neg(&self) -> Affine { 159 | let mut ret = Affine::default(); 160 | ret.neg_in_place(self); 161 | ret 162 | } 163 | 164 | /// Set a group element equal to another which is given in 165 | /// jacobian coordinates. 166 | pub fn set_gej(&mut self, a: &Jacobian) { 167 | self.infinity = a.infinity; 168 | let mut a = *a; 169 | a.z = a.z.inv(); 170 | let z2 = a.z.sqr(); 171 | let z3 = a.z * z2; 172 | a.x *= z2; 173 | a.y *= z3; 174 | a.z.set_int(1); 175 | self.x = a.x; 176 | self.y = a.y; 177 | } 178 | 179 | pub fn from_gej(a: &Jacobian) -> Self { 180 | let mut ge = Self::default(); 181 | ge.set_gej(a); 182 | ge 183 | } 184 | 185 | pub fn set_gej_var(&mut self, a: &Jacobian) { 186 | let mut a = *a; 187 | self.infinity = a.infinity; 188 | if a.is_infinity() { 189 | return; 190 | } 191 | a.z = a.z.inv_var(); 192 | let z2 = a.z.sqr(); 193 | let z3 = a.z * z2; 194 | a.x *= &z2; 195 | a.y *= &z3; 196 | a.z.set_int(1); 197 | self.x = a.x; 198 | self.y = a.y; 199 | } 200 | 201 | pub fn set_gej_zinv(&mut self, a: &Jacobian, zi: &Field) { 202 | let zi2 = zi.sqr(); 203 | let zi3 = zi2 * *zi; 204 | self.x = a.x * zi2; 205 | self.y = a.y * zi3; 206 | self.infinity = a.infinity; 207 | } 208 | 209 | /// Clear a secp256k1_ge to prevent leaking sensitive information. 210 | pub fn clear(&mut self) { 211 | self.infinity = false; 212 | self.x.clear(); 213 | self.y.clear(); 214 | } 215 | } 216 | 217 | pub fn set_table_gej_var(r: &mut [Affine], a: &[Jacobian], zr: &[Field]) { 218 | debug_assert!(r.len() == a.len()); 219 | 220 | let mut i = r.len() - 1; 221 | let mut zi: Field; 222 | 223 | if !r.is_empty() { 224 | zi = a[i].z.inv(); 225 | r[i].set_gej_zinv(&a[i], &zi); 226 | 227 | while i > 0 { 228 | zi *= &zr[i]; 229 | i -= 1; 230 | r[i].set_gej_zinv(&a[i], &zi); 231 | } 232 | } 233 | } 234 | 235 | pub fn globalz_set_table_gej(r: &mut [Affine], globalz: &mut Field, a: &[Jacobian], zr: &[Field]) { 236 | debug_assert!(r.len() == a.len() && a.len() == zr.len()); 237 | 238 | let mut i = r.len() - 1; 239 | let mut zs: Field; 240 | 241 | if !r.is_empty() { 242 | r[i].x = a[i].x; 243 | r[i].y = a[i].y; 244 | *globalz = a[i].z; 245 | r[i].infinity = false; 246 | zs = zr[i]; 247 | 248 | while i > 0 { 249 | if i != r.len() - 1 { 250 | zs *= zr[i]; 251 | } 252 | i -= 1; 253 | r[i].set_gej_zinv(&a[i], &zs); 254 | } 255 | } 256 | } 257 | 258 | impl Jacobian { 259 | /// Create a new jacobian. 260 | pub const fn new(x: Field, y: Field) -> Self { 261 | Self { 262 | x, 263 | y, 264 | infinity: false, 265 | z: Field::new(0, 0, 0, 0, 0, 0, 0, 1), 266 | } 267 | } 268 | 269 | /// Set a group element (jacobian) equal to the point at infinity. 270 | pub fn set_infinity(&mut self) { 271 | self.infinity = true; 272 | self.x.clear(); 273 | self.y.clear(); 274 | self.z.clear(); 275 | } 276 | 277 | /// Set a group element (jacobian) equal to another which is given 278 | /// in affine coordinates. 279 | pub fn set_ge(&mut self, a: &Affine) { 280 | self.infinity = a.infinity; 281 | self.x = a.x; 282 | self.y = a.y; 283 | self.z.set_int(1); 284 | } 285 | 286 | pub fn from_ge(a: &Affine) -> Self { 287 | let mut gej = Self::default(); 288 | gej.set_ge(a); 289 | gej 290 | } 291 | 292 | /// Compare the X coordinate of a group element (jacobian). 293 | pub fn eq_x_var(&self, x: &Field) -> bool { 294 | debug_assert!(!self.is_infinity()); 295 | let mut r = self.z.sqr(); 296 | r *= x; 297 | let mut r2 = self.x; 298 | r2.normalize_weak(); 299 | r.eq_var(&r2) 300 | } 301 | 302 | /// Set r equal to the inverse of a (i.e., mirrored around the X 303 | /// axis). 304 | pub fn neg_in_place(&mut self, a: &Jacobian) { 305 | self.infinity = a.infinity; 306 | self.x = a.x; 307 | self.y = a.y; 308 | self.z = a.z; 309 | self.y.normalize_weak(); 310 | self.y = self.y.neg(1); 311 | } 312 | 313 | pub fn neg(&self) -> Jacobian { 314 | let mut ret = Jacobian::default(); 315 | ret.neg_in_place(self); 316 | ret 317 | } 318 | 319 | /// Check whether a group element is the point at infinity. 320 | pub fn is_infinity(&self) -> bool { 321 | self.infinity 322 | } 323 | 324 | /// Check whether a group element's y coordinate is a quadratic residue. 325 | pub fn has_quad_y_var(&self) -> bool { 326 | if self.infinity { 327 | return false; 328 | } 329 | 330 | let yz = self.y * self.z; 331 | yz.is_quad_var() 332 | } 333 | 334 | /// Set r equal to the double of a. If rzr is not-NULL, r->z = 335 | /// a->z * *rzr (where infinity means an implicit z = 0). a may 336 | /// not be zero. Constant time. 337 | pub fn double_nonzero_in_place(&mut self, a: &Jacobian, rzr: Option<&mut Field>) { 338 | debug_assert!(!self.is_infinity()); 339 | self.double_var_in_place(a, rzr); 340 | } 341 | 342 | /// Set r equal to the double of a. If rzr is not-NULL, r->z = 343 | /// a->z * *rzr (where infinity means an implicit z = 0). 344 | pub fn double_var_in_place(&mut self, a: &Jacobian, rzr: Option<&mut Field>) { 345 | self.infinity = a.infinity; 346 | if self.infinity { 347 | if let Some(rzr) = rzr { 348 | rzr.set_int(1); 349 | } 350 | return; 351 | } 352 | 353 | if let Some(rzr) = rzr { 354 | *rzr = a.y; 355 | rzr.normalize_weak(); 356 | rzr.mul_int(2); 357 | } 358 | 359 | self.z = a.z * a.y; 360 | self.z.mul_int(2); 361 | let mut t1 = a.x.sqr(); 362 | t1.mul_int(3); 363 | let mut t2 = t1.sqr(); 364 | let mut t3 = a.y.sqr(); 365 | t3.mul_int(2); 366 | let mut t4 = t3.sqr(); 367 | t4.mul_int(2); 368 | t3 *= &a.x; 369 | self.x = t3; 370 | self.x.mul_int(4); 371 | self.x = self.x.neg(4); 372 | self.x += &t2; 373 | t2 = t2.neg(1); 374 | t3.mul_int(6); 375 | t3 += &t2; 376 | self.y = t1 * t3; 377 | t2 = t4.neg(2); 378 | self.y += t2; 379 | } 380 | 381 | pub fn double_var(&self, rzr: Option<&mut Field>) -> Jacobian { 382 | let mut ret = Jacobian::default(); 383 | ret.double_var_in_place(&self, rzr); 384 | ret 385 | } 386 | 387 | /// Set r equal to the sum of a and b. If rzr is non-NULL, r->z = 388 | /// a->z * *rzr (a cannot be infinity in that case). 389 | pub fn add_var_in_place(&mut self, a: &Jacobian, b: &Jacobian, rzr: Option<&mut Field>) { 390 | if a.is_infinity() { 391 | debug_assert!(rzr.is_none()); 392 | *self = *b; 393 | return; 394 | } 395 | if b.is_infinity() { 396 | if let Some(rzr) = rzr { 397 | rzr.set_int(1); 398 | } 399 | *self = *a; 400 | return; 401 | } 402 | 403 | self.infinity = false; 404 | let z22 = b.z.sqr(); 405 | let z12 = a.z.sqr(); 406 | let u1 = a.x * z22; 407 | let u2 = b.x * z12; 408 | let mut s1 = a.y * z22; 409 | s1 *= b.z; 410 | let mut s2 = b.y * z12; 411 | s2 *= a.z; 412 | let mut h = u1.neg(1); 413 | h += u2; 414 | let mut i = s1.neg(1); 415 | i += s2; 416 | if h.normalizes_to_zero_var() { 417 | if i.normalizes_to_zero_var() { 418 | self.double_var_in_place(a, rzr); 419 | } else { 420 | if let Some(rzr) = rzr { 421 | rzr.set_int(0); 422 | } 423 | self.infinity = true; 424 | } 425 | return; 426 | } 427 | let i2 = i.sqr(); 428 | let h2 = h.sqr(); 429 | let mut h3 = h * h2; 430 | h *= b.z; 431 | if let Some(rzr) = rzr { 432 | *rzr = h; 433 | } 434 | self.z = a.z * h; 435 | let t = u1 * h2; 436 | self.x = t; 437 | self.x.mul_int(2); 438 | self.x += h3; 439 | self.x = self.x.neg(3); 440 | self.x += i2; 441 | self.y = self.x.neg(5); 442 | self.y += t; 443 | self.y *= i; 444 | h3 *= s1; 445 | h3 = h3.neg(1); 446 | self.y += h3; 447 | } 448 | 449 | pub fn add_var(&self, b: &Jacobian, rzr: Option<&mut Field>) -> Jacobian { 450 | let mut ret = Jacobian::default(); 451 | ret.add_var_in_place(self, b, rzr); 452 | ret 453 | } 454 | 455 | /// Set r equal to the sum of a and b (with b given in affine 456 | /// coordinates, and not infinity). 457 | pub fn add_ge_in_place(&mut self, a: &Jacobian, b: &Affine) { 458 | const FE1: Field = Field::new(0, 0, 0, 0, 0, 0, 0, 1); 459 | 460 | debug_assert!(!b.infinity); 461 | 462 | let zz = a.z.sqr(); 463 | let mut u1 = a.x; 464 | u1.normalize_weak(); 465 | let u2 = b.x * zz; 466 | let mut s1 = a.y; 467 | s1.normalize_weak(); 468 | let mut s2 = b.y * zz; 469 | s2 *= a.z; 470 | let mut t = u1; 471 | t += u2; 472 | let mut m = s1; 473 | m += s2; 474 | let mut rr = t.sqr(); 475 | let mut m_alt = u2.neg(1); 476 | let tt = u1 * m_alt; 477 | rr += tt; 478 | let degenerate = m.normalizes_to_zero() && rr.normalizes_to_zero(); 479 | let mut rr_alt = s1; 480 | rr_alt.mul_int(2); 481 | m_alt += u1; 482 | 483 | rr_alt.cmov(&rr, !degenerate); 484 | m_alt.cmov(&m, !degenerate); 485 | 486 | let mut n = m_alt.sqr(); 487 | let mut q = n * t; 488 | 489 | n = n.sqr(); 490 | n.cmov(&m, degenerate); 491 | t = rr_alt.sqr(); 492 | self.z = a.z * m_alt; 493 | let infinity = { 494 | let p = self.z.normalizes_to_zero(); 495 | let q = a.infinity; 496 | 497 | match (p, q) { 498 | (true, true) => false, 499 | (true, false) => true, 500 | (false, true) => false, 501 | (false, false) => false, 502 | } 503 | }; 504 | self.z.mul_int(2); 505 | q = q.neg(1); 506 | t += q; 507 | t.normalize_weak(); 508 | self.x = t; 509 | t.mul_int(2); 510 | t += q; 511 | t *= rr_alt; 512 | t += n; 513 | self.y = t.neg(3); 514 | self.y.normalize_weak(); 515 | self.x.mul_int(4); 516 | self.y.mul_int(4); 517 | 518 | self.x.cmov(&b.x, a.infinity); 519 | self.y.cmov(&b.y, a.infinity); 520 | self.z.cmov(&FE1, a.infinity); 521 | self.infinity = infinity; 522 | } 523 | 524 | pub fn add_ge(&self, b: &Affine) -> Jacobian { 525 | let mut ret = Jacobian::default(); 526 | ret.add_ge_in_place(self, b); 527 | ret 528 | } 529 | 530 | /// Set r equal to the sum of a and b (with b given in affine 531 | /// coordinates). This is more efficient than 532 | /// secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge 533 | /// but without constant-time guarantee, and b is allowed to be 534 | /// infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be 535 | /// infinity in that case). 536 | pub fn add_ge_var_in_place(&mut self, a: &Jacobian, b: &Affine, rzr: Option<&mut Field>) { 537 | if a.is_infinity() { 538 | debug_assert!(rzr.is_none()); 539 | self.set_ge(b); 540 | return; 541 | } 542 | if b.is_infinity() { 543 | if let Some(rzr) = rzr { 544 | rzr.set_int(1); 545 | } 546 | *self = *a; 547 | return; 548 | } 549 | self.infinity = false; 550 | 551 | let z12 = a.z.sqr(); 552 | let mut u1 = a.x; 553 | u1.normalize_weak(); 554 | let u2 = b.x * z12; 555 | let mut s1 = a.y; 556 | s1.normalize_weak(); 557 | let mut s2 = b.y * z12; 558 | s2 *= a.z; 559 | let mut h = u1.neg(1); 560 | h += u2; 561 | let mut i = s1.neg(1); 562 | i += s2; 563 | if h.normalizes_to_zero_var() { 564 | if i.normalizes_to_zero_var() { 565 | self.double_var_in_place(a, rzr); 566 | } else { 567 | if let Some(rzr) = rzr { 568 | rzr.set_int(0); 569 | } 570 | self.infinity = true; 571 | } 572 | return; 573 | } 574 | let i2 = i.sqr(); 575 | let h2 = h.sqr(); 576 | let mut h3 = h * h2; 577 | if let Some(rzr) = rzr { 578 | *rzr = h; 579 | } 580 | self.z = a.z * h; 581 | let t = u1 * h2; 582 | self.x = t; 583 | self.x.mul_int(2); 584 | self.x += h3; 585 | self.x = self.x.neg(3); 586 | self.x += i2; 587 | self.y = self.x.neg(5); 588 | self.y += t; 589 | self.y *= i; 590 | h3 *= s1; 591 | h3 = h3.neg(1); 592 | self.y += h3; 593 | } 594 | 595 | pub fn add_ge_var(&self, b: &Affine, rzr: Option<&mut Field>) -> Jacobian { 596 | let mut ret = Jacobian::default(); 597 | ret.add_ge_var_in_place(&self, b, rzr); 598 | ret 599 | } 600 | 601 | /// Set r equal to the sum of a and b (with the inverse of b's Z 602 | /// coordinate passed as bzinv). 603 | pub fn add_zinv_var_in_place(&mut self, a: &Jacobian, b: &Affine, bzinv: &Field) { 604 | if b.is_infinity() { 605 | *self = *a; 606 | return; 607 | } 608 | if a.is_infinity() { 609 | self.infinity = b.infinity; 610 | let bzinv2 = bzinv.sqr(); 611 | let bzinv3 = &bzinv2 * bzinv; 612 | self.x = b.x * bzinv2; 613 | self.y = b.y * bzinv3; 614 | self.z.set_int(1); 615 | return; 616 | } 617 | self.infinity = false; 618 | 619 | let az = a.z * *bzinv; 620 | let z12 = az.sqr(); 621 | let mut u1 = a.x; 622 | u1.normalize_weak(); 623 | let u2 = b.x * z12; 624 | let mut s1 = a.y; 625 | s1.normalize_weak(); 626 | let mut s2 = b.y * z12; 627 | s2 *= &az; 628 | let mut h = u1.neg(1); 629 | h += &u2; 630 | let mut i = s1.neg(1); 631 | i += &s2; 632 | if h.normalizes_to_zero_var() { 633 | if i.normalizes_to_zero_var() { 634 | self.double_var_in_place(a, None); 635 | } else { 636 | self.infinity = true; 637 | } 638 | return; 639 | } 640 | let i2 = i.sqr(); 641 | let h2 = h.sqr(); 642 | let mut h3 = h * h2; 643 | self.z = a.z; 644 | self.z *= h; 645 | let t = u1 * h2; 646 | self.x = t; 647 | self.x.mul_int(2); 648 | self.x += h3; 649 | self.x = self.x.neg(3); 650 | self.x += i2; 651 | self.y = self.x.neg(5); 652 | self.y += t; 653 | self.y *= i; 654 | h3 *= s1; 655 | h3 = h3.neg(1); 656 | self.y += h3; 657 | } 658 | 659 | pub fn add_zinv_var(&mut self, b: &Affine, bzinv: &Field) -> Jacobian { 660 | let mut ret = Jacobian::default(); 661 | ret.add_zinv_var_in_place(&self, b, bzinv); 662 | ret 663 | } 664 | 665 | /// Clear a secp256k1_gej to prevent leaking sensitive 666 | /// information. 667 | pub fn clear(&mut self) { 668 | self.infinity = false; 669 | self.x.clear(); 670 | self.y.clear(); 671 | self.z.clear(); 672 | } 673 | 674 | /// Rescale a jacobian point by b which must be 675 | /// non-zero. Constant-time. 676 | pub fn rescale(&mut self, s: &Field) { 677 | debug_assert!(!s.is_zero()); 678 | let zz = s.sqr(); 679 | self.x *= &zz; 680 | self.y *= &zz; 681 | self.y *= s; 682 | self.z *= s; 683 | } 684 | } 685 | 686 | impl From for Affine { 687 | fn from(a: AffineStorage) -> Affine { 688 | Affine::new(a.x.into(), a.y.into()) 689 | } 690 | } 691 | 692 | impl Into for Affine { 693 | fn into(mut self) -> AffineStorage { 694 | debug_assert!(!self.is_infinity()); 695 | self.x.normalize(); 696 | self.y.normalize(); 697 | AffineStorage::new(self.x.into(), self.y.into()) 698 | } 699 | } 700 | 701 | impl AffineStorage { 702 | /// Create a new affine storage. 703 | pub const fn new(x: FieldStorage, y: FieldStorage) -> Self { 704 | Self { x, y } 705 | } 706 | 707 | /// If flag is true, set *r equal to *a; otherwise leave 708 | /// it. Constant-time. 709 | pub fn cmov(&mut self, a: &AffineStorage, flag: bool) { 710 | self.x.cmov(&a.x, flag); 711 | self.y.cmov(&a.y, flag); 712 | } 713 | } 714 | -------------------------------------------------------------------------------- /core/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Core libraries for libsecp256k1. 2 | 3 | #![allow( 4 | clippy::cast_ptr_alignment, 5 | clippy::identity_op, 6 | clippy::many_single_char_names, 7 | clippy::needless_range_loop, 8 | clippy::suspicious_op_assign_impl, 9 | clippy::too_many_arguments, 10 | clippy::type_complexity 11 | )] 12 | #![deny( 13 | unused_import_braces, 14 | unused_imports, 15 | unused_comparisons, 16 | unused_must_use, 17 | unused_variables, 18 | non_shorthand_field_patterns, 19 | unreachable_code, 20 | unused_parens 21 | )] 22 | #![cfg_attr(not(feature = "std"), no_std)] 23 | extern crate alloc; 24 | 25 | #[macro_use] 26 | mod field; 27 | #[macro_use] 28 | mod group; 29 | mod der; 30 | mod ecdh; 31 | mod ecdsa; 32 | mod ecmult; 33 | mod error; 34 | mod scalar; 35 | 36 | pub use crate::error::Error; 37 | 38 | /// Curve related structs. 39 | pub mod curve { 40 | pub use crate::{ 41 | field::{Field, FieldStorage}, 42 | group::{Affine, AffineStorage, Jacobian, AFFINE_G, CURVE_B}, 43 | scalar::Scalar, 44 | }; 45 | 46 | pub use crate::ecmult::{ECMultContext, ECMultGenContext}; 47 | } 48 | 49 | /// Utilities to manipulate the secp256k1 curve parameters. 50 | pub mod util { 51 | pub const TAG_PUBKEY_EVEN: u8 = 0x02; 52 | pub const TAG_PUBKEY_ODD: u8 = 0x03; 53 | pub const TAG_PUBKEY_FULL: u8 = 0x04; 54 | pub const TAG_PUBKEY_HYBRID_EVEN: u8 = 0x06; 55 | pub const TAG_PUBKEY_HYBRID_ODD: u8 = 0x07; 56 | 57 | pub const MESSAGE_SIZE: usize = 32; 58 | pub const SECRET_KEY_SIZE: usize = 32; 59 | pub const RAW_PUBLIC_KEY_SIZE: usize = 64; 60 | pub const FULL_PUBLIC_KEY_SIZE: usize = 65; 61 | pub const COMPRESSED_PUBLIC_KEY_SIZE: usize = 33; 62 | pub const SIGNATURE_SIZE: usize = 64; 63 | pub const DER_MAX_SIGNATURE_SIZE: usize = 72; 64 | 65 | pub use crate::{ 66 | ecmult::{ 67 | odd_multiples_table, ECMULT_TABLE_SIZE_A, ECMULT_TABLE_SIZE_G, WINDOW_A, WINDOW_G, 68 | }, 69 | group::{globalz_set_table_gej, set_table_gej_var, AFFINE_INFINITY, JACOBIAN_INFINITY}, 70 | }; 71 | 72 | pub use crate::der::{Decoder, SignatureArray}; 73 | } 74 | -------------------------------------------------------------------------------- /core/src/scalar.rs: -------------------------------------------------------------------------------- 1 | use core::ops::{Add, AddAssign, Mul, MulAssign, Neg}; 2 | use crunchy::unroll; 3 | use subtle::Choice; 4 | 5 | const SECP256K1_N: [u32; 8] = [ 6 | 0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 7 | ]; 8 | 9 | const SECP256K1_N_C_0: u32 = !SECP256K1_N[0] + 1; 10 | const SECP256K1_N_C_1: u32 = !SECP256K1_N[1]; 11 | const SECP256K1_N_C_2: u32 = !SECP256K1_N[2]; 12 | const SECP256K1_N_C_3: u32 = !SECP256K1_N[3]; 13 | const SECP256K1_N_C_4: u32 = 1; 14 | 15 | const SECP256K1_N_H_0: u32 = 0x681B20A0; 16 | const SECP256K1_N_H_1: u32 = 0xDFE92F46; 17 | const SECP256K1_N_H_2: u32 = 0x57A4501D; 18 | const SECP256K1_N_H_3: u32 = 0x5D576E73; 19 | const SECP256K1_N_H_4: u32 = 0xFFFFFFFF; 20 | const SECP256K1_N_H_5: u32 = 0xFFFFFFFF; 21 | const SECP256K1_N_H_6: u32 = 0xFFFFFFFF; 22 | const SECP256K1_N_H_7: u32 = 0x7FFFFFFF; 23 | 24 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 25 | /// A 256-bit scalar value. 26 | pub struct Scalar(pub [u32; 8]); 27 | 28 | impl Scalar { 29 | /// Clear a scalar to prevent the leak of sensitive data. 30 | pub fn clear(&mut self) { 31 | unsafe { 32 | core::ptr::write_volatile(&mut self.0, [0u32; 8]); 33 | } 34 | } 35 | 36 | /// Set a scalar to an unsigned integer. 37 | pub fn set_int(&mut self, v: u32) { 38 | self.0 = [v, 0, 0, 0, 0, 0, 0, 0]; 39 | } 40 | 41 | /// Create a scalar from an unsigned integer. 42 | pub fn from_int(v: u32) -> Self { 43 | let mut scalar = Self::default(); 44 | scalar.set_int(v); 45 | scalar 46 | } 47 | 48 | /// Access bits from a scalar. All requested bits must belong to 49 | /// the same 32-bit limb. 50 | pub fn bits(&self, offset: usize, count: usize) -> u32 { 51 | debug_assert!((offset + count - 1) >> 5 == offset >> 5); 52 | (self.0[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1) 53 | } 54 | 55 | /// Access bits from a scalar. Not constant time. 56 | pub fn bits_var(&self, offset: usize, count: usize) -> u32 { 57 | debug_assert!(count < 32); 58 | debug_assert!(offset + count <= 256); 59 | if (offset + count - 1) >> 5 == offset >> 5 { 60 | self.bits(offset, count) 61 | } else { 62 | debug_assert!((offset >> 5) + 1 < 8); 63 | ((self.0[offset >> 5] >> (offset & 0x1f)) 64 | | (self.0[(offset >> 5) + 1] << (32 - (offset & 0x1f)))) 65 | & ((1 << count) - 1) 66 | } 67 | } 68 | 69 | #[must_use] 70 | fn check_overflow(&self) -> Choice { 71 | let mut yes: Choice = 0.into(); 72 | let mut no: Choice = 0.into(); 73 | no |= Choice::from((self.0[7] < SECP256K1_N[7]) as u8); /* No need for a > check. */ 74 | no |= Choice::from((self.0[6] < SECP256K1_N[6]) as u8); /* No need for a > check. */ 75 | no |= Choice::from((self.0[5] < SECP256K1_N[5]) as u8); /* No need for a > check. */ 76 | no |= Choice::from((self.0[4] < SECP256K1_N[4]) as u8); 77 | yes |= Choice::from((self.0[4] > SECP256K1_N[4]) as u8) & !no; 78 | no |= Choice::from((self.0[3] < SECP256K1_N[3]) as u8) & !yes; 79 | yes |= Choice::from((self.0[3] > SECP256K1_N[3]) as u8) & !no; 80 | no |= Choice::from((self.0[2] < SECP256K1_N[2]) as u8) & !yes; 81 | yes |= Choice::from((self.0[2] > SECP256K1_N[2]) as u8) & !no; 82 | no |= Choice::from((self.0[1] < SECP256K1_N[1]) as u8) & !yes; 83 | yes |= Choice::from((self.0[1] > SECP256K1_N[1]) as u8) & !no; 84 | yes |= Choice::from((self.0[0] >= SECP256K1_N[0]) as u8) & !no; 85 | 86 | yes 87 | } 88 | 89 | fn reduce(&mut self, overflow: Choice) { 90 | let o = overflow.unwrap_u8() as u64; 91 | let mut t: u64; 92 | 93 | t = (self.0[0] as u64) + o * (SECP256K1_N_C_0 as u64); 94 | self.0[0] = (t & 0xFFFFFFFF) as u32; 95 | t >>= 32; 96 | 97 | t += (self.0[1] as u64) + o * (SECP256K1_N_C_1 as u64); 98 | self.0[1] = (t & 0xFFFFFFFF) as u32; 99 | t >>= 32; 100 | 101 | t += (self.0[2] as u64) + o * (SECP256K1_N_C_2 as u64); 102 | self.0[2] = (t & 0xFFFFFFFF) as u32; 103 | t >>= 32; 104 | 105 | t += (self.0[3] as u64) + o * (SECP256K1_N_C_3 as u64); 106 | self.0[3] = (t & 0xFFFFFFFF) as u32; 107 | t >>= 32; 108 | 109 | t += (self.0[4] as u64) + o * (SECP256K1_N_C_4 as u64); 110 | self.0[4] = (t & 0xFFFFFFFF) as u32; 111 | t >>= 32; 112 | 113 | t += self.0[5] as u64; 114 | self.0[5] = (t & 0xFFFFFFFF) as u32; 115 | t >>= 32; 116 | 117 | t += self.0[6] as u64; 118 | self.0[6] = (t & 0xFFFFFFFF) as u32; 119 | t >>= 32; 120 | 121 | t += self.0[7] as u64; 122 | self.0[7] = (t & 0xFFFFFFFF) as u32; 123 | } 124 | 125 | /// Conditionally add a power of two to a scalar. The result is 126 | /// not allowed to overflow. 127 | pub fn cadd_bit(&mut self, mut bit: usize, flag: bool) { 128 | let mut t: u64; 129 | debug_assert!(bit < 256); 130 | bit += if flag { 0 } else { usize::max_value() } & 0x100; 131 | t = (self.0[0] as u64) + ((if (bit >> 5) == 0 { 1 } else { 0 }) << (bit & 0x1F)); 132 | self.0[0] = (t & 0xFFFFFFFF) as u32; 133 | t >>= 32; 134 | t += (self.0[1] as u64) + ((if (bit >> 5) == 1 { 1 } else { 0 }) << (bit & 0x1F)); 135 | self.0[1] = (t & 0xFFFFFFFF) as u32; 136 | t >>= 32; 137 | t += (self.0[2] as u64) + ((if (bit >> 5) == 2 { 1 } else { 0 }) << (bit & 0x1F)); 138 | self.0[2] = (t & 0xFFFFFFFF) as u32; 139 | t >>= 32; 140 | t += (self.0[3] as u64) + ((if (bit >> 5) == 3 { 1 } else { 0 }) << (bit & 0x1F)); 141 | self.0[3] = (t & 0xFFFFFFFF) as u32; 142 | t >>= 32; 143 | t += (self.0[4] as u64) + ((if (bit >> 5) == 4 { 1 } else { 0 }) << (bit & 0x1F)); 144 | self.0[4] = (t & 0xFFFFFFFF) as u32; 145 | t >>= 32; 146 | t += (self.0[5] as u64) + ((if (bit >> 5) == 5 { 1 } else { 0 }) << (bit & 0x1F)); 147 | self.0[5] = (t & 0xFFFFFFFF) as u32; 148 | t >>= 32; 149 | t += (self.0[6] as u64) + ((if (bit >> 5) == 6 { 1 } else { 0 }) << (bit & 0x1F)); 150 | self.0[6] = (t & 0xFFFFFFFF) as u32; 151 | t >>= 32; 152 | t += (self.0[7] as u64) + ((if (bit >> 5) == 7 { 1 } else { 0 }) << (bit & 0x1F)); 153 | self.0[7] = (t & 0xFFFFFFFF) as u32; 154 | debug_assert!((t >> 32) == 0); 155 | debug_assert!(!bool::from(self.check_overflow())); 156 | } 157 | 158 | /// Set a scalar from a big endian byte array, return whether it overflowed. 159 | #[must_use] 160 | pub fn set_b32(&mut self, b32: &[u8; 32]) -> Choice { 161 | self.0[0] = (b32[31] as u32) 162 | | ((b32[30] as u32) << 8) 163 | | ((b32[29] as u32) << 16) 164 | | ((b32[28] as u32) << 24); 165 | self.0[1] = (b32[27] as u32) 166 | | ((b32[26] as u32) << 8) 167 | | ((b32[25] as u32) << 16) 168 | | ((b32[24] as u32) << 24); 169 | self.0[2] = (b32[23] as u32) 170 | | ((b32[22] as u32) << 8) 171 | | ((b32[21] as u32) << 16) 172 | | ((b32[20] as u32) << 24); 173 | self.0[3] = (b32[19] as u32) 174 | | ((b32[18] as u32) << 8) 175 | | ((b32[17] as u32) << 16) 176 | | ((b32[16] as u32) << 24); 177 | self.0[4] = (b32[15] as u32) 178 | | ((b32[14] as u32) << 8) 179 | | ((b32[13] as u32) << 16) 180 | | ((b32[12] as u32) << 24); 181 | self.0[5] = (b32[11] as u32) 182 | | ((b32[10] as u32) << 8) 183 | | ((b32[9] as u32) << 16) 184 | | ((b32[8] as u32) << 24); 185 | self.0[6] = (b32[7] as u32) 186 | | ((b32[6] as u32) << 8) 187 | | ((b32[5] as u32) << 16) 188 | | ((b32[4] as u32) << 24); 189 | self.0[7] = (b32[3] as u32) 190 | | ((b32[2] as u32) << 8) 191 | | ((b32[1] as u32) << 16) 192 | | ((b32[0] as u32) << 24); 193 | 194 | let overflow = self.check_overflow(); 195 | self.reduce(overflow); 196 | 197 | overflow 198 | } 199 | 200 | /// Convert a scalar to a byte array. 201 | pub fn b32(&self) -> [u8; 32] { 202 | let mut bin = [0u8; 32]; 203 | self.fill_b32(&mut bin); 204 | bin 205 | } 206 | 207 | /// Convert a scalar to a byte array. 208 | pub fn fill_b32(&self, bin: &mut [u8; 32]) { 209 | bin[0] = (self.0[7] >> 24) as u8; 210 | bin[1] = (self.0[7] >> 16) as u8; 211 | bin[2] = (self.0[7] >> 8) as u8; 212 | bin[3] = (self.0[7]) as u8; 213 | bin[4] = (self.0[6] >> 24) as u8; 214 | bin[5] = (self.0[6] >> 16) as u8; 215 | bin[6] = (self.0[6] >> 8) as u8; 216 | bin[7] = (self.0[6]) as u8; 217 | bin[8] = (self.0[5] >> 24) as u8; 218 | bin[9] = (self.0[5] >> 16) as u8; 219 | bin[10] = (self.0[5] >> 8) as u8; 220 | bin[11] = (self.0[5]) as u8; 221 | bin[12] = (self.0[4] >> 24) as u8; 222 | bin[13] = (self.0[4] >> 16) as u8; 223 | bin[14] = (self.0[4] >> 8) as u8; 224 | bin[15] = (self.0[4]) as u8; 225 | bin[16] = (self.0[3] >> 24) as u8; 226 | bin[17] = (self.0[3] >> 16) as u8; 227 | bin[18] = (self.0[3] >> 8) as u8; 228 | bin[19] = (self.0[3]) as u8; 229 | bin[20] = (self.0[2] >> 24) as u8; 230 | bin[21] = (self.0[2] >> 16) as u8; 231 | bin[22] = (self.0[2] >> 8) as u8; 232 | bin[23] = (self.0[2]) as u8; 233 | bin[24] = (self.0[1] >> 24) as u8; 234 | bin[25] = (self.0[1] >> 16) as u8; 235 | bin[26] = (self.0[1] >> 8) as u8; 236 | bin[27] = (self.0[1]) as u8; 237 | bin[28] = (self.0[0] >> 24) as u8; 238 | bin[29] = (self.0[0] >> 16) as u8; 239 | bin[30] = (self.0[0] >> 8) as u8; 240 | bin[31] = (self.0[0]) as u8; 241 | } 242 | 243 | /// Check whether a scalar equals zero. 244 | pub fn is_zero(&self) -> bool { 245 | (self.0[0] 246 | | self.0[1] 247 | | self.0[2] 248 | | self.0[3] 249 | | self.0[4] 250 | | self.0[5] 251 | | self.0[6] 252 | | self.0[7]) 253 | == 0 254 | } 255 | 256 | /// Check whether a scalar equals one. 257 | pub fn is_one(&self) -> bool { 258 | ((self.0[0] ^ 1) 259 | | self.0[1] 260 | | self.0[2] 261 | | self.0[3] 262 | | self.0[4] 263 | | self.0[5] 264 | | self.0[6] 265 | | self.0[7]) 266 | == 0 267 | } 268 | 269 | /// Check whether a scalar is higher than the group order divided 270 | /// by 2. 271 | pub fn is_high(&self) -> bool { 272 | let mut yes: Choice = 0.into(); 273 | let mut no: Choice = 0.into(); 274 | no |= Choice::from((self.0[7] < SECP256K1_N_H_7) as u8); 275 | yes |= Choice::from((self.0[7] > SECP256K1_N_H_7) as u8) & !no; 276 | no |= Choice::from((self.0[6] < SECP256K1_N_H_6) as u8) & !yes; /* No need for a > check. */ 277 | no |= Choice::from((self.0[5] < SECP256K1_N_H_5) as u8) & !yes; /* No need for a > check. */ 278 | no |= Choice::from((self.0[4] < SECP256K1_N_H_4) as u8) & !yes; /* No need for a > check. */ 279 | no |= Choice::from((self.0[3] < SECP256K1_N_H_3) as u8) & !yes; 280 | yes |= Choice::from((self.0[3] > SECP256K1_N_H_3) as u8) & !no; 281 | no |= Choice::from((self.0[2] < SECP256K1_N_H_2) as u8) & !yes; 282 | yes |= Choice::from((self.0[2] > SECP256K1_N_H_2) as u8) & !no; 283 | no |= Choice::from((self.0[1] < SECP256K1_N_H_1) as u8) & !yes; 284 | yes |= Choice::from((self.0[1] > SECP256K1_N_H_1) as u8) & !no; 285 | yes |= Choice::from((self.0[0] >= SECP256K1_N_H_0) as u8) & !no; 286 | yes.into() 287 | } 288 | 289 | /// Conditionally negate a number, in constant time. 290 | pub fn cond_neg_assign(&mut self, flag: Choice) { 291 | let mask = u32::max_value() * flag.unwrap_u8() as u32; 292 | 293 | let nonzero = 0xFFFFFFFFu64 * !self.is_zero() as u64; 294 | let mut t = 1u64 * flag.unwrap_u8() as u64; 295 | 296 | unroll! { 297 | for i in 0..8 { 298 | t += (self.0[i] ^ mask) as u64 + (SECP256K1_N[i] & mask) as u64; 299 | self.0[i] = (t & nonzero) as u32; 300 | t >>= 32; 301 | } 302 | } 303 | 304 | let _ = t; 305 | } 306 | } 307 | 308 | macro_rules! define_ops { 309 | ($c0: ident, $c1: ident, $c2: ident) => { 310 | #[allow(unused_macros)] 311 | macro_rules! muladd { 312 | ($a: expr, $b: expr) => { 313 | let a = $a; 314 | let b = $b; 315 | let t = (a as u64) * (b as u64); 316 | let mut th = (t >> 32) as u32; 317 | let tl = t as u32; 318 | $c0 = $c0.wrapping_add(tl); 319 | th = th.wrapping_add(if $c0 < tl { 1 } else { 0 }); 320 | $c1 = $c1.wrapping_add(th); 321 | $c2 = $c2.wrapping_add(if $c1 < th { 1 } else { 0 }); 322 | debug_assert!($c1 >= th || $c2 != 0); 323 | }; 324 | } 325 | 326 | #[allow(unused_macros)] 327 | macro_rules! muladd_fast { 328 | ($a: expr, $b: expr) => { 329 | let a = $a; 330 | let b = $b; 331 | let t = (a as u64) * (b as u64); 332 | let mut th = (t >> 32) as u32; 333 | let tl = t as u32; 334 | $c0 = $c0.wrapping_add(tl); 335 | th = th.wrapping_add(if $c0 < tl { 1 } else { 0 }); 336 | $c1 = $c1.wrapping_add(th); 337 | debug_assert!($c1 >= th); 338 | }; 339 | } 340 | 341 | #[allow(unused_macros)] 342 | macro_rules! muladd2 { 343 | ($a: expr, $b: expr) => { 344 | let a = $a; 345 | let b = $b; 346 | let t = (a as u64) * (b as u64); 347 | let th = (t >> 32) as u32; 348 | let tl = t as u32; 349 | let mut th2 = th.wrapping_add(th); 350 | $c2 = $c2.wrapping_add(if th2 < th { 1 } else { 0 }); 351 | debug_assert!(th2 >= th || $c2 != 0); 352 | let tl2 = tl.wrapping_add(tl); 353 | th2 = th2.wrapping_add(if tl2 < tl { 1 } else { 0 }); 354 | $c0 = $c0.wrapping_add(tl2); 355 | th2 = th2.wrapping_add(if $c0 < tl2 { 1 } else { 0 }); 356 | $c2 = $c2.wrapping_add(if $c0 < tl2 && th2 == 0 { 1 } else { 0 }); 357 | debug_assert!($c0 >= tl2 || th2 != 0 || $c2 != 0); 358 | $c1 = $c1.wrapping_add(th2); 359 | $c2 = $c2.wrapping_add(if $c1 < th2 { 1 } else { 0 }); 360 | debug_assert!($c1 >= th2 || $c2 != 0); 361 | }; 362 | } 363 | 364 | #[allow(unused_macros)] 365 | macro_rules! sumadd { 366 | ($a: expr) => { 367 | let a = $a; 368 | $c0 = $c0.wrapping_add(a); 369 | let over = if $c0 < a { 1 } else { 0 }; 370 | $c1 = $c1.wrapping_add(over); 371 | $c2 = $c2.wrapping_add(if $c1 < over { 1 } else { 0 }); 372 | }; 373 | } 374 | 375 | #[allow(unused_macros)] 376 | macro_rules! sumadd_fast { 377 | ($a: expr) => { 378 | let a = $a; 379 | $c0 = $c0.wrapping_add(a); 380 | $c1 = $c1.wrapping_add(if $c0 < a { 1 } else { 0 }); 381 | debug_assert!($c1 != 0 || $c0 >= a); 382 | debug_assert!($c2 == 0); 383 | }; 384 | } 385 | 386 | #[allow(unused_macros)] 387 | macro_rules! extract { 388 | () => {{ 389 | #[allow(unused_assignments)] 390 | { 391 | let n = $c0; 392 | $c0 = $c1; 393 | $c1 = $c2; 394 | $c2 = 0; 395 | n 396 | } 397 | }}; 398 | } 399 | 400 | #[allow(unused_macros)] 401 | macro_rules! extract_fast { 402 | () => {{ 403 | #[allow(unused_assignments)] 404 | { 405 | let n = $c0; 406 | $c0 = $c1; 407 | $c1 = 0; 408 | debug_assert!($c2 == 0); 409 | n 410 | } 411 | }}; 412 | } 413 | }; 414 | } 415 | 416 | impl Scalar { 417 | fn reduce_512(&mut self, l: &[u32; 16]) { 418 | let (mut c0, mut c1, mut c2): (u32, u32, u32); 419 | define_ops!(c0, c1, c2); 420 | 421 | let mut c: u64; 422 | let (n0, n1, n2, n3, n4, n5, n6, n7) = 423 | (l[8], l[9], l[10], l[11], l[12], l[13], l[14], l[15]); 424 | let (m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12): ( 425 | u32, 426 | u32, 427 | u32, 428 | u32, 429 | u32, 430 | u32, 431 | u32, 432 | u32, 433 | u32, 434 | u32, 435 | u32, 436 | u32, 437 | u32, 438 | ); 439 | let (p0, p1, p2, p3, p4, p5, p6, p7, p8): (u32, u32, u32, u32, u32, u32, u32, u32, u32); 440 | 441 | c0 = l[0]; 442 | c1 = 0; 443 | c2 = 0; 444 | muladd_fast!(n0, SECP256K1_N_C_0); 445 | m0 = extract_fast!(); 446 | sumadd_fast!(l[1]); 447 | muladd!(n1, SECP256K1_N_C_0); 448 | muladd!(n0, SECP256K1_N_C_1); 449 | m1 = extract!(); 450 | sumadd!(l[2]); 451 | muladd!(n2, SECP256K1_N_C_0); 452 | muladd!(n1, SECP256K1_N_C_1); 453 | muladd!(n0, SECP256K1_N_C_2); 454 | m2 = extract!(); 455 | sumadd!(l[3]); 456 | muladd!(n3, SECP256K1_N_C_0); 457 | muladd!(n2, SECP256K1_N_C_1); 458 | muladd!(n1, SECP256K1_N_C_2); 459 | muladd!(n0, SECP256K1_N_C_3); 460 | m3 = extract!(); 461 | sumadd!(l[4]); 462 | muladd!(n4, SECP256K1_N_C_0); 463 | muladd!(n3, SECP256K1_N_C_1); 464 | muladd!(n2, SECP256K1_N_C_2); 465 | muladd!(n1, SECP256K1_N_C_3); 466 | sumadd!(n0); 467 | m4 = extract!(); 468 | sumadd!(l[5]); 469 | muladd!(n5, SECP256K1_N_C_0); 470 | muladd!(n4, SECP256K1_N_C_1); 471 | muladd!(n3, SECP256K1_N_C_2); 472 | muladd!(n2, SECP256K1_N_C_3); 473 | sumadd!(n1); 474 | m5 = extract!(); 475 | sumadd!(l[6]); 476 | muladd!(n6, SECP256K1_N_C_0); 477 | muladd!(n5, SECP256K1_N_C_1); 478 | muladd!(n4, SECP256K1_N_C_2); 479 | muladd!(n3, SECP256K1_N_C_3); 480 | sumadd!(n2); 481 | m6 = extract!(); 482 | sumadd!(l[7]); 483 | muladd!(n7, SECP256K1_N_C_0); 484 | muladd!(n6, SECP256K1_N_C_1); 485 | muladd!(n5, SECP256K1_N_C_2); 486 | muladd!(n4, SECP256K1_N_C_3); 487 | sumadd!(n3); 488 | m7 = extract!(); 489 | muladd!(n7, SECP256K1_N_C_1); 490 | muladd!(n6, SECP256K1_N_C_2); 491 | muladd!(n5, SECP256K1_N_C_3); 492 | sumadd!(n4); 493 | m8 = extract!(); 494 | muladd!(n7, SECP256K1_N_C_2); 495 | muladd!(n6, SECP256K1_N_C_3); 496 | sumadd!(n5); 497 | m9 = extract!(); 498 | muladd!(n7, SECP256K1_N_C_3); 499 | sumadd!(n6); 500 | m10 = extract!(); 501 | sumadd_fast!(n7); 502 | m11 = extract_fast!(); 503 | debug_assert!(c0 <= 1); 504 | m12 = c0; 505 | 506 | /* Reduce 385 bits into 258. */ 507 | /* p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. */ 508 | c0 = m0; 509 | c1 = 0; 510 | c2 = 0; 511 | muladd_fast!(m8, SECP256K1_N_C_0); 512 | p0 = extract_fast!(); 513 | sumadd_fast!(m1); 514 | muladd!(m9, SECP256K1_N_C_0); 515 | muladd!(m8, SECP256K1_N_C_1); 516 | p1 = extract!(); 517 | sumadd!(m2); 518 | muladd!(m10, SECP256K1_N_C_0); 519 | muladd!(m9, SECP256K1_N_C_1); 520 | muladd!(m8, SECP256K1_N_C_2); 521 | p2 = extract!(); 522 | sumadd!(m3); 523 | muladd!(m11, SECP256K1_N_C_0); 524 | muladd!(m10, SECP256K1_N_C_1); 525 | muladd!(m9, SECP256K1_N_C_2); 526 | muladd!(m8, SECP256K1_N_C_3); 527 | p3 = extract!(); 528 | sumadd!(m4); 529 | muladd!(m12, SECP256K1_N_C_0); 530 | muladd!(m11, SECP256K1_N_C_1); 531 | muladd!(m10, SECP256K1_N_C_2); 532 | muladd!(m9, SECP256K1_N_C_3); 533 | sumadd!(m8); 534 | p4 = extract!(); 535 | sumadd!(m5); 536 | muladd!(m12, SECP256K1_N_C_1); 537 | muladd!(m11, SECP256K1_N_C_2); 538 | muladd!(m10, SECP256K1_N_C_3); 539 | sumadd!(m9); 540 | p5 = extract!(); 541 | sumadd!(m6); 542 | muladd!(m12, SECP256K1_N_C_2); 543 | muladd!(m11, SECP256K1_N_C_3); 544 | sumadd!(m10); 545 | p6 = extract!(); 546 | sumadd_fast!(m7); 547 | muladd_fast!(m12, SECP256K1_N_C_3); 548 | sumadd_fast!(m11); 549 | p7 = extract_fast!(); 550 | p8 = c0 + m12; 551 | debug_assert!(p8 <= 2); 552 | 553 | /* Reduce 258 bits into 256. */ 554 | /* r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. */ 555 | c = p0 as u64 + SECP256K1_N_C_0 as u64 * p8 as u64; 556 | self.0[0] = (c & 0xFFFFFFFF) as u32; 557 | c >>= 32; 558 | c += p1 as u64 + SECP256K1_N_C_1 as u64 * p8 as u64; 559 | self.0[1] = (c & 0xFFFFFFFF) as u32; 560 | c >>= 32; 561 | c += p2 as u64 + SECP256K1_N_C_2 as u64 * p8 as u64; 562 | self.0[2] = (c & 0xFFFFFFFF) as u32; 563 | c >>= 32; 564 | c += p3 as u64 + SECP256K1_N_C_3 as u64 * p8 as u64; 565 | self.0[3] = (c & 0xFFFFFFFF) as u32; 566 | c >>= 32; 567 | c += p4 as u64 + p8 as u64; 568 | self.0[4] = (c & 0xFFFFFFFF) as u32; 569 | c >>= 32; 570 | c += p5 as u64; 571 | self.0[5] = (c & 0xFFFFFFFF) as u32; 572 | c >>= 32; 573 | c += p6 as u64; 574 | self.0[6] = (c & 0xFFFFFFFF) as u32; 575 | c >>= 32; 576 | c += p7 as u64; 577 | self.0[7] = (c & 0xFFFFFFFF) as u32; 578 | c >>= 32; 579 | 580 | let overflow = self.check_overflow(); 581 | self.reduce(Choice::from(c as u8) | overflow); 582 | } 583 | 584 | fn mul_512(&self, b: &Scalar, l: &mut [u32; 16]) { 585 | let (mut c0, mut c1, mut c2): (u32, u32, u32) = (0, 0, 0); 586 | define_ops!(c0, c1, c2); 587 | 588 | /* l[0..15] = a[0..7] * b[0..7]. */ 589 | muladd_fast!(self.0[0], b.0[0]); 590 | l[0] = extract_fast!(); 591 | muladd!(self.0[0], b.0[1]); 592 | muladd!(self.0[1], b.0[0]); 593 | l[1] = extract!(); 594 | muladd!(self.0[0], b.0[2]); 595 | muladd!(self.0[1], b.0[1]); 596 | muladd!(self.0[2], b.0[0]); 597 | l[2] = extract!(); 598 | muladd!(self.0[0], b.0[3]); 599 | muladd!(self.0[1], b.0[2]); 600 | muladd!(self.0[2], b.0[1]); 601 | muladd!(self.0[3], b.0[0]); 602 | l[3] = extract!(); 603 | muladd!(self.0[0], b.0[4]); 604 | muladd!(self.0[1], b.0[3]); 605 | muladd!(self.0[2], b.0[2]); 606 | muladd!(self.0[3], b.0[1]); 607 | muladd!(self.0[4], b.0[0]); 608 | l[4] = extract!(); 609 | muladd!(self.0[0], b.0[5]); 610 | muladd!(self.0[1], b.0[4]); 611 | muladd!(self.0[2], b.0[3]); 612 | muladd!(self.0[3], b.0[2]); 613 | muladd!(self.0[4], b.0[1]); 614 | muladd!(self.0[5], b.0[0]); 615 | l[5] = extract!(); 616 | muladd!(self.0[0], b.0[6]); 617 | muladd!(self.0[1], b.0[5]); 618 | muladd!(self.0[2], b.0[4]); 619 | muladd!(self.0[3], b.0[3]); 620 | muladd!(self.0[4], b.0[2]); 621 | muladd!(self.0[5], b.0[1]); 622 | muladd!(self.0[6], b.0[0]); 623 | l[6] = extract!(); 624 | muladd!(self.0[0], b.0[7]); 625 | muladd!(self.0[1], b.0[6]); 626 | muladd!(self.0[2], b.0[5]); 627 | muladd!(self.0[3], b.0[4]); 628 | muladd!(self.0[4], b.0[3]); 629 | muladd!(self.0[5], b.0[2]); 630 | muladd!(self.0[6], b.0[1]); 631 | muladd!(self.0[7], b.0[0]); 632 | l[7] = extract!(); 633 | muladd!(self.0[1], b.0[7]); 634 | muladd!(self.0[2], b.0[6]); 635 | muladd!(self.0[3], b.0[5]); 636 | muladd!(self.0[4], b.0[4]); 637 | muladd!(self.0[5], b.0[3]); 638 | muladd!(self.0[6], b.0[2]); 639 | muladd!(self.0[7], b.0[1]); 640 | l[8] = extract!(); 641 | muladd!(self.0[2], b.0[7]); 642 | muladd!(self.0[3], b.0[6]); 643 | muladd!(self.0[4], b.0[5]); 644 | muladd!(self.0[5], b.0[4]); 645 | muladd!(self.0[6], b.0[3]); 646 | muladd!(self.0[7], b.0[2]); 647 | l[9] = extract!(); 648 | muladd!(self.0[3], b.0[7]); 649 | muladd!(self.0[4], b.0[6]); 650 | muladd!(self.0[5], b.0[5]); 651 | muladd!(self.0[6], b.0[4]); 652 | muladd!(self.0[7], b.0[3]); 653 | l[10] = extract!(); 654 | muladd!(self.0[4], b.0[7]); 655 | muladd!(self.0[5], b.0[6]); 656 | muladd!(self.0[6], b.0[5]); 657 | muladd!(self.0[7], b.0[4]); 658 | l[11] = extract!(); 659 | muladd!(self.0[5], b.0[7]); 660 | muladd!(self.0[6], b.0[6]); 661 | muladd!(self.0[7], b.0[5]); 662 | l[12] = extract!(); 663 | muladd!(self.0[6], b.0[7]); 664 | muladd!(self.0[7], b.0[6]); 665 | l[13] = extract!(); 666 | muladd_fast!(self.0[7], b.0[7]); 667 | l[14] = extract_fast!(); 668 | debug_assert!(c1 == 0); 669 | l[15] = c0; 670 | } 671 | 672 | fn sqr_512(&self, l: &mut [u32; 16]) { 673 | let (mut c0, mut c1, mut c2): (u32, u32, u32) = (0, 0, 0); 674 | define_ops!(c0, c1, c2); 675 | 676 | /* l[0..15] = a[0..7]^2. */ 677 | muladd_fast!(self.0[0], self.0[0]); 678 | l[0] = extract_fast!(); 679 | muladd2!(self.0[0], self.0[1]); 680 | l[1] = extract!(); 681 | muladd2!(self.0[0], self.0[2]); 682 | muladd!(self.0[1], self.0[1]); 683 | l[2] = extract!(); 684 | muladd2!(self.0[0], self.0[3]); 685 | muladd2!(self.0[1], self.0[2]); 686 | l[3] = extract!(); 687 | muladd2!(self.0[0], self.0[4]); 688 | muladd2!(self.0[1], self.0[3]); 689 | muladd!(self.0[2], self.0[2]); 690 | l[4] = extract!(); 691 | muladd2!(self.0[0], self.0[5]); 692 | muladd2!(self.0[1], self.0[4]); 693 | muladd2!(self.0[2], self.0[3]); 694 | l[5] = extract!(); 695 | muladd2!(self.0[0], self.0[6]); 696 | muladd2!(self.0[1], self.0[5]); 697 | muladd2!(self.0[2], self.0[4]); 698 | muladd!(self.0[3], self.0[3]); 699 | l[6] = extract!(); 700 | muladd2!(self.0[0], self.0[7]); 701 | muladd2!(self.0[1], self.0[6]); 702 | muladd2!(self.0[2], self.0[5]); 703 | muladd2!(self.0[3], self.0[4]); 704 | l[7] = extract!(); 705 | muladd2!(self.0[1], self.0[7]); 706 | muladd2!(self.0[2], self.0[6]); 707 | muladd2!(self.0[3], self.0[5]); 708 | muladd!(self.0[4], self.0[4]); 709 | l[8] = extract!(); 710 | muladd2!(self.0[2], self.0[7]); 711 | muladd2!(self.0[3], self.0[6]); 712 | muladd2!(self.0[4], self.0[5]); 713 | l[9] = extract!(); 714 | muladd2!(self.0[3], self.0[7]); 715 | muladd2!(self.0[4], self.0[6]); 716 | muladd!(self.0[5], self.0[5]); 717 | l[10] = extract!(); 718 | muladd2!(self.0[4], self.0[7]); 719 | muladd2!(self.0[5], self.0[6]); 720 | l[11] = extract!(); 721 | muladd2!(self.0[5], self.0[7]); 722 | muladd!(self.0[6], self.0[6]); 723 | l[12] = extract!(); 724 | muladd2!(self.0[6], self.0[7]); 725 | l[13] = extract!(); 726 | muladd_fast!(self.0[7], self.0[7]); 727 | l[14] = extract_fast!(); 728 | debug_assert!(c1 == 0); 729 | l[15] = c0; 730 | } 731 | 732 | pub fn mul_in_place(&mut self, a: &Scalar, b: &Scalar) { 733 | let mut l = [0u32; 16]; 734 | a.mul_512(b, &mut l); 735 | self.reduce_512(&l); 736 | } 737 | 738 | /// Shift a scalar right by some amount strictly between 0 and 16, 739 | /// returning the low bits that were shifted off. 740 | pub fn shr_int(&mut self, n: usize) -> u32 { 741 | let ret: u32; 742 | debug_assert!(n > 0); 743 | debug_assert!(n < 16); 744 | ret = self.0[0] & ((1 << n) - 1); 745 | self.0[0] = (self.0[0] >> n) + (self.0[1] << (32 - n)); 746 | self.0[1] = (self.0[1] >> n) + (self.0[2] << (32 - n)); 747 | self.0[2] = (self.0[2] >> n) + (self.0[3] << (32 - n)); 748 | self.0[3] = (self.0[3] >> n) + (self.0[4] << (32 - n)); 749 | self.0[4] = (self.0[4] >> n) + (self.0[5] << (32 - n)); 750 | self.0[5] = (self.0[5] >> n) + (self.0[6] << (32 - n)); 751 | self.0[6] = (self.0[6] >> n) + (self.0[7] << (32 - n)); 752 | self.0[7] >>= n; 753 | ret 754 | } 755 | 756 | pub fn sqr_in_place(&mut self, a: &Scalar) { 757 | let mut l = [0u32; 16]; 758 | a.sqr_512(&mut l); 759 | self.reduce_512(&l); 760 | } 761 | 762 | pub fn sqr(&self) -> Scalar { 763 | let mut ret = Scalar::default(); 764 | ret.sqr_in_place(self); 765 | ret 766 | } 767 | 768 | pub fn inv_in_place(&mut self, x: &Scalar) { 769 | let u2 = x.sqr(); 770 | let x2 = u2 * *x; 771 | let u5 = u2 * x2; 772 | let x3 = u5 * u2; 773 | let u9 = x3 * u2; 774 | let u11 = u9 * u2; 775 | let u13 = u11 * u2; 776 | 777 | let mut x6 = u13.sqr(); 778 | x6 = x6.sqr(); 779 | x6 *= &u11; 780 | 781 | let mut x8 = x6.sqr(); 782 | x8 = x8.sqr(); 783 | x8 *= &x2; 784 | 785 | let mut x14 = x8.sqr(); 786 | for _ in 0..5 { 787 | x14 = x14.sqr(); 788 | } 789 | x14 *= &x6; 790 | 791 | let mut x28 = x14.sqr(); 792 | for _ in 0..13 { 793 | x28 = x28.sqr(); 794 | } 795 | x28 *= &x14; 796 | 797 | let mut x56 = x28.sqr(); 798 | for _ in 0..27 { 799 | x56 = x56.sqr(); 800 | } 801 | x56 *= &x28; 802 | 803 | let mut x112 = x56.sqr(); 804 | for _ in 0..55 { 805 | x112 = x112.sqr(); 806 | } 807 | x112 *= &x56; 808 | 809 | let mut x126 = x112.sqr(); 810 | for _ in 0..13 { 811 | x126 = x126.sqr(); 812 | } 813 | x126 *= &x14; 814 | 815 | let mut t = x126; 816 | for _ in 0..3 { 817 | t = t.sqr(); 818 | } 819 | t *= &u5; 820 | for _ in 0..4 { 821 | t = t.sqr(); 822 | } 823 | t *= &x3; 824 | for _ in 0..4 { 825 | t = t.sqr(); 826 | } 827 | t *= &u5; 828 | for _ in 0..5 { 829 | t = t.sqr(); 830 | } 831 | t *= &u11; 832 | for _ in 0..4 { 833 | t = t.sqr(); 834 | } 835 | t *= &u11; 836 | for _ in 0..4 { 837 | t = t.sqr(); 838 | } 839 | t *= &x3; 840 | for _ in 0..5 { 841 | t = t.sqr(); 842 | } 843 | t *= &x3; 844 | for _ in 0..6 { 845 | t = t.sqr(); 846 | } 847 | t *= &u13; 848 | for _ in 0..4 { 849 | t = t.sqr(); 850 | } 851 | t *= &u5; 852 | for _ in 0..3 { 853 | t = t.sqr(); 854 | } 855 | t *= &x3; 856 | for _ in 0..5 { 857 | t = t.sqr(); 858 | } 859 | t *= &u9; 860 | for _ in 0..6 { 861 | t = t.sqr(); 862 | } 863 | t *= &u5; 864 | for _ in 0..10 { 865 | t = t.sqr(); 866 | } 867 | t *= &x3; 868 | for _ in 0..4 { 869 | t = t.sqr(); 870 | } 871 | t *= &x3; 872 | for _ in 0..9 { 873 | t = t.sqr(); 874 | } 875 | t *= &x8; 876 | for _ in 0..5 { 877 | t = t.sqr(); 878 | } 879 | t *= &u9; 880 | for _ in 0..6 { 881 | t = t.sqr(); 882 | } 883 | t *= &u11; 884 | for _ in 0..4 { 885 | t = t.sqr(); 886 | } 887 | t *= &u13; 888 | for _ in 0..5 { 889 | t = t.sqr(); 890 | } 891 | t *= &x2; 892 | for _ in 0..6 { 893 | t = t.sqr(); 894 | } 895 | t *= &u13; 896 | for _ in 0..10 { 897 | t = t.sqr(); 898 | } 899 | t *= &u13; 900 | for _ in 0..4 { 901 | t = t.sqr(); 902 | } 903 | t *= &u9; 904 | for _ in 0..6 { 905 | t = t.sqr(); 906 | } 907 | t *= x; 908 | for _ in 0..8 { 909 | t = t.sqr(); 910 | } 911 | *self = t * x6; 912 | } 913 | 914 | pub fn inv(&self) -> Scalar { 915 | let mut ret = Scalar::default(); 916 | ret.inv_in_place(self); 917 | ret 918 | } 919 | 920 | pub fn inv_var(&self) -> Scalar { 921 | self.inv() 922 | } 923 | 924 | pub fn is_even(&self) -> bool { 925 | self.0[0] & 1 == 0 926 | } 927 | } 928 | 929 | impl Default for Scalar { 930 | fn default() -> Scalar { 931 | Scalar([0u32; 8]) 932 | } 933 | } 934 | 935 | impl Add for Scalar { 936 | type Output = Scalar; 937 | fn add(mut self, other: Scalar) -> Scalar { 938 | self.add_assign(&other); 939 | self 940 | } 941 | } 942 | 943 | impl<'a, 'b> Add<&'a Scalar> for &'b Scalar { 944 | type Output = Scalar; 945 | fn add(self, other: &'a Scalar) -> Scalar { 946 | let mut ret = *self; 947 | ret.add_assign(other); 948 | ret 949 | } 950 | } 951 | 952 | impl<'a> AddAssign<&'a Scalar> for Scalar { 953 | fn add_assign(&mut self, other: &'a Scalar) { 954 | let mut t = 0u64; 955 | 956 | unroll! { 957 | for i in 0..8 { 958 | t += (self.0[i] as u64) + (other.0[i] as u64); 959 | self.0[i] = (t & 0xFFFFFFFF) as u32; 960 | t >>= 32; 961 | } 962 | } 963 | 964 | let overflow = self.check_overflow(); 965 | self.reduce(Choice::from(t as u8) | overflow); 966 | } 967 | } 968 | 969 | impl AddAssign for Scalar { 970 | fn add_assign(&mut self, other: Scalar) { 971 | self.add_assign(&other) 972 | } 973 | } 974 | 975 | impl Mul for Scalar { 976 | type Output = Scalar; 977 | fn mul(self, other: Scalar) -> Scalar { 978 | let mut ret = Scalar::default(); 979 | ret.mul_in_place(&self, &other); 980 | ret 981 | } 982 | } 983 | 984 | impl<'a, 'b> Mul<&'a Scalar> for &'b Scalar { 985 | type Output = Scalar; 986 | fn mul(self, other: &'a Scalar) -> Scalar { 987 | let mut ret = Scalar::default(); 988 | ret.mul_in_place(self, other); 989 | ret 990 | } 991 | } 992 | 993 | impl<'a> MulAssign<&'a Scalar> for Scalar { 994 | fn mul_assign(&mut self, other: &'a Scalar) { 995 | let mut ret = Scalar::default(); 996 | ret.mul_in_place(self, other); 997 | *self = ret; 998 | } 999 | } 1000 | 1001 | impl MulAssign for Scalar { 1002 | fn mul_assign(&mut self, other: Scalar) { 1003 | self.mul_assign(&other) 1004 | } 1005 | } 1006 | 1007 | impl Neg for Scalar { 1008 | type Output = Scalar; 1009 | fn neg(mut self) -> Scalar { 1010 | self.cond_neg_assign(1.into()); 1011 | self 1012 | } 1013 | } 1014 | 1015 | impl<'a> Neg for &'a Scalar { 1016 | type Output = Scalar; 1017 | fn neg(self) -> Scalar { 1018 | let value = *self; 1019 | -value 1020 | } 1021 | } 1022 | 1023 | impl core::fmt::LowerHex for Scalar { 1024 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 1025 | for word in &self.0[..] { 1026 | for byte in word.to_be_bytes().iter() { 1027 | write!(f, "{:02x}", byte)?; 1028 | } 1029 | } 1030 | Ok(()) 1031 | } 1032 | } 1033 | -------------------------------------------------------------------------------- /gen/ecmult/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libsecp256k1-gen-ecmult" 3 | description = "Generator function of const_gen for libsecp256k1." 4 | license = "Apache-2.0" 5 | version = "0.3.0" 6 | authors = ["Wei Tang "] 7 | edition = "2018" 8 | repository = "https://github.com/paritytech/libsecp256k1" 9 | keywords = ["crypto", "ECDSA", "secp256k1", "bitcoin", "no_std"] 10 | 11 | [dependencies] 12 | libsecp256k1-core = { version = "0.3.0", path = "../../core" } 13 | -------------------------------------------------------------------------------- /gen/ecmult/src/lib.rs: -------------------------------------------------------------------------------- 1 | use libsecp256k1_core::curve::ECMultContext; 2 | use std::{ 3 | fs::File, 4 | io::{Error, Write}, 5 | }; 6 | 7 | pub fn generate_to(file: &mut File) -> Result<(), Error> { 8 | let context = ECMultContext::new_boxed(); 9 | let pre_g = context.inspect_raw().as_ref(); 10 | 11 | file.write_fmt(format_args!("["))?; 12 | for pg in pre_g { 13 | file.write_fmt( 14 | format_args!( 15 | " crate::curve::AffineStorage::new(crate::curve::FieldStorage::new({}, {}, {}, {}, {}, {}, {}, {}), crate::curve::FieldStorage::new({}, {}, {}, {}, {}, {}, {}, {})),", 16 | pg.x.0[7], pg.x.0[6], pg.x.0[5], pg.x.0[4], pg.x.0[3], pg.x.0[2], pg.x.0[1], pg.x.0[0], 17 | pg.y.0[7], pg.y.0[6], pg.y.0[5], pg.y.0[4], pg.y.0[3], pg.y.0[2], pg.y.0[1], pg.y.0[0] 18 | ) 19 | )?; 20 | } 21 | file.write_fmt(format_args!("]"))?; 22 | 23 | Ok(()) 24 | } 25 | -------------------------------------------------------------------------------- /gen/genmult/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libsecp256k1-gen-genmult" 3 | description = "Generator function of const for libsecp256k1." 4 | license = "Apache-2.0" 5 | version = "0.3.0" 6 | authors = ["Wei Tang "] 7 | edition = "2018" 8 | repository = "https://github.com/paritytech/libsecp256k1" 9 | keywords = ["crypto", "ECDSA", "secp256k1", "bitcoin", "no_std"] 10 | 11 | [dependencies] 12 | libsecp256k1-core = { version = "0.3.0", path = "../../core" } 13 | -------------------------------------------------------------------------------- /gen/genmult/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::needless_range_loop)] 2 | 3 | use libsecp256k1_core::curve::ECMultGenContext; 4 | use std::{ 5 | fs::File, 6 | io::{Error, Write}, 7 | }; 8 | 9 | pub fn generate_to(file: &mut File) -> Result<(), Error> { 10 | let context = ECMultGenContext::new_boxed(); 11 | let prec = context.inspect_raw().as_ref(); 12 | 13 | file.write_fmt(format_args!("["))?; 14 | for j in 0..64 { 15 | file.write_fmt(format_args!(" ["))?; 16 | for i in 0..16 { 17 | let pg = prec[j][i]; 18 | file.write_fmt(format_args!( 19 | " crate::curve::AffineStorage::new(crate::curve::FieldStorage::new({}, {}, {}, {}, {}, {}, {}, {}), crate::curve::FieldStorage::new({}, {}, {}, {}, {}, {}, {}, {})),", 20 | pg.x.0[7], pg.x.0[6], pg.x.0[5], pg.x.0[4], pg.x.0[3], pg.x.0[2], pg.x.0[1], pg.x.0[0], 21 | pg.y.0[7], pg.y.0[6], pg.y.0[5], pg.y.0[4], pg.y.0[3], pg.y.0[2], pg.y.0[1], pg.y.0[0] 22 | ))?; 23 | } 24 | file.write_fmt(format_args!(" ],"))?; 25 | } 26 | file.write_fmt(format_args!("]"))?; 27 | 28 | Ok(()) 29 | } 30 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paritytech/libsecp256k1/f992b80dedc1da7791b74ac01591e3336c41d893/rustfmt.toml -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Pure Rust implementation of the secp256k1 curve and fast ECDSA 2 | //! signatures. The secp256k1 curve is used extensively in Bitcoin and 3 | //! Ethereum-alike cryptocurrencies. 4 | 5 | #![deny( 6 | unused_import_braces, 7 | unused_imports, 8 | unused_comparisons, 9 | unused_must_use, 10 | unused_variables, 11 | non_shorthand_field_patterns, 12 | unreachable_code, 13 | unused_parens 14 | )] 15 | #![cfg_attr(not(feature = "std"), no_std)] 16 | 17 | pub use libsecp256k1_core::*; 18 | 19 | use arrayref::{array_mut_ref, array_ref}; 20 | use base64::{engine::Engine as _, prelude::BASE64_STANDARD}; 21 | use core::convert::TryFrom; 22 | use digest::{generic_array::GenericArray, Digest}; 23 | use rand::Rng; 24 | 25 | #[cfg(feature = "std")] 26 | use core::fmt; 27 | #[cfg(feature = "hmac")] 28 | use hmac_drbg::HmacDRBG; 29 | #[cfg(feature = "std")] 30 | use serde::{de, ser::Serializer, Deserialize, Serialize}; 31 | #[cfg(feature = "hmac")] 32 | use sha2::Sha256; 33 | #[cfg(feature = "hmac")] 34 | use typenum::U32; 35 | 36 | use crate::{ 37 | curve::{Affine, ECMultContext, ECMultGenContext, Field, Jacobian, Scalar}, 38 | util::{Decoder, SignatureArray}, 39 | }; 40 | 41 | #[cfg(feature = "lazy-static-context")] 42 | lazy_static::lazy_static! { 43 | /// A static ECMult context. 44 | pub static ref ECMULT_CONTEXT: Box = ECMultContext::new_boxed(); 45 | 46 | /// A static ECMultGen context. 47 | pub static ref ECMULT_GEN_CONTEXT: Box = ECMultGenContext::new_boxed(); 48 | } 49 | 50 | #[cfg(all(feature = "static-context", not(feature = "lazy-static-context")))] 51 | /// A static ECMult context. 52 | // Correct `pre_g` values are fed into `ECMultContext::new_from_raw`, generated by build script. 53 | pub static ECMULT_CONTEXT: ECMultContext = 54 | unsafe { ECMultContext::new_from_raw(include!(concat!(env!("OUT_DIR"), "/const.rs"))) }; 55 | 56 | #[cfg(all(feature = "static-context", not(feature = "lazy-static-context")))] 57 | /// A static ECMultGen context. 58 | // Correct `prec` values are fed into `ECMultGenContext::new_from_raw`, generated by build script. 59 | pub static ECMULT_GEN_CONTEXT: ECMultGenContext = 60 | unsafe { ECMultGenContext::new_from_raw(include!(concat!(env!("OUT_DIR"), "/const_gen.rs"))) }; 61 | 62 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 63 | /// Public key on a secp256k1 curve. 64 | pub struct PublicKey(Affine); 65 | 66 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 67 | /// Secret key (256-bit) on a secp256k1 curve. 68 | pub struct SecretKey(Scalar); 69 | 70 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 71 | /// An ECDSA signature. 72 | pub struct Signature { 73 | pub r: Scalar, 74 | pub s: Scalar, 75 | } 76 | 77 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 78 | /// Tag used for public key recovery from signatures. 79 | pub struct RecoveryId(u8); 80 | 81 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 82 | /// Hashed message input to an ECDSA signature. 83 | pub struct Message(pub Scalar); 84 | 85 | #[derive(Debug, Clone, Eq, PartialEq)] 86 | /// Shared secret using ECDH. 87 | pub struct SharedSecret(GenericArray); 88 | 89 | impl Copy for SharedSecret 90 | where 91 | D: Copy + Digest, 92 | GenericArray: Copy, 93 | { 94 | } 95 | 96 | /// Format for public key parsing. 97 | pub enum PublicKeyFormat { 98 | /// Compressed public key, 33 bytes. 99 | Compressed, 100 | /// Full length public key, 65 bytes. 101 | Full, 102 | /// Raw public key, 64 bytes. 103 | Raw, 104 | } 105 | 106 | impl PublicKey { 107 | pub fn from_secret_key_with_context( 108 | seckey: &SecretKey, 109 | context: &ECMultGenContext, 110 | ) -> PublicKey { 111 | let mut pj = Jacobian::default(); 112 | context.ecmult_gen(&mut pj, &seckey.0); 113 | let mut p = Affine::default(); 114 | p.set_gej(&pj); 115 | PublicKey(p) 116 | } 117 | 118 | #[cfg(any(feature = "static-context", feature = "lazy-static-context"))] 119 | pub fn from_secret_key(seckey: &SecretKey) -> PublicKey { 120 | Self::from_secret_key_with_context(seckey, &ECMULT_GEN_CONTEXT) 121 | } 122 | 123 | pub fn parse_slice(p: &[u8], format: Option) -> Result { 124 | let format = match (p.len(), format) { 125 | (util::FULL_PUBLIC_KEY_SIZE, None) 126 | | (util::FULL_PUBLIC_KEY_SIZE, Some(PublicKeyFormat::Full)) => PublicKeyFormat::Full, 127 | (util::COMPRESSED_PUBLIC_KEY_SIZE, None) 128 | | (util::COMPRESSED_PUBLIC_KEY_SIZE, Some(PublicKeyFormat::Compressed)) => { 129 | PublicKeyFormat::Compressed 130 | } 131 | (util::RAW_PUBLIC_KEY_SIZE, None) 132 | | (util::RAW_PUBLIC_KEY_SIZE, Some(PublicKeyFormat::Raw)) => PublicKeyFormat::Raw, 133 | _ => return Err(Error::InvalidInputLength), 134 | }; 135 | 136 | match format { 137 | PublicKeyFormat::Full => { 138 | let mut a = [0; util::FULL_PUBLIC_KEY_SIZE]; 139 | a.copy_from_slice(p); 140 | Self::parse(&a) 141 | } 142 | PublicKeyFormat::Raw => { 143 | use util::TAG_PUBKEY_FULL; 144 | 145 | let mut a = [0; util::FULL_PUBLIC_KEY_SIZE]; 146 | a[0] = TAG_PUBKEY_FULL; 147 | a[1..].copy_from_slice(p); 148 | Self::parse(&a) 149 | } 150 | PublicKeyFormat::Compressed => { 151 | let mut a = [0; util::COMPRESSED_PUBLIC_KEY_SIZE]; 152 | a.copy_from_slice(p); 153 | Self::parse_compressed(&a) 154 | } 155 | } 156 | } 157 | 158 | pub fn parse(p: &[u8; util::FULL_PUBLIC_KEY_SIZE]) -> Result { 159 | use util::{TAG_PUBKEY_FULL, TAG_PUBKEY_HYBRID_EVEN, TAG_PUBKEY_HYBRID_ODD}; 160 | 161 | if !(p[0] == TAG_PUBKEY_FULL 162 | || p[0] == TAG_PUBKEY_HYBRID_EVEN 163 | || p[0] == TAG_PUBKEY_HYBRID_ODD) 164 | { 165 | return Err(Error::InvalidPublicKey); 166 | } 167 | let mut x = Field::default(); 168 | let mut y = Field::default(); 169 | if !x.set_b32(array_ref!(p, 1, 32)) { 170 | return Err(Error::InvalidPublicKey); 171 | } 172 | if !y.set_b32(array_ref!(p, 33, 32)) { 173 | return Err(Error::InvalidPublicKey); 174 | } 175 | let mut elem = Affine::default(); 176 | elem.set_xy(&x, &y); 177 | if (p[0] == TAG_PUBKEY_HYBRID_EVEN || p[0] == TAG_PUBKEY_HYBRID_ODD) 178 | && (y.is_odd() != (p[0] == TAG_PUBKEY_HYBRID_ODD)) 179 | { 180 | return Err(Error::InvalidPublicKey); 181 | } 182 | if elem.is_infinity() { 183 | return Err(Error::InvalidPublicKey); 184 | } 185 | if elem.is_valid_var() { 186 | Ok(PublicKey(elem)) 187 | } else { 188 | Err(Error::InvalidPublicKey) 189 | } 190 | } 191 | 192 | pub fn parse_compressed( 193 | p: &[u8; util::COMPRESSED_PUBLIC_KEY_SIZE], 194 | ) -> Result { 195 | use util::{TAG_PUBKEY_EVEN, TAG_PUBKEY_ODD}; 196 | 197 | if !(p[0] == TAG_PUBKEY_EVEN || p[0] == TAG_PUBKEY_ODD) { 198 | return Err(Error::InvalidPublicKey); 199 | } 200 | let mut x = Field::default(); 201 | if !x.set_b32(array_ref!(p, 1, 32)) { 202 | return Err(Error::InvalidPublicKey); 203 | } 204 | let mut elem = Affine::default(); 205 | elem.set_xo_var(&x, p[0] == TAG_PUBKEY_ODD); 206 | if elem.is_infinity() { 207 | return Err(Error::InvalidPublicKey); 208 | } 209 | if elem.is_valid_var() { 210 | Ok(PublicKey(elem)) 211 | } else { 212 | Err(Error::InvalidPublicKey) 213 | } 214 | } 215 | 216 | pub fn serialize(&self) -> [u8; util::FULL_PUBLIC_KEY_SIZE] { 217 | use util::TAG_PUBKEY_FULL; 218 | 219 | debug_assert!(!self.0.is_infinity()); 220 | 221 | let mut ret = [0u8; 65]; 222 | let mut elem = self.0; 223 | 224 | elem.x.normalize_var(); 225 | elem.y.normalize_var(); 226 | elem.x.fill_b32(array_mut_ref!(ret, 1, 32)); 227 | elem.y.fill_b32(array_mut_ref!(ret, 33, 32)); 228 | ret[0] = TAG_PUBKEY_FULL; 229 | 230 | ret 231 | } 232 | 233 | pub fn serialize_compressed(&self) -> [u8; util::COMPRESSED_PUBLIC_KEY_SIZE] { 234 | use util::{TAG_PUBKEY_EVEN, TAG_PUBKEY_ODD}; 235 | 236 | debug_assert!(!self.0.is_infinity()); 237 | 238 | let mut ret = [0u8; 33]; 239 | let mut elem = self.0; 240 | 241 | elem.x.normalize_var(); 242 | elem.y.normalize_var(); 243 | elem.x.fill_b32(array_mut_ref!(ret, 1, 32)); 244 | ret[0] = if elem.y.is_odd() { 245 | TAG_PUBKEY_ODD 246 | } else { 247 | TAG_PUBKEY_EVEN 248 | }; 249 | 250 | ret 251 | } 252 | 253 | pub fn tweak_add_assign_with_context( 254 | &mut self, 255 | tweak: &SecretKey, 256 | context: &ECMultContext, 257 | ) -> Result<(), Error> { 258 | let mut r = Jacobian::default(); 259 | let a = Jacobian::from_ge(&self.0); 260 | let one = Scalar::from_int(1); 261 | context.ecmult(&mut r, &a, &one, &tweak.0); 262 | 263 | if r.is_infinity() { 264 | return Err(Error::TweakOutOfRange); 265 | } 266 | 267 | self.0.set_gej(&r); 268 | Ok(()) 269 | } 270 | 271 | #[cfg(any(feature = "static-context", feature = "lazy-static-context"))] 272 | pub fn tweak_add_assign(&mut self, tweak: &SecretKey) -> Result<(), Error> { 273 | self.tweak_add_assign_with_context(tweak, &ECMULT_CONTEXT) 274 | } 275 | 276 | pub fn tweak_mul_assign_with_context( 277 | &mut self, 278 | tweak: &SecretKey, 279 | context: &ECMultContext, 280 | ) -> Result<(), Error> { 281 | if tweak.0.is_zero() { 282 | return Err(Error::TweakOutOfRange); 283 | } 284 | 285 | let mut r = Jacobian::default(); 286 | let zero = Scalar::from_int(0); 287 | let pt = Jacobian::from_ge(&self.0); 288 | context.ecmult(&mut r, &pt, &tweak.0, &zero); 289 | 290 | self.0.set_gej(&r); 291 | Ok(()) 292 | } 293 | 294 | #[cfg(any(feature = "static-context", feature = "lazy-static-context"))] 295 | pub fn tweak_mul_assign(&mut self, tweak: &SecretKey) -> Result<(), Error> { 296 | self.tweak_mul_assign_with_context(tweak, &ECMULT_CONTEXT) 297 | } 298 | 299 | pub fn combine(keys: &[PublicKey]) -> Result { 300 | let mut qj = Jacobian::default(); 301 | qj.set_infinity(); 302 | 303 | for key in keys { 304 | qj = qj.add_ge(&key.0); 305 | } 306 | 307 | if qj.is_infinity() { 308 | return Err(Error::InvalidPublicKey); 309 | } 310 | 311 | let q = Affine::from_gej(&qj); 312 | Ok(PublicKey(q)) 313 | } 314 | } 315 | 316 | impl Into for PublicKey { 317 | fn into(self) -> Affine { 318 | self.0 319 | } 320 | } 321 | 322 | impl TryFrom for PublicKey { 323 | type Error = Error; 324 | 325 | fn try_from(value: Affine) -> Result { 326 | if value.is_infinity() || !value.is_valid_var() { 327 | Err(Error::InvalidAffine) 328 | } else { 329 | Ok(PublicKey(value)) 330 | } 331 | } 332 | } 333 | 334 | #[cfg(feature = "std")] 335 | impl Serialize for PublicKey { 336 | fn serialize(&self, serializer: S) -> Result 337 | where 338 | S: Serializer, 339 | { 340 | if serializer.is_human_readable() { 341 | serializer.serialize_str(&BASE64_STANDARD.encode(&self.serialize()[..])) 342 | } else { 343 | serializer.serialize_bytes(&self.serialize()) 344 | } 345 | } 346 | } 347 | 348 | #[cfg(feature = "std")] 349 | struct PublicKeyStrVisitor; 350 | 351 | #[cfg(feature = "std")] 352 | impl<'de> de::Visitor<'de> for PublicKeyStrVisitor { 353 | type Value = PublicKey; 354 | 355 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 356 | formatter 357 | .write_str("a bytestring of either 33 (compressed), 64 (raw), or 65 bytes in length") 358 | } 359 | 360 | fn visit_str(self, value: &str) -> Result 361 | where 362 | E: de::Error, 363 | { 364 | let value: &[u8] = &BASE64_STANDARD.decode(value).map_err(|e| E::custom(e))?; 365 | let key_format = match value.len() { 366 | 33 => PublicKeyFormat::Compressed, 367 | 64 => PublicKeyFormat::Raw, 368 | 65 => PublicKeyFormat::Full, 369 | _ => return Err(E::custom(Error::InvalidInputLength)), 370 | }; 371 | PublicKey::parse_slice(value, Some(key_format)) 372 | .map_err(|_e| E::custom(Error::InvalidPublicKey)) 373 | } 374 | } 375 | 376 | #[cfg(feature = "std")] 377 | struct PublicKeyBytesVisitor; 378 | 379 | #[cfg(feature = "std")] 380 | impl<'de> de::Visitor<'de> for PublicKeyBytesVisitor { 381 | type Value = PublicKey; 382 | 383 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 384 | formatter.write_str( 385 | "a byte slice that is either 33 (compressed), 64 (raw), or 65 bytes in length", 386 | ) 387 | } 388 | 389 | fn visit_bytes(self, value: &[u8]) -> Result 390 | where 391 | E: de::Error, 392 | { 393 | PublicKey::parse_slice(value, None).map_err(|_e| E::custom(Error::InvalidPublicKey)) 394 | } 395 | } 396 | 397 | #[cfg(feature = "std")] 398 | impl<'de> Deserialize<'de> for PublicKey { 399 | fn deserialize(deserializer: D) -> Result 400 | where 401 | D: de::Deserializer<'de>, 402 | { 403 | if deserializer.is_human_readable() { 404 | deserializer.deserialize_str(PublicKeyStrVisitor) 405 | } else { 406 | deserializer.deserialize_bytes(PublicKeyBytesVisitor) 407 | } 408 | } 409 | } 410 | 411 | impl SecretKey { 412 | pub fn parse(p: &[u8; util::SECRET_KEY_SIZE]) -> Result { 413 | let mut elem = Scalar::default(); 414 | if !bool::from(elem.set_b32(p)) { 415 | Self::try_from(elem) 416 | } else { 417 | Err(Error::InvalidSecretKey) 418 | } 419 | } 420 | 421 | pub fn parse_slice(p: &[u8]) -> Result { 422 | if p.len() != util::SECRET_KEY_SIZE { 423 | return Err(Error::InvalidInputLength); 424 | } 425 | 426 | let mut a = [0; 32]; 427 | a.copy_from_slice(p); 428 | Self::parse(&a) 429 | } 430 | 431 | pub fn random(rng: &mut R) -> SecretKey { 432 | loop { 433 | let mut ret = [0u8; util::SECRET_KEY_SIZE]; 434 | rng.fill_bytes(&mut ret); 435 | 436 | if let Ok(key) = Self::parse(&ret) { 437 | return key; 438 | } 439 | } 440 | } 441 | 442 | pub fn serialize(&self) -> [u8; util::SECRET_KEY_SIZE] { 443 | self.0.b32() 444 | } 445 | 446 | pub fn tweak_add_assign(&mut self, tweak: &SecretKey) -> Result<(), Error> { 447 | let v = self.0 + tweak.0; 448 | if v.is_zero() { 449 | return Err(Error::TweakOutOfRange); 450 | } 451 | self.0 = v; 452 | Ok(()) 453 | } 454 | 455 | pub fn tweak_mul_assign(&mut self, tweak: &SecretKey) -> Result<(), Error> { 456 | if tweak.0.is_zero() { 457 | return Err(Error::TweakOutOfRange); 458 | } 459 | 460 | self.0 *= &tweak.0; 461 | Ok(()) 462 | } 463 | 464 | pub fn inv(&self) -> Self { 465 | SecretKey(self.0.inv()) 466 | } 467 | 468 | pub fn clear(&mut self) { 469 | self.0.clear(); 470 | } 471 | 472 | pub fn is_zero(&self) -> bool { 473 | self.0.is_zero() 474 | } 475 | } 476 | 477 | impl Default for SecretKey { 478 | fn default() -> SecretKey { 479 | let mut elem = Scalar::default(); 480 | let overflowed = bool::from(elem.set_b32(&[ 481 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 482 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 483 | 0x00, 0x00, 0x00, 0x01, 484 | ])); 485 | debug_assert!(!overflowed); 486 | debug_assert!(!elem.is_zero()); 487 | SecretKey(elem) 488 | } 489 | } 490 | 491 | impl Into for SecretKey { 492 | fn into(self) -> Scalar { 493 | self.0 494 | } 495 | } 496 | 497 | impl TryFrom for SecretKey { 498 | type Error = Error; 499 | 500 | fn try_from(scalar: Scalar) -> Result { 501 | if scalar.is_zero() { 502 | Err(Error::InvalidSecretKey) 503 | } else { 504 | Ok(Self(scalar)) 505 | } 506 | } 507 | } 508 | 509 | impl core::fmt::LowerHex for SecretKey { 510 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 511 | let scalar = self.0; 512 | 513 | write!(f, "{:x}", scalar) 514 | } 515 | } 516 | 517 | impl Signature { 518 | /// Parse an possibly overflowing signature. 519 | /// 520 | /// A SECP256K1 signature is usually required to be within 0 and curve 521 | /// order. This function, however, allows signatures larger than curve order 522 | /// by taking the signature and minus curve order. 523 | /// 524 | /// Note that while this function is technically safe, it is non-standard, 525 | /// meaning you will have compatibility issues if you also use other 526 | /// SECP256K1 libraries. It's not recommended to use this function. Please 527 | /// use `parse_standard` instead. 528 | pub fn parse_overflowing(p: &[u8; util::SIGNATURE_SIZE]) -> Signature { 529 | let mut r = Scalar::default(); 530 | let mut s = Scalar::default(); 531 | 532 | // Okay for signature to overflow 533 | let _ = r.set_b32(array_ref!(p, 0, 32)); 534 | let _ = s.set_b32(array_ref!(p, 32, 32)); 535 | 536 | Signature { r, s } 537 | } 538 | 539 | /// Parse a standard SECP256K1 signature. The signature is required to be 540 | /// within 0 and curve order. Returns error if it overflows. 541 | pub fn parse_standard(p: &[u8; util::SIGNATURE_SIZE]) -> Result { 542 | let mut r = Scalar::default(); 543 | let mut s = Scalar::default(); 544 | 545 | // It's okay for the signature to overflow here, it's checked below. 546 | let overflowed_r = r.set_b32(array_ref!(p, 0, 32)); 547 | let overflowed_s = s.set_b32(array_ref!(p, 32, 32)); 548 | 549 | if bool::from(overflowed_r | overflowed_s) { 550 | return Err(Error::InvalidSignature); 551 | } 552 | 553 | Ok(Signature { r, s }) 554 | } 555 | 556 | /// Parse a possibly overflowing signature slice. See also 557 | /// `parse_overflowing`. 558 | /// 559 | /// It's not recommended to use this function. Please use 560 | /// `parse_standard_slice` instead. 561 | pub fn parse_overflowing_slice(p: &[u8]) -> Result { 562 | if p.len() != util::SIGNATURE_SIZE { 563 | return Err(Error::InvalidInputLength); 564 | } 565 | 566 | let mut a = [0; util::SIGNATURE_SIZE]; 567 | a.copy_from_slice(p); 568 | Ok(Self::parse_overflowing(&a)) 569 | } 570 | 571 | /// Parse a standard signature slice. See also `parse_standard`. 572 | pub fn parse_standard_slice(p: &[u8]) -> Result { 573 | if p.len() != util::SIGNATURE_SIZE { 574 | return Err(Error::InvalidInputLength); 575 | } 576 | 577 | let mut a = [0; util::SIGNATURE_SIZE]; 578 | a.copy_from_slice(p); 579 | Ok(Self::parse_standard(&a)?) 580 | } 581 | 582 | /// Parse a DER-encoded byte slice to a signature. 583 | pub fn parse_der(p: &[u8]) -> Result { 584 | let mut decoder = Decoder::new(p); 585 | 586 | decoder.read_constructed_sequence()?; 587 | let rlen = decoder.read_len()?; 588 | 589 | if rlen != decoder.remaining_len() { 590 | return Err(Error::InvalidSignature); 591 | } 592 | 593 | let r = decoder.read_integer()?; 594 | let s = decoder.read_integer()?; 595 | 596 | if decoder.remaining_len() != 0 { 597 | return Err(Error::InvalidSignature); 598 | } 599 | 600 | Ok(Signature { r, s }) 601 | } 602 | 603 | /// Converts a "lax DER"-encoded byte slice to a signature. This is basically 604 | /// only useful for validating signatures in the Bitcoin blockchain from before 605 | /// 2016. It should never be used in new applications. This library does not 606 | /// support serializing to this "format" 607 | pub fn parse_der_lax(p: &[u8]) -> Result { 608 | let mut decoder = Decoder::new(p); 609 | 610 | decoder.read_constructed_sequence()?; 611 | decoder.read_seq_len_lax()?; 612 | 613 | let r = decoder.read_integer_lax()?; 614 | let s = decoder.read_integer_lax()?; 615 | 616 | Ok(Signature { r, s }) 617 | } 618 | 619 | /// Normalizes a signature to a "low S" form. In ECDSA, signatures are 620 | /// of the form (r, s) where r and s are numbers lying in some finite 621 | /// field. The verification equation will pass for (r, s) iff it passes 622 | /// for (r, -s), so it is possible to ``modify'' signatures in transit 623 | /// by flipping the sign of s. This does not constitute a forgery since 624 | /// the signed message still cannot be changed, but for some applications, 625 | /// changing even the signature itself can be a problem. Such applications 626 | /// require a "strong signature". It is believed that ECDSA is a strong 627 | /// signature except for this ambiguity in the sign of s, so to accommodate 628 | /// these applications libsecp256k1 will only accept signatures for which 629 | /// s is in the lower half of the field range. This eliminates the 630 | /// ambiguity. 631 | /// 632 | /// However, for some systems, signatures with high s-values are considered 633 | /// valid. (For example, parsing the historic Bitcoin blockchain requires 634 | /// this.) For these applications we provide this normalization function, 635 | /// which ensures that the s value lies in the lower half of its range. 636 | pub fn normalize_s(&mut self) { 637 | if self.s.is_high() { 638 | self.s = -self.s; 639 | } 640 | } 641 | 642 | /// Serialize a signature to a standard byte representation. This is the 643 | /// reverse of `parse_standard`. 644 | pub fn serialize(&self) -> [u8; util::SIGNATURE_SIZE] { 645 | let mut ret = [0u8; 64]; 646 | self.r.fill_b32(array_mut_ref!(ret, 0, 32)); 647 | self.s.fill_b32(array_mut_ref!(ret, 32, 32)); 648 | ret 649 | } 650 | 651 | /// Serialize a signature to a DER encoding. This is the reverse of 652 | /// `parse_der`. 653 | pub fn serialize_der(&self) -> SignatureArray { 654 | fn fill_scalar_with_leading_zero(scalar: &Scalar) -> [u8; 33] { 655 | let mut ret = [0u8; 33]; 656 | scalar.fill_b32(array_mut_ref!(ret, 1, 32)); 657 | ret 658 | } 659 | 660 | let r_full = fill_scalar_with_leading_zero(&self.r); 661 | let s_full = fill_scalar_with_leading_zero(&self.s); 662 | 663 | fn integer_slice(full: &[u8; 33]) -> &[u8] { 664 | let mut len = 33; 665 | while len > 1 && full[full.len() - len] == 0 && full[full.len() - len + 1] < 0x80 { 666 | len -= 1; 667 | } 668 | &full[(full.len() - len)..] 669 | } 670 | 671 | let r = integer_slice(&r_full); 672 | let s = integer_slice(&s_full); 673 | 674 | let mut ret = SignatureArray::new(6 + r.len() + s.len()); 675 | { 676 | let l = ret.as_mut(); 677 | l[0] = 0x30; 678 | l[1] = 4 + r.len() as u8 + s.len() as u8; 679 | l[2] = 0x02; 680 | l[3] = r.len() as u8; 681 | l[4..(4 + r.len())].copy_from_slice(r); 682 | l[4 + r.len()] = 0x02; 683 | l[5 + r.len()] = s.len() as u8; 684 | l[(6 + r.len())..(6 + r.len() + s.len())].copy_from_slice(s); 685 | } 686 | 687 | ret 688 | } 689 | } 690 | 691 | impl Message { 692 | pub fn parse(p: &[u8; util::MESSAGE_SIZE]) -> Message { 693 | let mut m = Scalar::default(); 694 | 695 | // Okay for message to overflow. 696 | let _ = m.set_b32(p); 697 | 698 | Message(m) 699 | } 700 | 701 | pub fn parse_slice(p: &[u8]) -> Result { 702 | if p.len() != util::MESSAGE_SIZE { 703 | return Err(Error::InvalidInputLength); 704 | } 705 | 706 | let mut a = [0; util::MESSAGE_SIZE]; 707 | a.copy_from_slice(p); 708 | Ok(Self::parse(&a)) 709 | } 710 | 711 | pub fn serialize(&self) -> [u8; util::MESSAGE_SIZE] { 712 | self.0.b32() 713 | } 714 | } 715 | 716 | impl RecoveryId { 717 | /// Parse recovery ID starting with 0. 718 | pub fn parse(p: u8) -> Result { 719 | if p < 4 { 720 | Ok(RecoveryId(p)) 721 | } else { 722 | Err(Error::InvalidRecoveryId) 723 | } 724 | } 725 | 726 | /// Parse recovery ID as Ethereum RPC format, starting with 27. 727 | pub fn parse_rpc(p: u8) -> Result { 728 | if p >= 27 && p < 27 + 4 { 729 | RecoveryId::parse(p - 27) 730 | } else { 731 | Err(Error::InvalidRecoveryId) 732 | } 733 | } 734 | 735 | pub fn serialize(&self) -> u8 { 736 | self.0 737 | } 738 | } 739 | 740 | impl Into for RecoveryId { 741 | fn into(self) -> u8 { 742 | self.0 743 | } 744 | } 745 | 746 | impl Into for RecoveryId { 747 | fn into(self) -> i32 { 748 | self.0 as i32 749 | } 750 | } 751 | 752 | impl SharedSecret { 753 | pub fn new_with_context( 754 | pubkey: &PublicKey, 755 | seckey: &SecretKey, 756 | context: &ECMultContext, 757 | ) -> Result, Error> { 758 | let inner = match context.ecdh_raw::(&pubkey.0, &seckey.0) { 759 | Some(val) => val, 760 | None => return Err(Error::InvalidSecretKey), 761 | }; 762 | 763 | Ok(SharedSecret(inner)) 764 | } 765 | 766 | #[cfg(any(feature = "static-context", feature = "lazy-static-context"))] 767 | pub fn new(pubkey: &PublicKey, seckey: &SecretKey) -> Result, Error> { 768 | Self::new_with_context(pubkey, seckey, &ECMULT_CONTEXT) 769 | } 770 | } 771 | 772 | impl AsRef<[u8]> for SharedSecret { 773 | fn as_ref(&self) -> &[u8] { 774 | &self.0.as_ref() 775 | } 776 | } 777 | 778 | /// Check signature is a valid message signed by public key, using the given context. 779 | pub fn verify_with_context( 780 | message: &Message, 781 | signature: &Signature, 782 | pubkey: &PublicKey, 783 | context: &ECMultContext, 784 | ) -> bool { 785 | context.verify_raw(&signature.r, &signature.s, &pubkey.0, &message.0) 786 | } 787 | 788 | #[cfg(any(feature = "static-context", feature = "lazy-static-context"))] 789 | /// Check signature is a valid message signed by public key. 790 | pub fn verify(message: &Message, signature: &Signature, pubkey: &PublicKey) -> bool { 791 | verify_with_context(message, signature, pubkey, &ECMULT_CONTEXT) 792 | } 793 | 794 | /// Recover public key from a signed message, using the given context. 795 | pub fn recover_with_context( 796 | message: &Message, 797 | signature: &Signature, 798 | recovery_id: &RecoveryId, 799 | context: &ECMultContext, 800 | ) -> Result { 801 | context 802 | .recover_raw(&signature.r, &signature.s, recovery_id.0, &message.0) 803 | .map(PublicKey) 804 | } 805 | 806 | #[cfg(any(feature = "static-context", feature = "lazy-static-context"))] 807 | /// Recover public key from a signed message. 808 | pub fn recover( 809 | message: &Message, 810 | signature: &Signature, 811 | recovery_id: &RecoveryId, 812 | ) -> Result { 813 | recover_with_context(message, signature, recovery_id, &ECMULT_CONTEXT) 814 | } 815 | 816 | #[cfg(feature = "hmac")] 817 | /// Sign a message using the secret key, with the given context. 818 | pub fn sign_with_context( 819 | message: &Message, 820 | seckey: &SecretKey, 821 | context: &ECMultGenContext, 822 | ) -> (Signature, RecoveryId) { 823 | let seckey_b32 = seckey.0.b32(); 824 | let message_b32 = message.0.b32(); 825 | 826 | let mut drbg = HmacDRBG::::new(&seckey_b32, &message_b32, &[]); 827 | let mut nonce = Scalar::default(); 828 | let mut overflow; 829 | 830 | let result; 831 | loop { 832 | let generated = drbg.generate::(None); 833 | overflow = bool::from(nonce.set_b32(array_ref!(generated, 0, 32))); 834 | 835 | if !overflow && !nonce.is_zero() { 836 | if let Ok(val) = context.sign_raw(&seckey.0, &message.0, &nonce) { 837 | result = val; 838 | break; 839 | } 840 | } 841 | } 842 | 843 | #[allow(unused_assignments)] 844 | { 845 | nonce = Scalar::default(); 846 | } 847 | let (sigr, sigs, recid) = result; 848 | 849 | (Signature { r: sigr, s: sigs }, RecoveryId(recid)) 850 | } 851 | 852 | #[cfg(all( 853 | feature = "hmac", 854 | any(feature = "static-context", feature = "lazy-static-context") 855 | ))] 856 | /// Sign a message using the secret key. 857 | pub fn sign(message: &Message, seckey: &SecretKey) -> (Signature, RecoveryId) { 858 | sign_with_context(message, seckey, &ECMULT_GEN_CONTEXT) 859 | } 860 | 861 | #[cfg(test)] 862 | mod tests { 863 | use crate::SecretKey; 864 | use hex_literal::hex; 865 | 866 | #[test] 867 | fn secret_key_inverse_is_sane() { 868 | let sk = SecretKey::parse(&[1; 32]).unwrap(); 869 | let inv = sk.inv(); 870 | let invinv = inv.inv(); 871 | assert_eq!(sk, invinv); 872 | // Check that the inverse of `[1; 32]` is same as rust-secp256k1 873 | assert_eq!( 874 | inv, 875 | SecretKey::parse(&hex!( 876 | "1536f1d756d1abf83aaf173bc5ee3fc487c93010f18624d80bd6d4038fadd59e" 877 | )) 878 | .unwrap() 879 | ) 880 | } 881 | 882 | #[test] 883 | fn secret_key_clear_is_correct() { 884 | let mut sk = SecretKey::parse(&[1; 32]).unwrap(); 885 | sk.clear(); 886 | assert_eq!(sk.is_zero(), true); 887 | } 888 | } 889 | -------------------------------------------------------------------------------- /tests/serde.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "std")] 2 | 3 | use libsecp256k1::*; 4 | 5 | const DEBUG_SECRET_KEY: [u8; 32] = [1u8; 32]; 6 | // Public key for debug secret key 7 | const SERIALIZED_DEBUG_PUBLIC_KEY: &str = 8 | "\"BBuExVZ7EmRAmV0+1aq6BWXXHhg0YEgZ/5wX9enV3QePcL6vj1iLVBUH/tamQsWrQt/fgSCn9jneUSLUemmo6NE=\""; 9 | 10 | fn debug_public_key() -> PublicKey { 11 | let skey = SecretKey::parse(&DEBUG_SECRET_KEY).unwrap(); 12 | PublicKey::from_secret_key(&skey) 13 | } 14 | 15 | #[test] 16 | fn test_serialize_public_key() { 17 | let pkey = debug_public_key(); 18 | let serialized_pkey = serde_json::to_string(&pkey).unwrap(); 19 | assert_eq!(serialized_pkey, SERIALIZED_DEBUG_PUBLIC_KEY); 20 | } 21 | 22 | #[test] 23 | fn test_deserialize_public_key() { 24 | let pkey: PublicKey = serde_json::from_str(&SERIALIZED_DEBUG_PUBLIC_KEY).unwrap(); 25 | assert_eq!(pkey, debug_public_key()); 26 | } 27 | 28 | #[test] 29 | fn test_public_key_bincode_serde() { 30 | let pkey = debug_public_key(); 31 | let serialized_pkey: Vec = bincode::serialize(&pkey).unwrap(); 32 | let pkey2 = bincode::deserialize(&serialized_pkey).unwrap(); 33 | assert_eq!(pkey, pkey2); 34 | } 35 | -------------------------------------------------------------------------------- /tests/verify.rs: -------------------------------------------------------------------------------- 1 | use libsecp256k1::*; 2 | use secp256k1_test::{ 3 | key, rand::thread_rng, Error as SecpError, Message as SecpMessage, Secp256k1, 4 | Signature as SecpSignature, 5 | }; 6 | 7 | #[cfg(feature = "hmac")] 8 | mod signatures { 9 | use crate::{recover, sign, verify, Message, PublicKey, SecretKey, SharedSecret, Signature}; 10 | use secp256k1_test::{ 11 | ecdh::SharedSecret as SecpSharedSecret, 12 | key, 13 | rand::thread_rng, 14 | recovery::{ 15 | RecoverableSignature as SecpRecoverableSignature, RecoveryId as SecpRecoveryId, 16 | }, 17 | All, Message as SecpMessage, Secp256k1, Signature as SecpSignature, 18 | }; 19 | use sha2::Sha256; 20 | 21 | fn genkey( 22 | secp256k1: &Secp256k1, 23 | ) -> (key::PublicKey, key::SecretKey, PublicKey, SecretKey) { 24 | let (secp_privkey, secp_pubkey) = secp256k1.generate_keypair(&mut thread_rng()); 25 | let pubkey_a = secp_pubkey.serialize_uncompressed(); 26 | assert_eq!(pubkey_a.len(), 65); 27 | let pubkey = PublicKey::parse(&pubkey_a).unwrap(); 28 | let mut seckey_a = [0u8; 32]; 29 | for i in 0..32 { 30 | seckey_a[i] = secp_privkey[i]; 31 | } 32 | let seckey = SecretKey::parse(&seckey_a).unwrap(); 33 | 34 | (secp_pubkey, secp_privkey, pubkey, seckey) 35 | } 36 | 37 | #[test] 38 | fn test_signature_der() { 39 | let secp256k1 = Secp256k1::new(); 40 | 41 | let message_arr = [5u8; 32]; 42 | let (privkey, _) = secp256k1.generate_keypair(&mut thread_rng()); 43 | 44 | assert!(privkey[..].len() == 32); 45 | let mut privkey_a = [0u8; 32]; 46 | for i in 0..32 { 47 | privkey_a[i] = privkey[i]; 48 | } 49 | 50 | let ctx_privkey = SecretKey::parse(&privkey_a).unwrap(); 51 | let ctx_message = Message::parse(&message_arr); 52 | 53 | let (signature, _) = sign(&ctx_message, &ctx_privkey); 54 | let reconstructed = Signature::parse_der(signature.serialize_der().as_ref()).unwrap(); 55 | assert_eq!(signature, reconstructed); 56 | } 57 | 58 | #[test] 59 | fn test_sign_verify() { 60 | let secp256k1 = Secp256k1::new(); 61 | 62 | let message_arr = [6u8; 32]; 63 | let (secp_privkey, secp_pubkey) = secp256k1.generate_keypair(&mut thread_rng()); 64 | 65 | let secp_message = SecpMessage::from_slice(&message_arr).unwrap(); 66 | let pubkey_a = secp_pubkey.serialize_uncompressed(); 67 | assert_eq!(pubkey_a.len(), 65); 68 | let pubkey = PublicKey::parse(&pubkey_a).unwrap(); 69 | let mut seckey_a = [0u8; 32]; 70 | for i in 0..32 { 71 | seckey_a[i] = secp_privkey[i]; 72 | } 73 | let seckey = SecretKey::parse(&seckey_a).unwrap(); 74 | let message = Message::parse(&message_arr); 75 | 76 | let (sig, recid) = sign(&message, &seckey); 77 | 78 | // Self verify 79 | assert!(verify(&message, &sig, &pubkey)); 80 | 81 | // Self recover 82 | let recovered_pubkey = recover(&message, &sig, &recid).unwrap(); 83 | let rpa = recovered_pubkey.serialize(); 84 | let opa = pubkey.serialize(); 85 | let rpr: &[u8] = &rpa; 86 | let opr: &[u8] = &opa; 87 | assert_eq!(rpr, opr); 88 | 89 | let signature_a = sig.serialize(); 90 | let secp_recid = SecpRecoveryId::from_i32(recid.into()).unwrap(); 91 | let secp_rec_signature = 92 | SecpRecoverableSignature::from_compact(&signature_a, secp_recid).unwrap(); 93 | let secp_signature = SecpSignature::from_compact(&signature_a).unwrap(); 94 | 95 | // External verify 96 | secp256k1 97 | .verify(&secp_message, &secp_signature, &secp_pubkey) 98 | .unwrap(); 99 | 100 | // External recover 101 | let recovered_pubkey = secp256k1 102 | .recover(&secp_message, &secp_rec_signature) 103 | .unwrap(); 104 | let rpa = recovered_pubkey.serialize_uncompressed(); 105 | let rpr: &[u8] = &rpa; 106 | assert_eq!(rpr, opr); 107 | } 108 | 109 | #[test] 110 | fn test_failing_sign_verify() { 111 | let seckey_a: [u8; 32] = [ 112 | 169, 195, 92, 103, 2, 159, 75, 46, 158, 79, 249, 49, 208, 28, 48, 210, 5, 47, 136, 77, 113 | 21, 51, 224, 54, 213, 165, 90, 122, 233, 199, 0, 248, 114 | ]; 115 | let seckey = SecretKey::parse(&seckey_a).unwrap(); 116 | let pubkey = PublicKey::from_secret_key(&seckey); 117 | let message_arr = [6u8; 32]; 118 | let message = Message::parse(&message_arr); 119 | 120 | let (sig, recid) = sign(&message, &seckey); 121 | let tmp: u8 = recid.into(); 122 | assert_eq!(tmp, 1u8); 123 | 124 | let recovered_pubkey = recover(&message, &sig, &recid).unwrap(); 125 | let rpa = recovered_pubkey.serialize(); 126 | let opa = pubkey.serialize(); 127 | let rpr: &[u8] = &rpa; 128 | let opr: &[u8] = &opa; 129 | assert_eq!(rpr, opr); 130 | } 131 | 132 | #[test] 133 | fn test_shared_secret() { 134 | let secp256k1 = Secp256k1::new(); 135 | 136 | let (spub1, ssec1, pub1, sec1) = genkey(&secp256k1); 137 | let (spub2, ssec2, pub2, sec2) = genkey(&secp256k1); 138 | 139 | let shared1 = SharedSecret::::new(&pub1, &sec2).unwrap(); 140 | let shared2 = SharedSecret::::new(&pub2, &sec1).unwrap(); 141 | 142 | let secp_shared1 = SecpSharedSecret::new(&spub1, &ssec2); 143 | let secp_shared2 = SecpSharedSecret::new(&spub2, &ssec1); 144 | 145 | assert_eq!(shared1.as_ref(), shared2.as_ref()); 146 | 147 | for i in 0..32 { 148 | assert_eq!(shared1.as_ref()[i], secp_shared1[i]); 149 | } 150 | 151 | for i in 0..32 { 152 | assert_eq!(shared2.as_ref()[i], secp_shared2[i]); 153 | } 154 | } 155 | } 156 | 157 | #[test] 158 | fn test_verify() { 159 | let secp256k1 = Secp256k1::new(); 160 | 161 | let message_arr = [5u8; 32]; 162 | let (privkey, pubkey) = secp256k1.generate_keypair(&mut thread_rng()); 163 | let message = SecpMessage::from_slice(&message_arr).unwrap(); 164 | let signature = secp256k1.sign(&message, &privkey); 165 | 166 | let pubkey_a = pubkey.serialize_uncompressed(); 167 | assert_eq!(pubkey_a.len(), 65); 168 | 169 | let ctx_pubkey = PublicKey::parse(&pubkey_a).unwrap(); 170 | let ctx_message = Message::parse(&message_arr); 171 | let signature_a = signature.serialize_compact(); 172 | assert_eq!(signature_a.len(), 64); 173 | let ctx_sig = Signature::parse_standard(&signature_a).expect("signature is valid"); 174 | 175 | secp256k1.verify(&message, &signature, &pubkey).unwrap(); 176 | assert!(verify(&ctx_message, &ctx_sig, &ctx_pubkey)); 177 | let mut f_ctx_sig = ctx_sig; 178 | f_ctx_sig.r.set_int(0); 179 | if f_ctx_sig.r != ctx_sig.r { 180 | assert!(!ECMULT_CONTEXT.verify_raw( 181 | &f_ctx_sig.r, 182 | &ctx_sig.s, 183 | &ctx_pubkey.into(), 184 | &ctx_message.0 185 | )); 186 | } 187 | f_ctx_sig.r.set_int(1); 188 | if f_ctx_sig.r != ctx_sig.r { 189 | assert!(!ECMULT_CONTEXT.verify_raw( 190 | &f_ctx_sig.r, 191 | &ctx_sig.s, 192 | &ctx_pubkey.into(), 193 | &ctx_message.0 194 | )); 195 | } 196 | } 197 | 198 | #[test] 199 | fn secret_clear_on_drop() { 200 | let secret: [u8; 32] = [1; 32]; 201 | let mut seckey = SecretKey::parse(&secret).unwrap(); 202 | 203 | clear_on_drop::clear::Clear::clear(&mut seckey); 204 | assert_eq!(seckey, SecretKey::default()); 205 | } 206 | 207 | #[test] 208 | fn test_recover() { 209 | let secp256k1 = Secp256k1::new(); 210 | 211 | let message_arr = [5u8; 32]; 212 | let (privkey, pubkey) = secp256k1.generate_keypair(&mut thread_rng()); 213 | let message = SecpMessage::from_slice(&message_arr).unwrap(); 214 | let signature = secp256k1.sign_recoverable(&message, &privkey); 215 | 216 | let pubkey_a = pubkey.serialize_uncompressed(); 217 | assert_eq!(pubkey_a.len(), 65); 218 | 219 | let ctx_message = Message::parse(&message_arr); 220 | let (rec_id, signature_a) = signature.serialize_compact(); 221 | assert_eq!(signature_a.len(), 64); 222 | let ctx_sig = Signature::parse_standard(&signature_a).expect("signature is valid"); 223 | 224 | // secp256k1.recover(&message, &signature).unwrap(); 225 | let ctx_pubkey = recover( 226 | &ctx_message, 227 | &ctx_sig, 228 | &RecoveryId::parse(rec_id.to_i32() as u8).unwrap(), 229 | ) 230 | .unwrap(); 231 | let sp = ctx_pubkey.serialize(); 232 | 233 | let sps: &[u8] = &sp; 234 | let gps: &[u8] = &pubkey_a; 235 | assert_eq!(sps, gps); 236 | } 237 | 238 | fn from_hex(hex: &str, target: &mut [u8]) -> Result { 239 | if hex.len() % 2 == 1 || hex.len() > target.len() * 2 { 240 | return Err(()); 241 | } 242 | 243 | let mut b = 0; 244 | let mut idx = 0; 245 | for c in hex.bytes() { 246 | b <<= 4; 247 | match c { 248 | b'A'..=b'F' => b |= c - b'A' + 10, 249 | b'a'..=b'f' => b |= c - b'a' + 10, 250 | b'0'..=b'9' => b |= c - b'0', 251 | _ => return Err(()), 252 | } 253 | if (idx & 1) == 1 { 254 | target[idx / 2] = b; 255 | b = 0; 256 | } 257 | idx += 1; 258 | } 259 | Ok(idx / 2) 260 | } 261 | 262 | macro_rules! hex { 263 | ($hex:expr) => {{ 264 | let mut result = vec![0; $hex.len() / 2]; 265 | from_hex($hex, &mut result).expect("valid hex string"); 266 | result 267 | }}; 268 | } 269 | 270 | #[test] 271 | fn test_signature_der_lax() { 272 | macro_rules! check_lax_sig { 273 | ($hex:expr) => {{ 274 | let sig = hex!($hex); 275 | assert!(Signature::parse_der_lax(&sig[..]).is_ok()); 276 | }}; 277 | } 278 | 279 | check_lax_sig!("304402204c2dd8a9b6f8d425fcd8ee9a20ac73b619906a6367eac6cb93e70375225ec0160220356878eff111ff3663d7e6bf08947f94443845e0dcc54961664d922f7660b80c"); 280 | check_lax_sig!("304402202ea9d51c7173b1d96d331bd41b3d1b4e78e66148e64ed5992abd6ca66290321c0220628c47517e049b3e41509e9d71e480a0cdc766f8cdec265ef0017711c1b5336f"); 281 | check_lax_sig!("3045022100bf8e050c85ffa1c313108ad8c482c4849027937916374617af3f2e9a881861c9022023f65814222cab09d5ec41032ce9c72ca96a5676020736614de7b78a4e55325a"); 282 | check_lax_sig!("3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45"); 283 | check_lax_sig!("3046022100eaa5f90483eb20224616775891397d47efa64c68b969db1dacb1c30acdfc50aa022100cf9903bbefb1c8000cf482b0aeeb5af19287af20bd794de11d82716f9bae3db1"); 284 | check_lax_sig!("3045022047d512bc85842ac463ca3b669b62666ab8672ee60725b6c06759e476cebdc6c102210083805e93bd941770109bcc797784a71db9e48913f702c56e60b1c3e2ff379a60"); 285 | check_lax_sig!("3044022023ee4e95151b2fbbb08a72f35babe02830d14d54bd7ed1320e4751751d1baa4802206235245254f58fd1be6ff19ca291817da76da65c2f6d81d654b5185dd86b8acf"); 286 | } 287 | 288 | #[test] 289 | fn test_low_s() { 290 | // nb this is a transaction on testnet 291 | // txid 8ccc87b72d766ab3128f03176bb1c98293f2d1f85ebfaf07b82cc81ea6891fa9 292 | // input number 3 293 | let sig = hex!("3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45"); 294 | let pk = hex!("031ee99d2b786ab3b0991325f2de8489246a6a3fdb700f6d0511b1d80cf5f4cd43"); 295 | let msg = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d"); 296 | 297 | let secp = Secp256k1::new(); 298 | let mut sig = Signature::parse_der(&sig[..]).unwrap(); 299 | let pk = key::PublicKey::from_slice(&pk[..]).unwrap(); 300 | let msg = SecpMessage::from_slice(&msg[..]).unwrap(); 301 | 302 | // without normalization we expect this will fail 303 | assert_eq!( 304 | secp.verify( 305 | &msg, 306 | &SecpSignature::from_compact(&sig.serialize()).unwrap(), 307 | &pk 308 | ), 309 | Err(SecpError::IncorrectSignature) 310 | ); 311 | // after normalization it should pass 312 | sig.normalize_s(); 313 | assert_eq!( 314 | secp.verify( 315 | &msg, 316 | &SecpSignature::from_compact(&sig.serialize()).unwrap(), 317 | &pk 318 | ), 319 | Ok(()) 320 | ); 321 | } 322 | 323 | #[test] 324 | fn test_convert_key1() { 325 | let secret: [u8; 32] = [ 326 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 327 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 328 | 0x00, 0x01, 329 | ]; 330 | let expected: &[u8] = &[ 331 | 0x04, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce, 0x87, 332 | 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81, 0x5b, 0x16, 333 | 0xf8, 0x17, 0x98, 0x48, 0x3a, 0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65, 0x5d, 0xa4, 0xfb, 0xfc, 334 | 0x0e, 0x11, 0x08, 0xa8, 0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 0x19, 0x9c, 0x47, 0xd0, 335 | 0x8f, 0xfb, 0x10, 0xd4, 0xb8, 336 | ]; 337 | let seckey = SecretKey::parse(&secret).unwrap(); 338 | let pubkey = PublicKey::from_secret_key(&seckey); 339 | assert_eq!(expected, &pubkey.serialize()[..]); 340 | let pubkey_compressed = PublicKey::parse_compressed(&pubkey.serialize_compressed()).unwrap(); 341 | assert_eq!(expected, &pubkey_compressed.serialize()[..]); 342 | } 343 | 344 | #[test] 345 | fn test_convert_key2() { 346 | let secret: [u8; 32] = [ 347 | 0x4d, 0x5d, 0xb4, 0x10, 0x7d, 0x23, 0x7d, 0xf6, 0xa3, 0xd5, 0x8e, 0xe5, 0xf7, 0x0a, 0xe6, 348 | 0x3d, 0x73, 0xd7, 0x65, 0x8d, 0x40, 0x26, 0xf2, 0xee, 0xfd, 0x2f, 0x20, 0x4c, 0x81, 0x68, 349 | 0x2c, 0xb7, 350 | ]; 351 | let expected: &[u8] = &[ 352 | 0x04, 0x3f, 0xa8, 0xc0, 0x8c, 0x65, 0xa8, 0x3f, 0x6b, 0x4e, 0xa3, 0xe0, 0x4e, 0x1c, 0xc7, 353 | 0x0c, 0xbe, 0x3c, 0xd3, 0x91, 0x49, 0x9e, 0x3e, 0x05, 0xab, 0x7d, 0xed, 0xf2, 0x8a, 0xff, 354 | 0x9a, 0xfc, 0x53, 0x82, 0x00, 0xff, 0x93, 0xe3, 0xf2, 0xb2, 0xcb, 0x50, 0x29, 0xf0, 0x3c, 355 | 0x7e, 0xbe, 0xe8, 0x20, 0xd6, 0x3a, 0x4c, 0x5a, 0x95, 0x41, 0xc8, 0x3a, 0xce, 0xbe, 0x29, 356 | 0x3f, 0x54, 0xca, 0xcf, 0x0e, 357 | ]; 358 | let seckey = SecretKey::parse(&secret).unwrap(); 359 | let pubkey = PublicKey::from_secret_key(&seckey); 360 | assert_eq!(expected, &pubkey.serialize()[..]); 361 | let pubkey_compressed = PublicKey::parse_compressed(&pubkey.serialize_compressed()).unwrap(); 362 | assert_eq!(expected, &pubkey_compressed.serialize()[..]); 363 | } 364 | 365 | #[test] 366 | fn test_convert_anykey() { 367 | let secp256k1 = Secp256k1::new(); 368 | let (secp_privkey, secp_pubkey) = secp256k1.generate_keypair(&mut thread_rng()); 369 | 370 | let mut secret = [0u8; 32]; 371 | for i in 0..32 { 372 | secret[i] = secp_privkey[i]; 373 | } 374 | 375 | let seckey = SecretKey::parse(&secret).unwrap(); 376 | let pubkey = PublicKey::from_secret_key(&seckey); 377 | let public = pubkey.serialize(); 378 | let public_compressed = pubkey.serialize_compressed(); 379 | let pubkey_r: &[u8] = &public; 380 | let pubkey_compressed_r: &[u8] = &public_compressed; 381 | 382 | let secp_pubkey_a = secp_pubkey.serialize_uncompressed(); 383 | assert_eq!(secp_pubkey_a.len(), 65); 384 | let secp_pubkey_compressed_a = secp_pubkey.serialize(); 385 | assert_eq!(secp_pubkey_compressed_a.len(), 33); 386 | let secp_pubkey_r: &[u8] = &secp_pubkey_a; 387 | let secp_pubkey_compressed_r: &[u8] = &secp_pubkey_compressed_a; 388 | 389 | assert_eq!(secp_pubkey_r, pubkey_r); 390 | assert_eq!(secp_pubkey_compressed_r, pubkey_compressed_r); 391 | } 392 | 393 | #[test] 394 | fn test_pubkey_combine() { 395 | let pk1 = PublicKey::parse(&[ 396 | 4, 126, 60, 36, 91, 73, 177, 194, 111, 11, 3, 99, 246, 204, 86, 122, 109, 85, 28, 43, 169, 397 | 243, 35, 76, 152, 90, 76, 241, 17, 108, 232, 215, 115, 15, 19, 23, 164, 151, 43, 28, 44, 398 | 59, 141, 167, 134, 112, 105, 251, 15, 193, 183, 224, 238, 154, 204, 230, 163, 216, 235, 399 | 112, 77, 239, 98, 135, 132, 400 | ]) 401 | .unwrap(); 402 | let pk2 = PublicKey::parse(&[ 403 | 4, 40, 127, 167, 223, 38, 53, 6, 223, 67, 83, 204, 60, 226, 227, 107, 231, 172, 34, 3, 187, 404 | 79, 112, 167, 0, 217, 118, 69, 218, 189, 208, 150, 190, 54, 186, 220, 95, 80, 220, 183, 405 | 202, 117, 160, 18, 84, 245, 181, 23, 32, 51, 73, 178, 173, 92, 118, 92, 122, 83, 49, 54, 406 | 195, 194, 16, 229, 39, 407 | ]) 408 | .unwrap(); 409 | let cpk = PublicKey::parse(&[ 410 | 4, 101, 166, 20, 152, 34, 76, 121, 113, 139, 80, 13, 92, 122, 96, 38, 194, 205, 149, 93, 411 | 19, 147, 132, 195, 173, 42, 86, 26, 221, 170, 127, 180, 168, 145, 21, 75, 45, 248, 90, 114, 412 | 118, 62, 196, 194, 143, 245, 204, 184, 16, 175, 202, 175, 228, 207, 112, 219, 94, 237, 75, 413 | 105, 186, 56, 102, 46, 147, 414 | ]) 415 | .unwrap(); 416 | 417 | assert_eq!(PublicKey::combine(&[pk1, pk2]).unwrap(), cpk); 418 | } 419 | 420 | #[test] 421 | fn test_pubkey_equality() { 422 | for _ in 0..10 { 423 | let secret = SecretKey::random(&mut rand::rngs::OsRng); 424 | let public = PublicKey::from_secret_key(&secret); 425 | 426 | let public2 = PublicKey::parse(&public.serialize()).unwrap(); 427 | let public3 = PublicKey::parse_compressed(&public.serialize_compressed()).unwrap(); 428 | 429 | // Reflexivity 430 | assert_eq!(public, public); 431 | assert_eq!(public2, public2); 432 | assert_eq!(public3, public3); 433 | 434 | // Symmetry 435 | assert_eq!(public2, public); 436 | assert_eq!(public, public2); 437 | assert_eq!(public2, public3); 438 | assert_eq!(public3, public2); 439 | 440 | // Transitivity 441 | assert_eq!(public, public3); 442 | assert_eq!(public3, public); 443 | } 444 | } 445 | -------------------------------------------------------------------------------- /tests/wycheproof.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | use sha2::Digest; 3 | use std::collections::HashMap; 4 | 5 | #[derive(Deserialize)] 6 | #[serde(rename_all = "camelCase")] 7 | #[allow(dead_code)] 8 | struct TestCollection { 9 | algorithm: String, 10 | generator_version: String, 11 | number_of_tests: usize, 12 | header: Vec, 13 | notes: HashMap, 14 | schema: String, 15 | test_groups: Vec, 16 | } 17 | 18 | #[derive(Deserialize)] 19 | #[serde(rename_all = "camelCase")] 20 | #[allow(dead_code)] 21 | struct TestGroup { 22 | key: TestKey, 23 | key_der: String, 24 | key_pem: String, 25 | sha: String, 26 | #[serde(rename = "type")] 27 | typ: String, 28 | tests: Vec, 29 | } 30 | 31 | #[derive(Deserialize)] 32 | #[serde(rename_all = "camelCase")] 33 | #[allow(dead_code)] 34 | struct TestKey { 35 | curve: String, 36 | key_size: usize, 37 | #[serde(rename = "type")] 38 | typ: String, 39 | uncompressed: String, 40 | wx: String, 41 | wy: String, 42 | } 43 | 44 | #[derive(Deserialize)] 45 | #[serde(rename_all = "camelCase")] 46 | #[allow(dead_code)] 47 | struct TestUnit { 48 | tc_id: usize, 49 | comment: String, 50 | msg: String, 51 | sig: String, 52 | result: TestResult, 53 | flags: Vec, 54 | } 55 | 56 | #[derive(Deserialize, PartialEq, Eq, Debug)] 57 | #[serde(rename_all = "camelCase")] 58 | enum TestResult { 59 | Valid, 60 | Acceptable, 61 | Invalid, 62 | } 63 | 64 | enum TestError { 65 | MessageDecoding, 66 | SignatureDecoding, 67 | Verification, 68 | } 69 | 70 | fn test_unit(test: &TestUnit, key: &libsecp256k1::PublicKey) -> Result<(), TestError> { 71 | println!("tcId: {}, comment: {}", test.tc_id, test.comment); 72 | 73 | let msg_raw = hex::decode(&test.msg).unwrap(); 74 | let sig_raw = hex::decode(&test.sig).unwrap(); 75 | 76 | let msg_hashed_raw = sha2::Sha256::digest(&msg_raw); 77 | let msg = libsecp256k1::Message::parse_slice(&msg_hashed_raw) 78 | .map_err(|_| TestError::MessageDecoding)?; 79 | let sig = 80 | libsecp256k1::Signature::parse_der(&sig_raw).map_err(|_| TestError::SignatureDecoding)?; 81 | 82 | if libsecp256k1::verify(&msg, &sig, &key) { 83 | Ok(()) 84 | } else { 85 | Err(TestError::Verification) 86 | } 87 | } 88 | 89 | #[test] 90 | fn test_wycheproof() { 91 | let test_collection_str = include_str!("../res/ecdsa_secp256k1_sha256_test.json"); 92 | let test_collection: TestCollection = serde_json::from_str(test_collection_str).unwrap(); 93 | 94 | for test_group in test_collection.test_groups { 95 | assert_eq!(test_group.key.typ, "EcPublicKey"); 96 | assert_eq!(test_group.key.curve, "secp256k1"); 97 | assert_eq!(test_group.key.key_size, 256); 98 | 99 | let key_raw = hex::decode(test_group.key.uncompressed).unwrap(); 100 | let key = libsecp256k1::PublicKey::parse_slice(&key_raw, None).unwrap(); 101 | 102 | for test in test_group.tests { 103 | let res = test_unit(&test, &key); 104 | 105 | match res { 106 | Ok(()) => assert!(test.result == TestResult::Valid), 107 | Err(TestError::Verification) => assert_eq!(test.result, TestResult::Invalid), 108 | Err(TestError::MessageDecoding) => assert_eq!(test.result, TestResult::Invalid), 109 | // libsecp256k1 do not use any legacy formats, so "acceptable" 110 | // result in wycheproof is considered the same as invalid. 111 | Err(TestError::SignatureDecoding) => assert!( 112 | test.result == TestResult::Acceptable || test.result == TestResult::Invalid 113 | ), 114 | } 115 | } 116 | } 117 | } 118 | --------------------------------------------------------------------------------