├── .gitignore ├── .gitlab-ci.yml ├── .gitmodules ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── build.rs ├── depend ├── check_uint128_t.c └── ext.c └── src ├── constants.rs ├── ecdh.rs ├── ffi.rs ├── key.rs ├── lib.rs └── macros.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | *.swp 3 | Cargo.lock 4 | .idea -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # .gitlab-ci.yml 2 | # rust-secp256k1 3 | 4 | 5 | stages: 6 | - test 7 | - build 8 | 9 | 10 | 11 | image: parity/rust-builder:latest 12 | 13 | variables: 14 | GIT_STRATEGY: fetch 15 | GIT_SUBMODULE_STRATEGY: recursive 16 | CARGO_HOME: "/ci-cache/${CI_PROJECT_NAME}/cargo/${CI_JOB_NAME}" 17 | SCCACHE_DIR: "/ci-cache/${CI_PROJECT_NAME}/sccache" 18 | CI_SERVER_NAME: "GitLab CI" 19 | DOCKER_OS: "debian:stretch" 20 | ARCH: "x86_64" 21 | 22 | 23 | 24 | .docker-env: &docker-env 25 | tags: 26 | - linux-docker 27 | 28 | .compiler_info: &compiler_info 29 | before_script: 30 | - rustup show 31 | - cargo --version 32 | - sccache -s 33 | 34 | .build-refs: &build-refs 35 | only: 36 | - master 37 | - schedules 38 | - web 39 | - /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 40 | 41 | .test-refs: &test-refs 42 | only: 43 | - master 44 | - schedules 45 | - web 46 | - /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 47 | - /^[0-9]+$/ 48 | 49 | 50 | 51 | 52 | 53 | test-linux-stable: &test 54 | stage: test 55 | <<: *test-refs 56 | <<: *docker-env 57 | <<: *compiler_info 58 | variables: 59 | RUST_TOOLCHAIN: stable 60 | RUSTFLAGS: -Cdebug-assertions=y 61 | TARGET: native 62 | script: 63 | - time cargo test --all --release --verbose 64 | - sccache -s 65 | 66 | 67 | 68 | 69 | build-linux-release: &build 70 | stage: build 71 | <<: *build-refs 72 | <<: *docker-env 73 | <<: *compiler_info 74 | script: 75 | - time cargo build --release --verbose 76 | - sccache -s 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "depend/secp256k1"] 2 | path = depend/secp256k1 3 | url = https://github.com/bitcoin/secp256k1 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | sudo: false 3 | 4 | matrix: 5 | include: 6 | - rust: stable 7 | - rust: beta 8 | - rust: nightly 9 | 10 | install: 11 | - | 12 | pip install 'travis-cargo<0.2' --user && 13 | export PATH=$HOME/.local/bin:$PATH 14 | 15 | script: 16 | - | 17 | travis-cargo build && 18 | travis-cargo build -- --release && 19 | travis-cargo test && 20 | travis-cargo test -- --release && 21 | travis-cargo bench && 22 | travis-cargo --only stable doc 23 | 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parity-secp256k1" 3 | version = "0.7.0" 4 | authors = [ 5 | "Dawid Ciężarkiewicz ", 6 | "Andrew Poelstra ", 7 | "Parity Technologies ", 8 | ] 9 | license = "CC0-1.0" 10 | homepage = "https://github.com/paritytech/rust-secp256k1/" 11 | repository = "https://github.com/paritytech/rust-secp256k1/" 12 | documentation = "https://www.wpsoftware.net/rustdoc/secp256k1/" 13 | description = "Fork of Rust bindings for Pieter Wuille's `libsecp256k1` library. Implements ECDSA for the SECG elliptic curve group secp256k1 and related utilities." 14 | keywords = [ "ECDSA", "secp256k1", "libsecp256k1", "bitcoin", "ethereum" ] 15 | readme = "README.md" 16 | build = "build.rs" 17 | 18 | [build-dependencies] 19 | cc = "1.0.45" 20 | cfg-if = "0.1.10" 21 | 22 | [lib] 23 | name = "secp256k1" 24 | path = "src/lib.rs" 25 | 26 | [features] 27 | unstable = [] 28 | default = [] 29 | dev = ["clippy"] 30 | 31 | [dependencies] 32 | arrayvec = "0.5.1" 33 | clippy = { version = "0.0.302", optional = true } 34 | rand = "0.7.2" 35 | 36 | [dev-dependencies] 37 | hex-literal = "0.2.1" 38 | rand_core = "0.5.1" 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | 123 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | cargo test 3 | 4 | build: 5 | cargo build 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://gitlab.parity.io/parity/rust-secp256k1/badges/master/build.svg)](https://gitlab.parity.io/parity/rust-secp256k1/commits/master) 2 | [![crates.io](https://img.shields.io/crates/v/parity-secp256k1.svg)](https://crates.io/crates/parity-secp256k1) 3 | [![](https://tokei.rs/b1/github/paritytech/rust-secp256k1)](https://github.com/paritytech/rust-secp256k1) 4 | 5 | 6 | ### parity-secp256k1 7 | 8 | `parity-secp256k1` is a wrapper around [libsecp256k1](https://github.com/bitcoin/secp256k1), 9 | a C library by Peter Wuille for producing ECDSA signatures using the SECG curve 10 | `secp256k1`. It is a fork of [`rust-secp256k1`](https://github.com/rust-bitcoin/rust-secp256k1). 11 | 12 | This library 13 | * exposes type-safe Rust bindings for all `libsecp256k1` functions 14 | * implements key generation 15 | * implements deterministic nonce generation via RFC6979 16 | * implements many unit tests, adding to those already present in `libsecp256k1` 17 | * makes no allocations (except in unit tests) for efficiency and use in freestanding implementations 18 | 19 | [Full documentation](https://docs.rs/parity-secp256k1) 20 | 21 | #### Build 22 | 23 | Clone the repository. Run the following: 24 | 25 | ``` 26 | git submodule init 27 | git submodule update 28 | cargo check 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | // Bitcoin secp256k1 bindings 2 | // Written in 2015 by 3 | // Andrew Poelstra 4 | // 5 | // To the extent possible under law, the author(s) have dedicated all 6 | // copyright and related and neighboring rights to this software to 7 | // the public domain worldwide. This software is distributed without 8 | // any warranty. 9 | // 10 | // You should have received a copy of the CC0 Public Domain Dedication 11 | // along with this software. 12 | // If not, see . 13 | // 14 | 15 | //! # Build script 16 | 17 | // Coding conventions 18 | #![deny(non_upper_case_globals)] 19 | #![deny(non_camel_case_types)] 20 | #![deny(non_snake_case)] 21 | #![deny(unused_mut)] 22 | #![warn(missing_docs)] 23 | 24 | #[macro_use] 25 | extern crate cfg_if; 26 | 27 | extern crate cc; 28 | 29 | use std::env; 30 | use std::ffi::OsString; 31 | use std::path::PathBuf; 32 | 33 | cfg_if! { 34 | if #[cfg(target_os = "macos")] { 35 | const OS: &'static str = "darwin"; 36 | } else if #[cfg(target_os = "linux")] { 37 | const OS: &'static str = "linux"; 38 | } else if #[cfg(target_os = "windows")] { 39 | const OS: &'static str = "windows"; 40 | } else { 41 | // all other OS without android support 42 | const OS: &'static str = "unknown"; 43 | } 44 | } 45 | 46 | const ANDROID_INCLUDE: &'static str = "platforms/android-21/arch-arm64/usr/include"; 47 | 48 | fn android_aarch_compiler() -> String { 49 | "toolchains/aarch64-linux-android-4.9/prebuilt/".to_owned() + OS + "-x86_64/bin" 50 | } 51 | 52 | fn android_arm_compiler() -> String { 53 | "toolchains/arm-linux-androideabi-4.9/prebuilt/".to_owned() + OS + "-x86_64/bin" 54 | } 55 | 56 | fn android_i686_compiler() -> String { 57 | "toolchains/x86-4.9/prebuilt/".to_owned() + OS + "-x86_64/bin" 58 | } 59 | 60 | fn concat_paths(first: &str, second: &str) -> PathBuf { 61 | let mut path = PathBuf::from(first); 62 | path.push(second); 63 | path 64 | } 65 | 66 | fn setup_android(config: &mut cc::Build) { 67 | assert_ne!(OS, "unknown", "unsupported android toolchain"); 68 | let path = env::var_os("PATH").unwrap_or_else(OsString::new); 69 | let ndk_home = env::var("NDK_HOME").expect("NDK_HOME is not set"); 70 | let mut paths = env::split_paths(&path).collect::>(); 71 | paths.push(concat_paths(&ndk_home, &android_aarch_compiler())); 72 | paths.push(concat_paths(&ndk_home, &android_arm_compiler())); 73 | paths.push(concat_paths(&ndk_home, &android_i686_compiler())); 74 | 75 | let new_path = env::join_paths(paths).expect("all paths were created using PathBuf's; qed"); 76 | env::set_var("PATH", new_path); 77 | 78 | config.include(&concat_paths(&ndk_home, ANDROID_INCLUDE)); 79 | } 80 | 81 | fn main() { 82 | // Check whether we can use 64-bit compilation 83 | let use_64bit_compilation = if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "64" { 84 | let check = cc::Build::new().file("depend/check_uint128_t.c") 85 | .cargo_metadata(false) 86 | .try_compile("check_uint128_t") 87 | .is_ok(); 88 | if !check { 89 | println!("cargo:warning=Compiling in 32-bit mode on a 64-bit architecture due to lack of uint128_t support."); 90 | } 91 | check 92 | } else { 93 | false 94 | }; 95 | 96 | let mut base_config = cc::Build::new(); 97 | base_config.include("depend/secp256k1/") 98 | .include("depend/secp256k1/include") 99 | .include("depend/secp256k1/src") 100 | .debug(true) 101 | .flag_if_supported("-Wno-unused-function") // some ecmult stuff is defined but not used upstream 102 | .define("SECP256K1_BUILD", Some("1")) 103 | // Allowed values are 2..24, there is a tradeoff between 104 | // memory and cpu time (tuned for best ratio) 105 | .define("ECMULT_WINDOW_SIZE", Some("8")) 106 | // Allowed values are: 2, 4, and 8 (tuned for best perf) 107 | .define("ECMULT_GEN_PREC_BITS", Some("4")) 108 | // TODO these three should be changed to use libgmp, at least until secp PR 290 is merged 109 | .define("USE_NUM_NONE", Some("1")) 110 | .define("USE_FIELD_INV_BUILTIN", Some("1")) 111 | .define("USE_SCALAR_INV_BUILTIN", Some("1")) 112 | .define("USE_ENDOMORPHISM", Some("1")) 113 | .define("ENABLE_MODULE_ECDH", Some("1")) 114 | // SCHNORR support was removed in the upstream 115 | // .define("ENABLE_MODULE_SCHNORR", Some("1")) 116 | .define("ENABLE_MODULE_RECOVERY", Some("1")); 117 | 118 | let target = env::var("TARGET").expect("TARGET env variable is set by cargo; qed"); 119 | if target.contains("android") { 120 | setup_android(&mut base_config); 121 | } 122 | 123 | if let Ok(target_endian) = env::var("CARGO_CFG_TARGET_ENDIAN") { 124 | if target_endian == "big" { 125 | base_config.define("WORDS_BIGENDIAN", Some("1")); 126 | } 127 | } 128 | 129 | if use_64bit_compilation { 130 | base_config.define("USE_FIELD_5X52", Some("1")) 131 | .define("USE_SCALAR_4X64", Some("1")) 132 | .define("HAVE___INT128", Some("1")); 133 | } else { 134 | base_config.define("USE_FIELD_10X26", Some("1")) 135 | .define("USE_SCALAR_8X32", Some("1")); 136 | } 137 | 138 | // secp256k1 139 | base_config.file("depend/secp256k1/contrib/lax_der_parsing.c") 140 | .file("depend/ext.c") 141 | .compile("libsecp256k1.a"); 142 | } 143 | 144 | -------------------------------------------------------------------------------- /depend/check_uint128_t.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(void) { 4 | __uint128_t var_128; 5 | uint64_t var_64; 6 | 7 | /* Try to shut up "unused variable" warnings */ 8 | var_64 = 100; 9 | var_128 = 100; 10 | if (var_64 == var_128) { 11 | var_64 = 20; 12 | } 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /depend/ext.c: -------------------------------------------------------------------------------- 1 | /** @file ext.c 2 | * Ethereum extensions to libecp256k1 3 | * @authors: 4 | * Arkadiy Paronyan 5 | * @date 2015 6 | */ 7 | 8 | #include "src/secp256k1.c" 9 | 10 | 11 | static int ecdh_hash_function_raw(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { 12 | (void)y; 13 | (void)data; 14 | 15 | memcpy(output, x, 32); 16 | 17 | return 1; 18 | } 19 | 20 | const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_raw = ecdh_hash_function_raw; 21 | 22 | int secp256k1_ecdh_raw(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) 23 | { 24 | return secp256k1_ecdh(ctx, result, point, scalar, secp256k1_ecdh_hash_function_raw, NULL); 25 | } 26 | 27 | /// Returns inverse (1 / n) of secret key `seckey` 28 | int secp256k1_ec_privkey_inverse(const secp256k1_context* ctx, unsigned char *inversed, const unsigned char* seckey) { 29 | secp256k1_scalar inv; 30 | secp256k1_scalar sec; 31 | int ret = 0; 32 | int overflow = 0; 33 | VERIFY_CHECK(ctx != NULL); 34 | ARG_CHECK(inversed != NULL); 35 | ARG_CHECK(seckey != NULL); 36 | 37 | secp256k1_scalar_set_b32(&sec, seckey, NULL); 38 | ret = !overflow; 39 | if (ret) { 40 | memset(inversed, 0, 32); 41 | secp256k1_scalar_inverse(&inv, &sec); 42 | secp256k1_scalar_get_b32(inversed, &inv); 43 | } 44 | 45 | secp256k1_scalar_clear(&inv); 46 | secp256k1_scalar_clear(&sec); 47 | return ret; 48 | } 49 | -------------------------------------------------------------------------------- /src/constants.rs: -------------------------------------------------------------------------------- 1 | // Bitcoin secp256k1 bindings 2 | // Written in 2014 by 3 | // Dawid Ciężarkiewicz 4 | // Andrew Poelstra 5 | // 6 | // To the extent possible under law, the author(s) have dedicated all 7 | // copyright and related and neighboring rights to this software to 8 | // the public domain worldwide. This software is distributed without 9 | // any warranty. 10 | // 11 | // You should have received a copy of the CC0 Public Domain Dedication 12 | // along with this software. 13 | // If not, see . 14 | // 15 | 16 | //! # Constants 17 | //! Constants related to the API and the underlying curve 18 | 19 | /// The size (in bytes) of a message 20 | pub const MESSAGE_SIZE: usize = 32; 21 | 22 | /// The size (in bytes) of a secret key 23 | pub const SECRET_KEY_SIZE: usize = 32; 24 | 25 | /// The size (in bytes) of a public key array. This only needs to be 65 26 | /// but must be 72 for compatibility with the `ArrayVec` library. 27 | pub const PUBLIC_KEY_SIZE: usize = 72; 28 | 29 | /// The size (in bytes) of an uncompressed public key 30 | pub const UNCOMPRESSED_PUBLIC_KEY_SIZE: usize = 65; 31 | 32 | /// The size (in bytes) of a compressed public key 33 | pub const COMPRESSED_PUBLIC_KEY_SIZE: usize = 33; 34 | 35 | /// The maximum size of a signature 36 | pub const MAX_SIGNATURE_SIZE: usize = 72; 37 | 38 | /// The size of a Schnorr signature 39 | pub const SCHNORR_SIGNATURE_SIZE: usize = 64; 40 | 41 | /// The maximum size of a compact signature 42 | pub const COMPACT_SIGNATURE_SIZE: usize = 64; 43 | 44 | /// The order of the secp256k1 curve 45 | pub const CURVE_ORDER: [u8; 32] = [ 46 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 47 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 48 | 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 49 | 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 50 | ]; 51 | 52 | /// The X coordinate of the generator 53 | pub const GENERATOR_X: [u8; 32] = [ 54 | 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 55 | 0x55, 0xa0, 0x62, 0x95, 0xce, 0x87, 0x0b, 0x07, 56 | 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 57 | 0x59, 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98 58 | ]; 59 | 60 | /// The Y coordinate of the generator 61 | pub const GENERATOR_Y: [u8; 32] = [ 62 | 0x48, 0x3a, 0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65, 63 | 0x5d, 0xa4, 0xfb, 0xfc, 0x0e, 0x11, 0x08, 0xa8, 64 | 0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 0x19, 65 | 0x9c, 0x47, 0xd0, 0x8f, 0xfb, 0x10, 0xd4, 0xb8 66 | ]; 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/ecdh.rs: -------------------------------------------------------------------------------- 1 | // Bitcoin secp256k1 bindings 2 | // Written in 2015 by 3 | // Andrew Poelstra 4 | // 5 | // To the extent possible under law, the author(s) have dedicated all 6 | // copyright and related and neighboring rights to this software to 7 | // the public domain worldwide. This software is distributed without 8 | // any warranty. 9 | // 10 | // You should have received a copy of the CC0 Public Domain Dedication 11 | // along with this software. 12 | // If not, see . 13 | // 14 | 15 | //! # ECDH 16 | //! Support for shared secret computations 17 | //! 18 | 19 | use std::ops; 20 | 21 | use super::Secp256k1; 22 | use key::{SecretKey, PublicKey}; 23 | use ffi; 24 | 25 | /// A tag used for recovering the public key from a compact signature 26 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 27 | #[repr(C)] 28 | pub struct SharedSecret(ffi::SharedSecret); 29 | 30 | impl SharedSecret { 31 | /// Creates a new shared secret from a pubkey and secret key 32 | #[inline] 33 | pub fn new(secp: &Secp256k1, point: &PublicKey, scalar: &SecretKey) -> SharedSecret { 34 | unsafe { 35 | let mut ss = ffi::SharedSecret::new(); 36 | let res = ffi::secp256k1_ecdh(secp.ctx, 37 | &mut ss, 38 | point.as_ptr(), 39 | scalar.as_ptr(), 40 | ffi::secp256k1_ecdh_hash_function_default, 41 | std::ptr::null_mut()); 42 | debug_assert_eq!(res, 1); 43 | SharedSecret(ss) 44 | } 45 | } 46 | 47 | /// Creates a new unhashed shared secret from a pubkey and secret key 48 | #[inline] 49 | pub fn new_raw(secp: &Secp256k1, point: &PublicKey, scalar: &SecretKey) -> SharedSecret { 50 | unsafe { 51 | let mut ss = ffi::SharedSecret::new(); 52 | let res = ffi::secp256k1_ecdh_raw(secp.ctx, &mut ss, point.as_ptr(), scalar.as_ptr()); 53 | debug_assert_eq!(res, 1); 54 | SharedSecret(ss) 55 | } 56 | } 57 | 58 | /// Obtains a raw pointer suitable for use with FFI functions 59 | #[inline] 60 | pub fn as_ptr(&self) -> *const ffi::SharedSecret { 61 | &self.0 as *const _ 62 | } 63 | } 64 | 65 | /// Creates a new shared secret from a FFI shared secret 66 | impl From for SharedSecret { 67 | #[inline] 68 | fn from(ss: ffi::SharedSecret) -> SharedSecret { 69 | SharedSecret(ss) 70 | } 71 | } 72 | 73 | 74 | impl ops::Index for SharedSecret { 75 | type Output = u8; 76 | 77 | #[inline] 78 | fn index(&self, index: usize) -> &u8 { 79 | &self.0[index] 80 | } 81 | } 82 | 83 | impl ops::Index> for SharedSecret { 84 | type Output = [u8]; 85 | 86 | #[inline] 87 | fn index(&self, index: ops::Range) -> &[u8] { 88 | &self.0[index] 89 | } 90 | } 91 | 92 | impl ops::Index> for SharedSecret { 93 | type Output = [u8]; 94 | 95 | #[inline] 96 | fn index(&self, index: ops::RangeFrom) -> &[u8] { 97 | &self.0[index.start..] 98 | } 99 | } 100 | 101 | impl ops::Index for SharedSecret { 102 | type Output = [u8]; 103 | 104 | #[inline] 105 | fn index(&self, _: ops::RangeFull) -> &[u8] { 106 | &self.0[..] 107 | } 108 | } 109 | 110 | #[cfg(test)] 111 | mod tests { 112 | use rand::thread_rng; 113 | use super::SharedSecret; 114 | use super::super::Secp256k1; 115 | 116 | #[test] 117 | fn ecdh() { 118 | let s = Secp256k1::with_caps(::ContextFlag::SignOnly); 119 | let (sk1, pk1) = s.generate_keypair(&mut thread_rng()).unwrap(); 120 | let (sk2, pk2) = s.generate_keypair(&mut thread_rng()).unwrap(); 121 | 122 | let sec1 = SharedSecret::new(&s, &pk1, &sk2); 123 | let sec2 = SharedSecret::new(&s, &pk2, &sk1); 124 | let sec_odd = SharedSecret::new(&s, &pk1, &sk1); 125 | assert_eq!(sec1, sec2); 126 | assert!(sec_odd != sec2); 127 | } 128 | 129 | #[test] 130 | fn ecdh_raw() { 131 | let s = Secp256k1::with_caps(::ContextFlag::SignOnly); 132 | let (sk1, pk1) = s.generate_keypair(&mut thread_rng()).unwrap(); 133 | let (sk2, pk2) = s.generate_keypair(&mut thread_rng()).unwrap(); 134 | 135 | let sec1 = SharedSecret::new_raw(&s, &pk1, &sk2); 136 | let sec2 = SharedSecret::new_raw(&s, &pk2, &sk1); 137 | let sec_odd = SharedSecret::new_raw(&s, &pk1, &sk1); 138 | assert_eq!(sec1, sec2); 139 | assert!(sec_odd != sec2); 140 | } 141 | } 142 | 143 | #[cfg(all(test, feature = "unstable"))] 144 | mod benches { 145 | use rand::thread_rng; 146 | use test::{Bencher, black_box}; 147 | 148 | use super::SharedSecret; 149 | use super::super::Secp256k1; 150 | 151 | #[bench] 152 | pub fn bench_ecdh(bh: &mut Bencher) { 153 | let s = Secp256k1::with_caps(::ContextFlag::SignOnly); 154 | let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap(); 155 | 156 | let s = Secp256k1::new(); 157 | bh.iter( || { 158 | let res = SharedSecret::new(&s, &pk, &sk); 159 | black_box(res); 160 | }); 161 | } 162 | } 163 | 164 | -------------------------------------------------------------------------------- /src/ffi.rs: -------------------------------------------------------------------------------- 1 | // Bitcoin secp256k1 bindings 2 | // Written in 2014 by 3 | // Dawid Ciężarkiewicz 4 | // Andrew Poelstra 5 | // 6 | // To the extent possible under law, the author(s) have dedicated all 7 | // copyright and related and neighboring rights to this software to 8 | // the public domain worldwide. This software is distributed without 9 | // any warranty. 10 | // 11 | // You should have received a copy of the CC0 Public Domain Dedication 12 | // along with this software. 13 | // If not, see . 14 | // 15 | 16 | //! # FFI bindings 17 | //! Direct bindings to the underlying C library functions. These should 18 | //! not be needed for most users. 19 | use std::hash; 20 | use std::os::raw::{c_int, c_uchar, c_uint, c_void}; 21 | 22 | /// Flag for context to enable no precomputation 23 | pub const SECP256K1_START_NONE: c_uint = (1 << 0) | 0; 24 | /// Flag for context to enable verification precomputation 25 | pub const SECP256K1_START_VERIFY: c_uint = (1 << 0) | (1 << 8); 26 | /// Flag for context to enable signing precomputation 27 | pub const SECP256K1_START_SIGN: c_uint = (1 << 0) | (1 << 9); 28 | /// Flag for keys to indicate uncompressed serialization format 29 | pub const SECP256K1_SER_UNCOMPRESSED: c_uint = (1 << 1) | 0; 30 | /// Flag for keys to indicate compressed serialization format 31 | pub const SECP256K1_SER_COMPRESSED: c_uint = (1 << 1) | (1 << 8); 32 | 33 | /// A nonce generation function. Ordinary users of the library 34 | /// never need to see this type; only if you need to control 35 | /// nonce generation do you need to use it. I have deliberately 36 | /// made this hard to do: you have to write your own wrapper 37 | /// around the FFI functions to use it. And it's an unsafe type. 38 | /// Nonces are generated deterministically by RFC6979 by 39 | /// default; there should be no need to ever change this. 40 | pub type NonceFn = unsafe extern "C" fn(nonce32: *mut c_uchar, 41 | msg32: *const c_uchar, 42 | key32: *const c_uchar, 43 | algo16: *const c_uchar, 44 | attempt: c_uint, 45 | data: *const c_void); 46 | 47 | /// A pointer to a function that applies a hash function to a point 48 | /// 49 | /// Returns: 1 if a point was successfully hashed. 0 will cause ecdh to fail 50 | /// 51 | /// Out: output: pointer to an array to be filled by the function 52 | /// In: x: pointer to a 32-byte x coordinate 53 | /// y: pointer to a 32-byte y coordinate 54 | /// data: Arbitrary data pointer that is passed through 55 | /// 56 | pub type EcdhHashFn = unsafe extern "C" fn(output: *mut c_uchar, 57 | x: *const c_uchar, 58 | y: *const c_uchar, 59 | data: *mut c_void) 60 | -> c_int; 61 | 62 | 63 | 64 | /// A Secp256k1 context, containing various precomputed values and such 65 | /// needed to do elliptic curve computations. If you create one of these 66 | /// with `secp256k1_context_create` you MUST destroy it with 67 | /// `secp256k1_context_destroy`, or else you will have a memory leak. 68 | #[derive(Clone, Debug)] 69 | #[repr(C)] pub struct Context(c_int); 70 | 71 | /// Library-internal representation of a Secp256k1 public key 72 | #[repr(C)] 73 | pub struct PublicKey([c_uchar; 64]); 74 | impl_array_newtype!(PublicKey, c_uchar, 64); 75 | impl_raw_debug!(PublicKey); 76 | 77 | impl PublicKey { 78 | /// Create a new (zeroed) public key usable for the FFI interface 79 | pub fn new() -> PublicKey { PublicKey([0; 64]) } 80 | } 81 | 82 | impl hash::Hash for PublicKey { 83 | fn hash(&self, state: &mut H) { 84 | state.write(&self.0) 85 | } 86 | } 87 | 88 | /// Library-internal representation of a Secp256k1 signature 89 | #[repr(C)] 90 | pub struct Signature([c_uchar; 64]); 91 | impl_array_newtype!(Signature, c_uchar, 64); 92 | impl_raw_debug!(Signature); 93 | 94 | /// Library-internal representation of a Secp256k1 signature + recovery ID 95 | #[repr(C)] 96 | pub struct RecoverableSignature([c_uchar; 65]); 97 | impl_array_newtype!(RecoverableSignature, c_uchar, 65); 98 | impl_raw_debug!(RecoverableSignature); 99 | 100 | impl Signature { 101 | /// Create a new (zeroed) signature usable for the FFI interface 102 | pub fn new() -> Signature { Signature([0; 64]) } 103 | } 104 | 105 | impl RecoverableSignature { 106 | /// Create a new (zeroed) signature usable for the FFI interface 107 | pub fn new() -> RecoverableSignature { RecoverableSignature([0; 65]) } 108 | } 109 | 110 | /// Library-internal representation of an ECDH shared secret 111 | #[repr(C)] 112 | pub struct SharedSecret([c_uchar; 32]); 113 | impl_array_newtype!(SharedSecret, c_uchar, 32); 114 | impl_raw_debug!(SharedSecret); 115 | 116 | impl SharedSecret { 117 | /// Create a new (zeroed) signature usable for the FFI interface 118 | pub fn new() -> SharedSecret { SharedSecret([0; 32]) } 119 | } 120 | 121 | extern "C" { 122 | pub static secp256k1_nonce_function_rfc6979: NonceFn; 123 | 124 | pub static secp256k1_nonce_function_default: NonceFn; 125 | 126 | pub static secp256k1_ecdh_hash_function_sha256: EcdhHashFn; 127 | 128 | pub static secp256k1_ecdh_hash_function_default: EcdhHashFn; 129 | 130 | // Contexts 131 | pub fn secp256k1_context_create(flags: c_uint) -> *mut Context; 132 | 133 | pub fn secp256k1_context_clone(cx: *mut Context) -> *mut Context; 134 | 135 | pub fn secp256k1_context_destroy(cx: *mut Context); 136 | 137 | pub fn secp256k1_context_randomize(cx: *mut Context, 138 | seed32: *const c_uchar) 139 | -> c_int; 140 | 141 | // TODO secp256k1_context_set_illegal_callback 142 | // TODO secp256k1_context_set_error_callback 143 | // (Actually, I don't really want these exposed; if either of these 144 | // are ever triggered it indicates a bug in rust-secp256k1, since 145 | // one goal is to use Rust's type system to eliminate all possible 146 | // bad inputs.) 147 | 148 | // Pubkeys 149 | pub fn secp256k1_ec_pubkey_parse(cx: *const Context, pk: *mut PublicKey, 150 | input: *const c_uchar, in_len: usize) 151 | -> c_int; 152 | 153 | pub fn secp256k1_ec_pubkey_serialize(cx: *const Context, output: *const c_uchar, 154 | out_len: *mut usize, pk: *const PublicKey, 155 | compressed: c_uint) 156 | -> c_int; 157 | 158 | // Signatures 159 | pub fn secp256k1_ecdsa_signature_parse_der(cx: *const Context, sig: *mut Signature, 160 | input: *const c_uchar, in_len: usize) 161 | -> c_int; 162 | 163 | pub fn ecdsa_signature_parse_der_lax(cx: *const Context, sig: *mut Signature, 164 | input: *const c_uchar, in_len: usize) 165 | -> c_int; 166 | 167 | pub fn secp256k1_ecdsa_signature_serialize_der(cx: *const Context, output: *const c_uchar, 168 | out_len: *mut usize, sig: *const Signature) 169 | -> c_int; 170 | 171 | pub fn secp256k1_ecdsa_recoverable_signature_parse_compact(cx: *const Context, sig: *mut RecoverableSignature, 172 | input64: *const c_uchar, recid: c_int) 173 | -> c_int; 174 | 175 | pub fn secp256k1_ecdsa_recoverable_signature_serialize_compact(cx: *const Context, output64: *const c_uchar, 176 | recid: *mut c_int, sig: *const RecoverableSignature) 177 | -> c_int; 178 | 179 | pub fn secp256k1_ecdsa_recoverable_signature_convert(cx: *const Context, sig: *mut Signature, 180 | input: *const RecoverableSignature) 181 | -> c_int; 182 | 183 | pub fn secp256k1_ecdsa_signature_normalize(cx: *const Context, out_sig: *mut Signature, 184 | in_sig: *const Signature) 185 | -> c_int; 186 | 187 | // ECDSA 188 | pub fn secp256k1_ecdsa_verify(cx: *const Context, 189 | sig: *const Signature, 190 | msg32: *const c_uchar, 191 | pk: *const PublicKey) 192 | -> c_int; 193 | 194 | pub fn secp256k1_ecdsa_sign(cx: *const Context, 195 | sig: *mut Signature, 196 | msg32: *const c_uchar, 197 | sk: *const c_uchar, 198 | noncefn: NonceFn, 199 | noncedata: *const c_void) 200 | -> c_int; 201 | 202 | pub fn secp256k1_ecdsa_sign_recoverable(cx: *const Context, 203 | sig: *mut RecoverableSignature, 204 | msg32: *const c_uchar, 205 | sk: *const c_uchar, 206 | noncefn: NonceFn, 207 | noncedata: *const c_void) 208 | -> c_int; 209 | 210 | pub fn secp256k1_ecdsa_recover(cx: *const Context, 211 | pk: *mut PublicKey, 212 | sig: *const RecoverableSignature, 213 | msg32: *const c_uchar) 214 | -> c_int; 215 | 216 | // EC 217 | pub fn secp256k1_ec_seckey_verify(cx: *const Context, 218 | sk: *const c_uchar) -> c_int; 219 | 220 | pub fn secp256k1_ec_pubkey_create(cx: *const Context, pk: *mut PublicKey, 221 | sk: *const c_uchar) -> c_int; 222 | 223 | //TODO secp256k1_ec_privkey_export 224 | //TODO secp256k1_ec_privkey_import 225 | 226 | pub fn secp256k1_ec_privkey_tweak_add(cx: *const Context, 227 | sk: *mut c_uchar, 228 | tweak: *const c_uchar) 229 | -> c_int; 230 | 231 | pub fn secp256k1_ec_pubkey_tweak_add(cx: *const Context, 232 | pk: *mut PublicKey, 233 | tweak: *const c_uchar) 234 | -> c_int; 235 | 236 | pub fn secp256k1_ec_privkey_tweak_mul(cx: *const Context, 237 | sk: *mut c_uchar, 238 | tweak: *const c_uchar) 239 | -> c_int; 240 | 241 | pub fn secp256k1_ec_pubkey_tweak_mul(cx: *const Context, 242 | pk: *mut PublicKey, 243 | tweak: *const c_uchar) 244 | -> c_int; 245 | 246 | pub fn secp256k1_ec_pubkey_combine(cx: *const Context, 247 | out: *mut PublicKey, 248 | ins: *const *const PublicKey, 249 | n: c_int) 250 | -> c_int; 251 | 252 | pub fn secp256k1_ecdh(cx: *const Context, 253 | out: *mut SharedSecret, 254 | point: *const PublicKey, 255 | scalar: *const c_uchar, 256 | hash_fn: EcdhHashFn, 257 | data: *mut c_void) 258 | -> c_int; 259 | 260 | pub fn secp256k1_ecdh_raw(cx: *const Context, 261 | out: *mut SharedSecret, 262 | point: *const PublicKey, 263 | scalar: *const c_uchar) 264 | -> c_int; 265 | 266 | pub fn secp256k1_ec_privkey_inverse(cx: *const Context, 267 | out: *mut c_uchar, 268 | scalar: *const c_uchar) 269 | -> c_int; 270 | } 271 | 272 | -------------------------------------------------------------------------------- /src/key.rs: -------------------------------------------------------------------------------- 1 | // Bitcoin secp256k1 bindings 2 | // Written in 2014 by 3 | // Dawid Ciężarkiewicz 4 | // Andrew Poelstra 5 | // 6 | // To the extent possible under law, the author(s) have dedicated all 7 | // copyright and related and neighboring rights to this software to 8 | // the public domain worldwide. This software is distributed without 9 | // any warranty. 10 | // 11 | // You should have received a copy of the CC0 Public Domain Dedication 12 | // along with this software. 13 | // If not, see . 14 | // 15 | 16 | //! # Public and secret keys 17 | 18 | use arrayvec::ArrayVec; 19 | use rand::RngCore; 20 | 21 | use super::{Secp256k1, ContextFlag}; 22 | use super::Error::{self, IncapableContext, InvalidPublicKey, InvalidSecretKey}; 23 | use constants; 24 | use ffi; 25 | 26 | /// Secret 256-bit key used as `x` in an ECDSA signature 27 | #[repr(C)] 28 | pub struct SecretKey([u8; constants::SECRET_KEY_SIZE]); 29 | impl_array_newtype!(SecretKey, u8, constants::SECRET_KEY_SIZE); 30 | impl_pretty_debug!(SecretKey); 31 | 32 | impl From<[u8; constants::SECRET_KEY_SIZE]> for SecretKey { 33 | fn from(raw: [u8; constants::SECRET_KEY_SIZE]) -> Self { 34 | SecretKey(raw) 35 | } 36 | } 37 | 38 | /// The number 1 encoded as a secret key 39 | /// Deprecated; `static` is not what I want; use `ONE_KEY` instead 40 | pub static ONE: SecretKey = SecretKey([0, 0, 0, 0, 0, 0, 0, 0, 41 | 0, 0, 0, 0, 0, 0, 0, 0, 42 | 0, 0, 0, 0, 0, 0, 0, 0, 43 | 0, 0, 0, 0, 0, 0, 0, 1]); 44 | 45 | /// The number 0 encoded as a secret key 46 | pub const ZERO_KEY: SecretKey = SecretKey([0, 0, 0, 0, 0, 0, 0, 0, 47 | 0, 0, 0, 0, 0, 0, 0, 0, 48 | 0, 0, 0, 0, 0, 0, 0, 0, 49 | 0, 0, 0, 0, 0, 0, 0, 0]); 50 | 51 | /// The number 1 encoded as a secret key 52 | pub const ONE_KEY: SecretKey = SecretKey([0, 0, 0, 0, 0, 0, 0, 0, 53 | 0, 0, 0, 0, 0, 0, 0, 0, 54 | 0, 0, 0, 0, 0, 0, 0, 0, 55 | 0, 0, 0, 0, 0, 0, 0, 1]); 56 | 57 | /// The number -1 encoded as a secret key 58 | pub const MINUS_ONE_KEY: SecretKey = SecretKey([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 59 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 60 | 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 61 | 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40]); 62 | 63 | /// A Secp256k1 public key, used for verification of signatures 64 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 65 | pub struct PublicKey(ffi::PublicKey); 66 | 67 | fn random_32_bytes(rng: &mut R) -> [u8; 32] { 68 | let mut ret = [0u8; 32]; 69 | rng.fill_bytes(&mut ret); 70 | ret 71 | } 72 | 73 | impl SecretKey { 74 | /// Creates a new random secret key 75 | #[inline] 76 | pub fn new(secp: &Secp256k1, rng: &mut R) -> SecretKey { 77 | let mut data = random_32_bytes(rng); 78 | unsafe { 79 | while ffi::secp256k1_ec_seckey_verify(secp.ctx, data.as_ptr()) == 0 { 80 | data = random_32_bytes(rng); 81 | } 82 | } 83 | SecretKey(data) 84 | } 85 | 86 | /// Converts a `SECRET_KEY_SIZE`-byte slice to a secret key 87 | #[inline] 88 | pub fn from_slice(secp: &Secp256k1, data: &[u8]) 89 | -> Result { 90 | match data.len() { 91 | constants::SECRET_KEY_SIZE => { 92 | let mut ret = [0; constants::SECRET_KEY_SIZE]; 93 | unsafe { 94 | if ffi::secp256k1_ec_seckey_verify(secp.ctx, data.as_ptr()) == 0 { 95 | return Err(InvalidSecretKey); 96 | } 97 | } 98 | ret[..].copy_from_slice(data); 99 | Ok(SecretKey(ret)) 100 | } 101 | _ => Err(InvalidSecretKey) 102 | } 103 | } 104 | 105 | #[inline] 106 | /// Adds one secret key to another, modulo the curve order 107 | pub fn add_assign(&mut self, secp: &Secp256k1, other: &SecretKey) 108 | -> Result<(), Error> { 109 | unsafe { 110 | if ffi::secp256k1_ec_privkey_tweak_add(secp.ctx, self.as_mut_ptr(), other.as_ptr()) != 1 { 111 | Err(InvalidSecretKey) 112 | } else { 113 | Ok(()) 114 | } 115 | } 116 | } 117 | 118 | #[inline] 119 | /// Multiplies one secret key by another, modulo the curve order 120 | pub fn mul_assign(&mut self, secp: &Secp256k1, other: &SecretKey) 121 | -> Result<(), Error> { 122 | unsafe { 123 | if ffi::secp256k1_ec_privkey_tweak_mul(secp.ctx, self.as_mut_ptr(), other.as_ptr()) != 1 { 124 | Err(InvalidSecretKey) 125 | } else { 126 | Ok(()) 127 | } 128 | } 129 | } 130 | 131 | #[inline] 132 | /// Inverts (1 / self) this secret key. 133 | pub fn inv_assign(&mut self, secp: &Secp256k1) -> Result<(), Error> { 134 | let original = self.clone(); 135 | unsafe { 136 | if ffi::secp256k1_ec_privkey_inverse(secp.ctx, self.as_mut_ptr(), original.as_ptr()) != 1 { 137 | Err(InvalidSecretKey) 138 | } else { 139 | Ok(()) 140 | } 141 | } 142 | } 143 | } 144 | 145 | impl PublicKey { 146 | /// Creates a new zeroed out public key 147 | #[inline] 148 | pub fn new() -> PublicKey { 149 | PublicKey(ffi::PublicKey::new()) 150 | } 151 | 152 | /// Determines whether a pubkey is valid 153 | #[inline] 154 | pub fn is_valid(&self) -> bool { 155 | // The only invalid pubkey the API should be able to create is 156 | // the zero one. 157 | self.0[..].iter().any(|&x| x != 0) 158 | } 159 | 160 | /// Obtains a raw pointer suitable for use with FFI functions 161 | #[inline] 162 | pub fn as_ptr(&self) -> *const ffi::PublicKey { 163 | &self.0 as *const _ 164 | } 165 | 166 | /// Creates a new public key from a secret key. 167 | #[inline] 168 | pub fn from_secret_key(secp: &Secp256k1, 169 | sk: &SecretKey) 170 | -> Result { 171 | if secp.caps == ContextFlag::VerifyOnly || secp.caps == ContextFlag::None { 172 | return Err(IncapableContext); 173 | } 174 | let mut pk = ffi::PublicKey::new(); 175 | unsafe { 176 | // We can assume the return value because it's not possible to construct 177 | // an invalid `SecretKey` without transmute trickery or something 178 | let res = ffi::secp256k1_ec_pubkey_create(secp.ctx, &mut pk, sk.as_ptr()); 179 | debug_assert_eq!(res, 1); 180 | } 181 | Ok(PublicKey(pk)) 182 | } 183 | 184 | /// Creates a public key directly from a slice 185 | #[inline] 186 | pub fn from_slice(secp: &Secp256k1, data: &[u8]) 187 | -> Result { 188 | 189 | let mut pk = ffi::PublicKey::new(); 190 | unsafe { 191 | if ffi::secp256k1_ec_pubkey_parse(secp.ctx, &mut pk, data.as_ptr(), 192 | data.len() as usize) == 1 { 193 | Ok(PublicKey(pk)) 194 | } else { 195 | Err(InvalidPublicKey) 196 | } 197 | } 198 | } 199 | 200 | #[inline] 201 | /// Serialize the key as a byte-encoded pair of values. In compressed form 202 | /// the y-coordinate is represented by only a single bit, as x determines 203 | /// it up to one bit. 204 | pub fn serialize_vec(&self, secp: &Secp256k1, compressed: bool) -> ArrayVec<[u8; constants::PUBLIC_KEY_SIZE]> { 205 | let mut ret = ArrayVec::new(); 206 | 207 | unsafe { 208 | let mut ret_len = constants::PUBLIC_KEY_SIZE as usize; 209 | let compressed = if compressed { ffi::SECP256K1_SER_COMPRESSED } else { ffi::SECP256K1_SER_UNCOMPRESSED }; 210 | let err = ffi::secp256k1_ec_pubkey_serialize(secp.ctx, ret.as_ptr(), 211 | &mut ret_len, self.as_ptr(), 212 | compressed); 213 | debug_assert_eq!(err, 1); 214 | ret.set_len(ret_len as usize); 215 | } 216 | ret 217 | } 218 | 219 | #[inline] 220 | /// Adds the pk corresponding to `other` to the pk `self` in place 221 | pub fn add_exp_assign(&mut self, secp: &Secp256k1, other: &SecretKey) 222 | -> Result<(), Error> { 223 | if secp.caps == ContextFlag::SignOnly || secp.caps == ContextFlag::None { 224 | return Err(IncapableContext); 225 | } 226 | unsafe { 227 | if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0 as *mut _, 228 | other.as_ptr()) == 1 { 229 | Ok(()) 230 | } else { 231 | Err(InvalidSecretKey) 232 | } 233 | } 234 | } 235 | 236 | #[inline] 237 | /// Adds another point on the curve in place 238 | pub fn add_assign(&mut self, secp: &Secp256k1, other: &PublicKey) -> Result<(), Error> { 239 | let mut public = ffi::PublicKey::new(); 240 | let res = unsafe { 241 | if ffi::secp256k1_ec_pubkey_combine( 242 | secp.ctx, 243 | &mut public as *mut _, 244 | [other.as_ptr(), self.as_ptr()].as_ptr(), 245 | 2) == 1 246 | { 247 | Ok(()) 248 | } else { 249 | Err(InvalidSecretKey) 250 | } 251 | }; 252 | if res.is_ok() { self.0 = public } 253 | res 254 | } 255 | 256 | #[inline] 257 | /// Multiplies this point by `secret` scalar 258 | pub fn mul_assign(&mut self, secp: &Secp256k1, other: &SecretKey) -> Result<(), Error> { 259 | if secp.caps == ContextFlag::SignOnly || secp.caps == ContextFlag::None { 260 | return Err(IncapableContext); 261 | } 262 | unsafe { 263 | if ffi::secp256k1_ec_pubkey_tweak_mul(secp.ctx, &mut self.0 as *mut _, 264 | other.as_ptr()) == 1 { 265 | Ok(()) 266 | } else { 267 | Err(InvalidSecretKey) 268 | } 269 | } 270 | } 271 | } 272 | 273 | /// Creates a new public key from a FFI public key 274 | impl From for PublicKey { 275 | #[inline] 276 | fn from(pk: ffi::PublicKey) -> PublicKey { 277 | PublicKey(pk) 278 | } 279 | } 280 | 281 | #[cfg(test)] 282 | mod test { 283 | use super::super::{Secp256k1, ContextFlag}; 284 | use super::super::Error::{InvalidPublicKey, InvalidSecretKey, IncapableContext}; 285 | use super::{PublicKey, SecretKey}; 286 | use super::super::constants; 287 | 288 | use rand::{RngCore, thread_rng}; 289 | 290 | #[test] 291 | fn skey_from_slice() { 292 | let s = Secp256k1::new(); 293 | let sk = SecretKey::from_slice(&s, &[1; 31]); 294 | assert_eq!(sk, Err(InvalidSecretKey)); 295 | 296 | let sk = SecretKey::from_slice(&s, &[1; 32]); 297 | assert!(sk.is_ok()); 298 | } 299 | 300 | #[test] 301 | fn pubkey_from_slice() { 302 | let s = Secp256k1::new(); 303 | assert_eq!(PublicKey::from_slice(&s, &[]), Err(InvalidPublicKey)); 304 | assert_eq!(PublicKey::from_slice(&s, &[1, 2, 3]), Err(InvalidPublicKey)); 305 | 306 | let uncompressed = PublicKey::from_slice(&s, &[4, 54, 57, 149, 239, 162, 148, 175, 246, 254, 239, 75, 154, 152, 10, 82, 234, 224, 85, 220, 40, 100, 57, 121, 30, 162, 94, 156, 135, 67, 74, 49, 179, 57, 236, 53, 162, 124, 149, 144, 168, 77, 74, 30, 72, 211, 229, 110, 111, 55, 96, 193, 86, 227, 183, 152, 195, 155, 51, 247, 123, 113, 60, 228, 188]); 307 | assert!(uncompressed.is_ok()); 308 | 309 | let compressed = PublicKey::from_slice(&s, &[3, 23, 183, 225, 206, 31, 159, 148, 195, 42, 67, 115, 146, 41, 248, 140, 11, 3, 51, 41, 111, 180, 110, 143, 114, 134, 88, 73, 198, 174, 52, 184, 78]); 310 | assert!(compressed.is_ok()); 311 | } 312 | 313 | #[test] 314 | fn keypair_slice_round_trip() { 315 | let s = Secp256k1::new(); 316 | 317 | let (sk1, pk1) = s.generate_keypair(&mut thread_rng()).unwrap(); 318 | assert_eq!(SecretKey::from_slice(&s, &sk1[..]), Ok(sk1)); 319 | assert_eq!(PublicKey::from_slice(&s, &pk1.serialize_vec(&s, true)[..]), Ok(pk1)); 320 | assert_eq!(PublicKey::from_slice(&s, &pk1.serialize_vec(&s, false)[..]), Ok(pk1)); 321 | } 322 | 323 | #[test] 324 | fn invalid_secret_key() { 325 | let s = Secp256k1::new(); 326 | // Zero 327 | assert_eq!(SecretKey::from_slice(&s, &[0; 32]), Err(InvalidSecretKey)); 328 | // -1 329 | assert_eq!(SecretKey::from_slice(&s, &[0xff; 32]), Err(InvalidSecretKey)); 330 | // Top of range 331 | assert!(SecretKey::from_slice(&s, 332 | &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 333 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 334 | 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 335 | 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40]).is_ok()); 336 | // One past top of range 337 | assert!(SecretKey::from_slice(&s, 338 | &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 339 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 340 | 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 341 | 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41]).is_err()); 342 | } 343 | 344 | #[test] 345 | fn test_pubkey_from_slice_bad_context() { 346 | let s = Secp256k1::without_caps(); 347 | let sk = SecretKey::new(&s, &mut thread_rng()); 348 | assert_eq!(PublicKey::from_secret_key(&s, &sk), Err(IncapableContext)); 349 | 350 | let s = Secp256k1::with_caps(ContextFlag::VerifyOnly); 351 | assert_eq!(PublicKey::from_secret_key(&s, &sk), Err(IncapableContext)); 352 | 353 | let s = Secp256k1::with_caps(ContextFlag::SignOnly); 354 | assert!(PublicKey::from_secret_key(&s, &sk).is_ok()); 355 | 356 | let s = Secp256k1::with_caps(ContextFlag::Full); 357 | assert!(PublicKey::from_secret_key(&s, &sk).is_ok()); 358 | } 359 | 360 | #[test] 361 | fn test_add_exp_bad_context() { 362 | let s = Secp256k1::with_caps(ContextFlag::Full); 363 | let (sk, mut pk) = s.generate_keypair(&mut thread_rng()).unwrap(); 364 | 365 | assert!(pk.add_exp_assign(&s, &sk).is_ok()); 366 | 367 | let s = Secp256k1::with_caps(ContextFlag::VerifyOnly); 368 | assert!(pk.add_exp_assign(&s, &sk).is_ok()); 369 | 370 | let s = Secp256k1::with_caps(ContextFlag::SignOnly); 371 | assert_eq!(pk.add_exp_assign(&s, &sk), Err(IncapableContext)); 372 | 373 | let s = Secp256k1::with_caps(ContextFlag::None); 374 | assert_eq!(pk.add_exp_assign(&s, &sk), Err(IncapableContext)); 375 | } 376 | 377 | #[test] 378 | fn test_out_of_range() { 379 | 380 | struct BadRng(u8); 381 | impl RngCore for BadRng { 382 | fn next_u32(&mut self) -> u32 { unimplemented!() } 383 | fn next_u64(&mut self) -> u64 { unimplemented!() } 384 | // This will set a secret key to a little over the 385 | // group order, then decrement with repeated calls 386 | // until it returns a valid key 387 | fn fill_bytes(&mut self, data: &mut [u8]) { 388 | let group_order: [u8; 32] = [ 389 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 390 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 391 | 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 392 | 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41]; 393 | assert_eq!(data.len(), 32); 394 | data.copy_from_slice(&group_order[..]); 395 | data[31] = self.0; 396 | self.0 -= 1; 397 | } 398 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { 399 | Ok(self.fill_bytes(dest)) 400 | } 401 | } 402 | 403 | let s = Secp256k1::new(); 404 | s.generate_keypair(&mut BadRng(0xff)).unwrap(); 405 | } 406 | 407 | #[test] 408 | fn test_pubkey_from_bad_slice() { 409 | let s = Secp256k1::new(); 410 | // Bad sizes 411 | assert_eq!(PublicKey::from_slice(&s, &[0; constants::COMPRESSED_PUBLIC_KEY_SIZE - 1]), 412 | Err(InvalidPublicKey)); 413 | assert_eq!(PublicKey::from_slice(&s, &[0; constants::COMPRESSED_PUBLIC_KEY_SIZE + 1]), 414 | Err(InvalidPublicKey)); 415 | assert_eq!(PublicKey::from_slice(&s, &[0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE - 1]), 416 | Err(InvalidPublicKey)); 417 | assert_eq!(PublicKey::from_slice(&s, &[0; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE + 1]), 418 | Err(InvalidPublicKey)); 419 | 420 | // Bad parse 421 | assert_eq!(PublicKey::from_slice(&s, &[0xff; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE]), 422 | Err(InvalidPublicKey)); 423 | assert_eq!(PublicKey::from_slice(&s, &[0x55; constants::COMPRESSED_PUBLIC_KEY_SIZE]), 424 | Err(InvalidPublicKey)); 425 | } 426 | 427 | struct DumbRng(u32); 428 | impl RngCore for DumbRng { 429 | fn next_u32(&mut self) -> u32 { 430 | self.0 = self.0.wrapping_add(1); 431 | self.0 432 | } 433 | fn next_u64(&mut self) -> u64 { 434 | let hi = self.next_u32(); 435 | let lo = self.next_u32(); 436 | ((hi as u64) << 32 | lo as u64) 437 | } 438 | fn fill_bytes(&mut self, data: &mut [u8]) { 439 | rand_core::impls::fill_bytes_via_next(self, data); 440 | } 441 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { 442 | Ok(self.fill_bytes(dest)) 443 | } 444 | } 445 | 446 | 447 | #[test] 448 | fn test_debug_output() { 449 | let s = Secp256k1::new(); 450 | let (sk, _) = s.generate_keypair(&mut DumbRng(0)).unwrap(); 451 | 452 | assert_eq!(&format!("{:?}", sk), 453 | "SecretKey(0200000001000000040000000300000006000000050000000800000007000000)"); 454 | } 455 | 456 | #[test] 457 | fn test_pubkey_serialize() { 458 | let s = Secp256k1::new(); 459 | let (_, pk1) = s.generate_keypair(&mut DumbRng(0)).unwrap(); 460 | assert_eq!(&pk1.serialize_vec(&s, false)[..], 461 | &[4, 149, 16, 196, 140, 38, 92, 239, 179, 65, 59, 224, 230, 183, 91, 238, 240, 46, 186, 252, 175, 102, 52, 249, 98, 178, 123, 72, 50, 171, 196, 254, 236, 1, 189, 143, 242, 227, 16, 87, 247, 183, 162, 68, 237, 140, 92, 205, 151, 129, 166, 58, 111, 96, 123, 64, 180, 147, 51, 12, 209, 89, 236, 213, 206][..]); 462 | assert_eq!(&pk1.serialize_vec(&s, true)[..], 463 | &[2, 149, 16, 196, 140, 38, 92, 239, 179, 65, 59, 224, 230, 183, 91, 238, 240, 46, 186, 252, 175, 102, 52, 249, 98, 178, 123, 72, 50, 171, 196, 254, 236][..]); 464 | } 465 | 466 | #[test] 467 | fn test_addition() { 468 | let s = Secp256k1::new(); 469 | 470 | let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng()).unwrap(); 471 | let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng()).unwrap(); 472 | 473 | assert_eq!(PublicKey::from_secret_key(&s, &sk1).unwrap(), pk1); 474 | assert!(sk1.add_assign(&s, &sk2).is_ok()); 475 | assert!(pk1.add_exp_assign(&s, &sk2).is_ok()); 476 | assert_eq!(PublicKey::from_secret_key(&s, &sk1).unwrap(), pk1); 477 | 478 | assert_eq!(PublicKey::from_secret_key(&s, &sk2).unwrap(), pk2); 479 | assert!(sk2.add_assign(&s, &sk1).is_ok()); 480 | assert!(pk2.add_exp_assign(&s, &sk1).is_ok()); 481 | assert_eq!(PublicKey::from_secret_key(&s, &sk2).unwrap(), pk2); 482 | } 483 | 484 | #[test] 485 | fn test_multiplication() { 486 | let s = Secp256k1::new(); 487 | 488 | let (mut sk1, mut pk1) = s.generate_keypair(&mut thread_rng()).unwrap(); 489 | let (mut sk2, mut pk2) = s.generate_keypair(&mut thread_rng()).unwrap(); 490 | 491 | assert_eq!(PublicKey::from_secret_key(&s, &sk1).unwrap(), pk1); 492 | assert!(sk1.mul_assign(&s, &sk2).is_ok()); 493 | assert!(pk1.mul_assign(&s, &sk2).is_ok()); 494 | assert_eq!(PublicKey::from_secret_key(&s, &sk1).unwrap(), pk1); 495 | 496 | assert_eq!(PublicKey::from_secret_key(&s, &sk2).unwrap(), pk2); 497 | assert!(sk2.mul_assign(&s, &sk1).is_ok()); 498 | assert!(pk2.mul_assign(&s, &sk1).is_ok()); 499 | assert_eq!(PublicKey::from_secret_key(&s, &sk2).unwrap(), pk2); 500 | } 501 | 502 | #[test] 503 | fn pubkey_hash() { 504 | use std::collections::hash_map::DefaultHasher; 505 | use std::hash::{Hash, Hasher}; 506 | use std::collections::HashSet; 507 | 508 | fn hash(t: &T) -> u64 { 509 | let mut s = DefaultHasher::new(); 510 | t.hash(&mut s); 511 | s.finish() 512 | } 513 | 514 | let s = Secp256k1::new(); 515 | let mut set = HashSet::new(); 516 | const COUNT : usize = 1024; 517 | let count = (0..COUNT).map(|_| { 518 | let (_, pk) = s.generate_keypair(&mut thread_rng()).unwrap(); 519 | let hash = hash(&pk); 520 | assert!(!set.contains(&hash)); 521 | set.insert(hash); 522 | }).count(); 523 | assert_eq!(count, COUNT); 524 | } 525 | 526 | #[test] 527 | fn pubkey_add() { 528 | let s = Secp256k1::new(); 529 | let (_, mut pk1) = s.generate_keypair(&mut thread_rng()).unwrap(); 530 | let (_, pk2) = s.generate_keypair(&mut thread_rng()).unwrap(); 531 | 532 | let result = pk1.add_assign(&s, &pk2); 533 | 534 | assert!(result.is_ok()); 535 | } 536 | 537 | #[test] 538 | fn pubkey_mul() { 539 | let s = Secp256k1::new(); 540 | let (_, mut pk1) = s.generate_keypair(&mut thread_rng()).unwrap(); 541 | let (sk2, _) = s.generate_keypair(&mut thread_rng()).unwrap(); 542 | 543 | let result = pk1.mul_assign(&s, &sk2); 544 | 545 | assert!(result.is_ok()); 546 | } 547 | 548 | #[test] 549 | fn skey_mul() { 550 | let s = Secp256k1::new(); 551 | let (mut sk1, _) = s.generate_keypair(&mut thread_rng()).unwrap(); 552 | let (sk2, _) = s.generate_keypair(&mut thread_rng()).unwrap(); 553 | 554 | let result = sk1.mul_assign(&s, &sk2); 555 | 556 | assert!(result.is_ok()); 557 | } 558 | 559 | #[test] 560 | fn skey_inv() { 561 | let s = Secp256k1::new(); 562 | let (mut sk, _) = s.generate_keypair(&mut thread_rng()).unwrap(); 563 | 564 | let result = sk.inv_assign(&s); 565 | 566 | assert!(result.is_ok()); 567 | } 568 | } 569 | 570 | 571 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Bitcoin secp256k1 bindings 2 | // Written in 2014 by 3 | // Dawid Ciężarkiewicz 4 | // Andrew Poelstra 5 | // 6 | // To the extent possible under law, the author(s) have dedicated all 7 | // copyright and related and neighboring rights to this software to 8 | // the public domain worldwide. This software is distributed without 9 | // any warranty. 10 | // 11 | // You should have received a copy of the CC0 Public Domain Dedication 12 | // along with this software. 13 | // If not, see . 14 | // 15 | 16 | //! # Secp256k1 17 | //! Rust bindings for Pieter Wuille's secp256k1 library, which is used for 18 | //! fast and accurate manipulation of ECDSA signatures on the secp256k1 19 | //! curve. Such signatures are used extensively by the Bitcoin network 20 | //! and its derivatives. 21 | //! 22 | 23 | #![crate_type = "lib"] 24 | #![crate_type = "rlib"] 25 | #![crate_type = "dylib"] 26 | #![crate_name = "secp256k1"] 27 | 28 | // Coding conventions 29 | #![deny(non_upper_case_globals)] 30 | #![deny(non_camel_case_types)] 31 | #![deny(non_snake_case)] 32 | #![deny(unused_mut)] 33 | #![warn(missing_docs)] 34 | 35 | #![cfg_attr(feature = "dev", allow(unstable_features))] 36 | #![cfg_attr(feature = "dev", feature(plugin))] 37 | #![cfg_attr(feature = "dev", plugin(clippy))] 38 | 39 | #![cfg_attr(all(test, feature = "unstable"), feature(test))] 40 | #[cfg(all(test, feature = "unstable"))] extern crate test; 41 | 42 | extern crate arrayvec; 43 | 44 | pub extern crate rand; 45 | #[cfg(test)] 46 | extern crate rand_core; 47 | #[cfg(test)] 48 | #[macro_use] 49 | extern crate hex_literal; 50 | 51 | use std::{error, fmt, ops, ptr}; 52 | use rand::Rng; 53 | 54 | #[macro_use] 55 | mod macros; 56 | pub mod constants; 57 | pub mod ecdh; 58 | pub mod ffi; 59 | pub mod key; 60 | 61 | /// A tag used for recovering the public key from a compact signature 62 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 63 | pub struct RecoveryId(i32); 64 | 65 | /// An ECDSA signature 66 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 67 | pub struct Signature(ffi::Signature); 68 | 69 | /// An ECDSA signature with a recovery ID for pubkey recovery 70 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] 71 | pub struct RecoverableSignature(ffi::RecoverableSignature); 72 | 73 | impl RecoveryId { 74 | #[inline] 75 | /// Allows library users to create valid recovery IDs from i32. 76 | pub fn from_i32(id: i32) -> Result { 77 | match id { 78 | 0 | 1 | 2 | 3 => Ok(RecoveryId(id)), 79 | _ => Err(Error::InvalidRecoveryId) 80 | } 81 | } 82 | 83 | #[inline] 84 | /// Allows library users to convert recovery IDs to i32. 85 | pub fn to_i32(&self) -> i32 { 86 | self.0 87 | } 88 | } 89 | 90 | impl Signature { 91 | #[inline] 92 | /// Converts a DER-encoded byte slice to a signature 93 | pub fn from_der(secp: &Secp256k1, data: &[u8]) -> Result { 94 | let mut ret = ffi::Signature::new(); 95 | 96 | unsafe { 97 | if ffi::secp256k1_ecdsa_signature_parse_der(secp.ctx, &mut ret, 98 | data.as_ptr(), data.len() as usize) == 1 { 99 | Ok(Signature(ret)) 100 | } else { 101 | Err(Error::InvalidSignature) 102 | } 103 | } 104 | } 105 | 106 | /// Converts a "lax DER"-encoded byte slice to a signature. This is basically 107 | /// only useful for validating signatures in the Bitcoin blockchain from before 108 | /// 2016. It should never be used in new applications. This library does not 109 | /// support serializing to this "format" 110 | pub fn from_der_lax(secp: &Secp256k1, data: &[u8]) -> Result { 111 | unsafe { 112 | let mut ret = ffi::Signature::new(); 113 | if ffi::ecdsa_signature_parse_der_lax(secp.ctx, &mut ret, 114 | data.as_ptr(), data.len() as usize) == 1 { 115 | Ok(Signature(ret)) 116 | } else { 117 | Err(Error::InvalidSignature) 118 | } 119 | } 120 | } 121 | 122 | /// Normalizes a signature to a "low S" form. In ECDSA, signatures are 123 | /// of the form (r, s) where r and s are numbers lying in some finite 124 | /// field. The verification equation will pass for (r, s) iff it passes 125 | /// for (r, -s), so it is possible to ``modify'' signatures in transit 126 | /// by flipping the sign of s. This does not constitute a forgery since 127 | /// the signed message still cannot be changed, but for some applications, 128 | /// changing even the signature itself can be a problem. Such applications 129 | /// require a "strong signature". It is believed that ECDSA is a strong 130 | /// signature except for this ambiguity in the sign of s, so to accomodate 131 | /// these applications libsecp256k1 will only accept signatures for which 132 | /// s is in the lower half of the field range. This eliminates the 133 | /// ambiguity. 134 | /// 135 | /// However, for some systems, signatures with high s-values are considered 136 | /// valid. (For example, parsing the historic Bitcoin blockchain requires 137 | /// this.) For these applications we provide this normalization function, 138 | /// which ensures that the s value lies in the lower half of its range. 139 | pub fn normalize_s(&mut self, secp: &Secp256k1) { 140 | unsafe { 141 | // Ignore return value, which indicates whether the sig 142 | // was already normalized. We don't care. 143 | ffi::secp256k1_ecdsa_signature_normalize(secp.ctx, self.as_mut_ptr(), 144 | self.as_ptr()); 145 | } 146 | } 147 | 148 | /// Obtains a raw pointer suitable for use with FFI functions 149 | #[inline] 150 | pub fn as_ptr(&self) -> *const ffi::Signature { 151 | &self.0 as *const _ 152 | } 153 | 154 | /// Obtains a raw mutable pointer suitable for use with FFI functions 155 | #[inline] 156 | pub fn as_mut_ptr(&mut self) -> *mut ffi::Signature { 157 | &mut self.0 as *mut _ 158 | } 159 | 160 | #[inline] 161 | /// Serializes the signature in DER format 162 | pub fn serialize_der(&self, secp: &Secp256k1) -> Vec { 163 | let mut ret = Vec::with_capacity(72); 164 | let mut len: usize = ret.capacity() as usize; 165 | unsafe { 166 | let err = ffi::secp256k1_ecdsa_signature_serialize_der(secp.ctx, ret.as_mut_ptr(), 167 | &mut len, self.as_ptr()); 168 | debug_assert!(err == 1); 169 | ret.set_len(len as usize); 170 | } 171 | ret 172 | } 173 | } 174 | 175 | /// Creates a new signature from a FFI signature 176 | impl From for Signature { 177 | #[inline] 178 | fn from(sig: ffi::Signature) -> Signature { 179 | Signature(sig) 180 | } 181 | } 182 | 183 | 184 | impl RecoverableSignature { 185 | #[inline] 186 | /// Converts a compact-encoded byte slice to a signature. This 187 | /// representation is nonstandard and defined by the libsecp256k1 188 | /// library. 189 | pub fn from_compact(secp: &Secp256k1, data: &[u8], recid: RecoveryId) -> Result { 190 | let mut ret = ffi::RecoverableSignature::new(); 191 | 192 | unsafe { 193 | if data.len() != 64 { 194 | Err(Error::InvalidSignature) 195 | } else if ffi::secp256k1_ecdsa_recoverable_signature_parse_compact(secp.ctx, &mut ret, 196 | data.as_ptr(), recid.0) == 1 { 197 | Ok(RecoverableSignature(ret)) 198 | } else { 199 | Err(Error::InvalidSignature) 200 | } 201 | } 202 | } 203 | 204 | /// Obtains a raw pointer suitable for use with FFI functions 205 | #[inline] 206 | pub fn as_ptr(&self) -> *const ffi::RecoverableSignature { 207 | &self.0 as *const _ 208 | } 209 | 210 | #[inline] 211 | /// Serializes the recoverable signature in compact format 212 | pub fn serialize_compact(&self, secp: &Secp256k1) -> (RecoveryId, [u8; 64]) { 213 | let mut ret = [0u8; 64]; 214 | let mut recid = 0i32; 215 | unsafe { 216 | let err = ffi::secp256k1_ecdsa_recoverable_signature_serialize_compact( 217 | secp.ctx, ret.as_mut_ptr(), &mut recid, self.as_ptr()); 218 | assert!(err == 1); 219 | } 220 | (RecoveryId(recid), ret) 221 | } 222 | 223 | /// Converts a recoverable signature to a non-recoverable one (this is needed 224 | /// for verification 225 | #[inline] 226 | pub fn to_standard(&self, secp: &Secp256k1) -> Signature { 227 | let mut ret = ffi::Signature::new(); 228 | unsafe { 229 | let err = ffi::secp256k1_ecdsa_recoverable_signature_convert(secp.ctx, &mut ret, self.as_ptr()); 230 | assert!(err == 1); 231 | } 232 | Signature(ret) 233 | } 234 | } 235 | 236 | /// Creates a new recoverable signature from a FFI one 237 | impl From for RecoverableSignature { 238 | #[inline] 239 | fn from(sig: ffi::RecoverableSignature) -> RecoverableSignature { 240 | RecoverableSignature(sig) 241 | } 242 | } 243 | 244 | impl ops::Index for Signature { 245 | type Output = u8; 246 | 247 | #[inline] 248 | fn index(&self, index: usize) -> &u8 { 249 | &self.0[index] 250 | } 251 | } 252 | 253 | impl ops::Index> for Signature { 254 | type Output = [u8]; 255 | 256 | #[inline] 257 | fn index(&self, index: ops::Range) -> &[u8] { 258 | &self.0[index] 259 | } 260 | } 261 | 262 | impl ops::Index> for Signature { 263 | type Output = [u8]; 264 | 265 | #[inline] 266 | fn index(&self, index: ops::RangeFrom) -> &[u8] { 267 | &self.0[index.start..] 268 | } 269 | } 270 | 271 | impl ops::Index for Signature { 272 | type Output = [u8]; 273 | 274 | #[inline] 275 | fn index(&self, _: ops::RangeFull) -> &[u8] { 276 | &self.0[..] 277 | } 278 | } 279 | 280 | /// A (hashed) message input to an ECDSA signature 281 | pub struct Message([u8; constants::MESSAGE_SIZE]); 282 | impl_array_newtype!(Message, u8, constants::MESSAGE_SIZE); 283 | impl_pretty_debug!(Message); 284 | 285 | impl Message { 286 | /// Converts a `MESSAGE_SIZE`-byte slice to a message object 287 | #[inline] 288 | pub fn from_slice(data: &[u8]) -> Result { 289 | match data.len() { 290 | constants::MESSAGE_SIZE => { 291 | let mut ret = [0; constants::MESSAGE_SIZE]; 292 | ret[..].copy_from_slice(data); 293 | Ok(Message(ret)) 294 | } 295 | _ => Err(Error::InvalidMessage) 296 | } 297 | } 298 | } 299 | 300 | /// Creates a message from a `MESSAGE_SIZE` byte array 301 | impl From<[u8; constants::MESSAGE_SIZE]> for Message { 302 | fn from(buf: [u8; constants::MESSAGE_SIZE]) -> Message { 303 | Message(buf) 304 | } 305 | } 306 | 307 | /// An ECDSA error 308 | #[derive(Copy, PartialEq, Eq, Clone, Debug)] 309 | pub enum Error { 310 | /// A `Secp256k1` was used for an operation, but it was not created to 311 | /// support this (so necessary precomputations have not been done) 312 | IncapableContext, 313 | /// Signature failed verification 314 | IncorrectSignature, 315 | /// Badly sized message ("messages" are actually fixed-sized digests; see the `MESSAGE_SIZE` 316 | /// constant) 317 | InvalidMessage, 318 | /// Bad public key 319 | InvalidPublicKey, 320 | /// Bad signature 321 | InvalidSignature, 322 | /// Bad secret key 323 | InvalidSecretKey, 324 | /// Bad recovery id 325 | InvalidRecoveryId, 326 | } 327 | 328 | // Passthrough Debug to Display, since errors should be user-visible 329 | impl fmt::Display for Error { 330 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 331 | f.write_str(error::Error::description(self)) 332 | } 333 | } 334 | 335 | impl error::Error for Error { 336 | fn cause(&self) -> Option<&dyn error::Error> { None } 337 | 338 | fn description(&self) -> &str { 339 | match *self { 340 | Error::IncapableContext => "secp: context does not have sufficient capabilities", 341 | Error::IncorrectSignature => "secp: signature failed verification", 342 | Error::InvalidMessage => "secp: message was not 32 bytes (do you need to hash?)", 343 | Error::InvalidPublicKey => "secp: malformed public key", 344 | Error::InvalidSignature => "secp: malformed signature", 345 | Error::InvalidSecretKey => "secp: malformed or out-of-range secret key", 346 | Error::InvalidRecoveryId => "secp: bad recovery id" 347 | } 348 | } 349 | } 350 | 351 | /// The secp256k1 engine, used to execute all signature operations 352 | pub struct Secp256k1 { 353 | ctx: *mut ffi::Context, 354 | caps: ContextFlag 355 | } 356 | 357 | unsafe impl Send for Secp256k1 {} 358 | unsafe impl Sync for Secp256k1 {} 359 | 360 | /// Flags used to determine the capabilities of a `Secp256k1` object; 361 | /// the more capabilities, the more expensive it is to create. 362 | #[derive(PartialEq, Eq, Copy, Clone, Debug)] 363 | pub enum ContextFlag { 364 | /// Can neither sign nor verify signatures (cheapest to create, useful 365 | /// for cases not involving signatures, such as creating keys from slices) 366 | None, 367 | /// Can sign but not verify signatures 368 | SignOnly, 369 | /// Can verify but not create signatures 370 | VerifyOnly, 371 | /// Can verify and create signatures 372 | Full 373 | } 374 | 375 | // Passthrough Debug to Display, since caps should be user-visible 376 | impl fmt::Display for ContextFlag { 377 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 378 | fmt::Debug::fmt(self, f) 379 | } 380 | } 381 | 382 | impl Clone for Secp256k1 { 383 | fn clone(&self) -> Secp256k1 { 384 | Secp256k1 { 385 | ctx: unsafe { ffi::secp256k1_context_clone(self.ctx) }, 386 | caps: self.caps 387 | } 388 | } 389 | } 390 | 391 | impl PartialEq for Secp256k1 { 392 | fn eq(&self, other: &Secp256k1) -> bool { self.caps == other.caps } 393 | } 394 | impl Eq for Secp256k1 { } 395 | 396 | impl fmt::Debug for Secp256k1 { 397 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 398 | write!(f, "Secp256k1 {{ [private], caps: {:?} }}", self.caps) 399 | } 400 | } 401 | 402 | impl Drop for Secp256k1 { 403 | fn drop(&mut self) { 404 | unsafe { ffi::secp256k1_context_destroy(self.ctx); } 405 | } 406 | } 407 | 408 | impl Secp256k1 { 409 | /// Creates a new Secp256k1 context 410 | #[inline] 411 | pub fn new() -> Secp256k1 { 412 | Secp256k1::with_caps(ContextFlag::Full) 413 | } 414 | 415 | /// Creates a new Secp256k1 context with the specified capabilities 416 | pub fn with_caps(caps: ContextFlag) -> Secp256k1 { 417 | let flag = match caps { 418 | ContextFlag::None => ffi::SECP256K1_START_NONE, 419 | ContextFlag::SignOnly => ffi::SECP256K1_START_SIGN, 420 | ContextFlag::VerifyOnly => ffi::SECP256K1_START_VERIFY, 421 | ContextFlag::Full => ffi::SECP256K1_START_SIGN | ffi::SECP256K1_START_VERIFY 422 | }; 423 | Secp256k1 { ctx: unsafe { ffi::secp256k1_context_create(flag) }, caps: caps } 424 | } 425 | 426 | /// Creates a new Secp256k1 context with no capabilities (just de/serialization) 427 | pub fn without_caps() -> Secp256k1 { 428 | Secp256k1::with_caps(ContextFlag::None) 429 | } 430 | 431 | /// (Re)randomizes the Secp256k1 context for cheap sidechannel resistence; 432 | /// see comment in libsecp256k1 commit d2275795f by Gregory Maxwell 433 | pub fn randomize(&mut self, rng: &mut R) { 434 | let mut seed = [0; 32]; 435 | rng.fill_bytes(&mut seed); 436 | unsafe { 437 | let err = ffi::secp256k1_context_randomize(self.ctx, seed.as_ptr()); 438 | // This function cannot fail; it has an error return for future-proofing. 439 | // We do not expose this error since it is impossible to hit, and we have 440 | // precedent for not exposing impossible errors (for example in 441 | // `PublicKey::from_secret_key` where it is impossble to create an invalid 442 | // secret key through the API.) 443 | // However, if this DOES fail, the result is potentially weaker side-channel 444 | // resistance, which is deadly and undetectable, so we take out the entire 445 | // thread to be on the safe side. 446 | assert!(err == 1); 447 | } 448 | } 449 | 450 | /// Generates a random keypair. Convenience function for `key::SecretKey::new` 451 | /// and `key::PublicKey::from_secret_key`; call those functions directly for 452 | /// batch key generation. Requires a signing-capable context. 453 | #[inline] 454 | pub fn generate_keypair(&self, rng: &mut R) 455 | -> Result<(key::SecretKey, key::PublicKey), Error> { 456 | let sk = key::SecretKey::new(self, rng); 457 | let pk = key::PublicKey::from_secret_key(self, &sk)?; 458 | Ok((sk, pk)) 459 | } 460 | 461 | /// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce 462 | /// Requires a signing-capable context. 463 | pub fn sign(&self, msg: &Message, sk: &key::SecretKey) 464 | -> Result { 465 | if self.caps == ContextFlag::VerifyOnly || self.caps == ContextFlag::None { 466 | return Err(Error::IncapableContext); 467 | } 468 | 469 | let mut ret = ffi::Signature::new(); 470 | unsafe { 471 | // We can assume the return value because it's not possible to construct 472 | // an invalid signature from a valid `Message` and `SecretKey` 473 | assert_eq!(ffi::secp256k1_ecdsa_sign(self.ctx, &mut ret, msg.as_ptr(), 474 | sk.as_ptr(), ffi::secp256k1_nonce_function_rfc6979, 475 | ptr::null()), 1); 476 | } 477 | Ok(Signature::from(ret)) 478 | } 479 | 480 | /// Constructs a signature for `msg` using the secret key `sk` and RFC6979 nonce 481 | /// Requires a signing-capable context. 482 | pub fn sign_recoverable(&self, msg: &Message, sk: &key::SecretKey) 483 | -> Result { 484 | if self.caps == ContextFlag::VerifyOnly || self.caps == ContextFlag::None { 485 | return Err(Error::IncapableContext); 486 | } 487 | 488 | let mut ret = ffi::RecoverableSignature::new(); 489 | unsafe { 490 | // We can assume the return value because it's not possible to construct 491 | // an invalid signature from a valid `Message` and `SecretKey` 492 | assert_eq!(ffi::secp256k1_ecdsa_sign_recoverable(self.ctx, &mut ret, msg.as_ptr(), 493 | sk.as_ptr(), ffi::secp256k1_nonce_function_rfc6979, 494 | ptr::null()), 1); 495 | } 496 | Ok(RecoverableSignature::from(ret)) 497 | } 498 | 499 | /// Determines the public key for which `sig` is a valid signature for 500 | /// `msg`. Requires a verify-capable context. 501 | pub fn recover(&self, msg: &Message, sig: &RecoverableSignature) 502 | -> Result { 503 | if self.caps == ContextFlag::SignOnly || self.caps == ContextFlag::None { 504 | return Err(Error::IncapableContext); 505 | } 506 | 507 | let mut pk = ffi::PublicKey::new(); 508 | 509 | unsafe { 510 | if ffi::secp256k1_ecdsa_recover(self.ctx, &mut pk, 511 | sig.as_ptr(), msg.as_ptr()) != 1 { 512 | return Err(Error::InvalidSignature); 513 | } 514 | }; 515 | Ok(key::PublicKey::from(pk)) 516 | } 517 | 518 | /// Checks that `sig` is a valid ECDSA signature for `msg` using the public 519 | /// key `pubkey`. Returns `Ok(true)` on success. Note that this function cannot 520 | /// be used for Bitcoin consensus checking since there may exist signatures 521 | /// which OpenSSL would verify but not libsecp256k1, or vice-versa. Requires a 522 | /// verify-capable context. 523 | #[inline] 524 | pub fn verify(&self, msg: &Message, sig: &Signature, pk: &key::PublicKey) -> Result<(), Error> { 525 | if self.caps == ContextFlag::SignOnly || self.caps == ContextFlag::None { 526 | return Err(Error::IncapableContext); 527 | } 528 | 529 | if !pk.is_valid() { 530 | Err(Error::InvalidPublicKey) 531 | } else if unsafe { ffi::secp256k1_ecdsa_verify(self.ctx, sig.as_ptr(), msg.as_ptr(), 532 | pk.as_ptr()) } == 0 { 533 | Err(Error::IncorrectSignature) 534 | } else { 535 | Ok(()) 536 | } 537 | } 538 | } 539 | 540 | 541 | #[cfg(test)] 542 | mod tests { 543 | use rand::{RngCore, thread_rng}; 544 | 545 | use key::{SecretKey, PublicKey}; 546 | use super::constants; 547 | use super::{Secp256k1, Signature, RecoverableSignature, Message, RecoveryId, ContextFlag}; 548 | use super::Error::{InvalidMessage, InvalidPublicKey, IncorrectSignature, InvalidSignature, 549 | IncapableContext}; 550 | 551 | #[test] 552 | fn capabilities() { 553 | let none = Secp256k1::with_caps(ContextFlag::None); 554 | let sign = Secp256k1::with_caps(ContextFlag::SignOnly); 555 | let vrfy = Secp256k1::with_caps(ContextFlag::VerifyOnly); 556 | let full = Secp256k1::with_caps(ContextFlag::Full); 557 | 558 | let mut msg = [0u8; 32]; 559 | thread_rng().fill_bytes(&mut msg); 560 | let msg = Message::from_slice(&msg).unwrap(); 561 | 562 | // Try key generation 563 | assert_eq!(none.generate_keypair(&mut thread_rng()), Err(IncapableContext)); 564 | assert_eq!(vrfy.generate_keypair(&mut thread_rng()), Err(IncapableContext)); 565 | assert!(sign.generate_keypair(&mut thread_rng()).is_ok()); 566 | assert!(full.generate_keypair(&mut thread_rng()).is_ok()); 567 | let (sk, pk) = full.generate_keypair(&mut thread_rng()).unwrap(); 568 | 569 | // Try signing 570 | assert_eq!(none.sign(&msg, &sk), Err(IncapableContext)); 571 | assert_eq!(vrfy.sign(&msg, &sk), Err(IncapableContext)); 572 | assert!(sign.sign(&msg, &sk).is_ok()); 573 | assert!(full.sign(&msg, &sk).is_ok()); 574 | assert_eq!(none.sign_recoverable(&msg, &sk), Err(IncapableContext)); 575 | assert_eq!(vrfy.sign_recoverable(&msg, &sk), Err(IncapableContext)); 576 | assert!(sign.sign_recoverable(&msg, &sk).is_ok()); 577 | assert!(full.sign_recoverable(&msg, &sk).is_ok()); 578 | assert_eq!(sign.sign(&msg, &sk), full.sign(&msg, &sk)); 579 | assert_eq!(sign.sign_recoverable(&msg, &sk), full.sign_recoverable(&msg, &sk)); 580 | let sig = full.sign(&msg, &sk).unwrap(); 581 | let sigr = full.sign_recoverable(&msg, &sk).unwrap(); 582 | 583 | // Try verifying 584 | assert_eq!(none.verify(&msg, &sig, &pk), Err(IncapableContext)); 585 | assert_eq!(sign.verify(&msg, &sig, &pk), Err(IncapableContext)); 586 | assert!(vrfy.verify(&msg, &sig, &pk).is_ok()); 587 | assert!(full.verify(&msg, &sig, &pk).is_ok()); 588 | 589 | // Try pk recovery 590 | assert_eq!(none.recover(&msg, &sigr), Err(IncapableContext)); 591 | assert_eq!(sign.recover(&msg, &sigr), Err(IncapableContext)); 592 | assert!(vrfy.recover(&msg, &sigr).is_ok()); 593 | assert!(full.recover(&msg, &sigr).is_ok()); 594 | 595 | assert_eq!(vrfy.recover(&msg, &sigr), 596 | full.recover(&msg, &sigr)); 597 | assert_eq!(full.recover(&msg, &sigr), Ok(pk)); 598 | 599 | // Check that we can produce keys from slices with no precomputation 600 | let (pk_slice, sk_slice) = (&pk.serialize_vec(&none, true), &sk[..]); 601 | let new_pk = PublicKey::from_slice(&none, pk_slice).unwrap(); 602 | let new_sk = SecretKey::from_slice(&none, sk_slice).unwrap(); 603 | assert_eq!(sk, new_sk); 604 | assert_eq!(pk, new_pk); 605 | } 606 | 607 | #[test] 608 | fn recid_sanity_check() { 609 | let one = RecoveryId(1); 610 | assert_eq!(one, one.clone()); 611 | } 612 | 613 | #[test] 614 | fn invalid_pubkey() { 615 | let s = Secp256k1::new(); 616 | let sig = RecoverableSignature::from_compact(&s, &[1; 64], RecoveryId(0)).unwrap(); 617 | let pk = PublicKey::new(); 618 | let mut msg = [0u8; 32]; 619 | thread_rng().fill_bytes(&mut msg); 620 | let msg = Message::from_slice(&msg).unwrap(); 621 | 622 | assert_eq!(s.verify(&msg, &sig.to_standard(&s), &pk), Err(InvalidPublicKey)); 623 | } 624 | 625 | #[test] 626 | fn sign() { 627 | let mut s = Secp256k1::new(); 628 | s.randomize(&mut thread_rng()); 629 | let one = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 630 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; 631 | 632 | let sk = SecretKey::from_slice(&s, &one).unwrap(); 633 | let msg = Message::from_slice(&one).unwrap(); 634 | 635 | let sig = s.sign_recoverable(&msg, &sk).unwrap(); 636 | assert_eq!(Ok(sig), RecoverableSignature::from_compact(&s, &[ 637 | 0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f, 638 | 0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6, 639 | 0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65, 640 | 0xc3, 0x6d, 0xed, 0xf4, 0x09, 0x2e, 0x88, 0x98, 641 | 0x4c, 0x1a, 0x97, 0x16, 0x52, 0xe0, 0xad, 0xa8, 642 | 0x80, 0x12, 0x0e, 0xf8, 0x02, 0x5e, 0x70, 0x9f, 643 | 0xff, 0x20, 0x80, 0xc4, 0xa3, 0x9a, 0xae, 0x06, 644 | 0x8d, 0x12, 0xee, 0xd0, 0x09, 0xb6, 0x8c, 0x89], 645 | RecoveryId(1))) 646 | } 647 | 648 | #[test] 649 | fn signature_der_roundtrip() { 650 | let mut s = Secp256k1::new(); 651 | s.randomize(&mut thread_rng()); 652 | 653 | let mut msg = [0; 32]; 654 | for _ in 0..100 { 655 | thread_rng().fill_bytes(&mut msg); 656 | let msg = Message::from_slice(&msg).unwrap(); 657 | 658 | let (sk, _) = s.generate_keypair(&mut thread_rng()).unwrap(); 659 | let sig1 = s.sign(&msg, &sk).unwrap(); 660 | let der = sig1.serialize_der(&s); 661 | let sig2 = Signature::from_der(&s, &der[..]).unwrap(); 662 | assert_eq!(sig1, sig2); 663 | } 664 | } 665 | 666 | #[test] 667 | fn signature_lax_der() { 668 | macro_rules! check_lax_sig( 669 | ($hex:expr) => ({ 670 | let secp = Secp256k1::without_caps(); 671 | let sig = hex!($hex); 672 | assert!(Signature::from_der_lax(&secp, &sig[..]).is_ok()); 673 | }) 674 | ); 675 | 676 | check_lax_sig!("304402204c2dd8a9b6f8d425fcd8ee9a20ac73b619906a6367eac6cb93e70375225ec0160220356878eff111ff3663d7e6bf08947f94443845e0dcc54961664d922f7660b80c"); 677 | check_lax_sig!("304402202ea9d51c7173b1d96d331bd41b3d1b4e78e66148e64ed5992abd6ca66290321c0220628c47517e049b3e41509e9d71e480a0cdc766f8cdec265ef0017711c1b5336f"); 678 | check_lax_sig!("3045022100bf8e050c85ffa1c313108ad8c482c4849027937916374617af3f2e9a881861c9022023f65814222cab09d5ec41032ce9c72ca96a5676020736614de7b78a4e55325a"); 679 | check_lax_sig!("3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45"); 680 | check_lax_sig!("3046022100eaa5f90483eb20224616775891397d47efa64c68b969db1dacb1c30acdfc50aa022100cf9903bbefb1c8000cf482b0aeeb5af19287af20bd794de11d82716f9bae3db1"); 681 | check_lax_sig!("3045022047d512bc85842ac463ca3b669b62666ab8672ee60725b6c06759e476cebdc6c102210083805e93bd941770109bcc797784a71db9e48913f702c56e60b1c3e2ff379a60"); 682 | check_lax_sig!("3044022023ee4e95151b2fbbb08a72f35babe02830d14d54bd7ed1320e4751751d1baa4802206235245254f58fd1be6ff19ca291817da76da65c2f6d81d654b5185dd86b8acf"); 683 | } 684 | 685 | #[test] 686 | fn sign_and_verify() { 687 | let mut s = Secp256k1::new(); 688 | s.randomize(&mut thread_rng()); 689 | 690 | let mut msg = [0; 32]; 691 | for _ in 0..100 { 692 | thread_rng().fill_bytes(&mut msg); 693 | let msg = Message::from_slice(&msg).unwrap(); 694 | 695 | let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap(); 696 | let sig = s.sign(&msg, &sk).unwrap(); 697 | assert_eq!(s.verify(&msg, &sig, &pk), Ok(())); 698 | } 699 | } 700 | 701 | #[test] 702 | fn sign_and_verify_extreme() { 703 | let mut s = Secp256k1::new(); 704 | s.randomize(&mut thread_rng()); 705 | 706 | // Wild keys: 1, CURVE_ORDER - 1 707 | // Wild msgs: 0, 1, CURVE_ORDER - 1, CURVE_ORDER 708 | let mut wild_keys = [[0; 32]; 2]; 709 | let mut wild_msgs = [[0; 32]; 4]; 710 | 711 | wild_keys[0][0] = 1; 712 | wild_msgs[1][0] = 1; 713 | 714 | use constants; 715 | wild_keys[1][..].copy_from_slice(&constants::CURVE_ORDER[..]); 716 | wild_msgs[1][..].copy_from_slice(&constants::CURVE_ORDER[..]); 717 | wild_msgs[2][..].copy_from_slice(&constants::CURVE_ORDER[..]); 718 | 719 | wild_keys[1][0] -= 1; 720 | wild_msgs[1][0] -= 1; 721 | 722 | for key in wild_keys.iter().map(|k| SecretKey::from_slice(&s, &k[..]).unwrap()) { 723 | for msg in wild_msgs.iter().map(|m| Message::from_slice(&m[..]).unwrap()) { 724 | let sig = s.sign(&msg, &key).unwrap(); 725 | let pk = PublicKey::from_secret_key(&s, &key).unwrap(); 726 | assert_eq!(s.verify(&msg, &sig, &pk), Ok(())); 727 | } 728 | } 729 | } 730 | 731 | #[test] 732 | fn sign_and_verify_fail() { 733 | let mut s = Secp256k1::new(); 734 | s.randomize(&mut thread_rng()); 735 | 736 | let mut msg = [0u8; 32]; 737 | thread_rng().fill_bytes(&mut msg); 738 | let msg = Message::from_slice(&msg).unwrap(); 739 | 740 | let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap(); 741 | 742 | let sigr = s.sign_recoverable(&msg, &sk).unwrap(); 743 | let sig = sigr.to_standard(&s); 744 | 745 | let mut msg = [0u8; 32]; 746 | thread_rng().fill_bytes(&mut msg); 747 | let msg = Message::from_slice(&msg).unwrap(); 748 | assert_eq!(s.verify(&msg, &sig, &pk), Err(IncorrectSignature)); 749 | 750 | let recovered_key = s.recover(&msg, &sigr).unwrap(); 751 | assert!(recovered_key != pk); 752 | } 753 | 754 | #[test] 755 | fn sign_with_recovery() { 756 | let mut s = Secp256k1::new(); 757 | s.randomize(&mut thread_rng()); 758 | 759 | let mut msg = [0u8; 32]; 760 | thread_rng().fill_bytes(&mut msg); 761 | let msg = Message::from_slice(&msg).unwrap(); 762 | 763 | let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap(); 764 | 765 | let sig = s.sign_recoverable(&msg, &sk).unwrap(); 766 | 767 | assert_eq!(s.recover(&msg, &sig), Ok(pk)); 768 | } 769 | 770 | #[test] 771 | fn bad_recovery() { 772 | let mut s = Secp256k1::new(); 773 | s.randomize(&mut thread_rng()); 774 | 775 | let msg = Message::from_slice(&[0x55; 32]).unwrap(); 776 | 777 | // Zero is not a valid sig 778 | let sig = RecoverableSignature::from_compact(&s, &[0; 64], RecoveryId(0)).unwrap(); 779 | assert_eq!(s.recover(&msg, &sig), Err(InvalidSignature)); 780 | // ...but 111..111 is 781 | let sig = RecoverableSignature::from_compact(&s, &[1; 64], RecoveryId(0)).unwrap(); 782 | assert!(s.recover(&msg, &sig).is_ok()); 783 | } 784 | 785 | #[test] 786 | fn test_bad_slice() { 787 | let s = Secp256k1::new(); 788 | assert_eq!(Signature::from_der(&s, &[0; constants::MAX_SIGNATURE_SIZE + 1]), 789 | Err(InvalidSignature)); 790 | assert_eq!(Signature::from_der(&s, &[0; constants::MAX_SIGNATURE_SIZE]), 791 | Err(InvalidSignature)); 792 | 793 | assert_eq!(Message::from_slice(&[0; constants::MESSAGE_SIZE - 1]), 794 | Err(InvalidMessage)); 795 | assert_eq!(Message::from_slice(&[0; constants::MESSAGE_SIZE + 1]), 796 | Err(InvalidMessage)); 797 | assert!(Message::from_slice(&[0; constants::MESSAGE_SIZE]).is_ok()); 798 | } 799 | 800 | #[test] 801 | fn test_debug_output() { 802 | let s = Secp256k1::new(); 803 | let sig = RecoverableSignature::from_compact(&s, &[ 804 | 0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f, 805 | 0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6, 806 | 0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65, 807 | 0xc3, 0x6d, 0xed, 0xf4, 0x09, 0x2e, 0x88, 0x98, 808 | 0x4c, 0x1a, 0x97, 0x16, 0x52, 0xe0, 0xad, 0xa8, 809 | 0x80, 0x12, 0x0e, 0xf8, 0x02, 0x5e, 0x70, 0x9f, 810 | 0xff, 0x20, 0x80, 0xc4, 0xa3, 0x9a, 0xae, 0x06, 811 | 0x8d, 0x12, 0xee, 0xd0, 0x09, 0xb6, 0x8c, 0x89], 812 | RecoveryId(1)).unwrap(); 813 | assert_eq!(&format!("{:?}", sig), "RecoverableSignature(98882e09f4ed6dc3659e43fc771e0cafa60b1f926f2b77041f744721adff7366898cb609d0ee128d06ae9aa3c48020ff9f705e02f80e1280a8ade05216971a4c01)"); 814 | 815 | let msg = Message([1, 2, 3, 4, 5, 6, 7, 8, 816 | 9, 10, 11, 12, 13, 14, 15, 16, 817 | 17, 18, 19, 20, 21, 22, 23, 24, 818 | 25, 26, 27, 28, 29, 30, 31, 255]); 819 | assert_eq!(&format!("{:?}", msg), "Message(0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fff)"); 820 | } 821 | 822 | #[test] 823 | fn test_recov_sig_serialize_compact() { 824 | let s = Secp256k1::new(); 825 | 826 | let recid_in = RecoveryId(1); 827 | let bytes_in = &[ 828 | 0x66, 0x73, 0xff, 0xad, 0x21, 0x47, 0x74, 0x1f, 829 | 0x04, 0x77, 0x2b, 0x6f, 0x92, 0x1f, 0x0b, 0xa6, 830 | 0xaf, 0x0c, 0x1e, 0x77, 0xfc, 0x43, 0x9e, 0x65, 831 | 0xc3, 0x6d, 0xed, 0xf4, 0x09, 0x2e, 0x88, 0x98, 832 | 0x4c, 0x1a, 0x97, 0x16, 0x52, 0xe0, 0xad, 0xa8, 833 | 0x80, 0x12, 0x0e, 0xf8, 0x02, 0x5e, 0x70, 0x9f, 834 | 0xff, 0x20, 0x80, 0xc4, 0xa3, 0x9a, 0xae, 0x06, 835 | 0x8d, 0x12, 0xee, 0xd0, 0x09, 0xb6, 0x8c, 0x89]; 836 | let sig = RecoverableSignature::from_compact( 837 | &s, bytes_in, recid_in).unwrap(); 838 | let (recid_out, bytes_out) = sig.serialize_compact(&s); 839 | assert_eq!(recid_in, recid_out); 840 | assert_eq!(&bytes_in[..], &bytes_out[..]); 841 | } 842 | 843 | #[test] 844 | fn test_recov_id_conversion_between_i32() { 845 | assert!(RecoveryId::from_i32(-1).is_err()); 846 | assert!(RecoveryId::from_i32(0).is_ok()); 847 | assert!(RecoveryId::from_i32(1).is_ok()); 848 | assert!(RecoveryId::from_i32(2).is_ok()); 849 | assert!(RecoveryId::from_i32(3).is_ok()); 850 | assert!(RecoveryId::from_i32(4).is_err()); 851 | let id0 = RecoveryId::from_i32(0).unwrap(); 852 | assert_eq!(id0.to_i32(), 0); 853 | let id1 = RecoveryId(1); 854 | assert_eq!(id1.to_i32(), 1); 855 | } 856 | 857 | #[test] 858 | fn test_low_s() { 859 | // nb this is a transaction on testnet 860 | // txid 8ccc87b72d766ab3128f03176bb1c98293f2d1f85ebfaf07b82cc81ea6891fa9 861 | // input number 3 862 | let sig = hex!("3046022100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45"); 863 | let pk = hex!("031ee99d2b786ab3b0991325f2de8489246a6a3fdb700f6d0511b1d80cf5f4cd43"); 864 | let msg = hex!("a4965ca63b7d8562736ceec36dfa5a11bf426eb65be8ea3f7a49ae363032da0d"); 865 | 866 | let secp = Secp256k1::new(); 867 | let mut sig = Signature::from_der(&secp, &sig[..]).unwrap(); 868 | let pk = PublicKey::from_slice(&secp, &pk[..]).unwrap(); 869 | let msg = Message::from_slice(&msg[..]).unwrap(); 870 | 871 | // without normalization we expect this will fail 872 | assert_eq!(secp.verify(&msg, &sig, &pk), Err(IncorrectSignature)); 873 | // after normalization it should pass 874 | sig.normalize_s(&secp); 875 | assert_eq!(secp.verify(&msg, &sig, &pk), Ok(())); 876 | } 877 | } 878 | 879 | #[cfg(all(test, feature = "unstable"))] 880 | mod benches { 881 | use rand::{Rng, thread_rng}; 882 | use test::{Bencher, black_box}; 883 | 884 | use super::{Secp256k1, Message}; 885 | 886 | #[bench] 887 | pub fn generate(bh: &mut Bencher) { 888 | struct CounterRng(u32); 889 | impl Rng for CounterRng { 890 | fn next_u32(&mut self) -> u32 { self.0 += 1; self.0 } 891 | } 892 | 893 | let s = Secp256k1::new(); 894 | let mut r = CounterRng(0); 895 | bh.iter( || { 896 | let (sk, pk) = s.generate_keypair(&mut r).unwrap(); 897 | black_box(sk); 898 | black_box(pk); 899 | }); 900 | } 901 | 902 | #[bench] 903 | pub fn bench_sign(bh: &mut Bencher) { 904 | let s = Secp256k1::new(); 905 | let mut msg = [0u8; 32]; 906 | thread_rng().fill_bytes(&mut msg); 907 | let msg = Message::from_slice(&msg).unwrap(); 908 | let (sk, _) = s.generate_keypair(&mut thread_rng()).unwrap(); 909 | 910 | bh.iter(|| { 911 | let sig = s.sign(&msg, &sk).unwrap(); 912 | black_box(sig); 913 | }); 914 | } 915 | 916 | #[bench] 917 | pub fn bench_verify(bh: &mut Bencher) { 918 | let s = Secp256k1::new(); 919 | let mut msg = [0u8; 32]; 920 | thread_rng().fill_bytes(&mut msg); 921 | let msg = Message::from_slice(&msg).unwrap(); 922 | let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap(); 923 | let sig = s.sign(&msg, &sk).unwrap(); 924 | 925 | bh.iter(|| { 926 | let res = s.verify(&msg, &sig, &pk).unwrap(); 927 | black_box(res); 928 | }); 929 | } 930 | 931 | #[bench] 932 | pub fn bench_recover(bh: &mut Bencher) { 933 | let s = Secp256k1::new(); 934 | let mut msg = [0u8; 32]; 935 | thread_rng().fill_bytes(&mut msg); 936 | let msg = Message::from_slice(&msg).unwrap(); 937 | let (sk, _) = s.generate_keypair(&mut thread_rng()).unwrap(); 938 | let sig = s.sign_recoverable(&msg, &sk).unwrap(); 939 | 940 | bh.iter(|| { 941 | let res = s.recover(&msg, &sig).unwrap(); 942 | black_box(res); 943 | }); 944 | } 945 | } 946 | 947 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | // Bitcoin secp256k1 bindings 2 | // Written in 2014 by 3 | // Dawid Ciężarkiewicz 4 | // Andrew Poelstra 5 | // 6 | // To the extent possible under law, the author(s) have dedicated all 7 | // copyright and related and neighboring rights to this software to 8 | // the public domain worldwide. This software is distributed without 9 | // any warranty. 10 | // 11 | // You should have received a copy of the CC0 Public Domain Dedication 12 | // along with this software. 13 | // If not, see . 14 | // 15 | 16 | // This is a macro that routinely comes in handy 17 | macro_rules! impl_array_newtype { 18 | ($thing:ident, $ty:ty, $len:expr) => { 19 | impl Copy for $thing {} 20 | 21 | impl $thing { 22 | #[inline] 23 | /// Converts the object to a raw pointer for FFI interfacing 24 | pub fn as_ptr(&self) -> *const $ty { 25 | let &$thing(ref dat) = self; 26 | dat.as_ptr() 27 | } 28 | 29 | #[inline] 30 | /// Converts the object to a mutable raw pointer for FFI interfacing 31 | pub fn as_mut_ptr(&mut self) -> *mut $ty { 32 | let &mut $thing(ref mut dat) = self; 33 | dat.as_mut_ptr() 34 | } 35 | 36 | #[inline] 37 | /// Returns the length of the object as an array 38 | pub fn len(&self) -> usize { $len } 39 | 40 | #[inline] 41 | /// Returns whether the object as an array is empty 42 | pub fn is_empty(&self) -> bool { false } 43 | } 44 | 45 | impl PartialEq for $thing { 46 | #[inline] 47 | fn eq(&self, other: &$thing) -> bool { 48 | &self[..] == &other[..] 49 | } 50 | } 51 | 52 | impl Eq for $thing {} 53 | 54 | impl Clone for $thing { 55 | #[inline] 56 | fn clone(&self) -> $thing { 57 | let &$thing(ref dat) = self; 58 | $thing(dat.clone()) 59 | } 60 | } 61 | 62 | impl ::std::ops::Index for $thing { 63 | type Output = $ty; 64 | 65 | #[inline] 66 | fn index(&self, index: usize) -> &$ty { 67 | let &$thing(ref dat) = self; 68 | &dat[index] 69 | } 70 | } 71 | 72 | impl ::std::ops::Index<::std::ops::Range> for $thing { 73 | type Output = [$ty]; 74 | 75 | #[inline] 76 | fn index(&self, index: ::std::ops::Range) -> &[$ty] { 77 | let &$thing(ref dat) = self; 78 | &dat[index] 79 | } 80 | } 81 | 82 | impl ::std::ops::Index<::std::ops::RangeTo> for $thing { 83 | type Output = [$ty]; 84 | 85 | #[inline] 86 | fn index(&self, index: ::std::ops::RangeTo) -> &[$ty] { 87 | let &$thing(ref dat) = self; 88 | &dat[index] 89 | } 90 | } 91 | 92 | impl ::std::ops::Index<::std::ops::RangeFrom> for $thing { 93 | type Output = [$ty]; 94 | 95 | #[inline] 96 | fn index(&self, index: ::std::ops::RangeFrom) -> &[$ty] { 97 | let &$thing(ref dat) = self; 98 | &dat[index] 99 | } 100 | } 101 | 102 | impl ::std::ops::Index<::std::ops::RangeFull> for $thing { 103 | type Output = [$ty]; 104 | 105 | #[inline] 106 | fn index(&self, _: ::std::ops::RangeFull) -> &[$ty] { 107 | let &$thing(ref dat) = self; 108 | &dat[..] 109 | } 110 | } 111 | } 112 | } 113 | 114 | macro_rules! impl_pretty_debug { 115 | ($thing:ident) => { 116 | impl ::std::fmt::Debug for $thing { 117 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 118 | write!(f, "{}(", stringify!($thing))?; 119 | for i in self[..].iter().cloned() { 120 | write!(f, "{:02x}", i)?; 121 | } 122 | write!(f, ")") 123 | } 124 | } 125 | } 126 | } 127 | 128 | macro_rules! impl_raw_debug { 129 | ($thing:ident) => { 130 | impl ::std::fmt::Debug for $thing { 131 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 132 | for i in self[..].iter().cloned() { 133 | write!(f, "{:02x}", i)?; 134 | } 135 | Ok(()) 136 | } 137 | } 138 | } 139 | } 140 | 141 | --------------------------------------------------------------------------------