diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..53eaa219 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..ad9a1b65 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,233 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "secp256k1" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "secp256k1-zkp" +version = "0.1.0" +dependencies = [ + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1-zkp-dev 0.1.0", + "secp256k1-zkp-sys 0.1.0", +] + +[[package]] +name = "secp256k1-zkp-dev" +version = "0.1.0" +dependencies = [ + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "secp256k1-zkp-sys" +version = "0.1.0" +dependencies = [ + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1-zkp-dev 0.1.0", + "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_test 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_test" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "42914d39aad277d9e176efbdad68acb1d5443ab65afe0e0e4f0d49352a950880" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum secp256k1 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb1f2c586f44331cd22561405885bb55d869e042715f29d019dbe68558b4f7ec" +"checksum serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "a72e9b96fa45ce22a4bc23da3858dfccfd60acd28a25bcd328a98fdd6bea43fd" +"checksum serde_test 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "164b351e29d8a2230b77c27e47dda5603be39a2d35db38f440f0b78946ce37c7" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..e847c121 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] +members = [ + "secp256k1-zkp-dev", + "secp256k1-zkp-sys", + "secp256k1-zkp" +] diff --git a/contrib/test.sh b/contrib/test.sh new file mode 100755 index 00000000..de73e295 --- /dev/null +++ b/contrib/test.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +if [ -z "$1" ]; then + echo This test script runs the workspace tests and the -sys tests with the + echo serde feature enabled. This is necessary because you can not test + echo features on the workspace level. The script also checks if the files are + echo rustfmt\'d. + echo + echo "ERROR: \$1 parameter must be the workspace directory" + exit 1 +fi +DIR=$1 + +shopt -s globstar + +( + cd "$DIR" + set -e + cargo test + ( + cd secp256k1-zkp-sys + cargo test --features serde + ) + rustfmt --check -- **/*.rs +) + +if [ $? -ne 0 ]; then + echo ERROR: $0 failed + exit 1 +fi + diff --git a/contrib/vendor-libsecp-zkp.sh b/contrib/vendor-libsecp-zkp.sh new file mode 100755 index 00000000..dc886463 --- /dev/null +++ b/contrib/vendor-libsecp-zkp.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -e + + +if [ -z "$1" ]; then + echo "\$1 parameter must be the rust-secp256k1-zkp-sys depend directory" + echo "\$2 parameter (optional) can be the revision to check out" + exit 1 +fi + +PARENT_DIR=$1 +REV=$2 +DIR=secp256k1-zkp + +while true; do + read -r -p "$PARENT_DIR/$DIR will be deleted [yn]: " yn + case $yn in + [Yy]* ) break;; + [Nn]* ) exit;; + * ) echo "Please answer yes or no.";; + esac +done + +cd "$PARENT_DIR" +rm -rf "$DIR" +git clone git@github.com:ElementsProject/secp256k1-zkp.git +cd "$DIR" +if [ -n "$REV" ]; then + git checkout "$REV" +fi +HEAD=$(git rev-parse HEAD) +cd .. +echo "\# This file was automatically created by $0" > ./secp256k1-zkp-HEAD-revision.txt +echo "$HEAD" >> ./secp256k1-zkp-HEAD-revision.txt + +find "$DIR" -not -path '*/\.*' -type f -print0 | xargs -0 sed -i '/^#include/! s/secp256k1_/secp256k1_zkp_/g' +# TODO: can be removed once 496c5b43b lands in secp-zkp +find "$DIR" -not -path '*/\.*' -type f -print0 | xargs -0 sed -i 's/^const int CURVE_B/static const int CURVE_B/g' diff --git a/secp256k1-zkp-dev/Cargo.toml b/secp256k1-zkp-dev/Cargo.toml new file mode 100644 index 00000000..859d3eb4 --- /dev/null +++ b/secp256k1-zkp-dev/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "secp256k1-zkp-dev" +version = "0.1.0" +authors = ["Jonas Nick "] + +license = "CC0-1.0" +homepage = "https://github.com/ElementsProject/rust-secp256k1-zkp/" +repository = "https://github.com/ElementsProject/rust-secp256k1-zkp/" +description = "dev-dependencies for secp256k1-zkp-sys and secp256k1-zkp." +keywords = [ "crypto", "ECDSA", "Schnorr", "secp256k1", "libsecp256k1", "secp256k1-zkp", "libsecp256k1-zkp", "bitcoin" ] + +[dependencies] +rand = "0.6" + +[dependencies.secp256k1] +version = "0.13" diff --git a/secp256k1-zkp-dev/src/lib.rs b/secp256k1-zkp-dev/src/lib.rs new file mode 100644 index 00000000..797296a3 --- /dev/null +++ b/secp256k1-zkp-dev/src/lib.rs @@ -0,0 +1,60 @@ +// secp256k1-zkp bindings +// Written in 2019 by +// Jonas Nick +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +/// The functions in this module are copied from secp256k1 because they can only be used when +/// compiled with the `rand` feature. But the other libraries need them as a dev-dependency for +/// `cargo test` also when `rand` is not enabled. Currently with cargo we can't have a `rand` +/// dev-dependency and a non-`rand` dependency at the same time (see +/// https://github.com/rust-lang/cargo/issues/1796). +pub extern crate rand; +pub extern crate secp256k1; + +use rand::Rng; +use secp256k1::{PublicKey, Secp256k1, SecretKey, Signing}; + +fn random_32_bytes(rng: &mut R) -> [u8; 32] { + let mut ret = [0u8; 32]; + rng.fill_bytes(&mut ret); + ret +} + +trait NewSecretKey { + fn new(rng: &mut R) -> SecretKey; +} + +impl NewSecretKey for SecretKey { + /// Creates a new random secret key. + #[inline] + fn new(rng: &mut R) -> SecretKey { + loop { + if let Ok(key) = SecretKey::from_slice(&random_32_bytes(rng)) { + return key; + } + } + } +} + +pub trait GenerateKeypair { + /// Generates a random keypair. + fn generate_keypair(&self, rng: &mut R) -> (SecretKey, PublicKey); +} + +impl GenerateKeypair for Secp256k1 { + #[inline] + fn generate_keypair(&self, rng: &mut R) -> (SecretKey, PublicKey) { + let sk = SecretKey::new(rng); + let pk = PublicKey::from_secret_key(self, &sk); + (sk, pk) + } +} diff --git a/secp256k1-zkp-sys/Cargo.toml b/secp256k1-zkp-sys/Cargo.toml new file mode 100644 index 00000000..8ae58164 --- /dev/null +++ b/secp256k1-zkp-sys/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "secp256k1-zkp-sys" +version = "0.1.0" +authors = ["Jonas Nick "] + +license = "CC0-1.0" +homepage = "https://github.com/ElementsProject/rust-secp256k1-zkp/" +repository = "https://github.com/ElementsProject/rust-secp256k1-zkp/" +description = "Rust bindings for the Elements Project's `libsecp256k1-zkp` library. Implements various cryptographic schemes for the SECG elliptic curve group secp256k1 and related utilities. This is a low-level, no_std library. There is also w higher level library called secp256k1-zkp." +keywords = [ "crypto", "ECDSA", "Schnorr", "secp256k1", "libsecp256k1", "secp256k1-zkp", "libsecp256k1-zkp", "bitcoin" ] +readme = "README.md" +build = "build.rs" + +[package.metadata.docs.rs] +features = [ "serde" ] +all-features = true + +[build-dependencies] +cc = ">= 1.0.28, <= 1.0.35" + +[dev-dependencies] +rand = "0.6" +serde_test = "1.0" + +[dev-dependencies.secp256k1-zkp-dev] +version = "0.1" +path = "../secp256k1-zkp-dev/" + +[dependencies.secp256k1] +version = "0.13" + +[dependencies.serde] +version = "1.0" +optional = true +default-features = false diff --git a/secp256k1-zkp-sys/build.rs b/secp256k1-zkp-sys/build.rs new file mode 100644 index 00000000..95731c9b --- /dev/null +++ b/secp256k1-zkp-sys/build.rs @@ -0,0 +1,83 @@ +// Bitcoin secp256k1 bindings +// Written in 2015 by +// Andrew Poelstra +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! # Build script + +// Coding conventions +#![deny(non_upper_case_globals)] +#![deny(non_camel_case_types)] +#![deny(non_snake_case)] +#![deny(unused_mut)] +#![warn(missing_docs)] + +extern crate cc; + +use std::env; + +fn main() { + // Check whether we can use 64-bit compilation + let use_64bit_compilation = if env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "64" { + let check = cc::Build::new() + .file("depend/check_uint128_t.c") + .cargo_metadata(false) + .try_compile("check_uint128_t") + .is_ok(); + if !check { + println!("cargo:warning=Compiling in 32-bit mode on a 64-bit architecture due to lack of uint128_t support."); + } + check + } else { + false + }; + + // Actual build + let mut base_config = cc::Build::new(); + base_config + .include("depend/secp256k1-zkp/") + .include("depend/secp256k1-zkp/include") + .include("depend/secp256k1-zkp/src") + .debug(true) + .flag_if_supported("-Wno-unused-function") // some ecmult stuff is defined but not used upstream + .define("SECP256K1_BUILD", Some("1")) + // TODO these three should be changed to use libgmp, at least until secp PR 290 is merged + .define("USE_NUM_NONE", Some("1")) + .define("USE_FIELD_INV_BUILTIN", Some("1")) + .define("USE_SCALAR_INV_BUILTIN", Some("1")) + .define("USE_ENDOMORPHISM", Some("1")) + .define("ECMULT_WINDOW_SIZE", Some("16")) + .define("ENABLE_MODULE_SCHNORRSIG", Some("1")); + + if let Ok(target_endian) = env::var("CARGO_CFG_TARGET_ENDIAN") { + if target_endian == "big" { + base_config.define("WORDS_BIGENDIAN", Some("1")); + } + } + + if use_64bit_compilation { + base_config + .define("USE_FIELD_5X52", Some("1")) + .define("USE_SCALAR_4X64", Some("1")) + .define("HAVE___INT128", Some("1")); + } else { + base_config + .define("USE_FIELD_10X26", Some("1")) + .define("USE_SCALAR_8X32", Some("1")); + } + + // secp256k1 + base_config + .file("depend/secp256k1-zkp/contrib/lax_der_parsing.c") + .file("depend/secp256k1-zkp/src/secp256k1.c") + .compile("libsecp256k1.a"); +} diff --git a/secp256k1-zkp-sys/depend/check_uint128_t.c b/secp256k1-zkp-sys/depend/check_uint128_t.c new file mode 100644 index 00000000..4d909552 --- /dev/null +++ b/secp256k1-zkp-sys/depend/check_uint128_t.c @@ -0,0 +1,16 @@ + +#include + +int main(void) { + __uint128_t var_128; + uint64_t var_64; + + /* Try to shut up "unused variable" warnings */ + var_64 = 100; + var_128 = 100; + if (var_64 == var_128) { + var_64 = 20; + } + return 0; +} + diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp-HEAD-revision.txt b/secp256k1-zkp-sys/depend/secp256k1-zkp-HEAD-revision.txt new file mode 100644 index 00000000..2b356e2c --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp-HEAD-revision.txt @@ -0,0 +1,2 @@ +\# This file was automatically created by ./contrib/vendor-libsecp-zkp.sh +1c830b4c9ac30aa32e246ea3ab8ef9ef99acf664 diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/.gitignore b/secp256k1-zkp-sys/depend/secp256k1-zkp/.gitignore new file mode 100644 index 00000000..905be987 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/.gitignore @@ -0,0 +1,50 @@ +bench_inv +bench_ecdh +bench_ecmult +bench_schnorrsig +bench_sign +bench_verify +bench_recover +bench_internal +tests +exhaustive_tests +gen_context +*.exe +*.so +*.a +!.gitignore + +Makefile +configure +.libs/ +Makefile.in +aclocal.m4 +autom4te.cache/ +config.log +config.status +*.tar.gz +*.la +libtool +.deps/ +.dirstamp +*.lo +*.o +*~ +src/libsecp256k1-config.h +src/libsecp256k1-config.h.in +src/ecmult_static_context.h +build-aux/config.guess +build-aux/config.sub +build-aux/depcomp +build-aux/install-sh +build-aux/ltmain.sh +build-aux/m4/libtool.m4 +build-aux/m4/lt~obsolete.m4 +build-aux/m4/ltoptions.m4 +build-aux/m4/ltsugar.m4 +build-aux/m4/ltversion.m4 +build-aux/missing +build-aux/compile +build-aux/test-driver +src/stamp-h1 +libsecp256k1.pc diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/.travis.yml b/secp256k1-zkp-sys/depend/secp256k1-zkp/.travis.yml new file mode 100644 index 00000000..dbb9d840 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/.travis.yml @@ -0,0 +1,71 @@ +language: c +sudo: false +addons: + apt: + packages: libgmp-dev +compiler: + - clang + - gcc +cache: + directories: + - src/java/guava/ +env: + global: + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no JNI=no GENERATOR=no RANGEPROOF=no WHITELIST=no + - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar + matrix: + - SCALAR=32bit FIELD=32bit EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes + - FIELD=64bit EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes + - SCALAR=32bit RECOVERY=yes + - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes + - SCALAR=64bit + - FIELD=64bit RECOVERY=yes + - FIELD=64bit ENDOMORPHISM=yes + - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes + - FIELD=64bit ASM=x86_64 + - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 + - FIELD=32bit ENDOMORPHISM=yes + - BIGNUM=no + - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes + - BIGNUM=no STATICPRECOMPUTATION=no + - BUILD=distcheck + - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC + - EXTRAFLAGS=CFLAGS=-O0 + - BUILD=check-java JNI=yes ECDH=yes EXPERIMENTAL=yes +matrix: + fast_finish: true + include: + - compiler: clang + env: HOST=i686-linux-gnu ENDOMORPHISM=yes + addons: + apt: + packages: + - gcc-multilib + - libgmp-dev:i386 + - compiler: clang + env: HOST=i686-linux-gnu + addons: + apt: + packages: + - gcc-multilib + - compiler: gcc + env: HOST=i686-linux-gnu ENDOMORPHISM=yes + addons: + apt: + packages: + - gcc-multilib + - compiler: gcc + env: HOST=i686-linux-gnu + addons: + apt: + packages: + - gcc-multilib + - libgmp-dev:i386 +before_install: mkdir -p `dirname $GUAVA_JAR` +install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi +before_script: ./autogen.sh +script: + - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi + - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi + - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-rangeproof=$RANGEPROOF --enable-module-whitelist=$WHITELIST --enable-module-generator=$GENERATOR --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 $BUILD +os: linux diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/COPYING b/secp256k1-zkp-sys/depend/secp256k1-zkp/COPYING new file mode 100644 index 00000000..4522a599 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/COPYING @@ -0,0 +1,19 @@ +Copyright (c) 2013 Pieter Wuille + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/Makefile.am b/secp256k1-zkp-sys/depend/secp256k1-zkp/Makefile.am new file mode 100644 index 00000000..f8f39c88 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/Makefile.am @@ -0,0 +1,208 @@ +ACLOCAL_AMFLAGS = -I build-aux/m4 + +lib_LTLIBRARIES = libsecp256k1.la +if USE_JNI +JNI_LIB = libsecp256k1_zkp_jni.la +noinst_LTLIBRARIES = $(JNI_LIB) +else +JNI_LIB = +endif +include_HEADERS = include/secp256k1.h +include_HEADERS += include/secp256k1_zkp_preallocated.h +noinst_HEADERS = +noinst_HEADERS += src/scalar.h +noinst_HEADERS += src/scalar_4x64.h +noinst_HEADERS += src/scalar_8x32.h +noinst_HEADERS += src/scalar_low.h +noinst_HEADERS += src/scalar_impl.h +noinst_HEADERS += src/scalar_4x64_impl.h +noinst_HEADERS += src/scalar_8x32_impl.h +noinst_HEADERS += src/scalar_low_impl.h +noinst_HEADERS += src/group.h +noinst_HEADERS += src/group_impl.h +noinst_HEADERS += src/num_gmp.h +noinst_HEADERS += src/num_gmp_impl.h +noinst_HEADERS += src/ecdsa.h +noinst_HEADERS += src/ecdsa_impl.h +noinst_HEADERS += src/eckey.h +noinst_HEADERS += src/eckey_impl.h +noinst_HEADERS += src/ecmult.h +noinst_HEADERS += src/ecmult_impl.h +noinst_HEADERS += src/ecmult_const.h +noinst_HEADERS += src/ecmult_const_impl.h +noinst_HEADERS += src/ecmult_gen.h +noinst_HEADERS += src/ecmult_gen_impl.h +noinst_HEADERS += src/num.h +noinst_HEADERS += src/num_impl.h +noinst_HEADERS += src/field_10x26.h +noinst_HEADERS += src/field_10x26_impl.h +noinst_HEADERS += src/field_5x52.h +noinst_HEADERS += src/field_5x52_impl.h +noinst_HEADERS += src/field_5x52_int128_impl.h +noinst_HEADERS += src/field_5x52_asm_impl.h +noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h +noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h +noinst_HEADERS += src/util.h +noinst_HEADERS += src/scratch.h +noinst_HEADERS += src/scratch_impl.h +noinst_HEADERS += src/testrand.h +noinst_HEADERS += src/testrand_impl.h +noinst_HEADERS += src/hash.h +noinst_HEADERS += src/hash_impl.h +noinst_HEADERS += src/field.h +noinst_HEADERS += src/field_impl.h +noinst_HEADERS += src/bench.h +noinst_HEADERS += contrib/lax_der_parsing.h +noinst_HEADERS += contrib/lax_der_parsing.c +noinst_HEADERS += contrib/lax_der_privatekey_parsing.h +noinst_HEADERS += contrib/lax_der_privatekey_parsing.c + +if USE_EXTERNAL_ASM +COMMON_LIB = libsecp256k1_zkp_common.la +noinst_LTLIBRARIES = $(COMMON_LIB) +else +COMMON_LIB = +endif + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libsecp256k1.pc + +if USE_EXTERNAL_ASM +if USE_ASM_ARM +libsecp256k1_zkp_common_la_SOURCES = src/asm/field_10x26_arm.s +endif +endif + +libsecp256k1_zkp_la_SOURCES = src/secp256k1.c +libsecp256k1_zkp_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) +libsecp256k1_zkp_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB) + +libsecp256k1_zkp_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c +libsecp256k1_zkp_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES) + +noinst_PROGRAMS = +if USE_BENCHMARK +noinst_PROGRAMS += bench_verify bench_sign bench_internal bench_ecmult +bench_verify_SOURCES = src/bench_verify.c +bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) +bench_sign_SOURCES = src/bench_sign.c +bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) +bench_internal_SOURCES = src/bench_internal.c +bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) +bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES) +bench_ecmult_SOURCES = src/bench_ecmult.c +bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB) +bench_ecmult_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES) +endif + +TESTS = +if USE_TESTS +noinst_PROGRAMS += tests +tests_SOURCES = src/tests.c +tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) +if !ENABLE_COVERAGE +tests_CPPFLAGS += -DVERIFY +endif +tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) +tests_LDFLAGS = -static +TESTS += tests +endif + +if USE_EXHAUSTIVE_TESTS +noinst_PROGRAMS += exhaustive_tests +exhaustive_tests_SOURCES = src/tests_exhaustive.c +exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES) +if !ENABLE_COVERAGE +exhaustive_tests_CPPFLAGS += -DVERIFY +endif +exhaustive_tests_LDADD = $(SECP_LIBS) +exhaustive_tests_LDFLAGS = -static +TESTS += exhaustive_tests +endif + +JAVAROOT=src/java +JAVAORG=org/bitcoin +JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar +CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA) +JAVA_FILES= \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \ + $(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java + +if USE_JNI + +$(JAVA_GUAVA): + @echo Guava is missing. Fetch it via: \ + wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@) + @false + +.stamp-java: $(JAVA_FILES) + @echo Compiling $^ + $(AM_V_at)$(CLASSPATH_ENV) javac $^ + @touch $@ + +if USE_TESTS + +check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java + $(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test + +endif +endif + +if USE_ECMULT_STATIC_PRECOMPUTATION +CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) +CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function + +gen_context_OBJECTS = gen_context.o +gen_context_BIN = gen_context$(BUILD_EXEEXT) +gen_%.o: src/gen_%.c + $(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@ + +$(gen_context_BIN): $(gen_context_OBJECTS) + $(CC_FOR_BUILD) $^ -o $@ + +$(libsecp256k1_zkp_la_OBJECTS): src/ecmult_static_context.h +$(tests_OBJECTS): src/ecmult_static_context.h +$(bench_internal_OBJECTS): src/ecmult_static_context.h +$(bench_ecmult_OBJECTS): src/ecmult_static_context.h + +src/ecmult_static_context.h: $(gen_context_BIN) + ./$(gen_context_BIN) + +CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java +endif + +EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES) + +if ENABLE_MODULE_ECDH +include src/modules/ecdh/Makefile.am.include +endif + +if ENABLE_MODULE_SCHNORRSIG +include src/modules/schnorrsig/Makefile.am.include +endif + +if ENABLE_MODULE_MUSIG +include src/modules/musig/Makefile.am.include +endif + +if ENABLE_MODULE_RECOVERY +include src/modules/recovery/Makefile.am.include +endif + +if ENABLE_MODULE_GENERATOR +include src/modules/generator/Makefile.am.include +endif + +if ENABLE_MODULE_RANGEPROOF +include src/modules/rangeproof/Makefile.am.include +endif + +if ENABLE_MODULE_WHITELIST +include src/modules/whitelist/Makefile.am.include +endif + +if ENABLE_MODULE_SURJECTIONPROOF +include src/modules/surjection/Makefile.am.include +endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/README.md b/secp256k1-zkp-sys/depend/secp256k1-zkp/README.md new file mode 100644 index 00000000..8cd344ea --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/README.md @@ -0,0 +1,61 @@ +libsecp256k1 +============ + +[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1) + +Optimized C library for EC operations on curve secp256k1. + +This library is a work in progress and is being used to research best practices. Use at your own risk. + +Features: +* secp256k1 ECDSA signing/verification and key generation. +* Adding/multiplying private/public keys. +* Serialization/parsing of private keys, public keys, signatures. +* Constant time, constant memory access signing and pubkey generation. +* Derandomized DSA (via RFC6979 or with a caller provided function.) +* Very efficient implementation. + +Implementation details +---------------------- + +* General + * No runtime heap allocation. + * Extensive testing infrastructure. + * Structured to facilitate review and analysis. + * Intended to be portable to any system with a C89 compiler and uint64_t support. + * Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.") +* Field operations + * Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1). + * Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys). + * Using 10 26-bit limbs. + * Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman). +* Scalar operations + * Optimized implementation without data-dependent branches of arithmetic modulo the curve's order. + * Using 4 64-bit limbs (relying on __int128 support in the compiler). + * Using 8 32-bit limbs. +* Group operations + * Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7). + * Use addition between points in Jacobian and affine coordinates where possible. + * Use a unified addition/doubling formula where necessary to avoid data-dependent branches. + * Point/x comparison without a field inversion by comparison in the Jacobian coordinate space. +* Point multiplication for verification (a*P + b*G). + * Use wNAF notation for point multiplicands. + * Use a much larger window for multiples of G, using precomputed multiples. + * Use Shamir's trick to do the multiplication with the public key and the generator simultaneously. + * Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. +* Point multiplication for signing + * Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions. + * Access the table with branch-free conditional moves so memory access is uniform. + * No data-dependent branches + * The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally. + +Build steps +----------- + +libsecp256k1 is built using autotools: + + $ ./autogen.sh + $ ./configure + $ make + $ ./tests + $ sudo make install # optional diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/TODO b/secp256k1-zkp-sys/depend/secp256k1-zkp/TODO new file mode 100644 index 00000000..a300e1c5 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/TODO @@ -0,0 +1,3 @@ +* Unit tests for fieldelem/groupelem, including ones intended to + trigger fieldelem's boundary cases. +* Complete constant-time operations for signing/keygen diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/autogen.sh b/secp256k1-zkp-sys/depend/secp256k1-zkp/autogen.sh new file mode 100755 index 00000000..65286b93 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/autogen.sh @@ -0,0 +1,3 @@ +#!/bin/sh +set -e +autoreconf -if --warnings=all diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/build-aux/m4/ax_jni_include_dir.m4 b/secp256k1-zkp-sys/depend/secp256k1-zkp/build-aux/m4/ax_jni_include_dir.m4 new file mode 100644 index 00000000..cdc78d87 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/build-aux/m4/ax_jni_include_dir.m4 @@ -0,0 +1,145 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_JNI_INCLUDE_DIR +# +# DESCRIPTION +# +# AX_JNI_INCLUDE_DIR finds include directories needed for compiling +# programs using the JNI interface. +# +# JNI include directories are usually in the Java distribution. This is +# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in +# that order. When this macro completes, a list of directories is left in +# the variable JNI_INCLUDE_DIRS. +# +# Example usage follows: +# +# AX_JNI_INCLUDE_DIR +# +# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS +# do +# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR" +# done +# +# If you want to force a specific compiler: +# +# - at the configure.in level, set JAVAC=yourcompiler before calling +# AX_JNI_INCLUDE_DIR +# +# - at the configure level, setenv JAVAC +# +# Note: This macro can work with the autoconf M4 macros for Java programs. +# This particular macro is not part of the original set of macros. +# +# LICENSE +# +# Copyright (c) 2008 Don Anderson +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 14 + +AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR]) +AC_DEFUN([AX_JNI_INCLUDE_DIR],[ + +JNI_INCLUDE_DIRS="" + +if test "x$JAVA_HOME" != x; then + _JTOPDIR="$JAVA_HOME" +else + if test "x$JAVAC" = x; then + JAVAC=javac + fi + AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no]) + if test "x$_ACJNI_JAVAC" = xno; then + AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME]) + fi + _ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC") + _JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'` +fi + +case "$host_os" in + darwin*) # Apple Java headers are inside the Xcode bundle. + macos_version=$(sw_vers -productVersion | sed -n -e 's/^@<:@0-9@:>@*.\(@<:@0-9@:>@*\).@<:@0-9@:>@*/\1/p') + if @<:@ "$macos_version" -gt "7" @:>@; then + _JTOPDIR="$(xcrun --show-sdk-path)/System/Library/Frameworks/JavaVM.framework" + _JINC="$_JTOPDIR/Headers" + else + _JTOPDIR="/System/Library/Frameworks/JavaVM.framework" + _JINC="$_JTOPDIR/Headers" + fi + ;; + *) _JINC="$_JTOPDIR/include";; +esac +_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR]) +_AS_ECHO_LOG([_JINC=$_JINC]) + +# On Mac OS X 10.6.4, jni.h is a symlink: +# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h +# -> ../../CurrentJDK/Headers/jni.h. +AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path, +[ + if test -f "$_JINC/jni.h"; then + ac_cv_jni_header_path="$_JINC" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" + else + _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + if test -f "$_JTOPDIR/include/jni.h"; then + ac_cv_jni_header_path="$_JTOPDIR/include" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" + else + ac_cv_jni_header_path=none + fi + fi +]) + +# get the likely subdirectories for system specific java includes +case "$host_os" in +bsdi*) _JNI_INC_SUBDIRS="bsdos";; +freebsd*) _JNI_INC_SUBDIRS="freebsd";; +darwin*) _JNI_INC_SUBDIRS="darwin";; +linux*) _JNI_INC_SUBDIRS="linux genunix";; +osf*) _JNI_INC_SUBDIRS="alpha";; +solaris*) _JNI_INC_SUBDIRS="solaris";; +mingw*) _JNI_INC_SUBDIRS="win32";; +cygwin*) _JNI_INC_SUBDIRS="win32";; +*) _JNI_INC_SUBDIRS="genunix";; +esac + +if test "x$ac_cv_jni_header_path" != "xnone"; then + # add any subdirectories that are present + for JINCSUBDIR in $_JNI_INC_SUBDIRS + do + if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR" + fi + done +fi +]) + +# _ACJNI_FOLLOW_SYMLINKS +# Follows symbolic links on , +# finally setting variable _ACJNI_FOLLOWED +# ---------------------------------------- +AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[ +# find the include directory relative to the javac executable +_cur="$1" +while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do + AC_MSG_CHECKING([symlink for $_cur]) + _slink=`ls -ld "$_cur" | sed 's/.* -> //'` + case "$_slink" in + /*) _cur="$_slink";; + # 'X' avoids triggering unwanted echo options. + *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";; + esac + AC_MSG_RESULT([$_cur]) +done +_ACJNI_FOLLOWED="$_cur" +])# _ACJNI diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/build-aux/m4/ax_prog_cc_for_build.m4 b/secp256k1-zkp-sys/depend/secp256k1-zkp/build-aux/m4/ax_prog_cc_for_build.m4 new file mode 100644 index 00000000..77fd346a --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/build-aux/m4/ax_prog_cc_for_build.m4 @@ -0,0 +1,125 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_CC_FOR_BUILD +# +# DESCRIPTION +# +# This macro searches for a C compiler that generates native executables, +# that is a C compiler that surely is not a cross-compiler. This can be +# useful if you have to generate source code at compile-time like for +# example GCC does. +# +# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything +# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD). +# The value of these variables can be overridden by the user by specifying +# a compiler with an environment variable (like you do for standard CC). +# +# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object +# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if +# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are +# substituted in the Makefile. +# +# LICENSE +# +# Copyright (c) 2008 Paolo Bonzini +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD]) +AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_CPP])dnl +AC_REQUIRE([AC_EXEEXT])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl + +dnl Use the standard macros, but make them use other variable names +dnl +pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl +pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl +pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl +pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl +pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl +pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl +pushdef([ac_cv_objext], ac_cv_build_objext)dnl +pushdef([ac_exeext], ac_build_exeext)dnl +pushdef([ac_objext], ac_build_objext)dnl +pushdef([CC], CC_FOR_BUILD)dnl +pushdef([CPP], CPP_FOR_BUILD)dnl +pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl +pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl +pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl +pushdef([host], build)dnl +pushdef([host_alias], build_alias)dnl +pushdef([host_cpu], build_cpu)dnl +pushdef([host_vendor], build_vendor)dnl +pushdef([host_os], build_os)dnl +pushdef([ac_cv_host], ac_cv_build)dnl +pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl +pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl +pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl +pushdef([ac_cv_host_os], ac_cv_build_os)dnl +pushdef([ac_cpp], ac_build_cpp)dnl +pushdef([ac_compile], ac_build_compile)dnl +pushdef([ac_link], ac_build_link)dnl + +save_cross_compiling=$cross_compiling +save_ac_tool_prefix=$ac_tool_prefix +cross_compiling=no +ac_tool_prefix= + +AC_PROG_CC +AC_PROG_CPP +AC_EXEEXT + +ac_tool_prefix=$save_ac_tool_prefix +cross_compiling=$save_cross_compiling + +dnl Restore the old definitions +dnl +popdef([ac_link])dnl +popdef([ac_compile])dnl +popdef([ac_cpp])dnl +popdef([ac_cv_host_os])dnl +popdef([ac_cv_host_vendor])dnl +popdef([ac_cv_host_cpu])dnl +popdef([ac_cv_host_alias])dnl +popdef([ac_cv_host])dnl +popdef([host_os])dnl +popdef([host_vendor])dnl +popdef([host_cpu])dnl +popdef([host_alias])dnl +popdef([host])dnl +popdef([LDFLAGS])dnl +popdef([CPPFLAGS])dnl +popdef([CFLAGS])dnl +popdef([CPP])dnl +popdef([CC])dnl +popdef([ac_objext])dnl +popdef([ac_exeext])dnl +popdef([ac_cv_objext])dnl +popdef([ac_cv_exeext])dnl +popdef([ac_cv_prog_cc_g])dnl +popdef([ac_cv_prog_cc_cross])dnl +popdef([ac_cv_prog_cc_works])dnl +popdef([ac_cv_prog_gcc])dnl +popdef([ac_cv_prog_CPP])dnl + +dnl Finally, set Makefile variables +dnl +BUILD_EXEEXT=$ac_build_exeext +BUILD_OBJEXT=$ac_build_objext +AC_SUBST(BUILD_EXEEXT)dnl +AC_SUBST(BUILD_OBJEXT)dnl +AC_SUBST([CFLAGS_FOR_BUILD])dnl +AC_SUBST([CPPFLAGS_FOR_BUILD])dnl +AC_SUBST([LDFLAGS_FOR_BUILD])dnl +]) diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/build-aux/m4/bitcoin_secp.m4 b/secp256k1-zkp-sys/depend/secp256k1-zkp/build-aux/m4/bitcoin_secp.m4 new file mode 100644 index 00000000..3b3975cb --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/build-aux/m4/bitcoin_secp.m4 @@ -0,0 +1,68 @@ +dnl libsecp25k1 helper checks +AC_DEFUN([SECP_INT128_CHECK],[ +has_int128=$ac_cv_type___int128 +]) + +dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell. +AC_DEFUN([SECP_64BIT_ASM_CHECK],[ +AC_MSG_CHECKING(for x86_64 assembly availability) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include ]],[[ + uint64_t a = 11, tmp; + __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); + ]])],[has_64bit_asm=yes],[has_64bit_asm=no]) +AC_MSG_RESULT([$has_64bit_asm]) +]) + +dnl +AC_DEFUN([SECP_OPENSSL_CHECK],[ + has_libcrypto=no + m4_ifdef([PKG_CHECK_MODULES],[ + PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no]) + if test x"$has_libcrypto" = x"yes"; then + TEMP_LIBS="$LIBS" + LIBS="$LIBS $CRYPTO_LIBS" + AC_CHECK_LIB(crypto, main,[AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])],[has_libcrypto=no]) + LIBS="$TEMP_LIBS" + fi + ]) + if test x$has_libcrypto = xno; then + AC_CHECK_HEADER(openssl/crypto.h,[ + AC_CHECK_LIB(crypto, main,[ + has_libcrypto=yes + CRYPTO_LIBS=-lcrypto + AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed]) + ]) + ]) + LIBS= + fi +if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then + AC_MSG_CHECKING(for EC functions in libcrypto) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + #include ]],[[ + EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1); + ECDSA_sign(0, NULL, 0, NULL, NULL, eckey); + ECDSA_verify(0, NULL, 0, NULL, 0, eckey); + EC_KEY_free(eckey); + ECDSA_SIG *sig_openssl; + sig_openssl = ECDSA_SIG_new(); + ECDSA_SIG_free(sig_openssl); + ]])],[has_openssl_ec=yes],[has_openssl_ec=no]) + AC_MSG_RESULT([$has_openssl_ec]) +fi +]) + +dnl +AC_DEFUN([SECP_GMP_CHECK],[ +if test x"$has_gmp" != x"yes"; then + CPPFLAGS_TEMP="$CPPFLAGS" + CPPFLAGS="$GMP_CPPFLAGS $CPPFLAGS" + LIBS_TEMP="$LIBS" + LIBS="$GMP_LIBS $LIBS" + AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS="$GMP_LIBS -lgmp"; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])]) + CPPFLAGS="$CPPFLAGS_TEMP" + LIBS="$LIBS_TEMP" +fi +]) diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/configure.ac b/secp256k1-zkp-sys/depend/secp256k1-zkp/configure.ac new file mode 100644 index 00000000..edfa02da --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/configure.ac @@ -0,0 +1,668 @@ +AC_PREREQ([2.60]) +AC_INIT([libsecp256k1],[0.1]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([build-aux/m4]) +AC_CANONICAL_HOST +AH_TOP([#ifndef LIBSECP256K1_CONFIG_H]) +AH_TOP([#define LIBSECP256K1_CONFIG_H]) +AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/]) +AM_INIT_AUTOMAKE([foreign subdir-objects]) +LT_INIT + +dnl make the compilation flags quiet unless V=1 is used +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +PKG_PROG_PKG_CONFIG + +AC_PATH_TOOL(AR, ar) +AC_PATH_TOOL(RANLIB, ranlib) +AC_PATH_TOOL(STRIP, strip) +AX_PROG_CC_FOR_BUILD + +if test "x$CFLAGS" = "x"; then + CFLAGS="-g" +fi + +AM_PROG_CC_C_O + +AC_PROG_CC_C89 +if test x"$ac_cv_prog_cc_c89" = x"no"; then + AC_MSG_ERROR([c89 compiler support required]) +fi +AM_PROG_AS + +case $host_os in + *darwin*) + if test x$cross_compiling != xyes; then + AC_PATH_PROG([BREW],brew,) + if test x$BREW != x; then + dnl These Homebrew packages may be keg-only, meaning that they won't be found + dnl in expected paths because they may conflict with system files. Ask + dnl Homebrew where each one is located, then adjust paths accordingly. + + openssl_prefix=`$BREW --prefix openssl 2>/dev/null` + gmp_prefix=`$BREW --prefix gmp 2>/dev/null` + if test x$openssl_prefix != x; then + PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH" + export PKG_CONFIG_PATH + fi + if test x$gmp_prefix != x; then + GMP_CPPFLAGS="-I$gmp_prefix/include" + GMP_LIBS="-L$gmp_prefix/lib" + fi + else + AC_PATH_PROG([PORT],port,) + dnl if homebrew isn't installed and macports is, add the macports default paths + dnl as a last resort. + if test x$PORT != x; then + CPPFLAGS="$CPPFLAGS -isystem /opt/local/include" + LDFLAGS="$LDFLAGS -L/opt/local/lib" + fi + fi + fi + ;; +esac + +CFLAGS="$CFLAGS -W" + +warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings" +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $warn_CFLAGS" +AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) + +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fvisibility=hidden" +AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) + +AC_ARG_ENABLE(benchmark, + AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]), + [use_benchmark=$enableval], + [use_benchmark=yes]) + +AC_ARG_ENABLE(coverage, + AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), + [enable_coverage=$enableval], + [enable_coverage=no]) + +AC_ARG_ENABLE(tests, + AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), + [use_tests=$enableval], + [use_tests=yes]) + +AC_ARG_ENABLE(openssl_tests, + AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests [default=auto]]), + [enable_openssl_tests=$enableval], + [enable_openssl_tests=auto]) + +AC_ARG_ENABLE(experimental, + AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), + [use_experimental=$enableval], + [use_experimental=no]) + +AC_ARG_ENABLE(exhaustive_tests, + AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]), + [use_exhaustive_tests=$enableval], + [use_exhaustive_tests=yes]) + +AC_ARG_ENABLE(endomorphism, + AS_HELP_STRING([--enable-endomorphism],[enable endomorphism [default=no]]), + [use_endomorphism=$enableval], + [use_endomorphism=no]) + +AC_ARG_ENABLE(ecmult_static_precomputation, + AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing [default=auto]]), + [use_ecmult_static_precomputation=$enableval], + [use_ecmult_static_precomputation=auto]) + +AC_ARG_ENABLE(module_ecdh, + AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]), + [enable_module_ecdh=$enableval], + [enable_module_ecdh=no]) + +AC_ARG_ENABLE(module_schnorrsig, + AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module (experimental)]), + [enable_module_schnorrsig=$enableval], + [enable_module_schnorrsig=no]) + +AC_ARG_ENABLE(module_musig, + AS_HELP_STRING([--enable-module-musig],[enable MuSig module (experimental)]), + [enable_module_musig=$enableval], + [enable_module_musig=no]) + +AC_ARG_ENABLE(module_recovery, + AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), + [enable_module_recovery=$enableval], + [enable_module_recovery=no]) + +AC_ARG_ENABLE(module_generator, + AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module [default=no]]), + [enable_module_generator=$enableval], + [enable_module_generator=no]) + +AC_ARG_ENABLE(module_rangeproof, + AS_HELP_STRING([--enable-module-rangeproof],[enable Pedersen / zero-knowledge range proofs module [default=no]]), + [enable_module_rangeproof=$enableval], + [enable_module_rangeproof=no]) + +AC_ARG_ENABLE(module_whitelist, + AS_HELP_STRING([--enable-module-whitelist],[enable key whitelisting module [default=no]]), + [enable_module_whitelist=$enableval], + [enable_module_whitelist=no]) + +AC_ARG_ENABLE(external_default_callbacks, + AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), + [use_external_default_callbacks=$enableval], + [use_external_default_callbacks=no]) + +AC_ARG_ENABLE(jni, + AS_HELP_STRING([--enable-jni],[enable libsecp256k1_zkp_jni [default=no]]), + [use_jni=$enableval], + [use_jni=no]) + +AC_ARG_ENABLE(module_surjectionproof, + AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module [default=no]]), + [enable_module_surjectionproof=$enableval], + [enable_module_surjectionproof=no]) + +AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], +[finite field implementation to use [default=auto]])],[req_field=$withval], [req_field=auto]) + +AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto], +[bignum implementation to use [default=auto]])],[req_bignum=$withval], [req_bignum=auto]) + +AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], +[scalar implementation to use [default=auto]])],[req_scalar=$withval], [req_scalar=auto]) + +AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto], +[assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto]) + +# Default is window size 16 (or window size 15 with endomorphism) which needs 1.375 MiB. */ +AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto], +[window size for ecmult precomputation for verification, specified as integer in range [3..24].] +[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.] +[The table will store 2^(SIZE-2) * 64 bytes of data but can be larger in memory due] +[to platform-specific padding and alignment. "auto" is a reasonable setting for desktop machines] +[(currently 15 if the endomorphism optimization is disabled and 16 if it is enabled). [default=auto]] +)], +[req_ecmult_window=$withval], [req_ecmult_window=auto]) + +AC_CHECK_TYPES([__int128]) + +AC_MSG_CHECKING([for __builtin_expect]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])], + [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ], + [ AC_MSG_RESULT([no]) + ]) + +if test x"$enable_coverage" = x"yes"; then + AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code]) + CFLAGS="$CFLAGS -O0 --coverage" + LDFLAGS="--coverage" +else + CFLAGS="$CFLAGS -O3" +fi + +AC_MSG_CHECKING([for __builtin_popcount]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_popcount(0);}]])], + [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_POPCOUNT,1,[Define this symbol if __builtin_popcount is available]) ], + [ AC_MSG_RESULT([no]) + ]) + +if test x"$use_ecmult_static_precomputation" != x"no"; then + save_cross_compiling=$cross_compiling + cross_compiling=no + TEMP_CC="$CC" + CC="$CC_FOR_BUILD" + AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([], [return 0])], + [working_native_cc=yes], + [working_native_cc=no],[dnl]) + CC="$TEMP_CC" + cross_compiling=$save_cross_compiling + + if test x"$working_native_cc" = x"no"; then + set_precomp=no + if test x"$use_ecmult_static_precomputation" = x"yes"; then + AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) + else + AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) + fi + else + AC_MSG_RESULT([ok]) + set_precomp=yes + fi +else + set_precomp=no +fi + +AC_MSG_CHECKING([for __builtin_clzll]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() { __builtin_clzll(1);}]])], + [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_CLZLL,1,[Define this symbol if __builtin_clzll is available]) ], + [ AC_MSG_RESULT([no]) + ]) + +if test x"$req_asm" = x"auto"; then + SECP_64BIT_ASM_CHECK + if test x"$has_64bit_asm" = x"yes"; then + set_asm=x86_64 + fi + if test x"$set_asm" = x; then + set_asm=no + fi +else + set_asm=$req_asm + case $set_asm in + x86_64) + SECP_64BIT_ASM_CHECK + if test x"$has_64bit_asm" != x"yes"; then + AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) + fi + ;; + arm) + ;; + no) + ;; + *) + AC_MSG_ERROR([invalid assembly optimization selection]) + ;; + esac +fi + +if test x"$req_field" = x"auto"; then + if test x"set_asm" = x"x86_64"; then + set_field=64bit + fi + if test x"$set_field" = x; then + SECP_INT128_CHECK + if test x"$has_int128" = x"yes"; then + set_field=64bit + fi + fi + if test x"$set_field" = x; then + set_field=32bit + fi +else + set_field=$req_field + case $set_field in + 64bit) + if test x"$set_asm" != x"x86_64"; then + SECP_INT128_CHECK + if test x"$has_int128" != x"yes"; then + AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available]) + fi + fi + ;; + 32bit) + ;; + *) + AC_MSG_ERROR([invalid field implementation selection]) + ;; + esac +fi + +if test x"$req_scalar" = x"auto"; then + SECP_INT128_CHECK + if test x"$has_int128" = x"yes"; then + set_scalar=64bit + fi + if test x"$set_scalar" = x; then + set_scalar=32bit + fi +else + set_scalar=$req_scalar + case $set_scalar in + 64bit) + SECP_INT128_CHECK + if test x"$has_int128" != x"yes"; then + AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available]) + fi + ;; + 32bit) + ;; + *) + AC_MSG_ERROR([invalid scalar implementation selected]) + ;; + esac +fi + +if test x"$req_bignum" = x"auto"; then + SECP_GMP_CHECK + if test x"$has_gmp" = x"yes"; then + set_bignum=gmp + fi + + if test x"$set_bignum" = x; then + set_bignum=no + fi +else + set_bignum=$req_bignum + case $set_bignum in + gmp) + SECP_GMP_CHECK + if test x"$has_gmp" != x"yes"; then + AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available]) + fi + ;; + no) + ;; + *) + AC_MSG_ERROR([invalid bignum implementation selection]) + ;; + esac +fi + +# select assembly optimization +use_external_asm=no + +case $set_asm in +x86_64) + AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations]) + ;; +arm) + use_external_asm=yes + ;; +no) + ;; +*) + AC_MSG_ERROR([invalid assembly optimizations]) + ;; +esac + +# select field implementation +case $set_field in +64bit) + AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation]) + ;; +32bit) + AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation]) + ;; +*) + AC_MSG_ERROR([invalid field implementation]) + ;; +esac + +# select bignum implementation +case $set_bignum in +gmp) + AC_DEFINE(HAVE_LIBGMP, 1, [Define this symbol if libgmp is installed]) + AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation for num]) + AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation]) + AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation]) + ;; +no) + AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation]) + AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation]) + AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation]) + ;; +*) + AC_MSG_ERROR([invalid bignum implementation]) + ;; +esac + +#select scalar implementation +case $set_scalar in +64bit) + AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation]) + ;; +32bit) + AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation]) + ;; +*) + AC_MSG_ERROR([invalid scalar implementation]) + ;; +esac + +#set ecmult window size +if test x"$req_ecmult_window" = x"auto"; then + if test x"$use_endomorphism" = x"yes"; then + set_ecmult_window=16 + else + set_ecmult_window=15 + fi +else + set_ecmult_window=$req_ecmult_window +fi + +error_window_size=['window size for ecmult precomputation not an integer in range [3..24] or "auto"'] +case $set_ecmult_window in +''|*[[!0-9]]*) + # no valid integer + AC_MSG_ERROR($error_window_size) + ;; +*) + if test "$set_ecmult_window" -lt 3 -o "$set_ecmult_window" -gt 24 ; then + # not in range + AC_MSG_ERROR($error_window_size) + fi + AC_DEFINE_UNQUOTED(ECMULT_WINDOW_SIZE, $set_ecmult_window, [Set window size for ecmult precomputation]) + ;; +esac + +if test x"$use_tests" = x"yes"; then + SECP_OPENSSL_CHECK + if test x"$has_openssl_ec" = x"yes"; then + if test x"$enable_openssl_tests" != x"no"; then + AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) + SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS" + SECP_TEST_LIBS="$CRYPTO_LIBS" + + case $host in + *mingw*) + SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32" + ;; + esac + fi + else + if test x"$enable_openssl_tests" = x"yes"; then + AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available]) + fi + fi +else + if test x"$enable_openssl_tests" = x"yes"; then + AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled]) + fi +fi + +if test x"$use_jni" != x"no"; then + AX_JNI_INCLUDE_DIR + have_jni_dependencies=yes + if test x"$enable_module_ecdh" = x"no"; then + have_jni_dependencies=no + fi + if test "x$JNI_INCLUDE_DIRS" = "x"; then + have_jni_dependencies=no + fi + if test "x$have_jni_dependencies" = "xno"; then + if test x"$use_jni" = x"yes"; then + AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.]) + fi + AC_MSG_WARN([jni headers/dependencies not found. jni support disabled]) + use_jni=no + else + use_jni=yes + for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do + JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR" + done + fi +fi + +if test x"$set_bignum" = x"gmp"; then + SECP_LIBS="$SECP_LIBS $GMP_LIBS" + SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS" +fi + +if test x"$use_endomorphism" = x"yes"; then + AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) +fi + +if test x"$set_precomp" = x"yes"; then + AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table]) +fi + +if test x"$enable_module_ecdh" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module]) +fi + +if test x"$enable_module_schnorrsig" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module]) +fi + +if test x"$enable_module_musig" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_MUSIG, 1, [Define this symbol to enable the MuSig module]) +fi + +if test x"$enable_module_recovery" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) +fi + +if test x"$enable_module_generator" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_GENERATOR, 1, [Define this symbol to enable the NUMS generator module]) +fi + +if test x"$enable_module_rangeproof" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_RANGEPROOF, 1, [Define this symbol to enable the Pedersen / zero knowledge range proof module]) +fi + +if test x"$enable_module_whitelist" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_WHITELIST, 1, [Define this symbol to enable the key whitelisting module]) +fi + +if test x"$enable_module_surjectionproof" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_SURJECTIONPROOF, 1, [Define this symbol to enable the surjection proof module]) +fi + +AC_C_BIGENDIAN() + +if test x"$use_external_asm" = x"yes"; then + AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used]) +fi + +if test x"$use_external_default_callbacks" = x"yes"; then + AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used]) +fi + +if test x"$enable_experimental" = x"yes"; then + AC_MSG_NOTICE([******]) + AC_MSG_NOTICE([WARNING: experimental build]) + AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) + AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) + AC_MSG_NOTICE([Building NUMS generator module: $enable_module_generator]) + AC_MSG_NOTICE([Building range proof module: $enable_module_rangeproof]) + AC_MSG_NOTICE([Building key whitelisting module: $enable_module_whitelist]) + AC_MSG_NOTICE([Building surjection proof module: $enable_module_surjectionproof]) + AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig]) + AC_MSG_NOTICE([Building MuSig module: $enable_module_musig]) + AC_MSG_NOTICE([******]) + + + if test x"$enable_module_schnorrsig" != x"yes"; then + if test x"$enable_module_musig" = x"yes"; then + AC_MSG_ERROR([MuSig module requires the schnorrsig module. Use --enable-module-schnorrsig to allow.]) + fi + fi + + if test x"$enable_module_generator" != x"yes"; then + if test x"$enable_module_rangeproof" = x"yes"; then + AC_MSG_ERROR([Rangeproof module requires the generator module. Use --enable-module-generator to allow.]) + fi + fi + + if test x"$enable_module_rangeproof" != x"yes"; then + if test x"$enable_module_whitelist" = x"yes"; then + AC_MSG_ERROR([Whitelist module requires the rangeproof module. Use --enable-module-rangeproof to allow.]) + fi + if test x"$enable_module_surjectionproof" = x"yes"; then + AC_MSG_ERROR([Surjection proof module requires the rangeproof module. Use --enable-module-rangeproof to allow.]) + fi + fi +else + if test x"$enable_module_ecdh" = x"yes"; then + AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.]) + fi + if test x"$enable_module_schnorrsig" = x"yes"; then + AC_MSG_ERROR([schnorrsig module is experimental. Use --enable-experimental to allow.]) + fi + if test x"$enable_module_musig" = x"yes"; then + AC_MSG_ERROR([MuSig module is experimental. Use --enable-experimental to allow.]) + fi + if test x"$set_asm" = x"arm"; then + AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.]) + fi + if test x"$enable_module_generator" = x"yes"; then + AC_MSG_ERROR([NUMS generator module is experimental. Use --enable-experimental to allow.]) + fi + if test x"$enable_module_rangeproof" = x"yes"; then + AC_MSG_ERROR([Range proof module is experimental. Use --enable-experimental to allow.]) + fi + if test x"$enable_module_whitelist" = x"yes"; then + AC_MSG_ERROR([Key whitelisting module is experimental. Use --enable-experimental to allow.]) + fi + if test x"$enable_module_surjectionproof" = x"yes"; then + AC_MSG_ERROR([Surjection proof module is experimental. Use --enable-experimental to allow.]) + fi +fi + +AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) +AC_CONFIG_FILES([Makefile libsecp256k1.pc]) +AC_SUBST(JNI_INCLUDES) +AC_SUBST(SECP_INCLUDES) +AC_SUBST(SECP_LIBS) +AC_SUBST(SECP_TEST_LIBS) +AC_SUBST(SECP_TEST_INCLUDES) +AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) +AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) +AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"]) +AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) +AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_GENERATOR], [test x"$enable_module_generator" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"yes"]) +AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"]) +AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"]) +AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"]) +AM_CONDITIONAL([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"]) + +dnl make sure nothing new is exported so that we don't break the cache +PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" +unset PKG_CONFIG_PATH +PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP" + +AC_OUTPUT + +echo +echo "Build Options:" +echo " with endomorphism = $use_endomorphism" +echo " with ecmult precomp = $set_precomp" +echo " with external callbacks = $use_external_default_callbacks" +echo " with jni = $use_jni" +echo " with benchmarks = $use_benchmark" +echo " with coverage = $enable_coverage" +echo " module ecdh = $enable_module_ecdh" +echo " module recovery = $enable_module_recovery" +echo +echo " asm = $set_asm" +echo " bignum = $set_bignum" +echo " field = $set_field" +echo " scalar = $set_scalar" +echo " ecmult window size = $set_ecmult_window" +echo +echo " CC = $CC" +echo " CFLAGS = $CFLAGS" +echo " CPPFLAGS = $CPPFLAGS" +echo " LDFLAGS = $LDFLAGS" +echo diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/contrib/lax_der_parsing.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/contrib/lax_der_parsing.c new file mode 100644 index 00000000..5217c186 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/contrib/lax_der_parsing.c @@ -0,0 +1,150 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "lax_der_parsing.h" + +int ecdsa_signature_parse_der_lax(const secp256k1_zkp_context* ctx, secp256k1_zkp_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + size_t rpos, rlen, spos, slen; + size_t pos = 0; + size_t lenbyte; + unsigned char tmpsig[64] = {0}; + int overflow = 0; + + /* Hack to initialize sig with a correctly-parsed but invalid signature. */ + secp256k1_zkp_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + + /* Sequence tag byte */ + if (pos == inputlen || input[pos] != 0x30) { + return 0; + } + pos++; + + /* Sequence length bytes */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + pos += lenbyte; + } + + /* Integer tag byte for R */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for R */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + rlen = 0; + while (lenbyte > 0) { + rlen = (rlen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + rlen = lenbyte; + } + if (rlen > inputlen - pos) { + return 0; + } + rpos = pos; + pos += rlen; + + /* Integer tag byte for S */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for S */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + slen = 0; + while (lenbyte > 0) { + slen = (slen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + slen = lenbyte; + } + if (slen > inputlen - pos) { + return 0; + } + spos = pos; + pos += slen; + + /* Ignore leading zeroes in R */ + while (rlen > 0 && input[rpos] == 0) { + rlen--; + rpos++; + } + /* Copy R value */ + if (rlen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 32 - rlen, input + rpos, rlen); + } + + /* Ignore leading zeroes in S */ + while (slen > 0 && input[spos] == 0) { + slen--; + spos++; + } + /* Copy S value */ + if (slen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 64 - slen, input + spos, slen); + } + + if (!overflow) { + overflow = !secp256k1_zkp_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + if (overflow) { + memset(tmpsig, 0, 64); + secp256k1_zkp_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + return 1; +} + diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/contrib/lax_der_parsing.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/contrib/lax_der_parsing.h new file mode 100644 index 00000000..5d606090 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/contrib/lax_der_parsing.h @@ -0,0 +1,91 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/**** + * Please do not link this file directly. It is not part of the libsecp256k1 + * project and does not promise any stability in its API, functionality or + * presence. Projects which use this code should instead copy this header + * and its accompanying .c file directly into their codebase. + ****/ + +/* This file defines a function that parses DER with various errors and + * violations. This is not a part of the library itself, because the allowed + * violations are chosen arbitrarily and do not follow or establish any + * standard. + * + * In many places it matters that different implementations do not only accept + * the same set of valid signatures, but also reject the same set of signatures. + * The only means to accomplish that is by strictly obeying a standard, and not + * accepting anything else. + * + * Nonetheless, sometimes there is a need for compatibility with systems that + * use signatures which do not strictly obey DER. The snippet below shows how + * certain violations are easily supported. You may need to adapt it. + * + * Do not use this for new systems. Use well-defined DER or compact signatures + * instead if you have the choice (see secp256k1_zkp_ecdsa_signature_parse_der and + * secp256k1_zkp_ecdsa_signature_parse_compact). + * + * The supported violations are: + * - All numbers are parsed as nonnegative integers, even though X.609-0207 + * section 8.3.3 specifies that integers are always encoded as two's + * complement. + * - Integers can have length 0, even though section 8.3.1 says they can't. + * - Integers with overly long padding are accepted, violation section + * 8.3.2. + * - 127-byte long length descriptors are accepted, even though section + * 8.1.3.5.c says that they are not. + * - Trailing garbage data inside or after the signature is ignored. + * - The length descriptor of the sequence is ignored. + * + * Compared to for example OpenSSL, many violations are NOT supported: + * - Using overly long tag descriptors for the sequence or integers inside, + * violating section 8.1.2.2. + * - Encoding primitive integers as constructed values, violating section + * 8.3.1. + */ + +#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H +#define SECP256K1_CONTRIB_LAX_DER_PARSING_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Parse a signature in "lax DER" format + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input: a pointer to the signature to be parsed + * inputlen: the length of the array pointed to be input + * + * This function will accept any valid DER encoded signature, even if the + * encoded numbers are out of range. In addition, it will accept signatures + * which violate the DER spec in various ways. Its purpose is to allow + * validation of the Bitcoin blockchain, which includes non-DER signatures + * from before the network rules were updated to enforce DER. Note that + * the set of supported violations is a strict subset of what OpenSSL will + * accept. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +int ecdsa_signature_parse_der_lax( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_ecdsa_signature* sig, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_CONTRIB_LAX_DER_PARSING_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/contrib/lax_der_privatekey_parsing.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/contrib/lax_der_privatekey_parsing.c new file mode 100644 index 00000000..d6322489 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/contrib/lax_der_privatekey_parsing.c @@ -0,0 +1,113 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "lax_der_privatekey_parsing.h" + +int ec_privkey_import_der(const secp256k1_zkp_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) { + const unsigned char *end = privkey + privkeylen; + int lenb = 0; + int len = 0; + memset(out32, 0, 32); + /* sequence header */ + if (end < privkey+1 || *privkey != 0x30) { + return 0; + } + privkey++; + /* sequence length constructor */ + if (end < privkey+1 || !(*privkey & 0x80)) { + return 0; + } + lenb = *privkey & ~0x80; privkey++; + if (lenb < 1 || lenb > 2) { + return 0; + } + if (end < privkey+lenb) { + return 0; + } + /* sequence length */ + len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); + privkey += lenb; + if (end < privkey+len) { + return 0; + } + /* sequence element 0: version number (=1) */ + if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { + return 0; + } + privkey += 3; + /* sequence element 1: octet string, up to 32 bytes */ + if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { + return 0; + } + memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); + if (!secp256k1_zkp_ec_seckey_verify(ctx, out32)) { + memset(out32, 0, 32); + return 0; + } + return 1; +} + +int ec_privkey_export_der(const secp256k1_zkp_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { + secp256k1_zkp_pubkey pubkey; + size_t pubkeylen = 0; + if (!secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, key32)) { + *privkeylen = 0; + return 0; + } + if (compressed) { + static const unsigned char begin[] = { + 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 33; + secp256k1_zkp_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } else { + static const unsigned char begin[] = { + 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, + 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, + 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 65; + secp256k1_zkp_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } + return 1; +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/contrib/lax_der_privatekey_parsing.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/contrib/lax_der_privatekey_parsing.h new file mode 100644 index 00000000..9759f754 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/contrib/lax_der_privatekey_parsing.h @@ -0,0 +1,90 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/**** + * Please do not link this file directly. It is not part of the libsecp256k1 + * project and does not promise any stability in its API, functionality or + * presence. Projects which use this code should instead copy this header + * and its accompanying .c file directly into their codebase. + ****/ + +/* This file contains code snippets that parse DER private keys with + * various errors and violations. This is not a part of the library + * itself, because the allowed violations are chosen arbitrarily and + * do not follow or establish any standard. + * + * It also contains code to serialize private keys in a compatible + * manner. + * + * These functions are meant for compatibility with applications + * that require BER encoded keys. When working with secp256k1-specific + * code, the simple 32-byte private keys normally used by the + * library are sufficient. + */ + +#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H +#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Export a private key in DER format. + * + * Returns: 1 if the private key was valid. + * Args: ctx: pointer to a context object, initialized for signing (cannot + * be NULL) + * Out: privkey: pointer to an array for storing the private key in BER. + * Should have space for 279 bytes, and cannot be NULL. + * privkeylen: Pointer to an int where the length of the private key in + * privkey will be stored. + * In: seckey: pointer to a 32-byte secret key to export. + * compressed: 1 if the key should be exported in + * compressed format, 0 otherwise + * + * This function is purely meant for compatibility with applications that + * require BER encoded keys. When working with secp256k1-specific code, the + * simple 32-byte private keys are sufficient. + * + * Note that this function does not guarantee correct DER output. It is + * guaranteed to be parsable by secp256k1_zkp_ec_privkey_import_der + */ +SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der( + const secp256k1_zkp_context* ctx, + unsigned char *privkey, + size_t *privkeylen, + const unsigned char *seckey, + int compressed +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Import a private key in DER format. + * Returns: 1 if a private key was extracted. + * Args: ctx: pointer to a context object (cannot be NULL). + * Out: seckey: pointer to a 32-byte array for storing the private key. + * (cannot be NULL). + * In: privkey: pointer to a private key in DER format (cannot be NULL). + * privkeylen: length of the DER private key pointed to be privkey. + * + * This function will accept more than just strict DER, and even allow some BER + * violations. The public key stored inside the DER-encoded private key is not + * verified for correctness, nor are the curve parameters. Use this function + * only if you know in advance it is supposed to contain a secp256k1 private + * key. + */ +SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der( + const secp256k1_zkp_context* ctx, + unsigned char *seckey, + const unsigned char *privkey, + size_t privkeylen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_CONTRIB_BER_PRIVATEKEY_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1.h new file mode 100644 index 00000000..71820094 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1.h @@ -0,0 +1,705 @@ +#ifndef SECP256K1_H +#define SECP256K1_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* These rules specify the order of arguments in API calls: + * + * 1. Context pointers go first, followed by output arguments, combined + * output/input arguments, and finally input-only arguments. + * 2. Array lengths always immediately the follow the argument whose length + * they describe, even if this violates rule 1. + * 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated + * later go first. This means: signatures, public nonces, private nonces, + * messages, public keys, secret keys, tweaks. + * 4. Arguments that are not data pointers go last, from more complex to less + * complex: function pointers, algorithm names, messages, void pointers, + * counts, flags, booleans. + * 5. Opaque data pointers follow the function pointer they are to be passed to. + */ + +/** Opaque data structure that holds context information (precomputed tables etc.). + * + * The purpose of context structures is to cache large precomputed data tables + * that are expensive to construct, and also to maintain the randomization data + * for blinding. + * + * Do not create a new context object for each operation, as construction is + * far slower than all other API calls (~100 times slower than an ECDSA + * verification). + * + * A constructed context can safely be used from multiple threads + * simultaneously, but API calls that take a non-const pointer to a context + * need exclusive access to it. In particular this is the case for + * secp256k1_zkp_context_destroy, secp256k1_zkp_context_preallocated_destroy, + * and secp256k1_zkp_context_randomize. + * + * Regarding randomization, either do it once at creation time (in which case + * you do not need any locking for the other calls), or use a read-write lock. + */ +typedef struct secp256k1_zkp_context_struct secp256k1_zkp_context; + +/** Opaque data structure that holds rewriteable "scratch space" + * + * The purpose of this structure is to replace dynamic memory allocations, + * because we target architectures where this may not be available. It is + * essentially a resizable (within specified parameters) block of bytes, + * which is initially created either by memory allocation or TODO as a pointer + * into some fixed rewritable space. + * + * Unlike the context object, this cannot safely be shared between threads + * without additional synchronization logic. + */ +typedef struct secp256k1_zkp_scratch_space_struct secp256k1_zkp_scratch_space; + +/** Opaque data structure that holds a parsed and valid public key. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use secp256k1_zkp_ec_pubkey_serialize and secp256k1_zkp_ec_pubkey_parse. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_zkp_pubkey; + +/** Opaque data structured that holds a parsed ECDSA signature. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use the secp256k1_zkp_ecdsa_signature_serialize_* and + * secp256k1_zkp_ecdsa_signature_parse_* functions. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_zkp_ecdsa_signature; + +/** A pointer to a function to deterministically generate a nonce. + * + * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. + * Out: nonce32: pointer to a 32-byte array to be filled by the function. + * In: msg32: the 32-byte message hash being verified (will not be NULL) + * key32: pointer to a 32-byte secret key (will not be NULL) + * algo16: pointer to a 16-byte array describing the signature + * algorithm (will be NULL for ECDSA for compatibility). + * data: Arbitrary data pointer that is passed through. + * attempt: how many iterations we have tried to find a nonce. + * This will almost always be 0, but different attempt values + * are required to result in a different nonce. + * + * Except for test cases, this function should compute some cryptographic hash of + * the message, the algorithm, the key and the attempt. + */ +typedef int (*secp256k1_zkp_nonce_function)( + unsigned char *nonce32, + const unsigned char *msg32, + const unsigned char *key32, + const unsigned char *algo16, + void *data, + unsigned int attempt +); + +# if !defined(SECP256K1_GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define SECP256K1_GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define SECP256K1_GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(2,7) +# define SECP256K1_INLINE __inline__ +# elif (defined(_MSC_VER)) +# define SECP256K1_INLINE __inline +# else +# define SECP256K1_INLINE +# endif +# else +# define SECP256K1_INLINE inline +# endif + +#ifndef SECP256K1_API +# if defined(_WIN32) +# ifdef SECP256K1_BUILD +# define SECP256K1_API __declspec(dllexport) +# else +# define SECP256K1_API +# endif +# elif defined(__GNUC__) && defined(SECP256K1_BUILD) +# define SECP256K1_API __attribute__ ((visibility ("default"))) +# else +# define SECP256K1_API +# endif +#endif + +/**Warning attributes + * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out + * some paranoid null checks. */ +# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) +# define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) +# else +# define SECP256K1_WARN_UNUSED_RESULT +# endif +# if !defined(SECP256K1_BUILD) && defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) +# define SECP256K1_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x))) +# else +# define SECP256K1_ARG_NONNULL(_x) +# endif + +/** All flags' lower 8 bits indicate what they're for. Do not use directly. */ +#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) +#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) +#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) +/** The higher bits contain the actual data. Do not use directly. */ +#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8) +#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) +#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) + +/** Flags to pass to secp256k1_zkp_context_create, secp256k1_zkp_context_preallocated_size, and + * secp256k1_zkp_context_preallocated_create. */ +#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) +#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) +#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) + +/** Flag to pass to secp256k1_zkp_ec_pubkey_serialize and secp256k1_zkp_ec_privkey_export. */ +#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) +#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) + +/** Prefix byte used to tag various encoded curvepoints for specific purposes */ +#define SECP256K1_TAG_PUBKEY_EVEN 0x02 +#define SECP256K1_TAG_PUBKEY_ODD 0x03 +#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04 +#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06 +#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07 + +/** A simple secp256k1 context object with no precomputed tables. These are useful for + * type serialization/parsing functions which require a context object to maintain + * API consistency, but currently do not require expensive precomputations or dynamic + * allocations. + */ +SECP256K1_API extern const secp256k1_zkp_context *secp256k1_zkp_context_no_precomp; + +/** Create a secp256k1 context object (in dynamically allocated memory). + * + * This function uses malloc to allocate memory. It is guaranteed that malloc is + * called at most once for every call of this function. If you need to avoid dynamic + * memory allocation entirely, see the functions in secp256k1_zkp_preallocated.h. + * + * Returns: a newly created context object. + * In: flags: which parts of the context to initialize. + * + * See also secp256k1_zkp_context_randomize. + */ +SECP256K1_API secp256k1_zkp_context* secp256k1_zkp_context_create( + unsigned int flags +) SECP256K1_WARN_UNUSED_RESULT; + +/** Copy a secp256k1 context object (into dynamically allocated memory). + * + * This function uses malloc to allocate memory. It is guaranteed that malloc is + * called at most once for every call of this function. If you need to avoid dynamic + * memory allocation entirely, see the functions in secp256k1_zkp_preallocated.h. + * + * Returns: a newly created context object. + * Args: ctx: an existing context to copy (cannot be NULL) + */ +SECP256K1_API secp256k1_zkp_context* secp256k1_zkp_context_clone( + const secp256k1_zkp_context* ctx +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; + +/** Destroy a secp256k1 context object (created in dynamically allocated memory). + * + * The context pointer may not be used afterwards. + * + * The context to destroy must have been created using secp256k1_zkp_context_create + * or secp256k1_zkp_context_clone. If the context has instead been created using + * secp256k1_zkp_context_preallocated_create or secp256k1_zkp_context_preallocated_clone, the + * behaviour is undefined. In that case, secp256k1_zkp_context_preallocated_destroy must + * be used instead. + * + * Args: ctx: an existing context to destroy, constructed using + * secp256k1_zkp_context_create or secp256k1_zkp_context_clone + */ +SECP256K1_API void secp256k1_zkp_context_destroy( + secp256k1_zkp_context* ctx +); + +/** Set a callback function to be called when an illegal argument is passed to + * an API call. It will only trigger for violations that are mentioned + * explicitly in the header. + * + * The philosophy is that these shouldn't be dealt with through a + * specific return value, as calling code should not have branches to deal with + * the case that this code itself is broken. + * + * On the other hand, during debug stage, one would want to be informed about + * such mistakes, and the default (crashing) may be inadvisable. + * When this callback is triggered, the API function called is guaranteed not + * to cause a crash, though its return value and output arguments are + * undefined. + * + * When this function has not been called (or called with fn=NULL), then the + * default handler will be used. The library provides a default handler which + * writes the message to stderr and calls abort. This default handler can be + * replaced at link time if the preprocessor macro + * USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build + * has been configured with --enable-external-default-callbacks. Then the + * following two symbols must be provided to link against: + * - void secp256k1_zkp_default_illegal_callback_fn(const char* message, void* data); + * - void secp256k1_zkp_default_error_callback_fn(const char* message, void* data); + * The library can call these default handlers even before a proper callback data + * pointer could have been using secp256k1_zkp_context_set_illegal_callback or + * secp256k1_zkp_context_set_illegal_callback, e.g., when the creation of a context + * fails. In this case, the corresponding default handler will be called with + * the data pointer argument set to NULL. + * + * Args: ctx: an existing context object (cannot be NULL) + * In: fun: a pointer to a function to call when an illegal argument is + * passed to the API, taking a message and an opaque pointer. + * (NULL restores the default handler.) + * data: the opaque pointer to pass to fun above. + * + * See also secp256k1_zkp_context_set_error_callback. + */ +SECP256K1_API void secp256k1_zkp_context_set_illegal_callback( + secp256k1_zkp_context* ctx, + void (*fun)(const char* message, void* data), + const void* data +) SECP256K1_ARG_NONNULL(1); + +/** Set a callback function to be called when an internal consistency check + * fails. The default is crashing. + * + * This can only trigger in case of a hardware failure, miscompilation, + * memory corruption, serious bug in the library, or other error would can + * otherwise result in undefined behaviour. It will not trigger due to mere + * incorrect usage of the API (see secp256k1_zkp_context_set_illegal_callback + * for that). After this callback returns, anything may happen, including + * crashing. + * + * Args: ctx: an existing context object (cannot be NULL) + * In: fun: a pointer to a function to call when an internal error occurs, + * taking a message and an opaque pointer (NULL restores the + * default handler, see secp256k1_zkp_context_set_illegal_callback + * for details). + * data: the opaque pointer to pass to fun above. + * + * See also secp256k1_zkp_context_set_illegal_callback. + */ +SECP256K1_API void secp256k1_zkp_context_set_error_callback( + secp256k1_zkp_context* ctx, + void (*fun)(const char* message, void* data), + const void* data +) SECP256K1_ARG_NONNULL(1); + +/** Create a secp256k1 scratch space object. + * + * Returns: a newly created scratch space. + * Args: ctx: an existing context object (cannot be NULL) + * In: max_size: maximum amount of memory to allocate + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_zkp_scratch_space* secp256k1_zkp_scratch_space_create( + const secp256k1_zkp_context* ctx, + size_t max_size +) SECP256K1_ARG_NONNULL(1); + +/** Destroy a secp256k1 scratch space. + * + * The pointer may not be used afterwards. + * Args: scratch: space to destroy + */ +SECP256K1_API void secp256k1_zkp_scratch_space_destroy( + secp256k1_zkp_scratch_space* scratch +); + +/** Parse a variable-length public key into the pubkey object. + * + * Returns: 1 if the public key was fully valid. + * 0 if the public key could not be parsed or is invalid. + * Args: ctx: a secp256k1 context object. + * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a + * parsed version of input. If not, its value is undefined. + * In: input: pointer to a serialized public key + * inputlen: length of the array pointed to by input + * + * This function supports parsing compressed (33 bytes, header byte 0x02 or + * 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header + * byte 0x06 or 0x07) format public keys. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_ec_pubkey_parse( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_pubkey* pubkey, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a pubkey object into a serialized byte sequence. + * + * Returns: 1 always. + * Args: ctx: a secp256k1 context object. + * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if + * compressed==1) byte array to place the serialized key + * in. + * In/Out: outputlen: a pointer to an integer which is initially set to the + * size of output, and is overwritten with the written + * size. + * In: pubkey: a pointer to a secp256k1_zkp_pubkey containing an + * initialized public key. + * flags: SECP256K1_EC_COMPRESSED if serialization should be in + * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED. + */ +SECP256K1_API int secp256k1_zkp_ec_pubkey_serialize( + const secp256k1_zkp_context* ctx, + unsigned char *output, + size_t *outputlen, + const secp256k1_zkp_pubkey* pubkey, + unsigned int flags +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Parse an ECDSA signature in compact (64 bytes) format. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input64: a pointer to the 64-byte array to parse + * + * The signature must consist of a 32-byte big endian R value, followed by a + * 32-byte big endian S value. If R or S fall outside of [0..order-1], the + * encoding is invalid. R and S with value 0 are allowed in the encoding. + * + * After the call, sig will always be initialized. If parsing failed or R or + * S are zero, the resulting sig value is guaranteed to fail validation for any + * message and public key. + */ +SECP256K1_API int secp256k1_zkp_ecdsa_signature_parse_compact( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_ecdsa_signature* sig, + const unsigned char *input64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse a DER ECDSA signature. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input: a pointer to the signature to be parsed + * inputlen: the length of the array pointed to be input + * + * This function will accept any valid DER encoded signature, even if the + * encoded numbers are out of range. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +SECP256K1_API int secp256k1_zkp_ecdsa_signature_parse_der( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_ecdsa_signature* sig, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in DER format. + * + * Returns: 1 if enough space was available to serialize, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: output: a pointer to an array to store the DER serialization + * In/Out: outputlen: a pointer to a length integer. Initially, this integer + * should be set to the length of output. After the call + * it will be set to the length of the serialization (even + * if 0 was returned). + * In: sig: a pointer to an initialized signature object + */ +SECP256K1_API int secp256k1_zkp_ecdsa_signature_serialize_der( + const secp256k1_zkp_context* ctx, + unsigned char *output, + size_t *outputlen, + const secp256k1_zkp_ecdsa_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Serialize an ECDSA signature in compact (64 byte) format. + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: output64: a pointer to a 64-byte array to store the compact serialization + * In: sig: a pointer to an initialized signature object + * + * See secp256k1_zkp_ecdsa_signature_parse_compact for details about the encoding. + */ +SECP256K1_API int secp256k1_zkp_ecdsa_signature_serialize_compact( + const secp256k1_zkp_context* ctx, + unsigned char *output64, + const secp256k1_zkp_ecdsa_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Verify an ECDSA signature. + * + * Returns: 1: correct signature + * 0: incorrect or unparseable signature + * Args: ctx: a secp256k1 context object, initialized for verification. + * In: sig: the signature being verified (cannot be NULL) + * msg32: the 32-byte message hash being verified (cannot be NULL) + * pubkey: pointer to an initialized public key to verify with (cannot be NULL) + * + * To avoid accepting malleable signatures, only ECDSA signatures in lower-S + * form are accepted. + * + * If you need to accept ECDSA signatures from sources that do not obey this + * rule, apply secp256k1_zkp_ecdsa_signature_normalize to the signature prior to + * validation, but be aware that doing so results in malleable signatures. + * + * For details, see the comments for that function. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_ecdsa_verify( + const secp256k1_zkp_context* ctx, + const secp256k1_zkp_ecdsa_signature *sig, + const unsigned char *msg32, + const secp256k1_zkp_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Convert a signature to a normalized lower-S form. + * + * Returns: 1 if sigin was not normalized, 0 if it already was. + * Args: ctx: a secp256k1 context object + * Out: sigout: a pointer to a signature to fill with the normalized form, + * or copy if the input was already normalized. (can be NULL if + * you're only interested in whether the input was already + * normalized). + * In: sigin: a pointer to a signature to check/normalize (cannot be NULL, + * can be identical to sigout) + * + * With ECDSA a third-party can forge a second distinct signature of the same + * message, given a single initial signature, but without knowing the key. This + * is done by negating the S value modulo the order of the curve, 'flipping' + * the sign of the random point R which is not included in the signature. + * + * Forgery of the same message isn't universally problematic, but in systems + * where message malleability or uniqueness of signatures is important this can + * cause issues. This forgery can be blocked by all verifiers forcing signers + * to use a normalized form. + * + * The lower-S form reduces the size of signatures slightly on average when + * variable length encodings (such as DER) are used and is cheap to verify, + * making it a good choice. Security of always using lower-S is assured because + * anyone can trivially modify a signature after the fact to enforce this + * property anyway. + * + * The lower S value is always between 0x1 and + * 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, + * inclusive. + * + * No other forms of ECDSA malleability are known and none seem likely, but + * there is no formal proof that ECDSA, even with this additional restriction, + * is free of other malleability. Commonly used serialization schemes will also + * accept various non-unique encodings, so care should be taken when this + * property is required for an application. + * + * The secp256k1_zkp_ecdsa_sign function will by default create signatures in the + * lower-S form, and secp256k1_zkp_ecdsa_verify will not accept others. In case + * signatures come from a system that cannot enforce this property, + * secp256k1_zkp_ecdsa_signature_normalize must be called before verification. + */ +SECP256K1_API int secp256k1_zkp_ecdsa_signature_normalize( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_ecdsa_signature *sigout, + const secp256k1_zkp_ecdsa_signature *sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); + +/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. + * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of + * extra entropy. + */ +SECP256K1_API extern const secp256k1_zkp_nonce_function secp256k1_zkp_nonce_function_rfc6979; + +/** A default safe nonce generation function (currently equal to secp256k1_zkp_nonce_function_rfc6979). */ +SECP256K1_API extern const secp256k1_zkp_nonce_function secp256k1_zkp_nonce_function_default; + +/** Create an ECDSA signature. + * + * Returns: 1: signature created + * 0: the nonce generation function failed, or the private key was invalid. + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) + * In: msg32: the 32-byte message hash being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp:pointer to a nonce generation function. If NULL, secp256k1_zkp_nonce_function_default is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + * + * The created signature is always in lower-S form. See + * secp256k1_zkp_ecdsa_signature_normalize for more details. + */ +SECP256K1_API int secp256k1_zkp_ecdsa_sign( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_ecdsa_signature *sig, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_zkp_nonce_function noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Verify an ECDSA secret key. + * + * Returns: 1: secret key is valid + * 0: secret key is invalid + * Args: ctx: pointer to a context object (cannot be NULL) + * In: seckey: pointer to a 32-byte secret key (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_ec_seckey_verify( + const secp256k1_zkp_context* ctx, + const unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Compute the public key for a secret key. + * + * Returns: 1: secret was valid, public key stores + * 0: secret was invalid, try again + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: pubkey: pointer to the created public key (cannot be NULL) + * In: seckey: pointer to a 32-byte private key (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_ec_pubkey_create( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_pubkey *pubkey, + const unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Negates a private key in place. + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * In/Out: seckey: pointer to the 32-byte private key to be negated (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_ec_privkey_negate( + const secp256k1_zkp_context* ctx, + unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Negates a public key in place. + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * In/Out: pubkey: pointer to the public key to be negated (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_ec_pubkey_negate( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Tweak a private key by adding tweak to it. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or if the resulting private key + * would be invalid (only when the tweak is the complement of the + * private key). 1 otherwise. + * Args: ctx: pointer to a context object (cannot be NULL). + * In/Out: seckey: pointer to a 32-byte private key. + * In: tweak: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_ec_privkey_tweak_add( + const secp256k1_zkp_context* ctx, + unsigned char *seckey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak a public key by adding tweak times the generator to it. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or if the resulting public key + * would be invalid (only when the tweak is the complement of the + * corresponding private key). 1 otherwise. + * Args: ctx: pointer to a context object initialized for validation + * (cannot be NULL). + * In/Out: pubkey: pointer to a public key object. + * In: tweak: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_ec_pubkey_tweak_add( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_pubkey *pubkey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak a private key by multiplying it by a tweak. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. + * Args: ctx: pointer to a context object (cannot be NULL). + * In/Out: seckey: pointer to a 32-byte private key. + * In: tweak: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_ec_privkey_tweak_mul( + const secp256k1_zkp_context* ctx, + unsigned char *seckey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak a public key by multiplying it by a tweak value. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. + * Args: ctx: pointer to a context object initialized for validation + * (cannot be NULL). + * In/Out: pubkey: pointer to a public key obkect. + * In: tweak: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_ec_pubkey_tweak_mul( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_pubkey *pubkey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Updates the context randomization to protect against side-channel leakage. + * Returns: 1: randomization successfully updated or nothing to randomize + * 0: error + * Args: ctx: pointer to a context object (cannot be NULL) + * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) + * + * While secp256k1 code is written to be constant-time no matter what secret + * values are, it's possible that a future compiler may output code which isn't, + * and also that the CPU may not emit the same radio frequencies or draw the same + * amount power for all values. + * + * This function provides a seed which is combined into the blinding value: that + * blinding value is added before each multiplication (and removed afterwards) so + * that it does not affect function results, but shields against attacks which + * rely on any input-dependent behaviour. + * + * This function has currently an effect only on contexts initialized for signing + * because randomization is currently used only for signing. However, this is not + * guaranteed and may change in the future. It is safe to call this function on + * contexts not initialized for signing; then it will have no effect and return 1. + * + * You should call this after secp256k1_zkp_context_create or + * secp256k1_zkp_context_clone (and secp256k1_zkp_context_preallocated_create or + * secp256k1_zkp_context_clone, resp.), and you may call this repeatedly afterwards. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_context_randomize( + secp256k1_zkp_context* ctx, + const unsigned char *seed32 +) SECP256K1_ARG_NONNULL(1); + +/** Add a number of public keys together. + * Returns: 1: the sum of the public keys is valid. + * 0: the sum of the public keys is not valid. + * Args: ctx: pointer to a context object + * Out: out: pointer to a public key object for placing the resulting public key + * (cannot be NULL) + * In: ins: pointer to array of pointers to public keys (cannot be NULL) + * n: the number of public keys to add together (must be at least 1) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_ec_pubkey_combine( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_pubkey *out, + const secp256k1_zkp_pubkey * const * ins, + size_t n +) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_ecdh.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_ecdh.h new file mode 100644 index 00000000..674097df --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_ecdh.h @@ -0,0 +1,55 @@ +#ifndef SECP256K1_ECDH_H +#define SECP256K1_ECDH_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** A pointer to a function that applies hash function to a point + * + * Returns: 1 if a point was successfully hashed. 0 will cause ecdh to fail + * Out: output: pointer to an array to be filled by the function + * In: x: pointer to a 32-byte x coordinate + * y: pointer to a 32-byte y coordinate + * data: Arbitrary data pointer that is passed through + */ +typedef int (*secp256k1_zkp_ecdh_hash_function)( + unsigned char *output, + const unsigned char *x, + const unsigned char *y, + void *data +); + +/** An implementation of SHA256 hash function that applies to compressed public key. */ +SECP256K1_API extern const secp256k1_zkp_ecdh_hash_function secp256k1_zkp_ecdh_hash_function_sha256; + +/** A default ecdh hash function (currently equal to secp256k1_zkp_ecdh_hash_function_sha256). */ +SECP256K1_API extern const secp256k1_zkp_ecdh_hash_function secp256k1_zkp_ecdh_hash_function_default; + +/** Compute an EC Diffie-Hellman secret in constant time + * Returns: 1: exponentiation was successful + * 0: scalar was invalid (zero or overflow) + * Args: ctx: pointer to a context object (cannot be NULL) + * Out: output: pointer to an array to be filled by the function + * In: pubkey: a pointer to a secp256k1_zkp_pubkey containing an + * initialized public key + * privkey: a 32-byte scalar with which to multiply the point + * hashfp: pointer to a hash function. If NULL, secp256k1_zkp_ecdh_hash_function_sha256 is used + * data: Arbitrary data pointer that is passed through + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_ecdh( + const secp256k1_zkp_context* ctx, + unsigned char *output, + const secp256k1_zkp_pubkey *pubkey, + const unsigned char *privkey, + secp256k1_zkp_ecdh_hash_function hashfp, + void *data +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_ECDH_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_generator.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_generator.h new file mode 100644 index 00000000..658e92d7 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_generator.h @@ -0,0 +1,93 @@ +#ifndef _SECP256K1_GENERATOR_ +# define _SECP256K1_GENERATOR_ + +# include "secp256k1.h" + +# ifdef __cplusplus +extern "C" { +# endif + +#include + +/** Opaque data structure that stores a base point + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use secp256k1_zkp_generator_serialize and secp256k1_zkp_generator_parse. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_zkp_generator; + +/** Parse a 33-byte generator byte sequence into a generator object. + * + * Returns: 1 if input contains a valid generator. + * Args: ctx: a secp256k1 context object. + * Out: gen: pointer to the output generator object + * In: input: pointer to a 33-byte serialized generator + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_generator_parse( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_generator* gen, + const unsigned char *input +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a 33-byte generator into a serialized byte sequence. + * + * Returns: 1 always. + * Args: ctx: a secp256k1 context object. + * Out: output: a pointer to a 33-byte byte array + * In: gen: a pointer to a generator + */ +SECP256K1_API int secp256k1_zkp_generator_serialize( + const secp256k1_zkp_context* ctx, + unsigned char *output, + const secp256k1_zkp_generator* gen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Generate a generator for the curve. + * + * Returns: 0 in the highly unlikely case the seed is not acceptable, + * 1 otherwise. + * Args: ctx: a secp256k1 context object + * Out: gen: a generator object + * In: seed32: a 32-byte seed + * + * If successful a valid generator will be placed in gen. The produced + * generators are distributed uniformly over the curve, and will not have a + * known discrete logarithm with respect to any other generator produced, + * or to the base generator G. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_generator_generate( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_generator* gen, + const unsigned char *seed32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Generate a blinded generator for the curve. + * + * Returns: 0 in the highly unlikely case the seed is not acceptable or when + * blind is out of range. 1 otherwise. + * Args: ctx: a secp256k1 context object, initialized for signing + * Out: gen: a generator object + * In: seed32: a 32-byte seed + * blind32: a 32-byte secret value to blind the generator with. + * + * The result is equivalent to first calling secp256k1_zkp_generator_generate, + * converting the result to a public key, calling secp256k1_zkp_ec_pubkey_tweak_add, + * and then converting back to generator form. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_generator_generate_blinded( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_generator* gen, + const unsigned char *key32, + const unsigned char *blind32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_musig.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_musig.h new file mode 100644 index 00000000..ffe2d41a --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_musig.h @@ -0,0 +1,422 @@ +#ifndef SECP256K1_MUSIG_H +#define SECP256K1_MUSIG_H + +#include + +/** This module implements a Schnorr-based multi-signature scheme called MuSig + * (https://eprint.iacr.org/2018/068.pdf). There's an example C source file in the + * module's directory (src/modules/musig/example.c) that demonstrates how it can be + * used. + * + * The documentation in this include file is for reference and may not be sufficient + * for users to begin using the library. A full description of API usage can be found + * in src/modules/musig/musig.md + */ + +/** Data structure containing data related to a signing session resulting in a single + * signature. + * + * This structure is not opaque, but it MUST NOT be copied or read or written to it + * directly. A signer who is online throughout the whole process and can keep this + * structure in memory can use the provided API functions for a safe standard + * workflow. See https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/ + * for more details about the risks associated with serializing or deserializing this + * structure. + * + * Fields: + * combined_pk: MuSig-computed combined public key + * n_signers: Number of signers + * pk_hash: The 32-byte hash of the original public keys + * combined_nonce: Summed combined public nonce (undefined if `nonce_is_set` is false) + * nonce_is_set: Whether the above nonce has been set + * nonce_is_negated: If `nonce_is_set`, whether the above nonce was negated after + * summing the participants' nonces. Needed to ensure the nonce's y + * coordinate has a quadratic-residue y coordinate + * msg: The 32-byte message (hash) to be signed + * msg_is_set: Whether the above message has been set + * has_secret_data: Whether this session object has a signers' secret data; if this + * is `false`, it may still be used for verification purposes. + * seckey: If `has_secret_data`, the signer's secret key + * secnonce: If `has_secret_data`, the signer's secret nonce + * nonce: If `has_secret_data`, the signer's public nonce + * nonce_commitments_hash: If `has_secret_data` and `nonce_commitments_hash_is_set`, + * the hash of all signers' commitments + * nonce_commitments_hash_is_set: If `has_secret_data`, whether the + * nonce_commitments_hash has been set + */ +typedef struct { + secp256k1_zkp_pubkey combined_pk; + uint32_t n_signers; + unsigned char pk_hash[32]; + secp256k1_zkp_pubkey combined_nonce; + int nonce_is_set; + int nonce_is_negated; + unsigned char msg[32]; + int msg_is_set; + int has_secret_data; + unsigned char seckey[32]; + unsigned char secnonce[32]; + secp256k1_zkp_pubkey nonce; + unsigned char nonce_commitments_hash[32]; + int nonce_commitments_hash_is_set; +} secp256k1_zkp_musig_session; + +/** Data structure containing data on all signers in a single session. + * + * The workflow for this structure is as follows: + * + * 1. This structure is initialized with `musig_session_initialize` or + * `musig_session_initialize_verifier`, which set the `index` field, and zero out + * all other fields. The public session is initialized with the signers' + * nonce_commitments. + * + * 2. In a non-public session the nonce_commitments are set with the function + * `musig_get_public_nonce`, which also returns the signer's public nonce. This + * ensures that the public nonce is not exposed until all commitments have been + * received. + * + * 3. Each individual data struct should be updated with `musig_set_nonce` once a + * nonce is available. This function takes a single signer data struct rather than + * an array because it may fail in the case that the provided nonce does not match + * the commitment. In this case, it is desirable to identify the exact party whose + * nonce was inconsistent. + * + * Fields: + * present: indicates whether the signer's nonce is set + * index: index of the signer in the MuSig key aggregation + * nonce: public nonce, must be a valid curvepoint if the signer is `present` + * nonce_commitment: commitment to the nonce, or all-bits zero if a commitment + * has not yet been set + */ +typedef struct { + int present; + uint32_t index; + secp256k1_zkp_pubkey nonce; + unsigned char nonce_commitment[32]; +} secp256k1_zkp_musig_session_signer_data; + +/** Opaque data structure that holds a MuSig partial signature. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is however + * guaranteed to be 32 bytes in size, and can be safely copied/moved. If you need + * to convert to a format suitable for storage, transmission, or comparison, use the + * `musig_partial_signature_serialize` and `musig_partial_signature_parse` + * functions. + */ +typedef struct { + unsigned char data[32]; +} secp256k1_zkp_musig_partial_signature; + +/** Computes a combined public key and the hash of the given public keys + * + * Returns: 1 if the public keys were successfully combined, 0 otherwise + * Args: ctx: pointer to a context object initialized for verification + * (cannot be NULL) + * scratch: scratch space used to compute the combined pubkey by + * multiexponentiation. If NULL, an inefficient algorithm is used. + * Out: combined_pk: the MuSig-combined public key (cannot be NULL) + * pk_hash32: if non-NULL, filled with the 32-byte hash of all input public + * keys in order to be used in `musig_session_initialize`. + * In: pubkeys: input array of public keys to combine. The order is important; + * a different order will result in a different combined public + * key (cannot be NULL) + * n_pubkeys: length of pubkeys array + */ +SECP256K1_API int secp256k1_zkp_musig_pubkey_combine( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_scratch_space *scratch, + secp256k1_zkp_pubkey *combined_pk, + unsigned char *pk_hash32, + const secp256k1_zkp_pubkey *pubkeys, + size_t n_pubkeys +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); + +/** Initializes a signing session for a signer + * + * Returns: 1: session is successfully initialized + * 0: session could not be initialized: secret key or secret nonce overflow + * Args: ctx: pointer to a context object, initialized for signing (cannot + * be NULL) + * Out: session: the session structure to initialize (cannot be NULL) + * signers: an array of signers' data to be initialized. Array length must + * equal to `n_signers` (cannot be NULL) + * nonce_commitment32: filled with a 32-byte commitment to the generated nonce + * (cannot be NULL) + * In: session_id32: a *unique* 32-byte ID to assign to this session (cannot be + * NULL). If a non-unique session_id32 was given then a partial + * signature will LEAK THE SECRET KEY. + * msg32: the 32-byte message to be signed. Shouldn't be NULL unless you + * require sharing public nonces before the message is known + * because it reduces nonce misuse resistance. If NULL, must be + * set with `musig_session_set_msg` before signing and verifying. + * combined_pk: the combined public key of all signers (cannot be NULL) + * pk_hash32: the 32-byte hash of the signers' individual keys (cannot be + * NULL) + * n_signers: length of signers array. Number of signers participating in + * the MuSig. Must be greater than 0 and at most 2^32 - 1. + * my_index: index of this signer in the signers array + * seckey: the signer's 32-byte secret key (cannot be NULL) + */ +SECP256K1_API int secp256k1_zkp_musig_session_initialize( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_musig_session *session, + secp256k1_zkp_musig_session_signer_data *signers, + unsigned char *nonce_commitment32, + const unsigned char *session_id32, + const unsigned char *msg32, + const secp256k1_zkp_pubkey *combined_pk, + const unsigned char *pk_hash32, + size_t n_signers, + size_t my_index, + const unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(11); + +/** Gets the signer's public nonce given a list of all signers' data with commitments + * + * Returns: 1: public nonce is written in nonce + * 0: signer data is missing commitments or session isn't initialized + * for signing + * Args: ctx: pointer to a context object (cannot be NULL) + * session: the signing session to get the nonce from (cannot be NULL) + * signers: an array of signers' data initialized with + * `musig_session_initialize`. Array length must equal to + * `n_commitments` (cannot be NULL) + * Out: nonce: the nonce (cannot be NULL) + * In: commitments: array of 32-byte nonce commitments (cannot be NULL) + * n_commitments: the length of commitments and signers array. Must be the total + * number of signers participating in the MuSig. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_musig_session_get_public_nonce( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_musig_session *session, + secp256k1_zkp_musig_session_signer_data *signers, + secp256k1_zkp_pubkey *nonce, + const unsigned char *const *commitments, + size_t n_commitments +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + +/** Initializes a verifier session that can be used for verifying nonce commitments + * and partial signatures. It does not have secret key material and therefore can not + * be used to create signatures. + * + * Returns: 1 when session is successfully initialized, 0 otherwise + * Args: ctx: pointer to a context object (cannot be NULL) + * Out: session: the session structure to initialize (cannot be NULL) + * signers: an array of signers' data to be initialized. Array length must + * equal to `n_signers`(cannot be NULL) + * In: msg32: the 32-byte message to be signed If NULL, must be set with + * `musig_session_set_msg` before using the session for verifying + * partial signatures. + * combined_pk: the combined public key of all signers (cannot be NULL) + * pk_hash32: the 32-byte hash of the signers' individual keys (cannot be NULL) + * commitments: array of 32-byte nonce commitments. Array length must equal to + * `n_signers` (cannot be NULL) + * n_signers: length of signers and commitments array. Number of signers + * participating in the MuSig. Must be greater than 0 and at most + * 2^32 - 1. + */ +SECP256K1_API int secp256k1_zkp_musig_session_initialize_verifier( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_musig_session *session, + secp256k1_zkp_musig_session_signer_data *signers, + const unsigned char *msg32, + const secp256k1_zkp_pubkey *combined_pk, + const unsigned char *pk_hash32, + const unsigned char *const *commitments, + size_t n_signers +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7); + +/** Checks a signer's public nonce against a commitment to said nonce, and update + * data structure if they match + * + * Returns: 1: commitment was valid, data structure updated + * 0: commitment was invalid, nothing happened + * Args: ctx: pointer to a context object (cannot be NULL) + * signer: pointer to the signer data to update (cannot be NULL). Must have + * been used with `musig_session_get_public_nonce` or initialized + * with `musig_session_initialize_verifier`. + * In: nonce: signer's alleged public nonce (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_musig_set_nonce( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_musig_session_signer_data *signer, + const secp256k1_zkp_pubkey *nonce +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Updates a session with the combined public nonce of all signers. The combined + * public nonce is the sum of every signer's public nonce. + * + * Returns: 1: nonces are successfully combined + * 0: a signer's nonce is missing + * Args: ctx: pointer to a context object (cannot be NULL) + * session: session to update with the combined public nonce (cannot be + * NULL) + * signers: an array of signers' data, which must have had public nonces + * set with `musig_set_nonce`. Array length must equal to `n_signers` + * (cannot be NULL) + * n_signers: the length of the signers array. Must be the total number of + * signers participating in the MuSig. + * Out: nonce_is_negated: a pointer to an integer that indicates if the combined + * public nonce had to be negated. + * adaptor: point to add to the combined public nonce. If NULL, nothing is + * added to the combined nonce. + */ +SECP256K1_API int secp256k1_zkp_musig_session_combine_nonces( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_musig_session *session, + const secp256k1_zkp_musig_session_signer_data *signers, + size_t n_signers, + int *nonce_is_negated, + const secp256k1_zkp_pubkey *adaptor +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + +/** Sets the message of a session if previously unset + * + * Returns 1 if the message was not set yet and is now successfully set + * 0 otherwise + * Args: ctx: pointer to a context object (cannot be NULL) + * session: the session structure to update with the message (cannot be NULL) + * In: msg32: the 32-byte message to be signed (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_musig_session_set_msg( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_musig_session *session, + const unsigned char *msg32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a MuSig partial signature or adaptor signature + * + * Returns: 1 when the signature could be serialized, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: out32: pointer to a 32-byte array to store the serialized signature + * In: sig: pointer to the signature + */ +SECP256K1_API int secp256k1_zkp_musig_partial_signature_serialize( + const secp256k1_zkp_context* ctx, + unsigned char *out32, + const secp256k1_zkp_musig_partial_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse and verify a MuSig partial signature. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: pointer to a signature object + * In: in32: pointer to the 32-byte signature to be parsed + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature verification with it is + * guaranteed to fail for every message and public key. + */ +SECP256K1_API int secp256k1_zkp_musig_partial_signature_parse( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_musig_partial_signature* sig, + const unsigned char *in32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Produces a partial signature + * + * Returns: 1: partial signature constructed + * 0: session in incorrect or inconsistent state + * Args: ctx: pointer to a context object (cannot be NULL) + * session: active signing session for which the combined nonce has been + * computed (cannot be NULL) + * Out: partial_sig: partial signature (cannot be NULL) + */ +SECP256K1_API int secp256k1_zkp_musig_partial_sign( + const secp256k1_zkp_context* ctx, + const secp256k1_zkp_musig_session *session, + secp256k1_zkp_musig_partial_signature *partial_sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Checks that an individual partial signature verifies + * + * This function is essential when using protocols with adaptor signatures. + * However, it is not essential for regular MuSig's, in the sense that if any + * partial signatures does not verify, the full signature will also not verify, so the + * problem will be caught. But this function allows determining the specific party + * who produced an invalid signature, so that signing can be restarted without them. + * + * Returns: 1: partial signature verifies + * 0: invalid signature or bad data + * Args: ctx: pointer to a context object (cannot be NULL) + * session: active session for which the combined nonce has been computed + * (cannot be NULL) + * signer: data for the signer who produced this signature (cannot be NULL) + * In: partial_sig: signature to verify (cannot be NULL) + * pubkey: public key of the signer who produced the signature (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_musig_partial_sig_verify( + const secp256k1_zkp_context* ctx, + const secp256k1_zkp_musig_session *session, + const secp256k1_zkp_musig_session_signer_data *signer, + const secp256k1_zkp_musig_partial_signature *partial_sig, + const secp256k1_zkp_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + +/** Combines partial signatures + * + * Returns: 1: all partial signatures have values in range. Does NOT mean the + * resulting signature verifies. + * 0: some partial signature had s/r out of range + * Args: ctx: pointer to a context object (cannot be NULL) + * session: initialized session for which the combined nonce has been + * computed (cannot be NULL) + * Out: sig: complete signature (cannot be NULL) + * In: partial_sigs: array of partial signatures to combine (cannot be NULL) + * n_sigs: number of signatures in the partial_sigs array + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_musig_partial_sig_combine( + const secp256k1_zkp_context* ctx, + const secp256k1_zkp_musig_session *session, + secp256k1_zkp_schnorrsig *sig, + const secp256k1_zkp_musig_partial_signature *partial_sigs, + size_t n_sigs +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Converts a partial signature to an adaptor signature by adding a given secret + * adaptor. + * + * Returns: 1: signature and secret adaptor contained valid values + * 0: otherwise + * Args: ctx: pointer to a context object (cannot be NULL) + * Out: adaptor_sig: adaptor signature to produce (cannot be NULL) + * In: partial_sig: partial signature to tweak with secret adaptor (cannot be NULL) + * sec_adaptor32: 32-byte secret adaptor to add to the partial signature (cannot + * be NULL) + * nonce_is_negated: the `nonce_is_negated` output of `musig_session_combine_nonces` + */ +SECP256K1_API int secp256k1_zkp_musig_partial_sig_adapt( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_musig_partial_signature *adaptor_sig, + const secp256k1_zkp_musig_partial_signature *partial_sig, + const unsigned char *sec_adaptor32, + int nonce_is_negated +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Extracts a secret adaptor from a MuSig, given all parties' partial + * signatures. This function will not fail unless given grossly invalid data; if it + * is merely given signatures that do not verify, the returned value will be + * nonsense. It is therefore important that all data be verified at earlier steps of + * any protocol that uses this function. + * + * Returns: 1: signatures contained valid data such that an adaptor could be extracted + * 0: otherwise + * Args: ctx: pointer to a context object (cannot be NULL) + * Out:sec_adaptor32: 32-byte secret adaptor (cannot be NULL) + * In: sig: complete 2-of-2 signature (cannot be NULL) + * partial_sigs: array of partial signatures (cannot be NULL) + * n_partial_sigs: number of elements in partial_sigs array + * nonce_is_negated: the `nonce_is_negated` output of `musig_session_combine_nonces` + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_musig_extract_secret_adaptor( + const secp256k1_zkp_context* ctx, + unsigned char *sec_adaptor32, + const secp256k1_zkp_schnorrsig *sig, + const secp256k1_zkp_musig_partial_signature *partial_sigs, + size_t n_partial_sigs, + int nonce_is_negated +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_preallocated.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_preallocated.h new file mode 100644 index 00000000..98328f51 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_preallocated.h @@ -0,0 +1,128 @@ +#ifndef SECP256K1_PREALLOCATED_H +#define SECP256K1_PREALLOCATED_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* The module provided by this header file is intended for settings in which it + * is not possible or desirable to rely on dynamic memory allocation. It provides + * functions for creating, cloning, and destroying secp256k1 context objects in a + * contiguous fixed-size block of memory provided by the caller. + * + * Context objects created by functions in this module can be used like contexts + * objects created by functions in secp256k1.h, i.e., they can be passed to any + * API function that excepts a context object (see secp256k1.h for details). The + * only exception is that context objects created by functions in this module + * must be destroyed using secp256k1_zkp_context_preallocated_destroy (in this + * module) instead of secp256k1_zkp_context_destroy (in secp256k1.h). + * + * It is guaranteed that functions in by this module will not call malloc or its + * friends realloc, calloc, and free. + */ + +/** Determine the memory size of a secp256k1 context object to be created in + * caller-provided memory. + * + * The purpose of this function is to determine how much memory must be provided + * to secp256k1_zkp_context_preallocated_create. + * + * Returns: the required size of the caller-provided memory block + * In: flags: which parts of the context to initialize. + */ +SECP256K1_API size_t secp256k1_zkp_context_preallocated_size( + unsigned int flags +) SECP256K1_WARN_UNUSED_RESULT; + +/** Create a secp256k1 context object in caller-provided memory. + * + * The caller must provide a pointer to a rewritable contiguous block of memory + * of size at least secp256k1_zkp_context_preallocated_size(flags) bytes, suitably + * aligned to hold an object of any type. + * + * The block of memory is exclusively owned by the created context object during + * the lifetime of this context object, which begins with the call to this + * function and ends when a call to secp256k1_zkp_context_preallocated_destroy + * (which destroys the context object again) returns. During the lifetime of the + * context object, the caller is obligated not to access this block of memory, + * i.e., the caller may not read or write the memory, e.g., by copying the memory + * contents to a different location or trying to create a second context object + * in the memory. In simpler words, the prealloc pointer (or any pointer derived + * from it) should not be used during the lifetime of the context object. + * + * Returns: a newly created context object. + * In: prealloc: a pointer to a rewritable contiguous block of memory of + * size at least secp256k1_zkp_context_preallocated_size(flags) + * bytes, as detailed above (cannot be NULL) + * flags: which parts of the context to initialize. + * + * See also secp256k1_zkp_context_randomize (in secp256k1.h) + * and secp256k1_zkp_context_preallocated_destroy. + */ +SECP256K1_API secp256k1_zkp_context* secp256k1_zkp_context_preallocated_create( + void* prealloc, + unsigned int flags +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; + +/** Determine the memory size of a secp256k1 context object to be copied into + * caller-provided memory. + * + * Returns: the required size of the caller-provided memory block. + * In: ctx: an existing context to copy (cannot be NULL) + */ +SECP256K1_API size_t secp256k1_zkp_context_preallocated_clone_size( + const secp256k1_zkp_context* ctx +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; + +/** Copy a secp256k1 context object into caller-provided memory. + * + * The caller must provide a pointer to a rewritable contiguous block of memory + * of size at least secp256k1_zkp_context_preallocated_size(flags) bytes, suitably + * aligned to hold an object of any type. + * + * The block of memory is exclusively owned by the created context object during + * the lifetime of this context object, see the description of + * secp256k1_zkp_context_preallocated_create for details. + * + * Returns: a newly created context object. + * Args: ctx: an existing context to copy (cannot be NULL) + * In: prealloc: a pointer to a rewritable contiguous block of memory of + * size at least secp256k1_zkp_context_preallocated_size(flags) + * bytes, as detailed above (cannot be NULL) + */ +SECP256K1_API secp256k1_zkp_context* secp256k1_zkp_context_preallocated_clone( + const secp256k1_zkp_context* ctx, + void* prealloc +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_WARN_UNUSED_RESULT; + +/** Destroy a secp256k1 context object that has been created in + * caller-provided memory. + * + * The context pointer may not be used afterwards. + * + * The context to destroy must have been created using + * secp256k1_zkp_context_preallocated_create or secp256k1_zkp_context_preallocated_clone. + * If the context has instead been created using secp256k1_zkp_context_create or + * secp256k1_zkp_context_clone, the behaviour is undefined. In that case, + * secp256k1_zkp_context_destroy must be used instead. + * + * If required, it is the responsibility of the caller to deallocate the block + * of memory properly after this function returns, e.g., by calling free on the + * preallocated pointer given to secp256k1_zkp_context_preallocated_create or + * secp256k1_zkp_context_preallocated_clone. + * + * Args: ctx: an existing context to destroy, constructed using + * secp256k1_zkp_context_preallocated_create or + * secp256k1_zkp_context_preallocated_clone (cannot be NULL) + */ +SECP256K1_API void secp256k1_zkp_context_preallocated_destroy( + secp256k1_zkp_context* ctx +); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_PREALLOCATED_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_rangeproof.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_rangeproof.h new file mode 100644 index 00000000..ad70c2ce --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_rangeproof.h @@ -0,0 +1,297 @@ +#ifndef _SECP256K1_RANGEPROOF_ +# define _SECP256K1_RANGEPROOF_ + +# include "secp256k1.h" +# include "secp256k1_zkp_generator.h" + +# ifdef __cplusplus +extern "C" { +# endif + +#include + +/** Opaque data structure that stores a Pedersen commitment + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use secp256k1_zkp_pedersen_commitment_serialize and + * secp256k1_zkp_pedersen_commitment_parse. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_zkp_pedersen_commitment; + +/** + * Static constant generator 'h' maintained for historical reasons. + */ +SECP256K1_API extern const secp256k1_zkp_generator *secp256k1_zkp_generator_h; + +/** Parse a 33-byte commitment into a commitment object. + * + * Returns: 1 if input contains a valid commitment. + * Args: ctx: a secp256k1 context object. + * Out: commit: pointer to the output commitment object + * In: input: pointer to a 33-byte serialized commitment key + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_pedersen_commitment_parse( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_pedersen_commitment* commit, + const unsigned char *input +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a commitment object into a serialized byte sequence. + * + * Returns: 1 always. + * Args: ctx: a secp256k1 context object. + * Out: output: a pointer to a 33-byte byte array + * In: commit: a pointer to a secp256k1_zkp_pedersen_commitment containing an + * initialized commitment + */ +SECP256K1_API int secp256k1_zkp_pedersen_commitment_serialize( + const secp256k1_zkp_context* ctx, + unsigned char *output, + const secp256k1_zkp_pedersen_commitment* commit +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Initialize a context for usage with Pedersen commitments. */ +void secp256k1_zkp_pedersen_context_initialize(secp256k1_zkp_context* ctx); + +/** Generate a pedersen commitment. + * Returns 1: Commitment successfully created. + * 0: Error. The blinding factor is larger than the group order + * (probability for random 32 byte number < 2^-127) or results in the + * point at infinity. Retry with a different factor. + * In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL) + * blind: pointer to a 32-byte blinding factor (cannot be NULL) + * value: unsigned 64-bit integer value to commit to. + * gen: additional generator 'h' + * Out: commit: pointer to the commitment (cannot be NULL) + * + * Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_pedersen_commit( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_pedersen_commitment *commit, + const unsigned char *blind, + uint64_t value, + const secp256k1_zkp_generator *gen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); + +/** Computes the sum of multiple positive and negative blinding factors. + * Returns 1: Sum successfully computed. + * 0: Error. A blinding factor is larger than the group order + * (probability for random 32 byte number < 2^-127). Retry with + * different factors. + * In: ctx: pointer to a context object (cannot be NULL) + * blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL) + * n: number of factors pointed to by blinds. + * npositive: how many of the initial factors should be treated with a positive sign. + * Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_pedersen_blind_sum( + const secp256k1_zkp_context* ctx, + unsigned char *blind_out, + const unsigned char * const *blinds, + size_t n, + size_t npositive +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Verify a tally of pedersen commitments + * Returns 1: commitments successfully sum to zero. + * 0: Commitments do not sum to zero or other error. + * In: ctx: pointer to a context object (cannot be NULL) + * commits: pointer to array of pointers to the commitments. (cannot be NULL if pcnt is non-zero) + * pcnt: number of commitments pointed to by commits. + * ncommits: pointer to array of pointers to the negative commitments. (cannot be NULL if ncnt is non-zero) + * ncnt: number of commitments pointed to by ncommits. + * + * This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) == 0. + * + * A pedersen commitment is xG + vA where G and A are generators for the secp256k1 group and x is a blinding factor, + * while v is the committed value. For a collection of commitments to sum to zero, for each distinct generator + * A all blinding factors and all values must sum to zero. + * + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_pedersen_verify_tally( + const secp256k1_zkp_context* ctx, + const secp256k1_zkp_pedersen_commitment * const* commits, + size_t pcnt, + const secp256k1_zkp_pedersen_commitment * const* ncommits, + size_t ncnt +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + +/** Sets the final Pedersen blinding factor correctly when the generators themselves + * have blinding factors. + * + * Consider a generator of the form A' = A + rG, where A is the "real" generator + * but A' is the generator provided to verifiers. Then a Pedersen commitment + * P = vA' + r'G really has the form vA + (vr + r')G. To get all these (vr + r') + * to sum to zero for multiple commitments, we take three arrays consisting of + * the `v`s, `r`s, and `r'`s, respectively called `value`s, `generator_blind`s + * and `blinding_factor`s, and sum them. + * + * The function then subtracts the sum of all (vr + r') from the last element + * of the `blinding_factor` array, setting the total sum to zero. + * + * Returns 1: Blinding factor successfully computed. + * 0: Error. A blinding_factor or generator_blind are larger than the group + * order (probability for random 32 byte number < 2^-127). Retry with + * different values. + * + * In: ctx: pointer to a context object + * value: array of asset values, `v` in the above paragraph. + * May not be NULL unless `n_total` is 0. + * generator_blind: array of asset blinding factors, `r` in the above paragraph + * May not be NULL unless `n_total` is 0. + * n_total: Total size of the above arrays + * n_inputs: How many of the initial array elements represent commitments that + * will be negated in the final sum + * In/Out: blinding_factor: array of commitment blinding factors, `r'` in the above paragraph + * May not be NULL unless `n_total` is 0. + * the last value will be modified to get the total sum to zero. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_pedersen_blind_generator_blind_sum( + const secp256k1_zkp_context* ctx, + const uint64_t *value, + const unsigned char* const* generator_blind, + unsigned char* const* blinding_factor, + size_t n_total, + size_t n_inputs +); + +/** Initialize a context for usage with Pedersen commitments. */ +void secp256k1_zkp_rangeproof_context_initialize(secp256k1_zkp_context* ctx); + +/** Verify a proof that a committed value is within a range. + * Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs. + * 0: Proof failed or other error. + * In: ctx: pointer to a context object, initialized for range-proof and commitment (cannot be NULL) + * commit: the commitment being proved. (cannot be NULL) + * proof: pointer to character array with the proof. (cannot be NULL) + * plen: length of proof in bytes. + * extra_commit: additional data covered in rangeproof signature + * extra_commit_len: length of extra_commit byte array (0 if NULL) + * gen: additional generator 'h' + * Out: min_value: pointer to a unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL) + * max_value: pointer to a unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_rangeproof_verify( + const secp256k1_zkp_context* ctx, + uint64_t *min_value, + uint64_t *max_value, + const secp256k1_zkp_pedersen_commitment *commit, + const unsigned char *proof, + size_t plen, + const unsigned char *extra_commit, + size_t extra_commit_len, + const secp256k1_zkp_generator* gen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(9); + +/** Verify a range proof proof and rewind the proof to recover information sent by its author. + * Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs, and the value and blinding were recovered. + * 0: Proof failed, rewind failed, or other error. + * In: ctx: pointer to a context object, initialized for range-proof and Pedersen commitment (cannot be NULL) + * commit: the commitment being proved. (cannot be NULL) + * proof: pointer to character array with the proof. (cannot be NULL) + * plen: length of proof in bytes. + * nonce: 32-byte secret nonce used by the prover (cannot be NULL) + * extra_commit: additional data covered in rangeproof signature + * extra_commit_len: length of extra_commit byte array (0 if NULL) + * gen: additional generator 'h' + * In/Out: blind_out: storage for the 32-byte blinding factor used for the commitment + * value_out: pointer to an unsigned int64 which has the exact value of the commitment. + * message_out: pointer to a 4096 byte character array to receive message data from the proof author. + * outlen: length of message data written to message_out. + * min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL) + * max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_rangeproof_rewind( + const secp256k1_zkp_context* ctx, + unsigned char *blind_out, + uint64_t *value_out, + unsigned char *message_out, + size_t *outlen, + const unsigned char *nonce, + uint64_t *min_value, + uint64_t *max_value, + const secp256k1_zkp_pedersen_commitment *commit, + const unsigned char *proof, + size_t plen, + const unsigned char *extra_commit, + size_t extra_commit_len, + const secp256k1_zkp_generator *gen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(9) SECP256K1_ARG_NONNULL(10) SECP256K1_ARG_NONNULL(14); + +/** Author a proof that a committed value is within a range. + * Returns 1: Proof successfully created. + * 0: Error + * In: ctx: pointer to a context object, initialized for range-proof, signing, and Pedersen commitment (cannot be NULL) + * proof: pointer to array to receive the proof, can be up to 5134 bytes. (cannot be NULL) + * min_value: constructs a proof where the verifer can tell the minimum value is at least the specified amount. + * commit: the commitment being proved. + * blind: 32-byte blinding factor used by commit. + * nonce: 32-byte secret nonce used to initialize the proof (value can be reverse-engineered out of the proof if this secret is known.) + * exp: Base-10 exponent. Digits below above will be made public, but the proof will be made smaller. Allowed range is -1 to 18. + * (-1 is a special case that makes the value public. 0 is the most private.) + * min_bits: Number of bits of the value to keep private. (0 = auto/minimal, - 64). + * value: Actual value of the commitment. + * message: pointer to a byte array of data to be embedded in the rangeproof that can be recovered by rewinding the proof + * msg_len: size of the message to be embedded in the rangeproof + * extra_commit: additional data to be covered in rangeproof signature + * extra_commit_len: length of extra_commit byte array (0 if NULL) + * gen: additional generator 'h' + * In/out: plen: point to an integer with the size of the proof buffer and the size of the constructed proof. + * + * If min_value or exp is non-zero then the value must be on the range [0, 2^63) to prevent the proof range from spanning past 2^64. + * + * If exp is -1 the value is revealed by the proof (e.g. it proves that the proof is a blinding of a specific value, without revealing the blinding key.) + * + * This can randomly fail with probability around one in 2^100. If this happens, buy a lottery ticket and retry with a different nonce or blinding. + * + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_rangeproof_sign( + const secp256k1_zkp_context* ctx, + unsigned char *proof, + size_t *plen, + uint64_t min_value, + const secp256k1_zkp_pedersen_commitment *commit, + const unsigned char *blind, + const unsigned char *nonce, + int exp, + int min_bits, + uint64_t value, + const unsigned char *message, + size_t msg_len, + const unsigned char *extra_commit, + size_t extra_commit_len, + const secp256k1_zkp_generator *gen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(15); + +/** Extract some basic information from a range-proof. + * Returns 1: Information successfully extracted. + * 0: Decode failed. + * In: ctx: pointer to a context object + * proof: pointer to character array with the proof. + * plen: length of proof in bytes. + * Out: exp: Exponent used in the proof (-1 means the value isn't private). + * mantissa: Number of bits covered by the proof. + * min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL) + * max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_rangeproof_info( + const secp256k1_zkp_context* ctx, + int *exp, + int *mantissa, + uint64_t *min_value, + uint64_t *max_value, + const unsigned char *proof, + size_t plen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_recovery.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_recovery.h new file mode 100644 index 00000000..9091babf --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_recovery.h @@ -0,0 +1,110 @@ +#ifndef SECP256K1_RECOVERY_H +#define SECP256K1_RECOVERY_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Opaque data structured that holds a parsed ECDSA signature, + * supporting pubkey recovery. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 65 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage or transmission, use + * the secp256k1_zkp_ecdsa_signature_serialize_* and + * secp256k1_zkp_ecdsa_signature_parse_* functions. + * + * Furthermore, it is guaranteed that identical signatures (including their + * recoverability) will have identical representation, so they can be + * memcmp'ed. + */ +typedef struct { + unsigned char data[65]; +} secp256k1_zkp_ecdsa_recoverable_signature; + +/** Parse a compact ECDSA signature (64 bytes + recovery id). + * + * Returns: 1 when the signature could be parsed, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input64: a pointer to a 64-byte compact signature + * recid: the recovery id (0, 1, 2 or 3) + */ +SECP256K1_API int secp256k1_zkp_ecdsa_recoverable_signature_parse_compact( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_ecdsa_recoverable_signature* sig, + const unsigned char *input64, + int recid +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Convert a recoverable signature into a normal signature. + * + * Returns: 1 + * Out: sig: a pointer to a normal signature (cannot be NULL). + * In: sigin: a pointer to a recoverable signature (cannot be NULL). + */ +SECP256K1_API int secp256k1_zkp_ecdsa_recoverable_signature_convert( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_ecdsa_signature* sig, + const secp256k1_zkp_ecdsa_recoverable_signature* sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in compact format (64 bytes + recovery id). + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL) + * recid: a pointer to an integer to hold the recovery id (can be NULL). + * In: sig: a pointer to an initialized signature object (cannot be NULL) + */ +SECP256K1_API int secp256k1_zkp_ecdsa_recoverable_signature_serialize_compact( + const secp256k1_zkp_context* ctx, + unsigned char *output64, + int *recid, + const secp256k1_zkp_ecdsa_recoverable_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Create a recoverable ECDSA signature. + * + * Returns: 1: signature created + * 0: the nonce generation function failed, or the private key was invalid. + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) + * In: msg32: the 32-byte message hash being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp:pointer to a nonce generation function. If NULL, secp256k1_zkp_nonce_function_default is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + */ +SECP256K1_API int secp256k1_zkp_ecdsa_sign_recoverable( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_ecdsa_recoverable_signature *sig, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_zkp_nonce_function noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Recover an ECDSA public key from a signature. + * + * Returns: 1: public key successfully recovered (which guarantees a correct signature). + * 0: otherwise. + * Args: ctx: pointer to a context object, initialized for verification (cannot be NULL) + * Out: pubkey: pointer to the recovered public key (cannot be NULL) + * In: sig: pointer to initialized signature that supports pubkey recovery (cannot be NULL) + * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_ecdsa_recover( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_pubkey *pubkey, + const secp256k1_zkp_ecdsa_recoverable_signature *sig, + const unsigned char *msg32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_RECOVERY_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_schnorrsig.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_schnorrsig.h new file mode 100644 index 00000000..be82d1b9 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_schnorrsig.h @@ -0,0 +1,118 @@ +#ifndef SECP256K1_SCHNORRSIG_H +#define SECP256K1_SCHNORRSIG_H + +/** This module implements a variant of Schnorr signatures compliant with + * BIP-schnorr + * (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki). + */ + +/** Opaque data structure that holds a parsed Schnorr signature. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use the `secp256k1_zkp_schnorrsig_serialize` and + * `secp256k1_zkp_schnorrsig_parse` functions. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_zkp_schnorrsig; + +/** Serialize a Schnorr signature. + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: out64: pointer to a 64-byte array to store the serialized signature + * In: sig: pointer to the signature + * + * See secp256k1_zkp_schnorrsig_parse for details about the encoding. + */ +SECP256K1_API int secp256k1_zkp_schnorrsig_serialize( + const secp256k1_zkp_context* ctx, + unsigned char *out64, + const secp256k1_zkp_schnorrsig* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse a Schnorr signature. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: pointer to a signature object + * In: in64: pointer to the 64-byte signature to be parsed + * + * The signature is serialized in the form R||s, where R is a 32-byte public + * key (x-coordinate only; the y-coordinate is considered to be the unique + * y-coordinate satisfying the curve equation that is a quadratic residue) + * and s is a 32-byte big-endian scalar. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +SECP256K1_API int secp256k1_zkp_schnorrsig_parse( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_schnorrsig* sig, + const unsigned char *in64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Create a Schnorr signature. + * + * Returns 1 on success, 0 on failure. + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: sig: pointer to the returned signature (cannot be NULL) + * nonce_is_negated: a pointer to an integer indicates if signing algorithm negated the + * nonce (can be NULL) + * In: msg32: the 32-byte message hash being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp: pointer to a nonce generation function. If NULL, secp256k1_zkp_nonce_function_bipschnorr is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + */ +SECP256K1_API int secp256k1_zkp_schnorrsig_sign( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_schnorrsig *sig, + int *nonce_is_negated, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_zkp_nonce_function noncefp, + void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + +/** Verify a Schnorr signature. + * + * Returns: 1: correct signature + * 0: incorrect or unparseable signature + * Args: ctx: a secp256k1 context object, initialized for verification. + * In: sig: the signature being verified (cannot be NULL) + * msg32: the 32-byte message hash being verified (cannot be NULL) + * pubkey: pointer to a public key to verify with (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_schnorrsig_verify( + const secp256k1_zkp_context* ctx, + const secp256k1_zkp_schnorrsig *sig, + const unsigned char *msg32, + const secp256k1_zkp_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Verifies a set of Schnorr signatures. + * + * Returns 1 if all succeeded, 0 otherwise. In particular, returns 1 if n_sigs is 0. + * + * Args: ctx: a secp256k1 context object, initialized for verification. + * scratch: scratch space used for the multiexponentiation + * In: sig: array of signatures, or NULL if there are no signatures + * msg32: array of messages, or NULL if there are no signatures + * pk: array of public keys, or NULL if there are no signatures + * n_sigs: number of signatures in above arrays. Must be smaller than + * 2^31 and smaller than half the maximum size_t value. Must be 0 + * if above arrays are NULL. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_schnorrsig_verify_batch( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_scratch_space *scratch, + const secp256k1_zkp_schnorrsig *const *sig, + const unsigned char *const *msg32, + const secp256k1_zkp_pubkey *const *pk, + size_t n_sigs +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_surjectionproof.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_surjectionproof.h new file mode 100644 index 00000000..e90c8547 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_surjectionproof.h @@ -0,0 +1,216 @@ +#ifndef _SECP256K1_SURJECTIONPROOF_ +#define _SECP256K1_SURJECTIONPROOF_ + +#include "secp256k1.h" +#include "secp256k1_rangeproof.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Maximum number of inputs that may be given in a surjection proof */ +#define SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS 256 + +/** Number of bytes a serialized surjection proof requires given the + * number of inputs and the number of used inputs. + */ +#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(n_inputs, n_used_inputs) \ + (2 + (n_inputs + 7)/8 + 32 * (1 + (n_used_inputs))) + +/** Maximum number of bytes a serialized surjection proof requires. */ +#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX \ + SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) + +/** Opaque data structure that holds a parsed surjection proof + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. Nor is + * it guaranteed to have any particular size, nor that identical proofs + * will have identical representation. (That is, memcmp may return nonzero + * even for identical proofs.) + * + * To obtain these properties, instead use secp256k1_zkp_surjectionproof_parse + * and secp256k1_zkp_surjectionproof_serialize to encode/decode proofs into a + * well-defined format. + * + * The representation is exposed to allow creation of these objects on the + * stack; please *do not* use these internals directly. + */ +typedef struct { +#ifdef VERIFY + /** Mark whether this proof has gone through `secp256k1_zkp_surjectionproof_initialize` */ + int initialized; +#endif + /** Total number of input asset tags */ + size_t n_inputs; + /** Bitmap of which input tags are used in the surjection proof */ + unsigned char used_inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS / 8]; + /** Borromean signature: e0, scalars */ + unsigned char data[32 * (1 + SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS)]; +} secp256k1_zkp_surjectionproof; + +/** Parse a surjection proof + * + * Returns: 1 when the proof could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: proof: a pointer to a proof object + * In: input: a pointer to the array to parse + * inputlen: length of the array pointed to by input + * + * The proof must consist of: + * - A 2-byte little-endian total input count `n` + * - A ceil(n/8)-byte bitmap indicating which inputs are used. + * - A big-endian 32-byte borromean signature e0 value + * - `m` big-endian 32-byte borromean signature s values, where `m` + * is the number of set bits in the bitmap + */ +SECP256K1_API int secp256k1_zkp_surjectionproof_parse( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_surjectionproof *proof, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a surjection proof + * + * Returns: 1 if enough space was available to serialize, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: output: a pointer to an array to store the serialization + * In/Out: outputlen: a pointer to an integer which is initially set to the + * size of output, and is overwritten with the written + * size. + * In: proof: a pointer to an initialized proof object + * + * See secp256k1_zkp_surjectionproof_parse for details about the encoding. + */ +SECP256K1_API int secp256k1_zkp_surjectionproof_serialize( + const secp256k1_zkp_context* ctx, + unsigned char *output, + size_t *outputlen, + const secp256k1_zkp_surjectionproof *proof +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Data structure that holds a fixed asset tag. + * + * This data type is *not* opaque. It will always be 32 bytes of whatever + * data the API user wants to use as an asset tag. Its contents have no + * semantic meaning to libsecp whatsoever. + */ +typedef struct { + unsigned char data[32]; +} secp256k1_zkp_fixed_asset_tag; + +/** Returns the total number of inputs a proof expects to be over. + * + * Returns: the number of inputs for the given proof + * In: ctx: pointer to a context object + * proof: a pointer to a proof object + */ +SECP256K1_API size_t secp256k1_zkp_surjectionproof_n_total_inputs( + const secp256k1_zkp_context* ctx, + const secp256k1_zkp_surjectionproof* proof +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Returns the actual number of inputs that a proof uses + * + * Returns: the number of inputs for the given proof + * In: ctx: pointer to a context object + * proof: a pointer to a proof object + */ +SECP256K1_API size_t secp256k1_zkp_surjectionproof_n_used_inputs( + const secp256k1_zkp_context* ctx, + const secp256k1_zkp_surjectionproof* proof +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Returns the total size this proof would take, in bytes, when serialized + * + * Returns: the total size + * In: ctx: pointer to a context object + * proof: a pointer to a proof object + */ +SECP256K1_API size_t secp256k1_zkp_surjectionproof_serialized_size( + const secp256k1_zkp_context* ctx, + const secp256k1_zkp_surjectionproof* proof +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Surjection proof initialization function; decides on inputs to use + * Returns 0: inputs could not be selected + * n: inputs were selected after n iterations of random selection + * + * In: ctx: pointer to a context object + * fixed_input_tags: fixed input tags `A_i` for all inputs. (If the fixed tag is not known, + * e.g. in a coinjoin with others' inputs, an ephemeral tag can be given; + * this won't match the output tag but might be used in the anonymity set.) + * n_input_tags: the number of entries in the fixed_input_tags array + * n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set + * fixed_output_tag: fixed output tag + * max_n_iterations: the maximum number of iterations to do before giving up. Because the + * maximum number of inputs (SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) is + * limited to 256 the probability of giving up is smaller than + * (255/256)^(n_input_tags_to_use*max_n_iterations). + * + * random_seed32: a random seed to be used for input selection + * Out: proof: The proof whose bitvector will be initialized. In case of failure, + * the state of the proof is undefined. + * input_index: The index of the actual input that is secretly mapped to the output + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_surjectionproof_initialize( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_surjectionproof* proof, + size_t *input_index, + const secp256k1_zkp_fixed_asset_tag* fixed_input_tags, + const size_t n_input_tags, + const size_t n_input_tags_to_use, + const secp256k1_zkp_fixed_asset_tag* fixed_output_tag, + const size_t n_max_iterations, + const unsigned char *random_seed32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7); + +/** Surjection proof generation function + * Returns 0: proof could not be created + * 1: proof was successfully created + * + * In: ctx: pointer to a context object, initialized for signing and verification + * ephemeral_input_tags: the ephemeral asset tag of all inputs + * n_ephemeral_input_tags: the number of entries in the ephemeral_input_tags array + * ephemeral_output_tag: the ephemeral asset tag of the output + * input_index: the index of the input that actually maps to the output + * input_blinding_key: the blinding key of the input + * output_blinding_key: the blinding key of the output + * In/Out: proof: The produced surjection proof. Must have already gone through `secp256k1_zkp_surjectionproof_initialize` + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_zkp_surjectionproof_generate( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_surjectionproof* proof, + const secp256k1_zkp_generator* ephemeral_input_tags, + size_t n_ephemeral_input_tags, + const secp256k1_zkp_generator* ephemeral_output_tag, + size_t input_index, + const unsigned char *input_blinding_key, + const unsigned char *output_blinding_key +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8); + + +/** Surjection proof verification function + * Returns 0: proof was invalid + * 1: proof was valid + * + * In: ctx: pointer to a context object, initialized for signing and verification + * proof: proof to be verified + * ephemeral_input_tags: the ephemeral asset tag of all inputs + * n_ephemeral_input_tags: the number of entries in the ephemeral_input_tags array + * ephemeral_output_tag: the ephemeral asset tag of the output + */ +SECP256K1_API int secp256k1_zkp_surjectionproof_verify( + const secp256k1_zkp_context* ctx, + const secp256k1_zkp_surjectionproof* proof, + const secp256k1_zkp_generator* ephemeral_input_tags, + size_t n_ephemeral_input_tags, + const secp256k1_zkp_generator* ephemeral_output_tag +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_whitelist.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_whitelist.h new file mode 100644 index 00000000..31cd064f --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/include/secp256k1_whitelist.h @@ -0,0 +1,152 @@ +/********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_WHITELIST_ +#define _SECP256K1_WHITELIST_ + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SECP256K1_WHITELIST_MAX_N_KEYS 256 + +/** Opaque data structure that holds a parsed whitelist proof + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. Nor is + * it guaranteed to have any particular size, nor that identical signatures + * will have identical representation. (That is, memcmp may return nonzero + * even for identical signatures.) + * + * To obtain these properties, instead use secp256k1_zkp_whitelist_signature_parse + * and secp256k1_zkp_whitelist_signature_serialize to encode/decode signatures + * into a well-defined format. + * + * The representation is exposed to allow creation of these objects on the + * stack; please *do not* use these internals directly. To learn the number + * of keys for a signature, use `secp256k1_zkp_whitelist_signature_n_keys`. + */ +typedef struct { + size_t n_keys; + /* e0, scalars */ + unsigned char data[32 * (1 + SECP256K1_WHITELIST_MAX_N_KEYS)]; +} secp256k1_zkp_whitelist_signature; + +/** Parse a whitelist signature + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input: a pointer to the array to parse + * input_len: the length of the above array + * + * The signature must consist of a 1-byte n_keys value, followed by a 32-byte + * big endian e0 value, followed by n_keys many 32-byte big endian s values. + * If n_keys falls outside of [0..SECP256K1_WHITELIST_MAX_N_KEYS] the encoding + * is invalid. + * + * The total length of the input array must therefore be 33 + 32 * n_keys. + * If the length `input_len` does not match this value, parsing will fail. + * + * After the call, sig will always be initialized. If parsing failed or any + * scalar values overflow or are zero, the resulting sig value is guaranteed + * to fail validation for any set of keys. + */ +SECP256K1_API int secp256k1_zkp_whitelist_signature_parse( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_whitelist_signature *sig, + const unsigned char *input, + size_t input_len +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Returns the number of keys a signature expects to have. + * + * Returns: the number of keys for the given signature + * In: sig: a pointer to a signature object + */ +SECP256K1_API size_t secp256k1_zkp_whitelist_signature_n_keys( + const secp256k1_zkp_whitelist_signature *sig +) SECP256K1_ARG_NONNULL(1); + +/** Serialize a whitelist signature + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: output64: a pointer to an array to store the serialization + * In/Out: output_len: length of the above array, updated with the actual serialized length + * In: sig: a pointer to an initialized signature object + * + * See secp256k1_zkp_whitelist_signature_parse for details about the encoding. + */ +SECP256K1_API int secp256k1_zkp_whitelist_signature_serialize( + const secp256k1_zkp_context* ctx, + unsigned char *output, + size_t *output_len, + const secp256k1_zkp_whitelist_signature *sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Compute a whitelist signature + * Returns 1: signature was successfully created + * 0: signature was not successfully created + * In: ctx: pointer to a context object, initialized for signing and verification + * online_pubkeys: list of all online pubkeys + * offline_pubkeys: list of all offline pubkeys + * n_keys: the number of entries in each of the above two arrays + * sub_pubkey: the key to be whitelisted + * online_seckey: the secret key to the signer's online pubkey + * summed_seckey: the secret key to the sum of (whitelisted key, signer's offline pubkey) + * index: the signer's index in the lists of keys + * noncefp:pointer to a nonce generation function. If NULL, secp256k1_zkp_nonce_function_default is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + * Out: sig: The produced signature. + * + * The signatures are of the list of all passed pubkeys in the order + * ( whitelist, online_1, offline_1, online_2, offline_2, ... ) + * The verification key list consists of + * online_i + H(offline_i + whitelist)(offline_i + whitelist) + * for each public key pair (offline_i, offline_i). Here H means sha256 of the + * compressed serialization of the key. + */ +SECP256K1_API int secp256k1_zkp_whitelist_sign( + const secp256k1_zkp_context* ctx, + secp256k1_zkp_whitelist_signature *sig, + const secp256k1_zkp_pubkey *online_pubkeys, + const secp256k1_zkp_pubkey *offline_pubkeys, + const size_t n_keys, + const secp256k1_zkp_pubkey *sub_pubkey, + const unsigned char *online_seckey, + const unsigned char *summed_seckey, + const size_t index, + secp256k1_zkp_nonce_function noncefp, + const void *noncedata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8); + +/** Verify a whitelist signature + * Returns 1: signature is valid + * 0: signature is not valid + * In: ctx: pointer to a context object, initialized for signing and verification + * sig: the signature to be verified + * online_pubkeys: list of all online pubkeys + * offline_pubkeys: list of all offline pubkeys + * n_keys: the number of entries in each of the above two arrays + * sub_pubkey: the key to be whitelisted + */ +SECP256K1_API int secp256k1_zkp_whitelist_verify( + const secp256k1_zkp_context* ctx, + const secp256k1_zkp_whitelist_signature *sig, + const secp256k1_zkp_pubkey *online_pubkeys, + const secp256k1_zkp_pubkey *offline_pubkeys, + const size_t n_keys, + const secp256k1_zkp_pubkey *sub_pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/libsecp256k1.pc.in b/secp256k1-zkp-sys/depend/secp256k1-zkp/libsecp256k1.pc.in new file mode 100644 index 00000000..a0d006f1 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/libsecp256k1.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libsecp256k1 +Description: Optimized C library for EC operations on curve secp256k1 +URL: https://github.com/bitcoin-core/secp256k1 +Version: @PACKAGE_VERSION@ +Cflags: -I${includedir} +Libs.private: @SECP_LIBS@ +Libs: -L${libdir} -lsecp256k1 + diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/obj/.gitignore b/secp256k1-zkp-sys/depend/secp256k1-zkp/obj/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/sage/group_prover.sage b/secp256k1-zkp-sys/depend/secp256k1-zkp/sage/group_prover.sage new file mode 100644 index 00000000..8521f079 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/sage/group_prover.sage @@ -0,0 +1,322 @@ +# This code supports verifying group implementations which have branches +# or conditional statements (like cmovs), by allowing each execution path +# to independently set assumptions on input or intermediary variables. +# +# The general approach is: +# * A constraint is a tuple of two sets of symbolic expressions: +# the first of which are required to evaluate to zero, the second of which +# are required to evaluate to nonzero. +# - A constraint is said to be conflicting if any of its nonzero expressions +# is in the ideal with basis the zero expressions (in other words: when the +# zero expressions imply that one of the nonzero expressions are zero). +# * There is a list of laws that describe the intended behaviour, including +# laws for addition and doubling. Each law is called with the symbolic point +# coordinates as arguments, and returns: +# - A constraint describing the assumptions under which it is applicable, +# called "assumeLaw" +# - A constraint describing the requirements of the law, called "require" +# * Implementations are transliterated into functions that operate as well on +# algebraic input points, and are called once per combination of branches +# executed. Each execution returns: +# - A constraint describing the assumptions this implementation requires +# (such as Z1=1), called "assumeFormula" +# - A constraint describing the assumptions this specific branch requires, +# but which is by construction guaranteed to cover the entire space by +# merging the results from all branches, called "assumeBranch" +# - The result of the computation +# * All combinations of laws with implementation branches are tried, and: +# - If the combination of assumeLaw, assumeFormula, and assumeBranch results +# in a conflict, it means this law does not apply to this branch, and it is +# skipped. +# - For others, we try to prove the require constraints hold, assuming the +# information in assumeLaw + assumeFormula + assumeBranch, and if this does +# not succeed, we fail. +# + To prove an expression is zero, we check whether it belongs to the +# ideal with the assumed zero expressions as basis. This test is exact. +# + To prove an expression is nonzero, we check whether each of its +# factors is contained in the set of nonzero assumptions' factors. +# This test is not exact, so various combinations of original and +# reduced expressions' factors are tried. +# - If we succeed, we print out the assumptions from assumeFormula that +# weren't implied by assumeLaw already. Those from assumeBranch are skipped, +# as we assume that all constraints in it are complementary with each other. +# +# Based on the sage verification scripts used in the Explicit-Formulas Database +# by Tanja Lange and others, see http://hyperelliptic.org/EFD + +class fastfrac: + """Fractions over rings.""" + + def __init__(self,R,top,bot=1): + """Construct a fractional, given a ring, a numerator, and denominator.""" + self.R = R + if parent(top) == ZZ or parent(top) == R: + self.top = R(top) + self.bot = R(bot) + elif top.__class__ == fastfrac: + self.top = top.top + self.bot = top.bot * bot + else: + self.top = R(numerator(top)) + self.bot = R(denominator(top)) * bot + + def iszero(self,I): + """Return whether this fraction is zero given an ideal.""" + return self.top in I and self.bot not in I + + def reduce(self,assumeZero): + zero = self.R.ideal(map(numerator, assumeZero)) + return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot)) + + def __add__(self,other): + """Add two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top + self.bot * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot) + return NotImplemented + + def __sub__(self,other): + """Subtract two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top - self.bot * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot) + return NotImplemented + + def __neg__(self): + """Return the negation of a fraction.""" + return fastfrac(self.R,-self.top,self.bot) + + def __mul__(self,other): + """Multiply two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.top,self.bot * other.bot) + return NotImplemented + + def __rmul__(self,other): + """Multiply something else with a fraction.""" + return self.__mul__(other) + + def __div__(self,other): + """Divide two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top,self.bot * other) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot,self.bot * other.top) + return NotImplemented + + def __pow__(self,other): + """Compute a power of a fraction.""" + if parent(other) == ZZ: + if other < 0: + # Negative powers require flipping top and bottom + return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other)) + else: + return fastfrac(self.R,self.top ^ other,self.bot ^ other) + return NotImplemented + + def __str__(self): + return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))" + def __repr__(self): + return "%s" % self + + def numerator(self): + return self.top + +class constraints: + """A set of constraints, consisting of zero and nonzero expressions. + + Constraints can either be used to express knowledge or a requirement. + + Both the fields zero and nonzero are maps from expressions to description + strings. The expressions that are the keys in zero are required to be zero, + and the expressions that are the keys in nonzero are required to be nonzero. + + Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in + nonzero could be multiplied into a single key. This is often much less + efficient to work with though, so we keep them separate inside the + constraints. This allows higher-level code to do fast checks on the individual + nonzero elements, or combine them if needed for stronger checks. + + We can't multiply the different zero elements, as it would suffice for one of + the factors to be zero, instead of all of them. Instead, the zero elements are + typically combined into an ideal first. + """ + + def __init__(self, **kwargs): + if 'zero' in kwargs: + self.zero = dict(kwargs['zero']) + else: + self.zero = dict() + if 'nonzero' in kwargs: + self.nonzero = dict(kwargs['nonzero']) + else: + self.nonzero = dict() + + def negate(self): + return constraints(zero=self.nonzero, nonzero=self.zero) + + def __add__(self, other): + zero = self.zero.copy() + zero.update(other.zero) + nonzero = self.nonzero.copy() + nonzero.update(other.nonzero) + return constraints(zero=zero, nonzero=nonzero) + + def __str__(self): + return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero) + + def __repr__(self): + return "%s" % self + + +def conflicts(R, con): + """Check whether any of the passed non-zero assumptions is implied by the zero assumptions""" + zero = R.ideal(map(numerator, con.zero)) + if 1 in zero: + return True + # First a cheap check whether any of the individual nonzero terms conflict on + # their own. + for nonzero in con.nonzero: + if nonzero.iszero(zero): + return True + # It can be the case that entries in the nonzero set do not individually + # conflict with the zero set, but their combination does. For example, knowing + # that either x or y is zero is equivalent to having x*y in the zero set. + # Having x or y individually in the nonzero set is not a conflict, but both + # simultaneously is, so that is the right thing to check for. + if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero): + return True + return False + + +def get_nonzero_set(R, assume): + """Calculate a simple set of nonzero expressions""" + zero = R.ideal(map(numerator, assume.zero)) + nonzero = set() + for nz in map(numerator, assume.nonzero): + for (f,n) in nz.factor(): + nonzero.add(f) + rnz = zero.reduce(nz) + for (f,n) in rnz.factor(): + nonzero.add(f) + return nonzero + + +def prove_nonzero(R, exprs, assume): + """Check whether an expression is provably nonzero, given assumptions""" + zero = R.ideal(map(numerator, assume.zero)) + nonzero = get_nonzero_set(R, assume) + expl = set() + ok = True + for expr in exprs: + if numerator(expr) in zero: + return (False, [exprs[expr]]) + allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1) + for (f, n) in allexprs.factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for (f, n) in zero.reduce(numerator(allexprs)).factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for expr in exprs: + for (f,n) in numerator(expr).factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for expr in exprs: + for (f,n) in zero.reduce(numerator(expr)).factor(): + if f not in nonzero: + expl.add(exprs[expr]) + if expl: + return (False, list(expl)) + else: + return (True, None) + + +def prove_zero(R, exprs, assume): + """Check whether all of the passed expressions are provably zero, given assumptions""" + r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume) + if not r: + return (False, map(lambda x: "Possibly zero denominator: %s" % x, e)) + zero = R.ideal(map(numerator, assume.zero)) + nonzero = prod(x for x in assume.nonzero) + expl = [] + for expr in exprs: + if not expr.iszero(zero): + expl.append(exprs[expr]) + if not expl: + return (True, None) + return (False, expl) + + +def describe_extra(R, assume, assumeExtra): + """Describe what assumptions are added, given existing assumptions""" + zerox = assume.zero.copy() + zerox.update(assumeExtra.zero) + zero = R.ideal(map(numerator, assume.zero)) + zeroextra = R.ideal(map(numerator, zerox)) + nonzero = get_nonzero_set(R, assume) + ret = set() + # Iterate over the extra zero expressions + for base in assumeExtra.zero: + if base not in zero: + add = [] + for (f, n) in numerator(base).factor(): + if f not in nonzero: + add += ["%s" % f] + if add: + ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base]) + # Iterate over the extra nonzero expressions + for nz in assumeExtra.nonzero: + nzr = zeroextra.reduce(numerator(nz)) + if nzr not in zeroextra: + for (f,n) in nzr.factor(): + if zeroextra.reduce(f) not in nonzero: + ret.add("%s != 0" % zeroextra.reduce(f)) + return ", ".join(x for x in ret) + + +def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require): + """Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions""" + assume = assumeLaw + assumeAssert + assumeBranch + + if conflicts(R, assume): + # This formula does not apply + return None + + describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert) + + ok, msg = prove_zero(R, require.zero, assume) + if not ok: + return "FAIL, %s fails (assuming %s)" % (str(msg), describe) + + res, expl = prove_nonzero(R, require.nonzero, assume) + if not res: + return "FAIL, %s fails (assuming %s)" % (str(expl), describe) + + if describe != "": + return "OK (assuming %s)" % describe + else: + return "OK" + + +def concrete_verify(c): + for k in c.zero: + if k != 0: + return (False, c.zero[k]) + for k in c.nonzero: + if k == 0: + return (False, c.nonzero[k]) + return (True, None) diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/sage/secp256k1.sage b/secp256k1-zkp-sys/depend/secp256k1-zkp/sage/secp256k1.sage new file mode 100644 index 00000000..b52155c2 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/sage/secp256k1.sage @@ -0,0 +1,306 @@ +# Test libsecp256k1' group operation implementations using prover.sage + +import sys + +load("group_prover.sage") +load("weierstrass_prover.sage") + +def formula_secp256k1_zkp_gej_double_var(a): + """libsecp256k1's secp256k1_zkp_gej_double_var, used by various addition functions""" + rz = a.Z * a.Y + rz = rz * 2 + t1 = a.X^2 + t1 = t1 * 3 + t2 = t1^2 + t3 = a.Y^2 + t3 = t3 * 2 + t4 = t3^2 + t4 = t4 * 2 + t3 = t3 * a.X + rx = t3 + rx = rx * 4 + rx = -rx + rx = rx + t2 + t2 = -t2 + t3 = t3 * 6 + t3 = t3 + t2 + ry = t1 * t3 + t2 = -t4 + ry = ry + t2 + return jacobianpoint(rx, ry, rz) + +def formula_secp256k1_zkp_gej_add_var(branch, a, b): + """libsecp256k1's secp256k1_zkp_gej_add_var""" + if branch == 0: + return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z22 = b.Z^2 + z12 = a.Z^2 + u1 = a.X * z22 + u2 = b.X * z12 + s1 = a.Y * z22 + s1 = s1 * b.Z + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if branch == 2: + r = formula_secp256k1_zkp_gej_double_var(a) + return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r) + if branch == 3: + return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h2 * h + h = h * b.Z + rz = a.Z * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_zkp_gej_add_ge_var(branch, a, b): + """libsecp256k1's secp256k1_zkp_gej_add_ge_var, which assume bz==1""" + if branch == 0: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z12 = a.Z^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if (branch == 2): + r = formula_secp256k1_zkp_gej_double_var(a) + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if (branch == 3): + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h * h2 + rz = a.Z * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_zkp_gej_add_zinv_var(branch, a, b): + """libsecp256k1's secp256k1_zkp_gej_add_zinv_var""" + bzinv = b.Z^(-1) + if branch == 0: + return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a) + if branch == 1: + bzinv2 = bzinv^2 + bzinv3 = bzinv2 * bzinv + rx = b.X * bzinv2 + ry = b.Y * bzinv3 + rz = 1 + return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz)) + azz = a.Z * bzinv + z12 = azz^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * azz + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if branch == 2: + r = formula_secp256k1_zkp_gej_double_var(a) + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if branch == 3: + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h * h2 + rz = a.Z + rz = rz * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_zkp_gej_add_ge(branch, a, b): + """libsecp256k1's secp256k1_zkp_gej_add_ge""" + zeroes = {} + nonzeroes = {} + a_infinity = False + if (branch & 4) != 0: + nonzeroes.update({a.Infinity : 'a_infinite'}) + a_infinity = True + else: + zeroes.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + rr = t^2 + m_alt = -u2 + tt = u1 * m_alt + rr = rr + tt + degenerate = (branch & 3) == 3 + if (branch & 1) != 0: + zeroes.update({m : 'm_zero'}) + else: + nonzeroes.update({m : 'm_nonzero'}) + if (branch & 2) != 0: + zeroes.update({rr : 'rr_zero'}) + else: + nonzeroes.update({rr : 'rr_nonzero'}) + rr_alt = s1 + rr_alt = rr_alt * 2 + m_alt = m_alt + u1 + if not degenerate: + rr_alt = rr + m_alt = m + n = m_alt^2 + q = n * t + n = n^2 + if degenerate: + n = m + t = rr_alt^2 + rz = a.Z * m_alt + infinity = False + if (branch & 8) != 0: + if not a_infinity: + infinity = True + zeroes.update({rz : 'r.z=0'}) + else: + nonzeroes.update({rz : 'r.z!=0'}) + rz = rz * 2 + q = -q + t = t + q + rx = t + t = t * 2 + t = t + q + t = t * rr_alt + t = t + n + ry = -t + rx = rx * 4 + ry = ry * 4 + if a_infinity: + rx = b.X + ry = b.Y + rz = 1 + if infinity: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_zkp_gej_add_ge_old(branch, a, b): + """libsecp256k1's old secp256k1_zkp_gej_add_ge, which fails when ay+by=0 but ax!=bx""" + a_infinity = (branch & 1) != 0 + zero = {} + nonzero = {} + if a_infinity: + nonzero.update({a.Infinity : 'a_infinite'}) + else: + zero.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + z = a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + n = m^2 + q = n * t + n = n^2 + rr = t^2 + t = u1 * u2 + t = -t + rr = rr + t + t = rr^2 + rz = m * z + infinity = False + if (branch & 2) != 0: + if not a_infinity: + infinity = True + else: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity()) + zero.update({rz : 'r.z=0'}) + else: + nonzero.update({rz : 'r.z!=0'}) + rz = rz * (0 if a_infinity else 2) + rx = t + q = -q + rx = rx + q + q = q * 3 + t = t * 2 + t = t + q + t = t * rr + t = t + n + ry = -t + rx = rx * (0 if a_infinity else 4) + ry = ry * (0 if a_infinity else 4) + t = b.X + t = t * (1 if a_infinity else 0) + rx = rx + t + t = b.Y + t = t * (1 if a_infinity else 0) + ry = ry + t + t = (1 if a_infinity else 0) + rz = rz + t + if infinity: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity()) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz)) + +if __name__ == "__main__": + check_symbolic_jacobian_weierstrass("secp256k1_zkp_gej_add_var", 0, 7, 5, formula_secp256k1_zkp_gej_add_var) + check_symbolic_jacobian_weierstrass("secp256k1_zkp_gej_add_ge_var", 0, 7, 5, formula_secp256k1_zkp_gej_add_ge_var) + check_symbolic_jacobian_weierstrass("secp256k1_zkp_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_zkp_gej_add_zinv_var) + check_symbolic_jacobian_weierstrass("secp256k1_zkp_gej_add_ge", 0, 7, 16, formula_secp256k1_zkp_gej_add_ge) + check_symbolic_jacobian_weierstrass("secp256k1_zkp_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_zkp_gej_add_ge_old) + + if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": + check_exhaustive_jacobian_weierstrass("secp256k1_zkp_gej_add_var", 0, 7, 5, formula_secp256k1_zkp_gej_add_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_zkp_gej_add_ge_var", 0, 7, 5, formula_secp256k1_zkp_gej_add_ge_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_zkp_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_zkp_gej_add_zinv_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_zkp_gej_add_ge", 0, 7, 16, formula_secp256k1_zkp_gej_add_ge, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_zkp_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_zkp_gej_add_ge_old, 43) diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/sage/shallue_van_de_woestijne.sage b/secp256k1-zkp-sys/depend/secp256k1-zkp/sage/shallue_van_de_woestijne.sage new file mode 100644 index 00000000..1cc97b65 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/sage/shallue_van_de_woestijne.sage @@ -0,0 +1,51 @@ + +### http://www.di.ens.fr/~fouque/pub/latincrypt12.pdf + +# Parameters for secp256k1 +p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F +a = 0 +b = 7 +F = FiniteField (p) +C = EllipticCurve ([F(a), F(b)]) + +def svdw(t): + sqrt_neg_3 = F(-3).nth_root(2) + + ## Compute candidate x values + w = sqrt_neg_3 * t / (1 + b + t^2) + x = [ F(0), F(0), F(0) ] + x[0] = (-1 + sqrt_neg_3) / 2 - t * w + x[1] = -1 - x[0] + x[2] = 1 + 1 / w^2 + + print + print "On %2d" % t + print " x1 %064x" % x[0] + print " x2 %064x" % x[1] + print " x3 %064x" % x[2] + + ## Select which to use + alph = jacobi_symbol(x[0]^3 + b, p) + beta = jacobi_symbol(x[1]^3 + b, p) + if alph == 1 and beta == 1: + i = 0 + elif alph == 1 and beta == -1: + i = 0 + elif alph == -1 and beta == 1: + i = 1 + elif alph == -1 and beta == -1: + i = 2 + else: + print "Help! I don't understand Python!" + + ## Expand to full point + sign = 1 - 2 * (int(F(t)) % 2) + ret_x = x[i] + ret_y = sign * F(x[i]^3 + b).nth_root(2) + return C.point((ret_x, ret_y)) + + +## main +for i in range(1, 11): + res = svdw(i) + print "Result: %064x %064x" % res.xy() diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/sage/weierstrass_prover.sage b/secp256k1-zkp-sys/depend/secp256k1-zkp/sage/weierstrass_prover.sage new file mode 100644 index 00000000..03ef2ec9 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/sage/weierstrass_prover.sage @@ -0,0 +1,264 @@ +# Prover implementation for Weierstrass curves of the form +# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws +# operating on affine and Jacobian coordinates, including the point at infinity +# represented by a 4th variable in coordinates. + +load("group_prover.sage") + + +class affinepoint: + def __init__(self, x, y, infinity=0): + self.x = x + self.y = y + self.infinity = infinity + def __str__(self): + return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity) + + +class jacobianpoint: + def __init__(self, x, y, z, infinity=0): + self.X = x + self.Y = y + self.Z = z + self.Infinity = infinity + def __str__(self): + return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity) + + +def point_at_infinity(): + return jacobianpoint(1, 1, 1, 1) + + +def negate(p): + if p.__class__ == affinepoint: + return affinepoint(p.x, -p.y) + if p.__class__ == jacobianpoint: + return jacobianpoint(p.X, -p.Y, p.Z) + assert(False) + + +def on_weierstrass_curve(A, B, p): + """Return a set of zero-expressions for an affine point to be on the curve""" + return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'}) + + +def tangential_to_weierstrass_curve(A, B, p12, p3): + """Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)""" + return constraints(zero={ + (p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve' + }) + + +def colinear(p1, p2, p3): + """Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear""" + return constraints(zero={ + (p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1', + (p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2', + (p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3' + }) + + +def good_affine_point(p): + return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'}) + + +def good_jacobian_point(p): + return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'}) + + +def good_point(p): + return constraints(nonzero={p.Z^6 : 'nonzero_X'}) + + +def finite(p, *affine_fns): + con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'}) + if p.Z != 0: + return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con) + else: + return con + +def infinite(p): + return constraints(nonzero={p.Infinity : 'infinite_point'}) + + +def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC): + """Check whether the passed set of coordinates is a valid Jacobian add, given assumptions""" + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(nonzero={pa.x - pb.x : 'different_x'})) + require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + + colinear(pa, pb, negate(pc)))) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC): + """Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions""" + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'})) + require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + + tangential_to_weierstrass_curve(A, B, pa, negate(pc)))) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'})) + require = infinite(pC) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pb) + + infinite(pA) + + finite(pB)) + require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'})) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + infinite(pB) + + finite(pA)) + require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'})) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + infinite(pA) + + infinite(pB)) + require = infinite(pC) + return (assumeLaw, require) + + +laws_jacobian_weierstrass = { + 'add': law_jacobian_weierstrass_add, + 'double': law_jacobian_weierstrass_double, + 'add_opposite': law_jacobian_weierstrass_add_opposites, + 'add_infinite_a': law_jacobian_weierstrass_add_infinite_a, + 'add_infinite_b': law_jacobian_weierstrass_add_infinite_b, + 'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab +} + + +def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p): + """Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field""" + F = Integers(p) + print "Formula %s on Z%i:" % (name, p) + points = [] + for x in xrange(0, p): + for y in xrange(0, p): + point = affinepoint(F(x), F(y)) + r, e = concrete_verify(on_weierstrass_curve(A, B, point)) + if r: + points.append(point) + + for za in xrange(1, p): + for zb in xrange(1, p): + for pa in points: + for pb in points: + for ia in xrange(2): + for ib in xrange(2): + pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia) + pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib) + for branch in xrange(0, branches): + assumeAssert, assumeBranch, pC = formula(branch, pA, pB) + pC.X = F(pC.X) + pC.Y = F(pC.Y) + pC.Z = F(pC.Z) + pC.Infinity = F(pC.Infinity) + r, e = concrete_verify(assumeAssert + assumeBranch) + if r: + match = False + for key in laws_jacobian_weierstrass: + assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC) + r, e = concrete_verify(assumeLaw) + if r: + if match: + print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity) + else: + match = True + r, e = concrete_verify(require) + if not r: + print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e) + print + + +def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC): + assumeLaw, require = f(A, B, pa, pb, pA, pB, pC) + return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require) + +def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula): + """Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically""" + R. = PolynomialRing(QQ,8,order='invlex') + lift = lambda x: fastfrac(R,x) + ax = lift(ax) + ay = lift(ay) + Az = lift(Az) + bx = lift(bx) + by = lift(by) + Bz = lift(Bz) + Ai = lift(Ai) + Bi = lift(Bi) + + pa = affinepoint(ax, ay, Ai) + pb = affinepoint(bx, by, Bi) + pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai) + pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi) + + res = {} + + for key in laws_jacobian_weierstrass: + res[key] = [] + + print ("Formula " + name + ":") + count = 0 + for branch in xrange(branches): + assumeFormula, assumeBranch, pC = formula(branch, pA, pB) + pC.X = lift(pC.X) + pC.Y = lift(pC.Y) + pC.Z = lift(pC.Z) + pC.Infinity = lift(pC.Infinity) + + for key in laws_jacobian_weierstrass: + res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch)) + + for key in res: + print " %s:" % key + val = res[key] + for x in val: + if x[0] is not None: + print " branch %i: %s" % (x[1], x[0]) + + print diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/asm/field_10x26_arm.s b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/asm/field_10x26_arm.s new file mode 100644 index 00000000..7c282d73 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/asm/field_10x26_arm.s @@ -0,0 +1,919 @@ +@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm: +/********************************************************************** + * Copyright (c) 2014 Wladimir J. van der Laan * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +/* +ARM implementation of field_10x26 inner loops. + +Note: + +- To avoid unnecessary loads and make use of available registers, two + 'passes' have every time been interleaved, with the odd passes accumulating c' and d' + which will be added to c and d respectively in the even passes + +*/ + + .syntax unified + .arch armv7-a + @ eabi attributes - see readelf -A + .eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes + .eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no + .eabi_attribute 10, 0 @ Tag_FP_arch = none + .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte + .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP + .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Aggressive Speed + .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6 + .text + + @ Field constants + .set field_R0, 0x3d10 + .set field_R1, 0x400 + .set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff + + .align 2 + .global secp256k1_zkp_fe_mul_inner + .type secp256k1_zkp_fe_mul_inner, %function + @ Arguments: + @ r0 r Restrict: can overlap with a, not with b + @ r1 a + @ r2 b + @ Stack (total 4+10*4 = 44) + @ sp + #0 saved 'r' pointer + @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 +secp256k1_zkp_fe_mul_inner: + stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} + sub sp, sp, #48 @ frame=44 + alignment + str r0, [sp, #0] @ save result address, we need it only at the end + + /****************************************** + * Main computation code. + ****************************************** + + Allocation: + r0,r14,r7,r8 scratch + r1 a (pointer) + r2 b (pointer) + r3:r4 c + r5:r6 d + r11:r12 c' + r9:r10 d' + + Note: do not write to r[] here, it may overlap with a[] + */ + + /* A - interleaved with B */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #9*4] @ b[9] + ldr r0, [r1, #1*4] @ a[1] + umull r5, r6, r7, r8 @ d = a[0] * b[9] + ldr r14, [r2, #8*4] @ b[8] + umull r9, r10, r0, r8 @ d' = a[1] * b[9] + ldr r7, [r1, #2*4] @ a[2] + umlal r5, r6, r0, r14 @ d += a[1] * b[8] + ldr r8, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r14 @ d' += a[2] * b[8] + ldr r0, [r1, #3*4] @ a[3] + umlal r5, r6, r7, r8 @ d += a[2] * b[7] + ldr r14, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r8 @ d' += a[3] * b[7] + ldr r7, [r1, #4*4] @ a[4] + umlal r5, r6, r0, r14 @ d += a[3] * b[6] + ldr r8, [r2, #5*4] @ b[5] + umlal r9, r10, r7, r14 @ d' += a[4] * b[6] + ldr r0, [r1, #5*4] @ a[5] + umlal r5, r6, r7, r8 @ d += a[4] * b[5] + ldr r14, [r2, #4*4] @ b[4] + umlal r9, r10, r0, r8 @ d' += a[5] * b[5] + ldr r7, [r1, #6*4] @ a[6] + umlal r5, r6, r0, r14 @ d += a[5] * b[4] + ldr r8, [r2, #3*4] @ b[3] + umlal r9, r10, r7, r14 @ d' += a[6] * b[4] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r8 @ d += a[6] * b[3] + ldr r14, [r2, #2*4] @ b[2] + umlal r9, r10, r0, r8 @ d' += a[7] * b[3] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r14 @ d += a[7] * b[2] + ldr r8, [r2, #1*4] @ b[1] + umlal r9, r10, r7, r14 @ d' += a[8] * b[2] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r8 @ d += a[8] * b[1] + ldr r14, [r2, #0*4] @ b[0] + umlal r9, r10, r0, r8 @ d' += a[9] * b[1] + ldr r7, [r1, #0*4] @ a[0] + umlal r5, r6, r0, r14 @ d += a[9] * b[0] + @ r7,r14 used in B + + bic r0, r5, field_not_M @ t9 = d & M + str r0, [sp, #4 + 4*9] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + /* B */ + umull r3, r4, r7, r14 @ c = a[0] * b[0] + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u0 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u0 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t0 = c & M + str r14, [sp, #4 + 0*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u0 * R1 + umlal r3, r4, r0, r14 + + /* C - interleaved with D */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #2*4] @ b[2] + ldr r14, [r2, #1*4] @ b[1] + umull r11, r12, r7, r8 @ c' = a[0] * b[2] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[1] * b[1] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[2] * b[0] + ldr r0, [r1, #3*4] @ a[3] + umlal r5, r6, r7, r14 @ d += a[2] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[3] * b[9] + ldr r7, [r1, #4*4] @ a[4] + umlal r5, r6, r0, r8 @ d += a[3] * b[8] + ldr r14, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r8 @ d' += a[4] * b[8] + ldr r0, [r1, #5*4] @ a[5] + umlal r5, r6, r7, r14 @ d += a[4] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r14 @ d' += a[5] * b[7] + ldr r7, [r1, #6*4] @ a[6] + umlal r5, r6, r0, r8 @ d += a[5] * b[6] + ldr r14, [r2, #5*4] @ b[5] + umlal r9, r10, r7, r8 @ d' += a[6] * b[6] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r14 @ d += a[6] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r9, r10, r0, r14 @ d' += a[7] * b[5] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r8 @ d += a[7] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r9, r10, r7, r8 @ d' += a[8] * b[4] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r9, r10, r0, r14 @ d' += a[9] * b[3] + umlal r5, r6, r0, r8 @ d += a[9] * b[2] + + bic r0, r5, field_not_M @ u1 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u1 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t1 = c & M + str r14, [sp, #4 + 1*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u1 * R1 + umlal r3, r4, r0, r14 + + /* D */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u2 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u2 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t2 = c & M + str r14, [sp, #4 + 2*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u2 * R1 + umlal r3, r4, r0, r14 + + /* E - interleaved with F */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #4*4] @ b[4] + umull r11, r12, r7, r8 @ c' = a[0] * b[4] + ldr r8, [r2, #3*4] @ b[3] + umlal r3, r4, r7, r8 @ c += a[0] * b[3] + ldr r7, [r1, #1*4] @ a[1] + umlal r11, r12, r7, r8 @ c' += a[1] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r3, r4, r7, r8 @ c += a[1] * b[2] + ldr r7, [r1, #2*4] @ a[2] + umlal r11, r12, r7, r8 @ c' += a[2] * b[2] + ldr r8, [r2, #1*4] @ b[1] + umlal r3, r4, r7, r8 @ c += a[2] * b[1] + ldr r7, [r1, #3*4] @ a[3] + umlal r11, r12, r7, r8 @ c' += a[3] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r3, r4, r7, r8 @ c += a[3] * b[0] + ldr r7, [r1, #4*4] @ a[4] + umlal r11, r12, r7, r8 @ c' += a[4] * b[0] + ldr r8, [r2, #9*4] @ b[9] + umlal r5, r6, r7, r8 @ d += a[4] * b[9] + ldr r7, [r1, #5*4] @ a[5] + umull r9, r10, r7, r8 @ d' = a[5] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umlal r5, r6, r7, r8 @ d += a[5] * b[8] + ldr r7, [r1, #6*4] @ a[6] + umlal r9, r10, r7, r8 @ d' += a[6] * b[8] + ldr r8, [r2, #7*4] @ b[7] + umlal r5, r6, r7, r8 @ d += a[6] * b[7] + ldr r7, [r1, #7*4] @ a[7] + umlal r9, r10, r7, r8 @ d' += a[7] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r5, r6, r7, r8 @ d += a[7] * b[6] + ldr r7, [r1, #8*4] @ a[8] + umlal r9, r10, r7, r8 @ d' += a[8] * b[6] + ldr r8, [r2, #5*4] @ b[5] + umlal r5, r6, r7, r8 @ d += a[8] * b[5] + ldr r7, [r1, #9*4] @ a[9] + umlal r9, r10, r7, r8 @ d' += a[9] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r5, r6, r7, r8 @ d += a[9] * b[4] + + bic r0, r5, field_not_M @ u3 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u3 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t3 = c & M + str r14, [sp, #4 + 3*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u3 * R1 + umlal r3, r4, r0, r14 + + /* F */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u4 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u4 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t4 = c & M + str r14, [sp, #4 + 4*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u4 * R1 + umlal r3, r4, r0, r14 + + /* G - interleaved with H */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #6*4] @ b[6] + ldr r14, [r2, #5*4] @ b[5] + umull r11, r12, r7, r8 @ c' = a[0] * b[6] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r11, r12, r0, r14 @ c' += a[1] * b[5] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r11, r12, r7, r8 @ c' += a[2] * b[4] + ldr r0, [r1, #3*4] @ a[3] + umlal r3, r4, r7, r14 @ c += a[2] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r11, r12, r0, r14 @ c' += a[3] * b[3] + ldr r7, [r1, #4*4] @ a[4] + umlal r3, r4, r0, r8 @ c += a[3] * b[2] + ldr r14, [r2, #1*4] @ b[1] + umlal r11, r12, r7, r8 @ c' += a[4] * b[2] + ldr r0, [r1, #5*4] @ a[5] + umlal r3, r4, r7, r14 @ c += a[4] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[5] * b[1] + ldr r7, [r1, #6*4] @ a[6] + umlal r3, r4, r0, r8 @ c += a[5] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[6] * b[0] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r14 @ d += a[6] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[7] * b[9] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r8 @ d += a[7] * b[8] + ldr r14, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r8 @ d' += a[8] * b[8] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r14 @ d' += a[9] * b[7] + umlal r5, r6, r0, r8 @ d += a[9] * b[6] + + bic r0, r5, field_not_M @ u5 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u5 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t5 = c & M + str r14, [sp, #4 + 5*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u5 * R1 + umlal r3, r4, r0, r14 + + /* H */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u6 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u6 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t6 = c & M + str r14, [sp, #4 + 6*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u6 * R1 + umlal r3, r4, r0, r14 + + /* I - interleaved with J */ + ldr r8, [r2, #8*4] @ b[8] + ldr r7, [r1, #0*4] @ a[0] + ldr r14, [r2, #7*4] @ b[7] + umull r11, r12, r7, r8 @ c' = a[0] * b[8] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r11, r12, r0, r14 @ c' += a[1] * b[7] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[6] + ldr r14, [r2, #5*4] @ b[5] + umlal r11, r12, r7, r8 @ c' += a[2] * b[6] + ldr r0, [r1, #3*4] @ a[3] + umlal r3, r4, r7, r14 @ c += a[2] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r11, r12, r0, r14 @ c' += a[3] * b[5] + ldr r7, [r1, #4*4] @ a[4] + umlal r3, r4, r0, r8 @ c += a[3] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r11, r12, r7, r8 @ c' += a[4] * b[4] + ldr r0, [r1, #5*4] @ a[5] + umlal r3, r4, r7, r14 @ c += a[4] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r11, r12, r0, r14 @ c' += a[5] * b[3] + ldr r7, [r1, #6*4] @ a[6] + umlal r3, r4, r0, r8 @ c += a[5] * b[2] + ldr r14, [r2, #1*4] @ b[1] + umlal r11, r12, r7, r8 @ c' += a[6] * b[2] + ldr r0, [r1, #7*4] @ a[7] + umlal r3, r4, r7, r14 @ c += a[6] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[7] * b[1] + ldr r7, [r1, #8*4] @ a[8] + umlal r3, r4, r0, r8 @ c += a[7] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[8] * b[0] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[9] * b[9] + umlal r5, r6, r0, r8 @ d += a[9] * b[8] + + bic r0, r5, field_not_M @ u7 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u7 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t7 = c & M + str r14, [sp, #4 + 7*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u7 * R1 + umlal r3, r4, r0, r14 + + /* J */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u8 = d & M + str r0, [sp, #4 + 8*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u8 * R0 + umlal r3, r4, r0, r14 + + /****************************************** + * compute and write back result + ****************************************** + Allocation: + r0 r + r3:r4 c + r5:r6 d + r7 t0 + r8 t1 + r9 t2 + r11 u8 + r12 t9 + r1,r2,r10,r14 scratch + + Note: do not read from a[] after here, it may overlap with r[] + */ + ldr r0, [sp, #0] + add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 + ldmia r1, {r2,r7,r8,r9,r10,r11,r12} + add r1, r0, #3*4 + stmia r1, {r2,r7,r8,r9,r10} + + bic r2, r3, field_not_M @ r[8] = c & M + str r2, [r0, #8*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u8 * R1 + umlal r3, r4, r11, r14 + movw r14, field_R0 @ c += d * R0 + umlal r3, r4, r5, r14 + adds r3, r3, r12 @ c += t9 + adc r4, r4, #0 + + add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 + ldmia r1, {r7,r8,r9} + + ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) + str r2, [r0, #9*4] + mov r3, r3, lsr #22 @ c >>= 22 + orr r3, r3, r4, asl #10 + mov r4, r4, lsr #22 + movw r14, field_R1 << 4 @ c += d * (R1 << 4) + umlal r3, r4, r5, r14 + + movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) + umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) + adds r5, r5, r7 @ d.lo += t0 + mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) + adc r6, r6, 0 @ d.hi += carry + + bic r2, r5, field_not_M @ r[0] = d & M + str r2, [r0, #0*4] + + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) + umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) + adds r5, r5, r8 @ d.lo += t1 + adc r6, r6, #0 @ d.hi += carry + adds r5, r5, r1 @ d.lo += tmp.lo + mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) + adc r6, r6, r2 @ d.hi += carry + tmp.hi + + bic r2, r5, field_not_M @ r[1] = d & M + str r2, [r0, #1*4] + mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) + orr r5, r5, r6, asl #6 + + add r5, r5, r9 @ d += t2 + str r5, [r0, #2*4] @ r[2] = d + + add sp, sp, #48 + ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} + .size secp256k1_zkp_fe_mul_inner, .-secp256k1_zkp_fe_mul_inner + + .align 2 + .global secp256k1_zkp_fe_sqr_inner + .type secp256k1_zkp_fe_sqr_inner, %function + @ Arguments: + @ r0 r Can overlap with a + @ r1 a + @ Stack (total 4+10*4 = 44) + @ sp + #0 saved 'r' pointer + @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 +secp256k1_zkp_fe_sqr_inner: + stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} + sub sp, sp, #48 @ frame=44 + alignment + str r0, [sp, #0] @ save result address, we need it only at the end + /****************************************** + * Main computation code. + ****************************************** + + Allocation: + r0,r14,r2,r7,r8 scratch + r1 a (pointer) + r3:r4 c + r5:r6 d + r11:r12 c' + r9:r10 d' + + Note: do not write to r[] here, it may overlap with a[] + */ + /* A interleaved with B */ + ldr r0, [r1, #1*4] @ a[1]*2 + ldr r7, [r1, #0*4] @ a[0] + mov r0, r0, asl #1 + ldr r14, [r1, #9*4] @ a[9] + umull r3, r4, r7, r7 @ c = a[0] * a[0] + ldr r8, [r1, #8*4] @ a[8] + mov r7, r7, asl #1 + umull r5, r6, r7, r14 @ d = a[0]*2 * a[9] + ldr r7, [r1, #2*4] @ a[2]*2 + umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9] + ldr r14, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8] + mov r7, r7, asl #1 + ldr r0, [r1, #3*4] @ a[3]*2 + umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8] + ldr r8, [r1, #6*4] @ a[6] + umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7] + mov r0, r0, asl #1 + ldr r7, [r1, #4*4] @ a[4]*2 + umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7] + ldr r14, [r1, #5*4] @ a[5] + mov r7, r7, asl #1 + umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6] + umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6] + umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5] + umlal r9, r10, r14, r14 @ d' += a[5] * a[5] + + bic r0, r5, field_not_M @ t9 = d & M + str r0, [sp, #4 + 9*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + /* B */ + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u0 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u0 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t0 = c & M + str r14, [sp, #4 + 0*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u0 * R1 + umlal r3, r4, r0, r14 + + /* C interleaved with D */ + ldr r0, [r1, #0*4] @ a[0]*2 + ldr r14, [r1, #1*4] @ a[1] + mov r0, r0, asl #1 + ldr r8, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1] + mov r7, r8, asl #1 @ a[2]*2 + umull r11, r12, r14, r14 @ c' = a[1] * a[1] + ldr r14, [r1, #9*4] @ a[9] + umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2] + ldr r0, [r1, #3*4] @ a[3]*2 + ldr r8, [r1, #8*4] @ a[8] + umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9] + mov r0, r0, asl #1 + ldr r7, [r1, #4*4] @ a[4]*2 + umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9] + ldr r14, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8] + mov r7, r7, asl #1 + ldr r0, [r1, #5*4] @ a[5]*2 + umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8] + ldr r8, [r1, #6*4] @ a[6] + mov r0, r0, asl #1 + umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7] + umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7] + umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6] + umlal r9, r10, r8, r8 @ d' += a[6] * a[6] + + bic r0, r5, field_not_M @ u1 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u1 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t1 = c & M + str r14, [sp, #4 + 1*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u1 * R1 + umlal r3, r4, r0, r14 + + /* D */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u2 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u2 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t2 = c & M + str r14, [sp, #4 + 2*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u2 * R1 + umlal r3, r4, r0, r14 + + /* E interleaved with F */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + ldr r14, [r1, #2*4] @ a[2] + mov r7, r7, asl #1 + ldr r8, [r1, #3*4] @ a[3] + ldr r2, [r1, #4*4] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4] + mov r2, r2, asl #1 @ a[4]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3] + ldr r8, [r1, #9*4] @ a[9] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2] + ldr r0, [r1, #5*4] @ a[5]*2 + umlal r11, r12, r14, r14 @ c' += a[2] * a[2] + ldr r14, [r1, #8*4] @ a[8] + mov r0, r0, asl #1 + umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9] + ldr r7, [r1, #6*4] @ a[6]*2 + umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9] + mov r7, r7, asl #1 + ldr r8, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8] + umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8] + umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7] + umlal r9, r10, r8, r8 @ d' += a[7] * a[7] + + bic r0, r5, field_not_M @ u3 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u3 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t3 = c & M + str r14, [sp, #4 + 3*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u3 * R1 + umlal r3, r4, r0, r14 + + /* F */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u4 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u4 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t4 = c & M + str r14, [sp, #4 + 4*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u4 * R1 + umlal r3, r4, r0, r14 + + /* G interleaved with H */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + mov r7, r7, asl #1 + ldr r8, [r1, #5*4] @ a[5] + ldr r2, [r1, #6*4] @ a[6] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5] + ldr r14, [r1, #4*4] @ a[4] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6] + ldr r7, [r1, #2*4] @ a[2]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5] + mov r7, r7, asl #1 + ldr r8, [r1, #3*4] @ a[3] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4] + mov r0, r2, asl #1 @ a[6]*2 + umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4] + ldr r14, [r1, #9*4] @ a[9] + umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3] + ldr r7, [r1, #7*4] @ a[7]*2 + umlal r11, r12, r8, r8 @ c' += a[3] * a[3] + mov r7, r7, asl #1 + ldr r8, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9] + umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9] + umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8] + umlal r9, r10, r8, r8 @ d' += a[8] * a[8] + + bic r0, r5, field_not_M @ u5 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u5 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t5 = c & M + str r14, [sp, #4 + 5*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u5 * R1 + umlal r3, r4, r0, r14 + + /* H */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u6 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u6 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t6 = c & M + str r14, [sp, #4 + 6*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u6 * R1 + umlal r3, r4, r0, r14 + + /* I interleaved with J */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + mov r7, r7, asl #1 + ldr r8, [r1, #7*4] @ a[7] + ldr r2, [r1, #8*4] @ a[8] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7] + ldr r14, [r1, #6*4] @ a[6] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8] + ldr r7, [r1, #2*4] @ a[2]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7] + ldr r8, [r1, #5*4] @ a[5] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6] + ldr r0, [r1, #3*4] @ a[3]*2 + mov r7, r7, asl #1 + umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6] + ldr r14, [r1, #4*4] @ a[4] + mov r0, r0, asl #1 + umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5] + mov r2, r2, asl #1 @ a[8]*2 + umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5] + umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4] + umlal r11, r12, r14, r14 @ c' += a[4] * a[4] + ldr r8, [r1, #9*4] @ a[9] + umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9] + @ r8 will be used in J + + bic r0, r5, field_not_M @ u7 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u7 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t7 = c & M + str r14, [sp, #4 + 7*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u7 * R1 + umlal r3, r4, r0, r14 + + /* J */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + umlal r5, r6, r8, r8 @ d += a[9] * a[9] + + bic r0, r5, field_not_M @ u8 = d & M + str r0, [sp, #4 + 8*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u8 * R0 + umlal r3, r4, r0, r14 + + /****************************************** + * compute and write back result + ****************************************** + Allocation: + r0 r + r3:r4 c + r5:r6 d + r7 t0 + r8 t1 + r9 t2 + r11 u8 + r12 t9 + r1,r2,r10,r14 scratch + + Note: do not read from a[] after here, it may overlap with r[] + */ + ldr r0, [sp, #0] + add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 + ldmia r1, {r2,r7,r8,r9,r10,r11,r12} + add r1, r0, #3*4 + stmia r1, {r2,r7,r8,r9,r10} + + bic r2, r3, field_not_M @ r[8] = c & M + str r2, [r0, #8*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u8 * R1 + umlal r3, r4, r11, r14 + movw r14, field_R0 @ c += d * R0 + umlal r3, r4, r5, r14 + adds r3, r3, r12 @ c += t9 + adc r4, r4, #0 + + add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 + ldmia r1, {r7,r8,r9} + + ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) + str r2, [r0, #9*4] + mov r3, r3, lsr #22 @ c >>= 22 + orr r3, r3, r4, asl #10 + mov r4, r4, lsr #22 + movw r14, field_R1 << 4 @ c += d * (R1 << 4) + umlal r3, r4, r5, r14 + + movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) + umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) + adds r5, r5, r7 @ d.lo += t0 + mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) + adc r6, r6, 0 @ d.hi += carry + + bic r2, r5, field_not_M @ r[0] = d & M + str r2, [r0, #0*4] + + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) + umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) + adds r5, r5, r8 @ d.lo += t1 + adc r6, r6, #0 @ d.hi += carry + adds r5, r5, r1 @ d.lo += tmp.lo + mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) + adc r6, r6, r2 @ d.hi += carry + tmp.hi + + bic r2, r5, field_not_M @ r[1] = d & M + str r2, [r0, #1*4] + mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) + orr r5, r5, r6, asl #6 + + add r5, r5, r9 @ d += t2 + str r5, [r0, #2*4] @ r[2] = d + + add sp, sp, #48 + ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} + .size secp256k1_zkp_fe_sqr_inner, .-secp256k1_zkp_fe_sqr_inner + diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/basic-config.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/basic-config.h new file mode 100644 index 00000000..7e99e829 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/basic-config.h @@ -0,0 +1,36 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_BASIC_CONFIG_H +#define SECP256K1_BASIC_CONFIG_H + +#ifdef USE_BASIC_CONFIG + +#undef USE_ASM_X86_64 +#undef USE_ECMULT_STATIC_PRECOMPUTATION +#undef USE_ENDOMORPHISM +#undef USE_EXTERNAL_ASM +#undef USE_EXTERNAL_DEFAULT_CALLBACKS +#undef USE_FIELD_10X26 +#undef USE_FIELD_5X52 +#undef USE_FIELD_INV_BUILTIN +#undef USE_FIELD_INV_NUM +#undef USE_NUM_GMP +#undef USE_NUM_NONE +#undef USE_SCALAR_4X64 +#undef USE_SCALAR_8X32 +#undef USE_SCALAR_INV_BUILTIN +#undef USE_SCALAR_INV_NUM + +#define USE_NUM_NONE 1 +#define USE_FIELD_INV_BUILTIN 1 +#define USE_SCALAR_INV_BUILTIN 1 +#define USE_FIELD_10X26 1 +#define USE_SCALAR_8X32 1 + +#endif /* USE_BASIC_CONFIG */ + +#endif /* SECP256K1_BASIC_CONFIG_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench.h new file mode 100644 index 00000000..5b59783f --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench.h @@ -0,0 +1,82 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_BENCH_H +#define SECP256K1_BENCH_H + +#include +#include +#include +#include "sys/time.h" + +static double gettimedouble(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_usec * 0.000001 + tv.tv_sec; +} + +void print_number(double x) { + double y = x; + int c = 0; + if (y < 0.0) { + y = -y; + } + while (y > 0 && y < 100.0) { + y *= 10.0; + c++; + } + printf("%.*f", c, x); +} + +void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) { + int i; + double min = HUGE_VAL; + double sum = 0.0; + double max = 0.0; + for (i = 0; i < count; i++) { + double begin, total; + if (setup != NULL) { + setup(data); + } + begin = gettimedouble(); + benchmark(data); + total = gettimedouble() - begin; + if (teardown != NULL) { + teardown(data); + } + if (total < min) { + min = total; + } + if (total > max) { + max = total; + } + sum += total; + } + printf("%s: min ", name); + print_number(min * 1000000.0 / iter); + printf("us / avg "); + print_number((sum / count) * 1000000.0 / iter); + printf("us / max "); + print_number(max * 1000000.0 / iter); + printf("us\n"); +} + +int have_flag(int argc, char** argv, char *flag) { + char** argm = argv + argc; + argv++; + if (argv == argm) { + return 1; + } + while (argv != NULL && argv != argm) { + if (strcmp(*argv, flag) == 0) { + return 1; + } + argv++; + } + return 0; +} + +#endif /* SECP256K1_BENCH_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_ecdh.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_ecdh.c new file mode 100644 index 00000000..d7b83acf --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_ecdh.c @@ -0,0 +1,54 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include + +#include "include/secp256k1.h" +#include "include/secp256k1_ecdh.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_zkp_context *ctx; + secp256k1_zkp_pubkey point; + unsigned char scalar[32]; +} bench_ecdh_data; + +static void bench_ecdh_setup(void* arg) { + int i; + bench_ecdh_data *data = (bench_ecdh_data*)arg; + const unsigned char point[] = { + 0x03, + 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, + 0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd, + 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb, + 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f + }; + + /* create a context with no capabilities */ + data->ctx = secp256k1_zkp_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); + for (i = 0; i < 32; i++) { + data->scalar[i] = i + 1; + } + CHECK(secp256k1_zkp_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); +} + +static void bench_ecdh(void* arg) { + int i; + unsigned char res[32]; + bench_ecdh_data *data = (bench_ecdh_data*)arg; + + for (i = 0; i < 20000; i++) { + CHECK(secp256k1_zkp_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1); + } +} + +int main(void) { + bench_ecdh_data data; + + run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000); + return 0; +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_ecmult.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_ecmult.c new file mode 100644 index 00000000..44354508 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_ecmult.c @@ -0,0 +1,196 @@ +/********************************************************************** + * Copyright (c) 2017 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +#include + +#include "include/secp256k1.h" + +#include "util.h" +#include "hash_impl.h" +#include "num_impl.h" +#include "field_impl.h" +#include "group_impl.h" +#include "scalar_impl.h" +#include "ecmult_impl.h" +#include "bench.h" +#include "secp256k1.c" + +#define POINTS 32768 +#define ITERS 10000 + +typedef struct { + /* Setup once in advance */ + secp256k1_zkp_context* ctx; + secp256k1_zkp_scratch_space* scratch; + secp256k1_zkp_scalar* scalars; + secp256k1_zkp_ge* pubkeys; + secp256k1_zkp_scalar* seckeys; + secp256k1_zkp_gej* expected_output; + secp256k1_zkp_ecmult_multi_func ecmult_multi; + + /* Changes per test */ + size_t count; + int includes_g; + + /* Changes per test iteration */ + size_t offset1; + size_t offset2; + + /* Test output. */ + secp256k1_zkp_gej* output; +} bench_data; + +static int bench_callback(secp256k1_zkp_scalar* sc, secp256k1_zkp_ge* ge, size_t idx, void* arg) { + bench_data* data = (bench_data*)arg; + if (data->includes_g) ++idx; + if (idx == 0) { + *sc = data->scalars[data->offset1]; + *ge = secp256k1_zkp_ge_const_g; + } else { + *sc = data->scalars[(data->offset1 + idx) % POINTS]; + *ge = data->pubkeys[(data->offset2 + idx - 1) % POINTS]; + } + return 1; +} + +static void bench_ecmult(void* arg) { + bench_data* data = (bench_data*)arg; + + size_t count = data->count; + int includes_g = data->includes_g; + size_t iters = 1 + ITERS / count; + size_t iter; + + for (iter = 0; iter < iters; ++iter) { + data->ecmult_multi(&data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_callback, arg, count - includes_g); + data->offset1 = (data->offset1 + count) % POINTS; + data->offset2 = (data->offset2 + count - 1) % POINTS; + } +} + +static void bench_ecmult_setup(void* arg) { + bench_data* data = (bench_data*)arg; + data->offset1 = (data->count * 0x537b7f6f + 0x8f66a481) % POINTS; + data->offset2 = (data->count * 0x7f6f537b + 0x6a1a8f49) % POINTS; +} + +static void bench_ecmult_teardown(void* arg) { + bench_data* data = (bench_data*)arg; + size_t iters = 1 + ITERS / data->count; + size_t iter; + /* Verify the results in teardown, to avoid doing comparisons while benchmarking. */ + for (iter = 0; iter < iters; ++iter) { + secp256k1_zkp_gej tmp; + secp256k1_zkp_gej_add_var(&tmp, &data->output[iter], &data->expected_output[iter], NULL); + CHECK(secp256k1_zkp_gej_is_infinity(&tmp)); + } +} + +static void generate_scalar(uint32_t num, secp256k1_zkp_scalar* scalar) { + secp256k1_zkp_sha256 sha256; + unsigned char c[11] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0}; + unsigned char buf[32]; + int overflow = 0; + c[6] = num; + c[7] = num >> 8; + c[8] = num >> 16; + c[9] = num >> 24; + secp256k1_zkp_sha256_initialize(&sha256); + secp256k1_zkp_sha256_write(&sha256, c, sizeof(c)); + secp256k1_zkp_sha256_finalize(&sha256, buf); + secp256k1_zkp_scalar_set_b32(scalar, buf, &overflow); + CHECK(!overflow); +} + +static void run_test(bench_data* data, size_t count, int includes_g) { + char str[32]; + static const secp256k1_zkp_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + size_t iters = 1 + ITERS / count; + size_t iter; + + data->count = count; + data->includes_g = includes_g; + + /* Compute (the negation of) the expected results directly. */ + data->offset1 = (data->count * 0x537b7f6f + 0x8f66a481) % POINTS; + data->offset2 = (data->count * 0x7f6f537b + 0x6a1a8f49) % POINTS; + for (iter = 0; iter < iters; ++iter) { + secp256k1_zkp_scalar tmp; + secp256k1_zkp_scalar total = data->scalars[(data->offset1++) % POINTS]; + size_t i = 0; + for (i = 0; i + 1 < count; ++i) { + secp256k1_zkp_scalar_mul(&tmp, &data->seckeys[(data->offset2++) % POINTS], &data->scalars[(data->offset1++) % POINTS]); + secp256k1_zkp_scalar_add(&total, &total, &tmp); + } + secp256k1_zkp_scalar_negate(&total, &total); + secp256k1_zkp_ecmult(&data->ctx->ecmult_ctx, &data->expected_output[iter], NULL, &zero, &total); + } + + /* Run the benchmark. */ + sprintf(str, includes_g ? "ecmult_%ig" : "ecmult_%i", (int)count); + run_benchmark(str, bench_ecmult, bench_ecmult_setup, bench_ecmult_teardown, data, 10, count * (1 + ITERS / count)); +} + +int main(int argc, char **argv) { + bench_data data; + int i, p; + secp256k1_zkp_gej* pubkeys_gej; + size_t scratch_size; + + if (argc > 1) { + if(have_flag(argc, argv, "pippenger_wnaf")) { + printf("Using pippenger_wnaf:\n"); + data.ecmult_multi = secp256k1_zkp_ecmult_pippenger_batch_single; + } else if(have_flag(argc, argv, "strauss_wnaf")) { + printf("Using strauss_wnaf:\n"); + data.ecmult_multi = secp256k1_zkp_ecmult_strauss_batch_single; + } + } else { + data.ecmult_multi = secp256k1_zkp_ecmult_multi_var; + } + + /* Allocate stuff */ + data.ctx = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + scratch_size = secp256k1_zkp_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16; + data.scratch = secp256k1_zkp_scratch_space_create(data.ctx, scratch_size); + data.scalars = malloc(sizeof(secp256k1_zkp_scalar) * POINTS); + data.seckeys = malloc(sizeof(secp256k1_zkp_scalar) * POINTS); + data.pubkeys = malloc(sizeof(secp256k1_zkp_ge) * POINTS); + data.expected_output = malloc(sizeof(secp256k1_zkp_gej) * (ITERS + 1)); + data.output = malloc(sizeof(secp256k1_zkp_gej) * (ITERS + 1)); + + /* Generate a set of scalars, and private/public keypairs. */ + pubkeys_gej = malloc(sizeof(secp256k1_zkp_gej) * POINTS); + secp256k1_zkp_gej_set_ge(&pubkeys_gej[0], &secp256k1_zkp_ge_const_g); + secp256k1_zkp_scalar_set_int(&data.seckeys[0], 1); + for (i = 0; i < POINTS; ++i) { + generate_scalar(i, &data.scalars[i]); + if (i) { + secp256k1_zkp_gej_double_var(&pubkeys_gej[i], &pubkeys_gej[i - 1], NULL); + secp256k1_zkp_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]); + } + } + secp256k1_zkp_ge_set_all_gej_var(data.pubkeys, pubkeys_gej, POINTS); + free(pubkeys_gej); + + for (i = 1; i <= 8; ++i) { + run_test(&data, i, 1); + } + + for (p = 0; p <= 11; ++p) { + for (i = 9; i <= 16; ++i) { + run_test(&data, i << p, 1); + } + } + secp256k1_zkp_context_destroy(data.ctx); + secp256k1_zkp_scratch_space_destroy(data.scratch); + free(data.scalars); + free(data.pubkeys); + free(data.seckeys); + free(data.output); + free(data.expected_output); + + return(0); +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_generator.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_generator.c new file mode 100644 index 00000000..1bd7db7b --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_generator.c @@ -0,0 +1,59 @@ +/********************************************************************** + * Copyright (c) 2016 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "include/secp256k1_generator.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_zkp_context* ctx; + unsigned char key[32]; + unsigned char blind[32]; +} bench_generator_t; + +static void bench_generator_setup(void* arg) { + bench_generator_t *data = (bench_generator_t*)arg; + memset(data->key, 0x31, 32); + memset(data->blind, 0x13, 32); +} + +static void bench_generator_generate(void* arg) { + int i; + bench_generator_t *data = (bench_generator_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_zkp_generator gen; + CHECK(secp256k1_zkp_generator_generate(data->ctx, &gen, data->key)); + data->key[i & 31]++; + } +} + +static void bench_generator_generate_blinded(void* arg) { + int i; + bench_generator_t *data = (bench_generator_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_zkp_generator gen; + CHECK(secp256k1_zkp_generator_generate_blinded(data->ctx, &gen, data->key, data->blind)); + data->key[1 + (i & 30)]++; + data->blind[1 + (i & 30)]++; + } +} + +int main(void) { + bench_generator_t data; + + data.ctx = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + run_benchmark("generator_generate", bench_generator_generate, bench_generator_setup, NULL, &data, 10, 20000); + run_benchmark("generator_generate_blinded", bench_generator_generate_blinded, bench_generator_setup, NULL, &data, 10, 20000); + + secp256k1_zkp_context_destroy(data.ctx); + return 0; +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_internal.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_internal.c new file mode 100644 index 00000000..8341f3a0 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_internal.c @@ -0,0 +1,367 @@ +/********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +#include + +#include "include/secp256k1.h" + +#include "util.h" +#include "hash_impl.h" +#include "num_impl.h" +#include "field_impl.h" +#include "group_impl.h" +#include "scalar_impl.h" +#include "ecmult_const_impl.h" +#include "ecmult_impl.h" +#include "bench.h" +#include "secp256k1.c" + +typedef struct { + secp256k1_zkp_scalar scalar_x, scalar_y; + secp256k1_zkp_fe fe_x, fe_y; + secp256k1_zkp_ge ge_x, ge_y; + secp256k1_zkp_gej gej_x, gej_y; + unsigned char data[64]; + int wnaf[256]; +} bench_inv; + +void bench_setup(void* arg) { + bench_inv *data = (bench_inv*)arg; + + static const unsigned char init_x[32] = { + 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, + 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35, + 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, + 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83 + }; + + static const unsigned char init_y[32] = { + 0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83, + 0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5, + 0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9, + 0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3 + }; + + secp256k1_zkp_scalar_set_b32(&data->scalar_x, init_x, NULL); + secp256k1_zkp_scalar_set_b32(&data->scalar_y, init_y, NULL); + secp256k1_zkp_fe_set_b32(&data->fe_x, init_x); + secp256k1_zkp_fe_set_b32(&data->fe_y, init_y); + CHECK(secp256k1_zkp_ge_set_xo_var(&data->ge_x, &data->fe_x, 0)); + CHECK(secp256k1_zkp_ge_set_xo_var(&data->ge_y, &data->fe_y, 1)); + secp256k1_zkp_gej_set_ge(&data->gej_x, &data->ge_x); + secp256k1_zkp_gej_set_ge(&data->gej_y, &data->ge_y); + memcpy(data->data, init_x, 32); + memcpy(data->data + 32, init_y, 32); +} + +void bench_scalar_add(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_zkp_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_scalar_negate(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_zkp_scalar_negate(&data->scalar_x, &data->scalar_x); + } +} + +void bench_scalar_sqr(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_zkp_scalar_sqr(&data->scalar_x, &data->scalar_x); + } +} + +void bench_scalar_mul(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_zkp_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +#ifdef USE_ENDOMORPHISM +void bench_scalar_split(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_zkp_scalar l, r; + secp256k1_zkp_scalar_split_lambda(&l, &r, &data->scalar_x); + secp256k1_zkp_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} +#endif + +void bench_scalar_inverse(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 2000; i++) { + secp256k1_zkp_scalar_inverse(&data->scalar_x, &data->scalar_x); + secp256k1_zkp_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_scalar_inverse_var(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 2000; i++) { + secp256k1_zkp_scalar_inverse_var(&data->scalar_x, &data->scalar_x); + secp256k1_zkp_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_field_normalize(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_zkp_fe_normalize(&data->fe_x); + } +} + +void bench_field_normalize_weak(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_zkp_fe_normalize_weak(&data->fe_x); + } +} + +void bench_field_mul(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_zkp_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y); + } +} + +void bench_field_sqr(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_zkp_fe_sqr(&data->fe_x, &data->fe_x); + } +} + +void bench_field_inverse(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_zkp_fe_inv(&data->fe_x, &data->fe_x); + secp256k1_zkp_fe_add(&data->fe_x, &data->fe_y); + } +} + +void bench_field_inverse_var(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_zkp_fe_inv_var(&data->fe_x, &data->fe_x); + secp256k1_zkp_fe_add(&data->fe_x, &data->fe_y); + } +} + +void bench_field_sqrt(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_zkp_fe_sqrt(&data->fe_x, &data->fe_x); + secp256k1_zkp_fe_add(&data->fe_x, &data->fe_y); + } +} + +void bench_group_double_var(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_zkp_gej_double_var(&data->gej_x, &data->gej_x, NULL); + } +} + +void bench_group_add_var(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_zkp_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL); + } +} + +void bench_group_add_affine(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_zkp_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y); + } +} + +void bench_group_add_affine_var(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_zkp_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL); + } +} + +void bench_group_jacobi_var(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_zkp_gej_has_quad_y_var(&data->gej_x); + } +} + +void bench_ecmult_wnaf(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_zkp_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A); + secp256k1_zkp_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_wnaf_const(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_zkp_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A, 256); + secp256k1_zkp_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + + +void bench_sha256(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_zkp_sha256 sha; + + for (i = 0; i < 20000; i++) { + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_sha256_write(&sha, data->data, 32); + secp256k1_zkp_sha256_finalize(&sha, data->data); + } +} + +void bench_hmac_sha256(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_zkp_hmac_sha256 hmac; + + for (i = 0; i < 20000; i++) { + secp256k1_zkp_hmac_sha256_initialize(&hmac, data->data, 32); + secp256k1_zkp_hmac_sha256_write(&hmac, data->data, 32); + secp256k1_zkp_hmac_sha256_finalize(&hmac, data->data); + } +} + +void bench_rfc6979_hmac_sha256(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_zkp_rfc6979_hmac_sha256 rng; + + for (i = 0; i < 20000; i++) { + secp256k1_zkp_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); + secp256k1_zkp_rfc6979_hmac_sha256_generate(&rng, data->data, 32); + } +} + +void bench_context_verify(void* arg) { + int i; + (void)arg; + for (i = 0; i < 20; i++) { + secp256k1_zkp_context_destroy(secp256k1_zkp_context_create(SECP256K1_CONTEXT_VERIFY)); + } +} + +void bench_context_sign(void* arg) { + int i; + (void)arg; + for (i = 0; i < 200; i++) { + secp256k1_zkp_context_destroy(secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN)); + } +} + +#ifndef USE_NUM_NONE +void bench_num_jacobi(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_zkp_num nx, norder; + + secp256k1_zkp_scalar_get_num(&nx, &data->scalar_x); + secp256k1_zkp_scalar_order_get_num(&norder); + secp256k1_zkp_scalar_get_num(&norder, &data->scalar_y); + + for (i = 0; i < 200000; i++) { + secp256k1_zkp_num_jacobi(&nx, &norder); + } +} +#endif + +int main(int argc, char **argv) { + bench_inv data; + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, 200000); +#ifdef USE_ENDOMORPHISM + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, 20000); +#endif + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000); + + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20); + if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200); + +#ifndef USE_NUM_NONE + if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000); +#endif + return 0; +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_rangeproof.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_rangeproof.c new file mode 100644 index 00000000..107c4be7 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_rangeproof.c @@ -0,0 +1,63 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille, Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include + +#include "include/secp256k1_rangeproof.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_zkp_context* ctx; + secp256k1_zkp_pedersen_commitment commit; + unsigned char proof[5134]; + unsigned char blind[32]; + size_t len; + int min_bits; + uint64_t v; +} bench_rangeproof_t; + +static void bench_rangeproof_setup(void* arg) { + int i; + uint64_t minv; + uint64_t maxv; + bench_rangeproof_t *data = (bench_rangeproof_t*)arg; + + data->v = 0; + for (i = 0; i < 32; i++) data->blind[i] = i + 1; + CHECK(secp256k1_zkp_pedersen_commit(data->ctx, &data->commit, data->blind, data->v, secp256k1_zkp_generator_h)); + data->len = 5134; + CHECK(secp256k1_zkp_rangeproof_sign(data->ctx, data->proof, &data->len, 0, &data->commit, data->blind, (const unsigned char*)&data->commit, 0, data->min_bits, data->v, NULL, 0, NULL, 0, secp256k1_zkp_generator_h)); + CHECK(secp256k1_zkp_rangeproof_verify(data->ctx, &minv, &maxv, &data->commit, data->proof, data->len, NULL, 0, secp256k1_zkp_generator_h)); +} + +static void bench_rangeproof(void* arg) { + int i; + bench_rangeproof_t *data = (bench_rangeproof_t*)arg; + + for (i = 0; i < 1000; i++) { + int j; + uint64_t minv; + uint64_t maxv; + j = secp256k1_zkp_rangeproof_verify(data->ctx, &minv, &maxv, &data->commit, data->proof, data->len, NULL, 0, secp256k1_zkp_generator_h); + for (j = 0; j < 4; j++) { + data->proof[j + 2 + 32 *((data->min_bits + 1) >> 1) - 4] = (i >> 8)&255; + } + } +} + +int main(void) { + bench_rangeproof_t data; + + data.ctx = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + data.min_bits = 32; + + run_benchmark("rangeproof_verify_bit", bench_rangeproof, bench_rangeproof_setup, NULL, &data, 10, 1000 * data.min_bits); + + secp256k1_zkp_context_destroy(data.ctx); + return 0; +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_recover.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_recover.c new file mode 100644 index 00000000..ea831e02 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_recover.c @@ -0,0 +1,60 @@ +/********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include "include/secp256k1.h" +#include "include/secp256k1_recovery.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_zkp_context *ctx; + unsigned char msg[32]; + unsigned char sig[64]; +} bench_recover_data; + +void bench_recover(void* arg) { + int i; + bench_recover_data *data = (bench_recover_data*)arg; + secp256k1_zkp_pubkey pubkey; + unsigned char pubkeyc[33]; + + for (i = 0; i < 20000; i++) { + int j; + size_t pubkeylen = 33; + secp256k1_zkp_ecdsa_recoverable_signature sig; + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2)); + CHECK(secp256k1_zkp_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg)); + CHECK(secp256k1_zkp_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); + for (j = 0; j < 32; j++) { + data->sig[j + 32] = data->msg[j]; /* Move former message to S. */ + data->msg[j] = data->sig[j]; /* Move former R to message. */ + data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ + } + } +} + +void bench_recover_setup(void* arg) { + int i; + bench_recover_data *data = (bench_recover_data*)arg; + + for (i = 0; i < 32; i++) { + data->msg[i] = 1 + i; + } + for (i = 0; i < 64; i++) { + data->sig[i] = 65 + i; + } +} + +int main(void) { + bench_recover_data data; + + data.ctx = secp256k1_zkp_context_create(SECP256K1_CONTEXT_VERIFY); + + run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, 20000); + + secp256k1_zkp_context_destroy(data.ctx); + return 0; +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_schnorrsig.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_schnorrsig.c new file mode 100644 index 00000000..6030f534 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_schnorrsig.c @@ -0,0 +1,128 @@ +/********************************************************************** + * Copyright (c) 2018 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "include/secp256k1.h" +#include "include/secp256k1_schnorrsig.h" +#include "util.h" +#include "bench.h" + +#define MAX_SIGS (32768) + +typedef struct { + secp256k1_zkp_context *ctx; + secp256k1_zkp_scratch_space *scratch; + size_t n; + const unsigned char **pk; + const secp256k1_zkp_schnorrsig **sigs; + const unsigned char **msgs; +} bench_schnorrsig_data; + +void bench_schnorrsig_sign(void* arg) { + bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; + size_t i; + unsigned char sk[32] = "benchmarkexample secrettemplate"; + unsigned char msg[32] = "benchmarkexamplemessagetemplate"; + secp256k1_zkp_schnorrsig sig; + + for (i = 0; i < 1000; i++) { + msg[0] = i; + msg[1] = i >> 8; + sk[0] = i; + sk[1] = i >> 8; + CHECK(secp256k1_zkp_schnorrsig_sign(data->ctx, &sig, NULL, msg, sk, NULL, NULL)); + } +} + +void bench_schnorrsig_verify(void* arg) { + bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; + size_t i; + + for (i = 0; i < 1000; i++) { + secp256k1_zkp_pubkey pk; + CHECK(secp256k1_zkp_ec_pubkey_parse(data->ctx, &pk, data->pk[i], 33) == 1); + CHECK(secp256k1_zkp_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], &pk)); + } +} + +void bench_schnorrsig_verify_n(void* arg) { + bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; + size_t i, j; + const secp256k1_zkp_pubkey **pk = (const secp256k1_zkp_pubkey **)malloc(data->n * sizeof(*pk)); + + CHECK(pk != NULL); + for (j = 0; j < MAX_SIGS/data->n; j++) { + for (i = 0; i < data->n; i++) { + secp256k1_zkp_pubkey *pk_nonconst = (secp256k1_zkp_pubkey *)malloc(sizeof(*pk_nonconst)); + CHECK(secp256k1_zkp_ec_pubkey_parse(data->ctx, pk_nonconst, data->pk[i], 33) == 1); + pk[i] = pk_nonconst; + } + CHECK(secp256k1_zkp_schnorrsig_verify_batch(data->ctx, data->scratch, data->sigs, data->msgs, pk, data->n)); + for (i = 0; i < data->n; i++) { + free((void *)pk[i]); + } + } + free(pk); +} + +int main(void) { + size_t i; + bench_schnorrsig_data data; + + data.ctx = secp256k1_zkp_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); + data.scratch = secp256k1_zkp_scratch_space_create(data.ctx, 1024 * 1024 * 1024); + data.pk = (const unsigned char **)malloc(MAX_SIGS * sizeof(unsigned char *)); + data.msgs = (const unsigned char **)malloc(MAX_SIGS * sizeof(unsigned char *)); + data.sigs = (const secp256k1_zkp_schnorrsig **)malloc(MAX_SIGS * sizeof(secp256k1_zkp_schnorrsig *)); + + for (i = 0; i < MAX_SIGS; i++) { + unsigned char sk[32]; + unsigned char *msg = (unsigned char *)malloc(32); + secp256k1_zkp_schnorrsig *sig = (secp256k1_zkp_schnorrsig *)malloc(sizeof(*sig)); + unsigned char *pk_char = (unsigned char *)malloc(33); + secp256k1_zkp_pubkey pk; + size_t pk_len = 33; + msg[0] = sk[0] = i; + msg[1] = sk[1] = i >> 8; + msg[2] = sk[2] = i >> 16; + msg[3] = sk[3] = i >> 24; + memset(&msg[4], 'm', 28); + memset(&sk[4], 's', 28); + + data.pk[i] = pk_char; + data.msgs[i] = msg; + data.sigs[i] = sig; + + CHECK(secp256k1_zkp_ec_pubkey_create(data.ctx, &pk, sk)); + CHECK(secp256k1_zkp_ec_pubkey_serialize(data.ctx, pk_char, &pk_len, &pk, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_zkp_schnorrsig_sign(data.ctx, sig, NULL, msg, sk, NULL, NULL)); + } + + run_benchmark("schnorrsig_sign", bench_schnorrsig_sign, NULL, NULL, (void *) &data, 10, 1000); + run_benchmark("schnorrsig_verify", bench_schnorrsig_verify, NULL, NULL, (void *) &data, 10, 1000); + for (i = 1; i <= MAX_SIGS; i *= 2) { + char name[64]; + sprintf(name, "schnorrsig_batch_verify_%d", (int) i); + + data.n = i; + run_benchmark(name, bench_schnorrsig_verify_n, NULL, NULL, (void *) &data, 3, MAX_SIGS); + } + + for (i = 0; i < MAX_SIGS; i++) { + free((void *)data.pk[i]); + free((void *)data.msgs[i]); + free((void *)data.sigs[i]); + } + free(data.pk); + free(data.msgs); + free(data.sigs); + + secp256k1_zkp_scratch_space_destroy(data.scratch); + secp256k1_zkp_context_destroy(data.ctx); + return 0; +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_sign.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_sign.c new file mode 100644 index 00000000..c9d68f80 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_sign.c @@ -0,0 +1,56 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include "include/secp256k1.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_zkp_context* ctx; + unsigned char msg[32]; + unsigned char key[32]; +} bench_sign; + +static void bench_sign_setup(void* arg) { + int i; + bench_sign *data = (bench_sign*)arg; + + for (i = 0; i < 32; i++) { + data->msg[i] = i + 1; + } + for (i = 0; i < 32; i++) { + data->key[i] = i + 65; + } +} + +static void bench_sign_run(void* arg) { + int i; + bench_sign *data = (bench_sign*)arg; + + unsigned char sig[74]; + for (i = 0; i < 20000; i++) { + size_t siglen = 74; + int j; + secp256k1_zkp_ecdsa_signature signature; + CHECK(secp256k1_zkp_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL)); + CHECK(secp256k1_zkp_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature)); + for (j = 0; j < 32; j++) { + data->msg[j] = sig[j]; + data->key[j] = sig[j + 32]; + } + } +} + +int main(void) { + bench_sign data; + + data.ctx = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN); + + run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, 20000); + + secp256k1_zkp_context_destroy(data.ctx); + return 0; +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_verify.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_verify.c new file mode 100644 index 00000000..15a78e95 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_verify.c @@ -0,0 +1,112 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "include/secp256k1.h" +#include "util.h" +#include "bench.h" + +#ifdef ENABLE_OPENSSL_TESTS +#include +#include +#include +#endif + +typedef struct { + secp256k1_zkp_context *ctx; + unsigned char msg[32]; + unsigned char key[32]; + unsigned char sig[72]; + size_t siglen; + unsigned char pubkey[33]; + size_t pubkeylen; +#ifdef ENABLE_OPENSSL_TESTS + EC_GROUP* ec_group; +#endif +} benchmark_verify_t; + +static void benchmark_verify(void* arg) { + int i; + benchmark_verify_t* data = (benchmark_verify_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_zkp_pubkey pubkey; + secp256k1_zkp_ecdsa_signature sig; + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + CHECK(secp256k1_zkp_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0)); + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + } +} + +#ifdef ENABLE_OPENSSL_TESTS +static void benchmark_verify_openssl(void* arg) { + int i; + benchmark_verify_t* data = (benchmark_verify_t*)arg; + + for (i = 0; i < 20000; i++) { + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + { + EC_KEY *pkey = EC_KEY_new(); + const unsigned char *pubkey = &data->pubkey[0]; + int result; + + CHECK(pkey != NULL); + result = EC_KEY_set_group(pkey, data->ec_group); + CHECK(result); + result = (o2i_ECPublicKey(&pkey, &pubkey, data->pubkeylen)) != NULL; + CHECK(result); + result = ECDSA_verify(0, &data->msg[0], sizeof(data->msg), &data->sig[0], data->siglen, pkey) == (i == 0); + CHECK(result); + EC_KEY_free(pkey); + } + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + } +} +#endif + +int main(void) { + int i; + secp256k1_zkp_pubkey pubkey; + secp256k1_zkp_ecdsa_signature sig; + benchmark_verify_t data; + + data.ctx = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + for (i = 0; i < 32; i++) { + data.msg[i] = 1 + i; + } + for (i = 0; i < 32; i++) { + data.key[i] = 33 + i; + } + data.siglen = 72; + CHECK(secp256k1_zkp_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL)); + CHECK(secp256k1_zkp_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); + CHECK(secp256k1_zkp_ec_pubkey_create(data.ctx, &pubkey, data.key)); + data.pubkeylen = 33; + CHECK(secp256k1_zkp_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + + run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000); +#ifdef ENABLE_OPENSSL_TESTS + data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1); + run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000); + EC_GROUP_free(data.ec_group); +#endif + + secp256k1_zkp_context_destroy(data.ctx); + return 0; +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_whitelist.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_whitelist.c new file mode 100644 index 00000000..f4ffc9da --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/bench_whitelist.c @@ -0,0 +1,104 @@ +/********************************************************************** + * Copyright (c) 2017 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +#include + +#include "include/secp256k1.h" + +#include "include/secp256k1_whitelist.h" +#include "bench.h" +#include "util.h" +#include "hash_impl.h" +#include "num_impl.h" +#include "scalar_impl.h" +#include "testrand_impl.h" + +#define MAX_N_KEYS 30 + +typedef struct { + secp256k1_zkp_context* ctx; + unsigned char online_seckey[MAX_N_KEYS][32]; + unsigned char summed_seckey[MAX_N_KEYS][32]; + secp256k1_zkp_pubkey online_pubkeys[MAX_N_KEYS]; + secp256k1_zkp_pubkey offline_pubkeys[MAX_N_KEYS]; + unsigned char csub[32]; + secp256k1_zkp_pubkey sub_pubkey; + secp256k1_zkp_whitelist_signature sig; + size_t n_keys; +} bench_data; + +static void bench_whitelist(void* arg) { + bench_data* data = (bench_data*)arg; + CHECK(secp256k1_zkp_whitelist_verify(data->ctx, &data->sig, data->online_pubkeys, data->offline_pubkeys, data->n_keys, &data->sub_pubkey) == 1); +} + +static void bench_whitelist_setup(void* arg) { + bench_data* data = (bench_data*)arg; + int i = 0; + CHECK(secp256k1_zkp_whitelist_sign(data->ctx, &data->sig, data->online_pubkeys, data->offline_pubkeys, data->n_keys, &data->sub_pubkey, data->online_seckey[i], data->summed_seckey[i], i, NULL, NULL)); +} + +static void run_test(bench_data* data) { + char str[32]; + sprintf(str, "whitelist_%i", (int)data->n_keys); + run_benchmark(str, bench_whitelist, bench_whitelist_setup, NULL, data, 100, 1); +} + +void random_scalar_order(secp256k1_zkp_scalar *num) { + do { + unsigned char b32[32]; + int overflow = 0; + secp256k1_zkp_rand256(b32); + secp256k1_zkp_scalar_set_b32(num, b32, &overflow); + if (overflow || secp256k1_zkp_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +int main(void) { + bench_data data; + size_t i; + size_t n_keys = 30; + secp256k1_zkp_scalar ssub; + + data.ctx = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + /* Start with subkey */ + random_scalar_order(&ssub); + secp256k1_zkp_scalar_get_b32(data.csub, &ssub); + CHECK(secp256k1_zkp_ec_seckey_verify(data.ctx, data.csub) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(data.ctx, &data.sub_pubkey, data.csub) == 1); + /* Then offline and online whitelist keys */ + for (i = 0; i < n_keys; i++) { + secp256k1_zkp_scalar son, soff; + + /* Create two keys */ + random_scalar_order(&son); + secp256k1_zkp_scalar_get_b32(data.online_seckey[i], &son); + CHECK(secp256k1_zkp_ec_seckey_verify(data.ctx, data.online_seckey[i]) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(data.ctx, &data.online_pubkeys[i], data.online_seckey[i]) == 1); + + random_scalar_order(&soff); + secp256k1_zkp_scalar_get_b32(data.summed_seckey[i], &soff); + CHECK(secp256k1_zkp_ec_seckey_verify(data.ctx, data.summed_seckey[i]) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(data.ctx, &data.offline_pubkeys[i], data.summed_seckey[i]) == 1); + + /* Make summed_seckey correspond to the sum of offline_pubkey and sub_pubkey */ + secp256k1_zkp_scalar_add(&soff, &soff, &ssub); + secp256k1_zkp_scalar_get_b32(data.summed_seckey[i], &soff); + CHECK(secp256k1_zkp_ec_seckey_verify(data.ctx, data.summed_seckey[i]) == 1); + } + + /* Run test */ + for (i = 1; i <= n_keys; ++i) { + data.n_keys = i; + run_test(&data); + } + + secp256k1_zkp_context_destroy(data.ctx); + return(0); +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecdsa.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecdsa.h new file mode 100644 index 00000000..00fd3608 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecdsa.h @@ -0,0 +1,21 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_ECDSA_H +#define SECP256K1_ECDSA_H + +#include + +#include "scalar.h" +#include "group.h" +#include "ecmult.h" + +static int secp256k1_zkp_ecdsa_sig_parse(secp256k1_zkp_scalar *r, secp256k1_zkp_scalar *s, const unsigned char *sig, size_t size); +static int secp256k1_zkp_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *s); +static int secp256k1_zkp_ecdsa_sig_verify(const secp256k1_zkp_ecmult_context *ctx, const secp256k1_zkp_scalar* r, const secp256k1_zkp_scalar* s, const secp256k1_zkp_ge *pubkey, const secp256k1_zkp_scalar *message); +static int secp256k1_zkp_ecdsa_sig_sign(const secp256k1_zkp_ecmult_gen_context *ctx, secp256k1_zkp_scalar* r, secp256k1_zkp_scalar* s, const secp256k1_zkp_scalar *seckey, const secp256k1_zkp_scalar *message, const secp256k1_zkp_scalar *nonce, int *recid); + +#endif /* SECP256K1_ECDSA_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecdsa_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecdsa_impl.h new file mode 100644 index 00000000..f9df33c4 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecdsa_impl.h @@ -0,0 +1,313 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + + +#ifndef SECP256K1_ECDSA_IMPL_H +#define SECP256K1_ECDSA_IMPL_H + +#include "scalar.h" +#include "field.h" +#include "group.h" +#include "ecmult.h" +#include "ecmult_gen.h" +#include "ecdsa.h" + +/** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1 + * sage: for t in xrange(1023, -1, -1): + * .. p = 2**256 - 2**32 - t + * .. if p.is_prime(): + * .. print '%x'%p + * .. break + * 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f' + * sage: a = 0 + * sage: b = 7 + * sage: F = FiniteField (p) + * sage: '%x' % (EllipticCurve ([F (a), F (b)]).order()) + * 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141' + */ +static const secp256k1_zkp_fe secp256k1_zkp_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL +); + +/** Difference between field and order, values 'p' and 'n' values defined in + * "Standards for Efficient Cryptography" (SEC2) 2.7.1. + * sage: p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F + * sage: a = 0 + * sage: b = 7 + * sage: F = FiniteField (p) + * sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order()) + * '14551231950b75fc4402da1722fc9baee' + */ +static const secp256k1_zkp_fe secp256k1_zkp_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( + 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL +); + +static int secp256k1_zkp_der_read_len(const unsigned char **sigp, const unsigned char *sigend) { + int lenleft, b1; + size_t ret = 0; + if (*sigp >= sigend) { + return -1; + } + b1 = *((*sigp)++); + if (b1 == 0xFF) { + /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */ + return -1; + } + if ((b1 & 0x80) == 0) { + /* X.690-0207 8.1.3.4 short form length octets */ + return b1; + } + if (b1 == 0x80) { + /* Indefinite length is not allowed in DER. */ + return -1; + } + /* X.690-207 8.1.3.5 long form length octets */ + lenleft = b1 & 0x7F; + if (lenleft > sigend - *sigp) { + return -1; + } + if (**sigp == 0) { + /* Not the shortest possible length encoding. */ + return -1; + } + if ((size_t)lenleft > sizeof(size_t)) { + /* The resulting length would exceed the range of a size_t, so + * certainly longer than the passed array size. + */ + return -1; + } + while (lenleft > 0) { + ret = (ret << 8) | **sigp; + if (ret + lenleft > (size_t)(sigend - *sigp)) { + /* Result exceeds the length of the passed array. */ + return -1; + } + (*sigp)++; + lenleft--; + } + if (ret < 128) { + /* Not the shortest possible length encoding. */ + return -1; + } + return ret; +} + +static int secp256k1_zkp_der_parse_integer(secp256k1_zkp_scalar *r, const unsigned char **sig, const unsigned char *sigend) { + int overflow = 0; + unsigned char ra[32] = {0}; + int rlen; + + if (*sig == sigend || **sig != 0x02) { + /* Not a primitive integer (X.690-0207 8.3.1). */ + return 0; + } + (*sig)++; + rlen = secp256k1_zkp_der_read_len(sig, sigend); + if (rlen <= 0 || (*sig) + rlen > sigend) { + /* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */ + return 0; + } + if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) { + /* Excessive 0x00 padding. */ + return 0; + } + if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) { + /* Excessive 0xFF padding. */ + return 0; + } + if ((**sig & 0x80) == 0x80) { + /* Negative. */ + overflow = 1; + } + while (rlen > 0 && **sig == 0) { + /* Skip leading zero bytes */ + rlen--; + (*sig)++; + } + if (rlen > 32) { + overflow = 1; + } + if (!overflow) { + memcpy(ra + 32 - rlen, *sig, rlen); + secp256k1_zkp_scalar_set_b32(r, ra, &overflow); + } + if (overflow) { + secp256k1_zkp_scalar_set_int(r, 0); + } + (*sig) += rlen; + return 1; +} + +static int secp256k1_zkp_ecdsa_sig_parse(secp256k1_zkp_scalar *rr, secp256k1_zkp_scalar *rs, const unsigned char *sig, size_t size) { + const unsigned char *sigend = sig + size; + int rlen; + if (sig == sigend || *(sig++) != 0x30) { + /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */ + return 0; + } + rlen = secp256k1_zkp_der_read_len(&sig, sigend); + if (rlen < 0 || sig + rlen > sigend) { + /* Tuple exceeds bounds */ + return 0; + } + if (sig + rlen != sigend) { + /* Garbage after tuple. */ + return 0; + } + + if (!secp256k1_zkp_der_parse_integer(rr, &sig, sigend)) { + return 0; + } + if (!secp256k1_zkp_der_parse_integer(rs, &sig, sigend)) { + return 0; + } + + if (sig != sigend) { + /* Trailing garbage inside tuple. */ + return 0; + } + + return 1; +} + +static int secp256k1_zkp_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_zkp_scalar* ar, const secp256k1_zkp_scalar* as) { + unsigned char r[33] = {0}, s[33] = {0}; + unsigned char *rp = r, *sp = s; + size_t lenR = 33, lenS = 33; + secp256k1_zkp_scalar_get_b32(&r[1], ar); + secp256k1_zkp_scalar_get_b32(&s[1], as); + while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; } + while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; } + if (*size < 6+lenS+lenR) { + *size = 6 + lenS + lenR; + return 0; + } + *size = 6 + lenS + lenR; + sig[0] = 0x30; + sig[1] = 4 + lenS + lenR; + sig[2] = 0x02; + sig[3] = lenR; + memcpy(sig+4, rp, lenR); + sig[4+lenR] = 0x02; + sig[5+lenR] = lenS; + memcpy(sig+lenR+6, sp, lenS); + return 1; +} + +static int secp256k1_zkp_ecdsa_sig_verify(const secp256k1_zkp_ecmult_context *ctx, const secp256k1_zkp_scalar *sigr, const secp256k1_zkp_scalar *sigs, const secp256k1_zkp_ge *pubkey, const secp256k1_zkp_scalar *message) { + unsigned char c[32]; + secp256k1_zkp_scalar sn, u1, u2; +#if !defined(EXHAUSTIVE_TEST_ORDER) + secp256k1_zkp_fe xr; +#endif + secp256k1_zkp_gej pubkeyj; + secp256k1_zkp_gej pr; + + if (secp256k1_zkp_scalar_is_zero(sigr) || secp256k1_zkp_scalar_is_zero(sigs)) { + return 0; + } + + secp256k1_zkp_scalar_inverse_var(&sn, sigs); + secp256k1_zkp_scalar_mul(&u1, &sn, message); + secp256k1_zkp_scalar_mul(&u2, &sn, sigr); + secp256k1_zkp_gej_set_ge(&pubkeyj, pubkey); + secp256k1_zkp_ecmult(ctx, &pr, &pubkeyj, &u2, &u1); + if (secp256k1_zkp_gej_is_infinity(&pr)) { + return 0; + } + +#if defined(EXHAUSTIVE_TEST_ORDER) +{ + secp256k1_zkp_scalar computed_r; + secp256k1_zkp_ge pr_ge; + secp256k1_zkp_ge_set_gej(&pr_ge, &pr); + secp256k1_zkp_fe_normalize(&pr_ge.x); + + secp256k1_zkp_fe_get_b32(c, &pr_ge.x); + secp256k1_zkp_scalar_set_b32(&computed_r, c, NULL); + return secp256k1_zkp_scalar_eq(sigr, &computed_r); +} +#else + secp256k1_zkp_scalar_get_b32(c, sigr); + secp256k1_zkp_fe_set_b32(&xr, c); + + /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) + * in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p), + * compute the remainder modulo n, and compare it to xr. However: + * + * xr == X(pr) mod n + * <=> exists h. (xr + h * n < p && xr + h * n == X(pr)) + * [Since 2 * n > p, h can only be 0 or 1] + * <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr)) + * [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p] + * <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p) + * [Multiplying both sides of the equations by pr.z^2 mod p] + * <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x) + * + * Thus, we can avoid the inversion, but we have to check both cases separately. + * secp256k1_zkp_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. + */ + if (secp256k1_zkp_gej_eq_x_var(&xr, &pr)) { + /* xr * pr.z^2 mod p == pr.x, so the signature is valid. */ + return 1; + } + if (secp256k1_zkp_fe_cmp_var(&xr, &secp256k1_zkp_ecdsa_const_p_minus_order) >= 0) { + /* xr + n >= p, so we can skip testing the second case. */ + return 0; + } + secp256k1_zkp_fe_add(&xr, &secp256k1_zkp_ecdsa_const_order_as_fe); + if (secp256k1_zkp_gej_eq_x_var(&xr, &pr)) { + /* (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. */ + return 1; + } + return 0; +#endif +} + +static int secp256k1_zkp_ecdsa_sig_sign(const secp256k1_zkp_ecmult_gen_context *ctx, secp256k1_zkp_scalar *sigr, secp256k1_zkp_scalar *sigs, const secp256k1_zkp_scalar *seckey, const secp256k1_zkp_scalar *message, const secp256k1_zkp_scalar *nonce, int *recid) { + unsigned char b[32]; + secp256k1_zkp_gej rp; + secp256k1_zkp_ge r; + secp256k1_zkp_scalar n; + int overflow = 0; + + secp256k1_zkp_ecmult_gen(ctx, &rp, nonce); + secp256k1_zkp_ge_set_gej(&r, &rp); + secp256k1_zkp_fe_normalize(&r.x); + secp256k1_zkp_fe_normalize(&r.y); + secp256k1_zkp_fe_get_b32(b, &r.x); + secp256k1_zkp_scalar_set_b32(sigr, b, &overflow); + /* These two conditions should be checked before calling */ + VERIFY_CHECK(!secp256k1_zkp_scalar_is_zero(sigr)); + VERIFY_CHECK(overflow == 0); + + if (recid) { + /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log + * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria. + */ + *recid = (overflow ? 2 : 0) | (secp256k1_zkp_fe_is_odd(&r.y) ? 1 : 0); + } + secp256k1_zkp_scalar_mul(&n, sigr, seckey); + secp256k1_zkp_scalar_add(&n, &n, message); + secp256k1_zkp_scalar_inverse(sigs, nonce); + secp256k1_zkp_scalar_mul(sigs, sigs, &n); + secp256k1_zkp_scalar_clear(&n); + secp256k1_zkp_gej_clear(&rp); + secp256k1_zkp_ge_clear(&r); + if (secp256k1_zkp_scalar_is_zero(sigs)) { + return 0; + } + if (secp256k1_zkp_scalar_is_high(sigs)) { + secp256k1_zkp_scalar_negate(sigs, sigs); + if (recid) { + *recid ^= 1; + } + } + return 1; +} + +#endif /* SECP256K1_ECDSA_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/eckey.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/eckey.h new file mode 100644 index 00000000..27d5933d --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/eckey.h @@ -0,0 +1,25 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_ECKEY_H +#define SECP256K1_ECKEY_H + +#include + +#include "group.h" +#include "scalar.h" +#include "ecmult.h" +#include "ecmult_gen.h" + +static int secp256k1_zkp_eckey_pubkey_parse(secp256k1_zkp_ge *elem, const unsigned char *pub, size_t size); +static int secp256k1_zkp_eckey_pubkey_serialize(secp256k1_zkp_ge *elem, unsigned char *pub, size_t *size, int compressed); + +static int secp256k1_zkp_eckey_privkey_tweak_add(secp256k1_zkp_scalar *key, const secp256k1_zkp_scalar *tweak); +static int secp256k1_zkp_eckey_pubkey_tweak_add(const secp256k1_zkp_ecmult_context *ctx, secp256k1_zkp_ge *key, const secp256k1_zkp_scalar *tweak); +static int secp256k1_zkp_eckey_privkey_tweak_mul(secp256k1_zkp_scalar *key, const secp256k1_zkp_scalar *tweak); +static int secp256k1_zkp_eckey_pubkey_tweak_mul(const secp256k1_zkp_ecmult_context *ctx, secp256k1_zkp_ge *key, const secp256k1_zkp_scalar *tweak); + +#endif /* SECP256K1_ECKEY_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/eckey_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/eckey_impl.h new file mode 100644 index 00000000..a2dbbcdb --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/eckey_impl.h @@ -0,0 +1,100 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_ECKEY_IMPL_H +#define SECP256K1_ECKEY_IMPL_H + +#include "eckey.h" + +#include "scalar.h" +#include "field.h" +#include "group.h" +#include "ecmult_gen.h" + +static int secp256k1_zkp_eckey_pubkey_parse(secp256k1_zkp_ge *elem, const unsigned char *pub, size_t size) { + if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) { + secp256k1_zkp_fe x; + return secp256k1_zkp_fe_set_b32(&x, pub+1) && secp256k1_zkp_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD); + } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) { + secp256k1_zkp_fe x, y; + if (!secp256k1_zkp_fe_set_b32(&x, pub+1) || !secp256k1_zkp_fe_set_b32(&y, pub+33)) { + return 0; + } + secp256k1_zkp_ge_set_xy(elem, &x, &y); + if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) && + secp256k1_zkp_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { + return 0; + } + return secp256k1_zkp_ge_is_valid_var(elem); + } else { + return 0; + } +} + +static int secp256k1_zkp_eckey_pubkey_serialize(secp256k1_zkp_ge *elem, unsigned char *pub, size_t *size, int compressed) { + if (secp256k1_zkp_ge_is_infinity(elem)) { + return 0; + } + secp256k1_zkp_fe_normalize_var(&elem->x); + secp256k1_zkp_fe_normalize_var(&elem->y); + secp256k1_zkp_fe_get_b32(&pub[1], &elem->x); + if (compressed) { + *size = 33; + pub[0] = secp256k1_zkp_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; + } else { + *size = 65; + pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; + secp256k1_zkp_fe_get_b32(&pub[33], &elem->y); + } + return 1; +} + +static int secp256k1_zkp_eckey_privkey_tweak_add(secp256k1_zkp_scalar *key, const secp256k1_zkp_scalar *tweak) { + secp256k1_zkp_scalar_add(key, key, tweak); + if (secp256k1_zkp_scalar_is_zero(key)) { + return 0; + } + return 1; +} + +static int secp256k1_zkp_eckey_pubkey_tweak_add(const secp256k1_zkp_ecmult_context *ctx, secp256k1_zkp_ge *key, const secp256k1_zkp_scalar *tweak) { + secp256k1_zkp_gej pt; + secp256k1_zkp_scalar one; + secp256k1_zkp_gej_set_ge(&pt, key); + secp256k1_zkp_scalar_set_int(&one, 1); + secp256k1_zkp_ecmult(ctx, &pt, &pt, &one, tweak); + + if (secp256k1_zkp_gej_is_infinity(&pt)) { + return 0; + } + secp256k1_zkp_ge_set_gej(key, &pt); + return 1; +} + +static int secp256k1_zkp_eckey_privkey_tweak_mul(secp256k1_zkp_scalar *key, const secp256k1_zkp_scalar *tweak) { + if (secp256k1_zkp_scalar_is_zero(tweak)) { + return 0; + } + + secp256k1_zkp_scalar_mul(key, key, tweak); + return 1; +} + +static int secp256k1_zkp_eckey_pubkey_tweak_mul(const secp256k1_zkp_ecmult_context *ctx, secp256k1_zkp_ge *key, const secp256k1_zkp_scalar *tweak) { + secp256k1_zkp_scalar zero; + secp256k1_zkp_gej pt; + if (secp256k1_zkp_scalar_is_zero(tweak)) { + return 0; + } + + secp256k1_zkp_scalar_set_int(&zero, 0); + secp256k1_zkp_gej_set_ge(&pt, key); + secp256k1_zkp_ecmult(ctx, &pt, &pt, tweak, &zero); + secp256k1_zkp_ge_set_gej(key, &pt); + return 1; +} + +#endif /* SECP256K1_ECKEY_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult.h new file mode 100644 index 00000000..2e42e311 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult.h @@ -0,0 +1,48 @@ +/********************************************************************** + * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_ECMULT_H +#define SECP256K1_ECMULT_H + +#include "num.h" +#include "group.h" +#include "scalar.h" +#include "scratch.h" + +typedef struct { + /* For accelerating the computation of a*P + b*G: */ + secp256k1_zkp_ge_storage (*pre_g)[]; /* odd multiples of the generator */ +#ifdef USE_ENDOMORPHISM + secp256k1_zkp_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */ +#endif +} secp256k1_zkp_ecmult_context; + +static const size_t SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE; +static void secp256k1_zkp_ecmult_context_init(secp256k1_zkp_ecmult_context *ctx); +static void secp256k1_zkp_ecmult_context_build(secp256k1_zkp_ecmult_context *ctx, void **prealloc); +static void secp256k1_zkp_ecmult_context_finalize_memcpy(secp256k1_zkp_ecmult_context *dst, const secp256k1_zkp_ecmult_context *src); +static void secp256k1_zkp_ecmult_context_clear(secp256k1_zkp_ecmult_context *ctx); +static int secp256k1_zkp_ecmult_context_is_built(const secp256k1_zkp_ecmult_context *ctx); + +/** Double multiply: R = na*A + ng*G */ +static void secp256k1_zkp_ecmult(const secp256k1_zkp_ecmult_context *ctx, secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, const secp256k1_zkp_scalar *na, const secp256k1_zkp_scalar *ng); + +typedef int (secp256k1_zkp_ecmult_multi_callback)(secp256k1_zkp_scalar *sc, secp256k1_zkp_ge *pt, size_t idx, void *data); + +/** + * Multi-multiply: R = inp_g_sc * G + sum_i ni * Ai. + * Chooses the right algorithm for a given number of points and scratch space + * size. Resets and overwrites the given scratch space. If the points do not + * fit in the scratch space the algorithm is repeatedly run with batches of + * points. If no scratch space is given then a simple algorithm is used that + * simply multiplies the points with the corresponding scalars and adds them up. + * Returns: 1 on success (including when inp_g_sc is NULL and n is 0) + * 0 if there is not enough scratch space for a single point or + * callback returns 0 + */ +static int secp256k1_zkp_ecmult_multi_var(const secp256k1_zkp_ecmult_context *ctx, secp256k1_zkp_scratch *scratch, secp256k1_zkp_gej *r, const secp256k1_zkp_scalar *inp_g_sc, secp256k1_zkp_ecmult_multi_callback cb, void *cbdata, size_t n); + +#endif /* SECP256K1_ECMULT_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_const.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_const.h new file mode 100644 index 00000000..f06bf463 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_const.h @@ -0,0 +1,17 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_ECMULT_CONST_H +#define SECP256K1_ECMULT_CONST_H + +#include "scalar.h" +#include "group.h" + +/* Here `bits` should be set to the maximum bitlength of the _absolute value_ of `q`, plus + * one because we internally sometimes add 2 to the number during the WNAF conversion. */ +static void secp256k1_zkp_ecmult_const(secp256k1_zkp_gej *r, const secp256k1_zkp_ge *a, const secp256k1_zkp_scalar *q, int bits); + +#endif /* SECP256K1_ECMULT_CONST_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_const_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_const_impl.h new file mode 100644 index 00000000..4263168c --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_const_impl.h @@ -0,0 +1,261 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_ECMULT_CONST_IMPL_H +#define SECP256K1_ECMULT_CONST_IMPL_H + +#include "scalar.h" +#include "group.h" +#include "ecmult_const.h" +#include "ecmult_impl.h" + +/* This is like `ECMULT_TABLE_GET_GE` but is constant time */ +#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \ + int m; \ + int abs_n = (n) * (((n) > 0) * 2 - 1); \ + int idx_n = abs_n / 2; \ + secp256k1_zkp_fe neg_y; \ + VERIFY_CHECK(((n) & 1) == 1); \ + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ + VERIFY_SETUP(secp256k1_zkp_fe_clear(&(r)->x)); \ + VERIFY_SETUP(secp256k1_zkp_fe_clear(&(r)->y)); \ + for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \ + /* This loop is used to avoid secret data in array indices. See + * the comment in ecmult_gen_impl.h for rationale. */ \ + secp256k1_zkp_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \ + secp256k1_zkp_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \ + } \ + (r)->infinity = 0; \ + secp256k1_zkp_fe_negate(&neg_y, &(r)->y, 1); \ + secp256k1_zkp_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \ +} while(0) + + +/** Convert a number to WNAF notation. + * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. + * It has the following guarantees: + * - each wnaf[i] an odd integer between -(1 << w) and (1 << w) + * - each wnaf[i] is nonzero + * - the number of words set is always WNAF_SIZE(w) + 1 + * + * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar + * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.) + * CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003 + * + * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335 + */ +static int secp256k1_zkp_wnaf_const(int *wnaf, secp256k1_zkp_scalar s, int w, int size) { + int global_sign; + int skew = 0; + int word = 0; + + /* 1 2 3 */ + int u_last; + int u; + + int flip; + int bit; + secp256k1_zkp_scalar neg_s; + int not_neg_one; + + VERIFY_CHECK(w > 0); + VERIFY_CHECK(size > 0); + + /* Note that we cannot handle even numbers by negating them to be odd, as is + * done in other implementations, since if our scalars were specified to have + * width < 256 for performance reasons, their negations would have width 256 + * and we'd lose any performance benefit. Instead, we use a technique from + * Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even) + * or 2 (for odd) to the number we are encoding, returning a skew value indicating + * this, and having the caller compensate after doing the multiplication. + * + * In fact, we _do_ want to negate numbers to minimize their bit-lengths (and in + * particular, to ensure that the outputs from the endomorphism-split fit into + * 128 bits). If we negate, the parity of our number flips, inverting which of + * {1, 2} we want to add to the scalar when ensuring that it's odd. Further + * complicating things, -1 interacts badly with `secp256k1_zkp_scalar_cadd_bit` and + * we need to special-case it in this logic. */ + flip = secp256k1_zkp_scalar_is_high(&s); + /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */ + bit = flip ^ !secp256k1_zkp_scalar_is_even(&s); + /* We check for negative one, since adding 2 to it will cause an overflow */ + secp256k1_zkp_scalar_negate(&neg_s, &s); + not_neg_one = !secp256k1_zkp_scalar_is_one(&neg_s); + secp256k1_zkp_scalar_cadd_bit(&s, bit, not_neg_one); + /* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects + * that we added two to it and flipped it. In fact for -1 these operations are + * identical. We only flipped, but since skewing is required (in the sense that + * the skew must be 1 or 2, never zero) and flipping is not, we need to change + * our flags to claim that we only skewed. */ + global_sign = secp256k1_zkp_scalar_cond_negate(&s, flip); + global_sign *= not_neg_one * 2 - 1; + skew = 1 << bit; + + /* 4 */ + u_last = secp256k1_zkp_scalar_shr_int(&s, w); + do { + int sign; + int even; + + /* 4.1 4.4 */ + u = secp256k1_zkp_scalar_shr_int(&s, w); + /* 4.2 */ + even = ((u & 1) == 0); + sign = 2 * (u_last > 0) - 1; + u += sign * even; + u_last -= sign * even * (1 << w); + + /* 4.3, adapted for global sign change */ + wnaf[word++] = u_last * global_sign; + + u_last = u; + } while (word * w < size); + wnaf[word] = u * global_sign; + + VERIFY_CHECK(secp256k1_zkp_scalar_is_zero(&s)); + VERIFY_CHECK(word == WNAF_SIZE_BITS(size, w)); + return skew; +} + +static void secp256k1_zkp_ecmult_const(secp256k1_zkp_gej *r, const secp256k1_zkp_ge *a, const secp256k1_zkp_scalar *scalar, int size) { + secp256k1_zkp_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_zkp_ge tmpa; + secp256k1_zkp_fe Z; + + int skew_1; +#ifdef USE_ENDOMORPHISM + secp256k1_zkp_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; + int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; + int skew_lam; + secp256k1_zkp_scalar q_1, q_lam; +#endif + int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; + + int i; + secp256k1_zkp_scalar sc = *scalar; + + /* build wnaf representation for q. */ + int rsize = size; +#ifdef USE_ENDOMORPHISM + if (size > 128) { + rsize = 128; + /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ + secp256k1_zkp_scalar_split_lambda(&q_1, &q_lam, &sc); + skew_1 = secp256k1_zkp_wnaf_const(wnaf_1, q_1, WINDOW_A - 1, 128); + skew_lam = secp256k1_zkp_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1, 128); + } else +#endif + { + skew_1 = secp256k1_zkp_wnaf_const(wnaf_1, sc, WINDOW_A - 1, size); +#ifdef USE_ENDOMORPHISM + skew_lam = 0; +#endif + } + + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + */ + secp256k1_zkp_gej_set_ge(r, a); + secp256k1_zkp_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r); + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_zkp_fe_normalize_weak(&pre_a[i].y); + } +#ifdef USE_ENDOMORPHISM + if (size > 128) { + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_zkp_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); + } + } +#endif + + /* first loop iteration (separated out so we can directly set r, rather + * than having it start at infinity, get doubled several times, then have + * its new value added to it) */ + i = wnaf_1[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); + secp256k1_zkp_gej_set_ge(r, &tmpa); +#ifdef USE_ENDOMORPHISM + if (size > 128) { + i = wnaf_lam[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); + secp256k1_zkp_gej_add_ge(r, r, &tmpa); + } +#endif + /* remaining loop iterations */ + for (i = WNAF_SIZE_BITS(rsize, WINDOW_A - 1) - 1; i >= 0; i--) { + int n; + int j; + for (j = 0; j < WINDOW_A - 1; ++j) { + secp256k1_zkp_gej_double_nonzero(r, r, NULL); + } + + n = wnaf_1[i]; + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + VERIFY_CHECK(n != 0); + secp256k1_zkp_gej_add_ge(r, r, &tmpa); +#ifdef USE_ENDOMORPHISM + if (size > 128) { + n = wnaf_lam[i]; + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); + VERIFY_CHECK(n != 0); + secp256k1_zkp_gej_add_ge(r, r, &tmpa); + } +#endif + } + + secp256k1_zkp_fe_mul(&r->z, &r->z, &Z); + + { + /* Correct for wNAF skew */ + secp256k1_zkp_ge correction = *a; + secp256k1_zkp_ge_storage correction_1_stor; +#ifdef USE_ENDOMORPHISM + secp256k1_zkp_ge_storage correction_lam_stor; +#endif + secp256k1_zkp_ge_storage a2_stor; + secp256k1_zkp_gej tmpj; + secp256k1_zkp_gej_set_ge(&tmpj, &correction); + secp256k1_zkp_gej_double_var(&tmpj, &tmpj, NULL); + secp256k1_zkp_ge_set_gej(&correction, &tmpj); + secp256k1_zkp_ge_to_storage(&correction_1_stor, a); +#ifdef USE_ENDOMORPHISM + if (size > 128) { + secp256k1_zkp_ge_to_storage(&correction_lam_stor, a); + } +#endif + secp256k1_zkp_ge_to_storage(&a2_stor, &correction); + + /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */ + secp256k1_zkp_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2); +#ifdef USE_ENDOMORPHISM + if (size > 128) { + secp256k1_zkp_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2); + } +#endif + + /* Apply the correction */ + secp256k1_zkp_ge_from_storage(&correction, &correction_1_stor); + secp256k1_zkp_ge_neg(&correction, &correction); + secp256k1_zkp_gej_add_ge(r, r, &correction); + +#ifdef USE_ENDOMORPHISM + if (size > 128) { + secp256k1_zkp_ge_from_storage(&correction, &correction_lam_stor); + secp256k1_zkp_ge_neg(&correction, &correction); + secp256k1_zkp_ge_mul_lambda(&correction, &correction); + secp256k1_zkp_gej_add_ge(r, r, &correction); + } +#endif + } +} + +#endif /* SECP256K1_ECMULT_CONST_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_gen.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_gen.h new file mode 100644 index 00000000..b0fff613 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_gen.h @@ -0,0 +1,43 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_ECMULT_GEN_H +#define SECP256K1_ECMULT_GEN_H + +#include "scalar.h" +#include "group.h" + +typedef struct { + /* For accelerating the computation of a*G: + * To harden against timing attacks, use the following mechanism: + * * Break up the multiplicand into groups of 4 bits, called n_0, n_1, n_2, ..., n_63. + * * Compute sum(n_i * 16^i * G + U_i, i=0..63), where: + * * U_i = U * 2^i (for i=0..62) + * * U_i = U * (1-2^63) (for i=63) + * where U is a point with no known corresponding scalar. Note that sum(U_i, i=0..63) = 0. + * For each i, and each of the 16 possible values of n_i, (n_i * 16^i * G + U_i) is + * precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63). + * None of the resulting prec group elements have a known scalar, and neither do any of + * the intermediate sums while computing a*G. + */ + secp256k1_zkp_ge_storage (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */ + secp256k1_zkp_scalar blind; + secp256k1_zkp_gej initial; +} secp256k1_zkp_ecmult_gen_context; + +static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE; +static void secp256k1_zkp_ecmult_gen_context_init(secp256k1_zkp_ecmult_gen_context* ctx); +static void secp256k1_zkp_ecmult_gen_context_build(secp256k1_zkp_ecmult_gen_context* ctx, void **prealloc); +static void secp256k1_zkp_ecmult_gen_context_finalize_memcpy(secp256k1_zkp_ecmult_gen_context *dst, const secp256k1_zkp_ecmult_gen_context* src); +static void secp256k1_zkp_ecmult_gen_context_clear(secp256k1_zkp_ecmult_gen_context* ctx); +static int secp256k1_zkp_ecmult_gen_context_is_built(const secp256k1_zkp_ecmult_gen_context* ctx); + +/** Multiply with the generator: R = a*G */ +static void secp256k1_zkp_ecmult_gen(const secp256k1_zkp_ecmult_gen_context* ctx, secp256k1_zkp_gej *r, const secp256k1_zkp_scalar *a); + +static void secp256k1_zkp_ecmult_gen_blind(secp256k1_zkp_ecmult_gen_context *ctx, const unsigned char *seed32); + +#endif /* SECP256K1_ECMULT_GEN_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_gen_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_gen_impl.h new file mode 100644 index 00000000..51f0a3eb --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_gen_impl.h @@ -0,0 +1,211 @@ +/********************************************************************** + * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_ECMULT_GEN_IMPL_H +#define SECP256K1_ECMULT_GEN_IMPL_H + +#include "util.h" +#include "scalar.h" +#include "group.h" +#include "ecmult_gen.h" +#include "hash_impl.h" +#ifdef USE_ECMULT_STATIC_PRECOMPUTATION +#include "ecmult_static_context.h" +#endif + +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE = ROUND_TO_ALIGN(sizeof(*((secp256k1_zkp_ecmult_gen_context*) NULL)->prec)); +#else + static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE = 0; +#endif + +static void secp256k1_zkp_ecmult_gen_context_init(secp256k1_zkp_ecmult_gen_context *ctx) { + ctx->prec = NULL; +} + +static void secp256k1_zkp_ecmult_gen_context_build(secp256k1_zkp_ecmult_gen_context *ctx, void **prealloc) { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + secp256k1_zkp_ge prec[1024]; + secp256k1_zkp_gej gj; + secp256k1_zkp_gej nums_gej; + int i, j; + size_t const prealloc_size = SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE; + void* const base = *prealloc; +#endif + + if (ctx->prec != NULL) { + return; + } +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + ctx->prec = (secp256k1_zkp_ge_storage (*)[64][16])manual_alloc(prealloc, prealloc_size, base, prealloc_size); + + /* get the generator */ + secp256k1_zkp_gej_set_ge(&gj, &secp256k1_zkp_ge_const_g); + + /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ + { + static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; + secp256k1_zkp_fe nums_x; + secp256k1_zkp_ge nums_ge; + int r; + r = secp256k1_zkp_fe_set_b32(&nums_x, nums_b32); + (void)r; + VERIFY_CHECK(r); + r = secp256k1_zkp_ge_set_xo_var(&nums_ge, &nums_x, 0); + (void)r; + VERIFY_CHECK(r); + secp256k1_zkp_gej_set_ge(&nums_gej, &nums_ge); + /* Add G to make the bits in x uniformly distributed. */ + secp256k1_zkp_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_zkp_ge_const_g, NULL); + } + + /* compute prec. */ + { + secp256k1_zkp_gej precj[1024]; /* Jacobian versions of prec. */ + secp256k1_zkp_gej gbase; + secp256k1_zkp_gej numsbase; + gbase = gj; /* 16^j * G */ + numsbase = nums_gej; /* 2^j * nums. */ + for (j = 0; j < 64; j++) { + /* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */ + precj[j*16] = numsbase; + for (i = 1; i < 16; i++) { + secp256k1_zkp_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL); + } + /* Multiply gbase by 16. */ + for (i = 0; i < 4; i++) { + secp256k1_zkp_gej_double_var(&gbase, &gbase, NULL); + } + /* Multiply numbase by 2. */ + secp256k1_zkp_gej_double_var(&numsbase, &numsbase, NULL); + if (j == 62) { + /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ + secp256k1_zkp_gej_neg(&numsbase, &numsbase); + secp256k1_zkp_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); + } + } + secp256k1_zkp_ge_set_all_gej_var(prec, precj, 1024); + } + for (j = 0; j < 64; j++) { + for (i = 0; i < 16; i++) { + secp256k1_zkp_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]); + } + } +#else + (void)prealloc; + ctx->prec = (secp256k1_zkp_ge_storage (*)[64][16])secp256k1_zkp_ecmult_static_context; +#endif + secp256k1_zkp_ecmult_gen_blind(ctx, NULL); +} + +static int secp256k1_zkp_ecmult_gen_context_is_built(const secp256k1_zkp_ecmult_gen_context* ctx) { + return ctx->prec != NULL; +} + +static void secp256k1_zkp_ecmult_gen_context_finalize_memcpy(secp256k1_zkp_ecmult_gen_context *dst, const secp256k1_zkp_ecmult_gen_context *src) { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + if (src->prec != NULL) { + /* We cast to void* first to suppress a -Wcast-align warning in clang. */ + dst->prec = (secp256k1_zkp_ge_storage (*)[64][16])(void*)((unsigned char*)dst + ((unsigned char*)src->prec - (unsigned char*)src)); + } +#else + (void)dst, (void)src; +#endif +} + +static void secp256k1_zkp_ecmult_gen_context_clear(secp256k1_zkp_ecmult_gen_context *ctx) { + secp256k1_zkp_scalar_clear(&ctx->blind); + secp256k1_zkp_gej_clear(&ctx->initial); + ctx->prec = NULL; +} + +static void secp256k1_zkp_ecmult_gen(const secp256k1_zkp_ecmult_gen_context *ctx, secp256k1_zkp_gej *r, const secp256k1_zkp_scalar *gn) { + secp256k1_zkp_ge add; + secp256k1_zkp_ge_storage adds; + secp256k1_zkp_scalar gnb; + int bits; + int i, j; + memset(&adds, 0, sizeof(adds)); + *r = ctx->initial; + /* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */ + secp256k1_zkp_scalar_add(&gnb, gn, &ctx->blind); + add.infinity = 0; + for (j = 0; j < 64; j++) { + bits = secp256k1_zkp_scalar_get_bits(&gnb, j * 4, 4); + for (i = 0; i < 16; i++) { + /** This uses a conditional move to avoid any secret data in array indexes. + * _Any_ use of secret indexes has been demonstrated to result in timing + * sidechannels, even when the cache-line access patterns are uniform. + * See also: + * "A word of warning", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe + * (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and + * "Cache Attacks and Countermeasures: the Case of AES", RSA 2006, + * by Dag Arne Osvik, Adi Shamir, and Eran Tromer + * (http://www.tau.ac.il/~tromer/papers/cache.pdf) + */ + secp256k1_zkp_ge_storage_cmov(&adds, &(*ctx->prec)[j][i], i == bits); + } + secp256k1_zkp_ge_from_storage(&add, &adds); + secp256k1_zkp_gej_add_ge(r, r, &add); + } + bits = 0; + secp256k1_zkp_ge_clear(&add); + secp256k1_zkp_scalar_clear(&gnb); +} + +/* Setup blinding values for secp256k1_zkp_ecmult_gen. */ +static void secp256k1_zkp_ecmult_gen_blind(secp256k1_zkp_ecmult_gen_context *ctx, const unsigned char *seed32) { + secp256k1_zkp_scalar b; + secp256k1_zkp_gej gb; + secp256k1_zkp_fe s; + unsigned char nonce32[32]; + secp256k1_zkp_rfc6979_hmac_sha256 rng; + int retry; + unsigned char keydata[64] = {0}; + if (seed32 == NULL) { + /* When seed is NULL, reset the initial point and blinding value. */ + secp256k1_zkp_gej_set_ge(&ctx->initial, &secp256k1_zkp_ge_const_g); + secp256k1_zkp_gej_neg(&ctx->initial, &ctx->initial); + secp256k1_zkp_scalar_set_int(&ctx->blind, 1); + } + /* The prior blinding value (if not reset) is chained forward by including it in the hash. */ + secp256k1_zkp_scalar_get_b32(nonce32, &ctx->blind); + /** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data, + * and guards against weak or adversarial seeds. This is a simpler and safer interface than + * asking the caller for blinding values directly and expecting them to retry on failure. + */ + memcpy(keydata, nonce32, 32); + if (seed32 != NULL) { + memcpy(keydata + 32, seed32, 32); + } + secp256k1_zkp_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32); + memset(keydata, 0, sizeof(keydata)); + /* Retry for out of range results to achieve uniformity. */ + do { + secp256k1_zkp_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + retry = !secp256k1_zkp_fe_set_b32(&s, nonce32); + retry |= secp256k1_zkp_fe_is_zero(&s); + } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */ + /* Randomize the projection to defend against multiplier sidechannels. */ + secp256k1_zkp_gej_rescale(&ctx->initial, &s); + secp256k1_zkp_fe_clear(&s); + do { + secp256k1_zkp_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_zkp_scalar_set_b32(&b, nonce32, &retry); + /* A blinding value of 0 works, but would undermine the projection hardening. */ + retry |= secp256k1_zkp_scalar_is_zero(&b); + } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */ + secp256k1_zkp_rfc6979_hmac_sha256_finalize(&rng); + memset(nonce32, 0, 32); + secp256k1_zkp_ecmult_gen(ctx, &gb, &b); + secp256k1_zkp_scalar_negate(&b, &b); + ctx->blind = b; + ctx->initial = gb; + secp256k1_zkp_scalar_clear(&b); + secp256k1_zkp_gej_clear(&gb); +} + +#endif /* SECP256K1_ECMULT_GEN_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_impl.h new file mode 100644 index 00000000..68461655 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/ecmult_impl.h @@ -0,0 +1,1190 @@ +/***************************************************************************** + * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php. * + *****************************************************************************/ + +#ifndef SECP256K1_ECMULT_IMPL_H +#define SECP256K1_ECMULT_IMPL_H + +#include +#include + +#include "util.h" +#include "group.h" +#include "scalar.h" +#include "ecmult.h" + +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need to lower these values for exhaustive tests because + * the tables cannot have infinities in them (this breaks the + * affine-isomorphism stuff which tracks z-ratios) */ +# if EXHAUSTIVE_TEST_ORDER > 128 +# define WINDOW_A 5 +# define WINDOW_G 8 +# elif EXHAUSTIVE_TEST_ORDER > 8 +# define WINDOW_A 4 +# define WINDOW_G 4 +# else +# define WINDOW_A 2 +# define WINDOW_G 2 +# endif +#else +/* optimal for 128-bit and 256-bit exponents. */ +# define WINDOW_A 5 +/** Larger values for ECMULT_WINDOW_SIZE result in possibly better + * performance at the cost of an exponentially larger precomputed + * table. The exact table size is + * (1 << (WINDOW_G - 2)) * sizeof(secp256k1_zkp_ge_storage) bytes, + * where sizeof(secp256k1_zkp_ge_storage) is typically 64 bytes but can + * be larger due to platform-specific padding and alignment. + */ +# ifdef USE_ENDOMORPHISM +# define WINDOW_G ((ECMULT_WINDOW_SIZE)-1) +# else +# define WINDOW_G (ECMULT_WINDOW_SIZE) +# endif +#endif + +/* Noone will ever need more than a window size of 24. The code might + * be correct for larger values of ECMULT_WINDOW_SIZE but this is not + * not tested. + * + * The following limitations are known, and there are probably more: + * If WINDOW_G > 27 and size_t has 32 bits, then the code is incorrect + * because the size of the memory object that we allocate (in bytes) + * will not fit in a size_t. + * If WINDOW_G > 31 and int has 32 bits, then the code is incorrect + * because certain expressions will overflow. + * */ +#if ECMULT_WINDOW_SIZE < 3 || ECMULT_WINDOW_SIZE > 24 +# error Set ECMULT_WINDOW_SIZE to an integer in range [3..24]. +#endif + +#ifdef USE_ENDOMORPHISM + #define WNAF_BITS 128 +#else + #define WNAF_BITS 256 +#endif +#define WNAF_SIZE_BITS(bits, w) (((bits) + (w) - 1) / (w)) +#define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w) + +/** The number of entries a table with precomputed multiples needs to have. */ +#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2)) + +/* The number of objects allocated on the scratch space for ecmult_multi algorithms */ +#define PIPPENGER_SCRATCH_OBJECTS 6 +#define STRAUSS_SCRATCH_OBJECTS 6 + +#define PIPPENGER_MAX_BUCKET_WINDOW 12 + +/* Minimum number of points for which pippenger_wnaf is faster than strauss wnaf */ +#ifdef USE_ENDOMORPHISM + #define ECMULT_PIPPENGER_THRESHOLD 88 +#else + #define ECMULT_PIPPENGER_THRESHOLD 160 +#endif + +#ifdef USE_ENDOMORPHISM + #define ECMULT_MAX_POINTS_PER_BATCH 5000000 +#else + #define ECMULT_MAX_POINTS_PER_BATCH 10000000 +#endif + +/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain + * the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will + * contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z. + * Prej's Z values are undefined, except for the last value. + */ +static void secp256k1_zkp_ecmult_odd_multiples_table(int n, secp256k1_zkp_gej *prej, secp256k1_zkp_fe *zr, const secp256k1_zkp_gej *a) { + secp256k1_zkp_gej d; + secp256k1_zkp_ge a_ge, d_ge; + int i; + + VERIFY_CHECK(!a->infinity); + + secp256k1_zkp_gej_double_var(&d, a, NULL); + + /* + * Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate + * of 'd', and scale the 1P starting value's x/y coordinates without changing its z. + */ + d_ge.x = d.x; + d_ge.y = d.y; + d_ge.infinity = 0; + + secp256k1_zkp_ge_set_gej_zinv(&a_ge, a, &d.z); + prej[0].x = a_ge.x; + prej[0].y = a_ge.y; + prej[0].z = a->z; + prej[0].infinity = 0; + + zr[0] = d.z; + for (i = 1; i < n; i++) { + secp256k1_zkp_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]); + } + + /* + * Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only + * the final point's z coordinate is actually used though, so just update that. + */ + secp256k1_zkp_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z); +} + +/** Fill a table 'pre' with precomputed odd multiples of a. + * + * There are two versions of this function: + * - secp256k1_zkp_ecmult_odd_multiples_table_globalz_windowa which brings its + * resulting point set to a single constant Z denominator, stores the X and Y + * coordinates as ge_storage points in pre, and stores the global Z in rz. + * It only operates on tables sized for WINDOW_A wnaf multiples. + * - secp256k1_zkp_ecmult_odd_multiples_table_storage_var, which converts its + * resulting point set to actually affine points, and stores those in pre. + * It operates on tables of any size, but uses heap-allocated temporaries. + * + * To compute a*P + b*G, we compute a table for P using the first function, + * and for G using the second (which requires an inverse, but it only needs to + * happen once). + */ +static void secp256k1_zkp_ecmult_odd_multiples_table_globalz_windowa(secp256k1_zkp_ge *pre, secp256k1_zkp_fe *globalz, const secp256k1_zkp_gej *a) { + secp256k1_zkp_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_zkp_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)]; + + /* Compute the odd multiples in Jacobian form. */ + secp256k1_zkp_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a); + /* Bring them to the same Z denominator. */ + secp256k1_zkp_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr); +} + +static void secp256k1_zkp_ecmult_odd_multiples_table_storage_var(const int n, secp256k1_zkp_ge_storage *pre, const secp256k1_zkp_gej *a) { + secp256k1_zkp_gej d; + secp256k1_zkp_ge d_ge, p_ge; + secp256k1_zkp_gej pj; + secp256k1_zkp_fe zi; + secp256k1_zkp_fe zr; + secp256k1_zkp_fe dx_over_dz_squared; + int i; + + VERIFY_CHECK(!a->infinity); + + secp256k1_zkp_gej_double_var(&d, a, NULL); + + /* First, we perform all the additions in an isomorphic curve obtained by multiplying + * all `z` coordinates by 1/`d.z`. In these coordinates `d` is affine so we can use + * `secp256k1_zkp_gej_add_ge_var` to perform the additions. For each addition, we store + * the resulting y-coordinate and the z-ratio, since we only have enough memory to + * store two field elements. These are sufficient to efficiently undo the isomorphism + * and recompute all the `x`s. + */ + d_ge.x = d.x; + d_ge.y = d.y; + d_ge.infinity = 0; + + secp256k1_zkp_ge_set_gej_zinv(&p_ge, a, &d.z); + pj.x = p_ge.x; + pj.y = p_ge.y; + pj.z = a->z; + pj.infinity = 0; + + for (i = 0; i < (n - 1); i++) { + secp256k1_zkp_fe_normalize_var(&pj.y); + secp256k1_zkp_fe_to_storage(&pre[i].y, &pj.y); + secp256k1_zkp_gej_add_ge_var(&pj, &pj, &d_ge, &zr); + secp256k1_zkp_fe_normalize_var(&zr); + secp256k1_zkp_fe_to_storage(&pre[i].x, &zr); + } + + /* Invert d.z in the same batch, preserving pj.z so we can extract 1/d.z */ + secp256k1_zkp_fe_mul(&zi, &pj.z, &d.z); + secp256k1_zkp_fe_inv_var(&zi, &zi); + + /* Directly set `pre[n - 1]` to `pj`, saving the inverted z-coordinate so + * that we can combine it with the saved z-ratios to compute the other zs + * without any more inversions. */ + secp256k1_zkp_ge_set_gej_zinv(&p_ge, &pj, &zi); + secp256k1_zkp_ge_to_storage(&pre[n - 1], &p_ge); + + /* Compute the actual x-coordinate of D, which will be needed below. */ + secp256k1_zkp_fe_mul(&d.z, &zi, &pj.z); /* d.z = 1/d.z */ + secp256k1_zkp_fe_sqr(&dx_over_dz_squared, &d.z); + secp256k1_zkp_fe_mul(&dx_over_dz_squared, &dx_over_dz_squared, &d.x); + + /* Going into the second loop, we have set `pre[n-1]` to its final affine + * form, but still need to set `pre[i]` for `i` in 0 through `n-2`. We + * have `zi = (p.z * d.z)^-1`, where + * + * `p.z` is the z-coordinate of the point on the isomorphic curve + * which was ultimately assigned to `pre[n-1]`. + * `d.z` is the multiplier that must be applied to all z-coordinates + * to move from our isomorphic curve back to secp256k1; so the + * product `p.z * d.z` is the z-coordinate of the secp256k1 + * point assigned to `pre[n-1]`. + * + * All subsequent inverse-z-coordinates can be obtained by multiplying this + * factor by successive z-ratios, which is much more efficient than directly + * computing each one. + * + * Importantly, these inverse-zs will be coordinates of points on secp256k1, + * while our other stored values come from computations on the isomorphic + * curve. So in the below loop, we will take care not to actually use `zi` + * or any derived values until we're back on secp256k1. + */ + i = n - 1; + while (i > 0) { + secp256k1_zkp_fe zi2, zi3; + const secp256k1_zkp_fe *rzr; + i--; + + secp256k1_zkp_ge_from_storage(&p_ge, &pre[i]); + + /* For each remaining point, we extract the z-ratio from the stored + * x-coordinate, compute its z^-1 from that, and compute the full + * point from that. */ + rzr = &p_ge.x; + secp256k1_zkp_fe_mul(&zi, &zi, rzr); + secp256k1_zkp_fe_sqr(&zi2, &zi); + secp256k1_zkp_fe_mul(&zi3, &zi2, &zi); + /* To compute the actual x-coordinate, we use the stored z ratio and + * y-coordinate, which we obtained from `secp256k1_zkp_gej_add_ge_var` + * in the loop above, as well as the inverse of the square of its + * z-coordinate. We store the latter in the `zi2` variable, which is + * computed iteratively starting from the overall Z inverse then + * multiplying by each z-ratio in turn. + * + * Denoting the z-ratio as `rzr`, we observe that it is equal to `h` + * from the inside of the above `gej_add_ge_var` call. This satisfies + * + * rzr = d_x * z^2 - x * d_z^2 + * + * where (`d_x`, `d_z`) are Jacobian coordinates of `D` and `(x, z)` + * are Jacobian coordinates of our desired point -- except both are on + * the isomorphic curve that we were using when we called `gej_add_ge_var`. + * To get back to secp256k1, we must multiply both `z`s by `d_z`, or + * equivalently divide both `x`s by `d_z^2`. Our equation then becomes + * + * rzr = d_x * z^2 / d_z^2 - x + * + * (The left-hand-side, being a ratio of z-coordinates, is unaffected + * by the isomorphism.) + * + * Rearranging to solve for `x`, we have + * + * x = d_x * z^2 / d_z^2 - rzr + * + * But what we actually want is the affine coordinate `X = x/z^2`, + * which will satisfy + * + * X = d_x / d_z^2 - rzr / z^2 + * = dx_over_dz_squared - rzr * zi2 + */ + secp256k1_zkp_fe_mul(&p_ge.x, rzr, &zi2); + secp256k1_zkp_fe_negate(&p_ge.x, &p_ge.x, 1); + secp256k1_zkp_fe_add(&p_ge.x, &dx_over_dz_squared); + /* y is stored_y/z^3, as we expect */ + secp256k1_zkp_fe_mul(&p_ge.y, &p_ge.y, &zi3); + /* Store */ + secp256k1_zkp_ge_to_storage(&pre[i], &p_ge); + } +} + +/** The following two macro retrieves a particular odd multiple from a table + * of precomputed multiples. */ +#define ECMULT_TABLE_GET_GE(r,pre,n,w) do { \ + VERIFY_CHECK(((n) & 1) == 1); \ + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ + if ((n) > 0) { \ + *(r) = (pre)[((n)-1)/2]; \ + } else { \ + secp256k1_zkp_ge_neg((r), &(pre)[(-(n)-1)/2]); \ + } \ +} while(0) + +#define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \ + VERIFY_CHECK(((n) & 1) == 1); \ + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ + if ((n) > 0) { \ + secp256k1_zkp_ge_from_storage((r), &(pre)[((n)-1)/2]); \ + } else { \ + secp256k1_zkp_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \ + secp256k1_zkp_ge_neg((r), (r)); \ + } \ +} while(0) + +static const size_t SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE = + ROUND_TO_ALIGN(sizeof((*((secp256k1_zkp_ecmult_context*) NULL)->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)) +#ifdef USE_ENDOMORPHISM + + ROUND_TO_ALIGN(sizeof((*((secp256k1_zkp_ecmult_context*) NULL)->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)) +#endif + ; + +static void secp256k1_zkp_ecmult_context_init(secp256k1_zkp_ecmult_context *ctx) { + ctx->pre_g = NULL; +#ifdef USE_ENDOMORPHISM + ctx->pre_g_128 = NULL; +#endif +} + +static void secp256k1_zkp_ecmult_context_build(secp256k1_zkp_ecmult_context *ctx, void **prealloc) { + secp256k1_zkp_gej gj; + void* const base = *prealloc; + size_t const prealloc_size = SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE; + + if (ctx->pre_g != NULL) { + return; + } + + /* get the generator */ + secp256k1_zkp_gej_set_ge(&gj, &secp256k1_zkp_ge_const_g); + + { + size_t size = sizeof((*ctx->pre_g)[0]) * ((size_t)ECMULT_TABLE_SIZE(WINDOW_G)); + /* check for overflow */ + VERIFY_CHECK(size / sizeof((*ctx->pre_g)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G))); + ctx->pre_g = (secp256k1_zkp_ge_storage (*)[])manual_alloc(prealloc, size, base, prealloc_size); + } + + /* precompute the tables with odd multiples */ + secp256k1_zkp_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj); + +#ifdef USE_ENDOMORPHISM + { + secp256k1_zkp_gej g_128j; + int i; + + size_t size = sizeof((*ctx->pre_g_128)[0]) * ((size_t) ECMULT_TABLE_SIZE(WINDOW_G)); + /* check for overflow */ + VERIFY_CHECK(size / sizeof((*ctx->pre_g_128)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G))); + ctx->pre_g_128 = (secp256k1_zkp_ge_storage (*)[])manual_alloc(prealloc, size, base, prealloc_size); + + /* calculate 2^128*generator */ + g_128j = gj; + for (i = 0; i < 128; i++) { + secp256k1_zkp_gej_double_var(&g_128j, &g_128j, NULL); + } + secp256k1_zkp_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j); + } +#endif +} + +static void secp256k1_zkp_ecmult_context_finalize_memcpy(secp256k1_zkp_ecmult_context *dst, const secp256k1_zkp_ecmult_context *src) { + if (src->pre_g != NULL) { + dst->pre_g = (secp256k1_zkp_ge_storage (*)[])((unsigned char*)dst + ((unsigned char*)(src->pre_g) - (unsigned char*)src)); + } +#ifdef USE_ENDOMORPHISM + if (src->pre_g_128 != NULL) { + dst->pre_g_128 = (secp256k1_zkp_ge_storage (*)[])((unsigned char*)dst + ((unsigned char*)(src->pre_g_128) - (unsigned char*)src)); + } +#endif +} + +static int secp256k1_zkp_ecmult_context_is_built(const secp256k1_zkp_ecmult_context *ctx) { + return ctx->pre_g != NULL; +} + +static void secp256k1_zkp_ecmult_context_clear(secp256k1_zkp_ecmult_context *ctx) { + secp256k1_zkp_ecmult_context_init(ctx); +} + +/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits), + * with the following guarantees: + * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) + * - two non-zero entries in wnaf are separated by at least w-1 zeroes. + * - the number of set values in wnaf is returned. This number is at most 256, and at most one more + * than the number of bits in the (absolute value) of the input. + */ +static int secp256k1_zkp_ecmult_wnaf(int *wnaf, int len, const secp256k1_zkp_scalar *a, int w) { + secp256k1_zkp_scalar s = *a; + int last_set_bit = -1; + int bit = 0; + int sign = 1; + int carry = 0; + + VERIFY_CHECK(wnaf != NULL); + VERIFY_CHECK(0 <= len && len <= 256); + VERIFY_CHECK(a != NULL); + VERIFY_CHECK(2 <= w && w <= 31); + + memset(wnaf, 0, len * sizeof(wnaf[0])); + + if (secp256k1_zkp_scalar_get_bits(&s, 255, 1)) { + secp256k1_zkp_scalar_negate(&s, &s); + sign = -1; + } + + while (bit < len) { + int now; + int word; + if (secp256k1_zkp_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) { + bit++; + continue; + } + + now = w; + if (now > len - bit) { + now = len - bit; + } + + word = secp256k1_zkp_scalar_get_bits_var(&s, bit, now) + carry; + + carry = (word >> (w-1)) & 1; + word -= carry << w; + + wnaf[bit] = sign * word; + last_set_bit = bit; + + bit += now; + } +#ifdef VERIFY + CHECK(carry == 0); + while (bit < 256) { + CHECK(secp256k1_zkp_scalar_get_bits(&s, bit++, 1) == 0); + } +#endif + return last_set_bit + 1; +} + +struct secp256k1_zkp_strauss_point_state { +#ifdef USE_ENDOMORPHISM + secp256k1_zkp_scalar na_1, na_lam; + int wnaf_na_1[130]; + int wnaf_na_lam[130]; + int bits_na_1; + int bits_na_lam; +#else + int wnaf_na[256]; + int bits_na; +#endif + size_t input_pos; +}; + +struct secp256k1_zkp_strauss_state { + secp256k1_zkp_gej* prej; + secp256k1_zkp_fe* zr; + secp256k1_zkp_ge* pre_a; +#ifdef USE_ENDOMORPHISM + secp256k1_zkp_ge* pre_a_lam; +#endif + struct secp256k1_zkp_strauss_point_state* ps; +}; + +static void secp256k1_zkp_ecmult_strauss_wnaf(const secp256k1_zkp_ecmult_context *ctx, const struct secp256k1_zkp_strauss_state *state, secp256k1_zkp_gej *r, int num, const secp256k1_zkp_gej *a, const secp256k1_zkp_scalar *na, const secp256k1_zkp_scalar *ng) { + secp256k1_zkp_ge tmpa; + secp256k1_zkp_fe Z; +#ifdef USE_ENDOMORPHISM + /* Splitted G factors. */ + secp256k1_zkp_scalar ng_1, ng_128; + int wnaf_ng_1[129]; + int bits_ng_1 = 0; + int wnaf_ng_128[129]; + int bits_ng_128 = 0; +#else + int wnaf_ng[256]; + int bits_ng = 0; +#endif + int i; + int bits = 0; + int np; + int no = 0; + + for (np = 0; np < num; ++np) { + if (secp256k1_zkp_scalar_is_zero(&na[np]) || secp256k1_zkp_gej_is_infinity(&a[np])) { + continue; + } + state->ps[no].input_pos = np; +#ifdef USE_ENDOMORPHISM + /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ + secp256k1_zkp_scalar_split_lambda(&state->ps[no].na_1, &state->ps[no].na_lam, &na[np]); + + /* build wnaf representation for na_1 and na_lam. */ + state->ps[no].bits_na_1 = secp256k1_zkp_ecmult_wnaf(state->ps[no].wnaf_na_1, 130, &state->ps[no].na_1, WINDOW_A); + state->ps[no].bits_na_lam = secp256k1_zkp_ecmult_wnaf(state->ps[no].wnaf_na_lam, 130, &state->ps[no].na_lam, WINDOW_A); + VERIFY_CHECK(state->ps[no].bits_na_1 <= 130); + VERIFY_CHECK(state->ps[no].bits_na_lam <= 130); + if (state->ps[no].bits_na_1 > bits) { + bits = state->ps[no].bits_na_1; + } + if (state->ps[no].bits_na_lam > bits) { + bits = state->ps[no].bits_na_lam; + } +#else + /* build wnaf representation for na. */ + state->ps[no].bits_na = secp256k1_zkp_ecmult_wnaf(state->ps[no].wnaf_na, 256, &na[np], WINDOW_A); + if (state->ps[no].bits_na > bits) { + bits = state->ps[no].bits_na; + } +#endif + ++no; + } + + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + * The exception is the precomputed G table points, which are actually + * affine. Compared to the base used for other points, they have a Z ratio + * of 1/Z, so we can use secp256k1_zkp_gej_add_zinv_var, which uses the same + * isomorphism to efficiently add with a known Z inverse. + */ + if (no > 0) { + /* Compute the odd multiples in Jacobian form. */ + secp256k1_zkp_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej, state->zr, &a[state->ps[0].input_pos]); + for (np = 1; np < no; ++np) { + secp256k1_zkp_gej tmp = a[state->ps[np].input_pos]; +#ifdef VERIFY + secp256k1_zkp_fe_normalize_var(&(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z)); +#endif + secp256k1_zkp_gej_rescale(&tmp, &(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z)); + secp256k1_zkp_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &tmp); + secp256k1_zkp_fe_mul(state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &(a[state->ps[np].input_pos].z)); + } + /* Bring them to the same Z denominator. */ + secp256k1_zkp_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, &Z, state->prej, state->zr); + } else { + secp256k1_zkp_fe_set_int(&Z, 1); + } + +#ifdef USE_ENDOMORPHISM + for (np = 0; np < no; ++np) { + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_zkp_ge_mul_lambda(&state->pre_a_lam[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i]); + } + } + + if (ng) { + /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ + secp256k1_zkp_scalar_split_128(&ng_1, &ng_128, ng); + + /* Build wnaf representation for ng_1 and ng_128 */ + bits_ng_1 = secp256k1_zkp_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G); + bits_ng_128 = secp256k1_zkp_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G); + if (bits_ng_1 > bits) { + bits = bits_ng_1; + } + if (bits_ng_128 > bits) { + bits = bits_ng_128; + } + } +#else + if (ng) { + bits_ng = secp256k1_zkp_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G); + if (bits_ng > bits) { + bits = bits_ng; + } + } +#endif + + secp256k1_zkp_gej_set_infinity(r); + + for (i = bits - 1; i >= 0; i--) { + int n; + secp256k1_zkp_gej_double_var(r, r, NULL); +#ifdef USE_ENDOMORPHISM + for (np = 0; np < no; ++np) { + if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) { + ECMULT_TABLE_GET_GE(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); + secp256k1_zkp_gej_add_ge_var(r, r, &tmpa, NULL); + } + if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) { + ECMULT_TABLE_GET_GE(&tmpa, state->pre_a_lam + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); + secp256k1_zkp_gej_add_ge_var(r, r, &tmpa, NULL); + } + } + if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); + secp256k1_zkp_gej_add_zinv_var(r, r, &tmpa, &Z); + } + if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G); + secp256k1_zkp_gej_add_zinv_var(r, r, &tmpa, &Z); + } +#else + for (np = 0; np < no; ++np) { + if (i < state->ps[np].bits_na && (n = state->ps[np].wnaf_na[i])) { + ECMULT_TABLE_GET_GE(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); + secp256k1_zkp_gej_add_ge_var(r, r, &tmpa, NULL); + } + } + if (i < bits_ng && (n = wnaf_ng[i])) { + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); + secp256k1_zkp_gej_add_zinv_var(r, r, &tmpa, &Z); + } +#endif + } + + if (!r->infinity) { + secp256k1_zkp_fe_mul(&r->z, &r->z, &Z); + } +} + +static void secp256k1_zkp_ecmult(const secp256k1_zkp_ecmult_context *ctx, secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, const secp256k1_zkp_scalar *na, const secp256k1_zkp_scalar *ng) { + secp256k1_zkp_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_zkp_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_zkp_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + struct secp256k1_zkp_strauss_point_state ps[1]; +#ifdef USE_ENDOMORPHISM + secp256k1_zkp_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; +#endif + struct secp256k1_zkp_strauss_state state; + + state.prej = prej; + state.zr = zr; + state.pre_a = pre_a; +#ifdef USE_ENDOMORPHISM + state.pre_a_lam = pre_a_lam; +#endif + state.ps = ps; + secp256k1_zkp_ecmult_strauss_wnaf(ctx, &state, r, 1, a, na, ng); +} + +static size_t secp256k1_zkp_strauss_scratch_size(size_t n_points) { +#ifdef USE_ENDOMORPHISM + static const size_t point_size = (2 * sizeof(secp256k1_zkp_ge) + sizeof(secp256k1_zkp_gej) + sizeof(secp256k1_zkp_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_zkp_strauss_point_state) + sizeof(secp256k1_zkp_gej) + sizeof(secp256k1_zkp_scalar); +#else + static const size_t point_size = (sizeof(secp256k1_zkp_ge) + sizeof(secp256k1_zkp_gej) + sizeof(secp256k1_zkp_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_zkp_strauss_point_state) + sizeof(secp256k1_zkp_gej) + sizeof(secp256k1_zkp_scalar); +#endif + return n_points*point_size; +} + +static int secp256k1_zkp_ecmult_strauss_batch(const secp256k1_zkp_ecmult_context *ctx, secp256k1_zkp_scratch *scratch, secp256k1_zkp_gej *r, const secp256k1_zkp_scalar *inp_g_sc, secp256k1_zkp_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { + secp256k1_zkp_gej* points; + secp256k1_zkp_scalar* scalars; + struct secp256k1_zkp_strauss_state state; + size_t i; + + secp256k1_zkp_gej_set_infinity(r); + if (inp_g_sc == NULL && n_points == 0) { + return 1; + } + + if (!secp256k1_zkp_scratch_allocate_frame(scratch, secp256k1_zkp_strauss_scratch_size(n_points), STRAUSS_SCRATCH_OBJECTS)) { + return 0; + } + points = (secp256k1_zkp_gej*)secp256k1_zkp_scratch_alloc(scratch, n_points * sizeof(secp256k1_zkp_gej)); + scalars = (secp256k1_zkp_scalar*)secp256k1_zkp_scratch_alloc(scratch, n_points * sizeof(secp256k1_zkp_scalar)); + state.prej = (secp256k1_zkp_gej*)secp256k1_zkp_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_zkp_gej)); + state.zr = (secp256k1_zkp_fe*)secp256k1_zkp_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_zkp_fe)); +#ifdef USE_ENDOMORPHISM + state.pre_a = (secp256k1_zkp_ge*)secp256k1_zkp_scratch_alloc(scratch, n_points * 2 * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_zkp_ge)); + state.pre_a_lam = state.pre_a + n_points * ECMULT_TABLE_SIZE(WINDOW_A); +#else + state.pre_a = (secp256k1_zkp_ge*)secp256k1_zkp_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_zkp_ge)); +#endif + state.ps = (struct secp256k1_zkp_strauss_point_state*)secp256k1_zkp_scratch_alloc(scratch, n_points * sizeof(struct secp256k1_zkp_strauss_point_state)); + + for (i = 0; i < n_points; i++) { + secp256k1_zkp_ge point; + if (!cb(&scalars[i], &point, i+cb_offset, cbdata)) { + secp256k1_zkp_scratch_deallocate_frame(scratch); + return 0; + } + secp256k1_zkp_gej_set_ge(&points[i], &point); + } + secp256k1_zkp_ecmult_strauss_wnaf(ctx, &state, r, n_points, points, scalars, inp_g_sc); + secp256k1_zkp_scratch_deallocate_frame(scratch); + return 1; +} + +/* Wrapper for secp256k1_zkp_ecmult_multi_func interface */ +static int secp256k1_zkp_ecmult_strauss_batch_single(const secp256k1_zkp_ecmult_context *actx, secp256k1_zkp_scratch *scratch, secp256k1_zkp_gej *r, const secp256k1_zkp_scalar *inp_g_sc, secp256k1_zkp_ecmult_multi_callback cb, void *cbdata, size_t n) { + return secp256k1_zkp_ecmult_strauss_batch(actx, scratch, r, inp_g_sc, cb, cbdata, n, 0); +} + +static size_t secp256k1_zkp_strauss_max_points(secp256k1_zkp_scratch *scratch) { + return secp256k1_zkp_scratch_max_allocation(scratch, STRAUSS_SCRATCH_OBJECTS) / secp256k1_zkp_strauss_scratch_size(1); +} + +/** Convert a number to WNAF notation. + * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. + * It has the following guarantees: + * - each wnaf[i] is either 0 or an odd integer between -(1 << w) and (1 << w) + * - the number of words set is always WNAF_SIZE(w) + * - the returned skew is 0 or 1 + */ +static int secp256k1_zkp_wnaf_fixed(int *wnaf, const secp256k1_zkp_scalar *s, int w) { + int skew = 0; + int pos; + int max_pos; + int last_w; + const secp256k1_zkp_scalar *work = s; + + if (secp256k1_zkp_scalar_is_zero(s)) { + for (pos = 0; pos < WNAF_SIZE(w); pos++) { + wnaf[pos] = 0; + } + return 0; + } + + if (secp256k1_zkp_scalar_is_even(s)) { + skew = 1; + } + + wnaf[0] = secp256k1_zkp_scalar_get_bits_var(work, 0, w) + skew; + /* Compute last window size. Relevant when window size doesn't divide the + * number of bits in the scalar */ + last_w = WNAF_BITS - (WNAF_SIZE(w) - 1) * w; + + /* Store the position of the first nonzero word in max_pos to allow + * skipping leading zeros when calculating the wnaf. */ + for (pos = WNAF_SIZE(w) - 1; pos > 0; pos--) { + int val = secp256k1_zkp_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); + if(val != 0) { + break; + } + wnaf[pos] = 0; + } + max_pos = pos; + pos = 1; + + while (pos <= max_pos) { + int val = secp256k1_zkp_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w); + if ((val & 1) == 0) { + wnaf[pos - 1] -= (1 << w); + wnaf[pos] = (val + 1); + } else { + wnaf[pos] = val; + } + /* Set a coefficient to zero if it is 1 or -1 and the proceeding digit + * is strictly negative or strictly positive respectively. Only change + * coefficients at previous positions because above code assumes that + * wnaf[pos - 1] is odd. + */ + if (pos >= 2 && ((wnaf[pos - 1] == 1 && wnaf[pos - 2] < 0) || (wnaf[pos - 1] == -1 && wnaf[pos - 2] > 0))) { + if (wnaf[pos - 1] == 1) { + wnaf[pos - 2] += 1 << w; + } else { + wnaf[pos - 2] -= 1 << w; + } + wnaf[pos - 1] = 0; + } + ++pos; + } + + return skew; +} + +struct secp256k1_zkp_pippenger_point_state { + int skew_na; + size_t input_pos; +}; + +struct secp256k1_zkp_pippenger_state { + int *wnaf_na; + struct secp256k1_zkp_pippenger_point_state* ps; +}; + +/* + * pippenger_wnaf computes the result of a multi-point multiplication as + * follows: The scalars are brought into wnaf with n_wnaf elements each. Then + * for every i < n_wnaf, first each point is added to a "bucket" corresponding + * to the point's wnaf[i]. Second, the buckets are added together such that + * r += 1*bucket[0] + 3*bucket[1] + 5*bucket[2] + ... + */ +static int secp256k1_zkp_ecmult_pippenger_wnaf(secp256k1_zkp_gej *buckets, int bucket_window, struct secp256k1_zkp_pippenger_state *state, secp256k1_zkp_gej *r, const secp256k1_zkp_scalar *sc, const secp256k1_zkp_ge *pt, size_t num) { + size_t n_wnaf = WNAF_SIZE(bucket_window+1); + size_t np; + size_t no = 0; + int i; + int j; + + for (np = 0; np < num; ++np) { + if (secp256k1_zkp_scalar_is_zero(&sc[np]) || secp256k1_zkp_ge_is_infinity(&pt[np])) { + continue; + } + state->ps[no].input_pos = np; + state->ps[no].skew_na = secp256k1_zkp_wnaf_fixed(&state->wnaf_na[no*n_wnaf], &sc[np], bucket_window+1); + no++; + } + secp256k1_zkp_gej_set_infinity(r); + + if (no == 0) { + return 1; + } + + for (i = n_wnaf - 1; i >= 0; i--) { + secp256k1_zkp_gej running_sum; + + for(j = 0; j < ECMULT_TABLE_SIZE(bucket_window+2); j++) { + secp256k1_zkp_gej_set_infinity(&buckets[j]); + } + + for (np = 0; np < no; ++np) { + int n = state->wnaf_na[np*n_wnaf + i]; + struct secp256k1_zkp_pippenger_point_state point_state = state->ps[np]; + secp256k1_zkp_ge tmp; + int idx; + + if (i == 0) { + /* correct for wnaf skew */ + int skew = point_state.skew_na; + if (skew) { + secp256k1_zkp_ge_neg(&tmp, &pt[point_state.input_pos]); + secp256k1_zkp_gej_add_ge_var(&buckets[0], &buckets[0], &tmp, NULL); + } + } + if (n > 0) { + idx = (n - 1)/2; + secp256k1_zkp_gej_add_ge_var(&buckets[idx], &buckets[idx], &pt[point_state.input_pos], NULL); + } else if (n < 0) { + idx = -(n + 1)/2; + secp256k1_zkp_ge_neg(&tmp, &pt[point_state.input_pos]); + secp256k1_zkp_gej_add_ge_var(&buckets[idx], &buckets[idx], &tmp, NULL); + } + } + + for(j = 0; j < bucket_window; j++) { + secp256k1_zkp_gej_double_var(r, r, NULL); + } + + secp256k1_zkp_gej_set_infinity(&running_sum); + /* Accumulate the sum: bucket[0] + 3*bucket[1] + 5*bucket[2] + 7*bucket[3] + ... + * = bucket[0] + bucket[1] + bucket[2] + bucket[3] + ... + * + 2 * (bucket[1] + 2*bucket[2] + 3*bucket[3] + ...) + * using an intermediate running sum: + * running_sum = bucket[0] + bucket[1] + bucket[2] + ... + * + * The doubling is done implicitly by deferring the final window doubling (of 'r'). + */ + for(j = ECMULT_TABLE_SIZE(bucket_window+2) - 1; j > 0; j--) { + secp256k1_zkp_gej_add_var(&running_sum, &running_sum, &buckets[j], NULL); + secp256k1_zkp_gej_add_var(r, r, &running_sum, NULL); + } + + secp256k1_zkp_gej_add_var(&running_sum, &running_sum, &buckets[0], NULL); + secp256k1_zkp_gej_double_var(r, r, NULL); + secp256k1_zkp_gej_add_var(r, r, &running_sum, NULL); + } + return 1; +} + +/** + * Returns optimal bucket_window (number of bits of a scalar represented by a + * set of buckets) for a given number of points. + */ +static int secp256k1_zkp_pippenger_bucket_window(size_t n) { +#ifdef USE_ENDOMORPHISM + if (n <= 1) { + return 1; + } else if (n <= 4) { + return 2; + } else if (n <= 20) { + return 3; + } else if (n <= 57) { + return 4; + } else if (n <= 136) { + return 5; + } else if (n <= 235) { + return 6; + } else if (n <= 1260) { + return 7; + } else if (n <= 4420) { + return 9; + } else if (n <= 7880) { + return 10; + } else if (n <= 16050) { + return 11; + } else { + return PIPPENGER_MAX_BUCKET_WINDOW; + } +#else + if (n <= 1) { + return 1; + } else if (n <= 11) { + return 2; + } else if (n <= 45) { + return 3; + } else if (n <= 100) { + return 4; + } else if (n <= 275) { + return 5; + } else if (n <= 625) { + return 6; + } else if (n <= 1850) { + return 7; + } else if (n <= 3400) { + return 8; + } else if (n <= 9630) { + return 9; + } else if (n <= 17900) { + return 10; + } else if (n <= 32800) { + return 11; + } else { + return PIPPENGER_MAX_BUCKET_WINDOW; + } +#endif +} + +/** + * Returns the maximum optimal number of points for a bucket_window. + */ +static size_t secp256k1_zkp_pippenger_bucket_window_inv(int bucket_window) { + switch(bucket_window) { +#ifdef USE_ENDOMORPHISM + case 1: return 1; + case 2: return 4; + case 3: return 20; + case 4: return 57; + case 5: return 136; + case 6: return 235; + case 7: return 1260; + case 8: return 1260; + case 9: return 4420; + case 10: return 7880; + case 11: return 16050; + case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX; +#else + case 1: return 1; + case 2: return 11; + case 3: return 45; + case 4: return 100; + case 5: return 275; + case 6: return 625; + case 7: return 1850; + case 8: return 3400; + case 9: return 9630; + case 10: return 17900; + case 11: return 32800; + case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX; +#endif + } + return 0; +} + + +#ifdef USE_ENDOMORPHISM +SECP256K1_INLINE static void secp256k1_zkp_ecmult_endo_split(secp256k1_zkp_scalar *s1, secp256k1_zkp_scalar *s2, secp256k1_zkp_ge *p1, secp256k1_zkp_ge *p2) { + secp256k1_zkp_scalar tmp = *s1; + secp256k1_zkp_scalar_split_lambda(s1, s2, &tmp); + secp256k1_zkp_ge_mul_lambda(p2, p1); + + if (secp256k1_zkp_scalar_is_high(s1)) { + secp256k1_zkp_scalar_negate(s1, s1); + secp256k1_zkp_ge_neg(p1, p1); + } + if (secp256k1_zkp_scalar_is_high(s2)) { + secp256k1_zkp_scalar_negate(s2, s2); + secp256k1_zkp_ge_neg(p2, p2); + } +} +#endif + +/** + * Returns the scratch size required for a given number of points (excluding + * base point G) without considering alignment. + */ +static size_t secp256k1_zkp_pippenger_scratch_size(size_t n_points, int bucket_window) { +#ifdef USE_ENDOMORPHISM + size_t entries = 2*n_points + 2; +#else + size_t entries = n_points + 1; +#endif + size_t entry_size = sizeof(secp256k1_zkp_ge) + sizeof(secp256k1_zkp_scalar) + sizeof(struct secp256k1_zkp_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); + return ((1<ps = (struct secp256k1_zkp_pippenger_point_state *) secp256k1_zkp_scratch_alloc(scratch, entries * sizeof(*state_space->ps)); + state_space->wnaf_na = (int *) secp256k1_zkp_scratch_alloc(scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int)); + buckets = (secp256k1_zkp_gej *) secp256k1_zkp_scratch_alloc(scratch, (1<ps[i].skew_na = 0; + for(j = 0; j < WNAF_SIZE(bucket_window+1); j++) { + state_space->wnaf_na[i * WNAF_SIZE(bucket_window+1) + j] = 0; + } + } + for(i = 0; i < 1< max_alloc) { + break; + } + space_for_points = max_alloc - space_overhead; + + n_points = space_for_points/entry_size; + n_points = n_points > max_points ? max_points : n_points; + if (n_points > res) { + res = n_points; + } + if (n_points < max_points) { + /* A larger bucket_window may support even more points. But if we + * would choose that then the caller couldn't safely use any number + * smaller than what this function returns */ + break; + } + } + return res; +} + +/* Computes ecmult_multi by simply multiplying and adding each point. Does not + * require a scratch space */ +static int secp256k1_zkp_ecmult_multi_var_simple(const secp256k1_zkp_ecmult_context *ctx, secp256k1_zkp_gej *r, const secp256k1_zkp_scalar *inp_g_sc, secp256k1_zkp_ecmult_multi_callback cb, void *cbdata, size_t n_points) { + size_t point_idx; + secp256k1_zkp_scalar szero; + secp256k1_zkp_gej tmpj; + + secp256k1_zkp_scalar_set_int(&szero, 0); + /* r = inp_g_sc*G */ + secp256k1_zkp_gej_set_infinity(r); + secp256k1_zkp_ecmult(ctx, r, &tmpj, &szero, inp_g_sc); + for (point_idx = 0; point_idx < n_points; point_idx++) { + secp256k1_zkp_ge point; + secp256k1_zkp_gej pointj; + secp256k1_zkp_scalar scalar; + if (!cb(&scalar, &point, point_idx, cbdata)) { + return 0; + } + /* r += scalar*point */ + secp256k1_zkp_gej_set_ge(&pointj, &point); + secp256k1_zkp_ecmult(ctx, &tmpj, &pointj, &scalar, NULL); + secp256k1_zkp_gej_add_var(r, r, &tmpj, NULL); + } + return 1; +} + +typedef int (*secp256k1_zkp_ecmult_multi_func)(const secp256k1_zkp_ecmult_context*, secp256k1_zkp_scratch*, secp256k1_zkp_gej*, const secp256k1_zkp_scalar*, secp256k1_zkp_ecmult_multi_callback cb, void*, size_t); +static int secp256k1_zkp_ecmult_multi_var(const secp256k1_zkp_ecmult_context *ctx, secp256k1_zkp_scratch *scratch, secp256k1_zkp_gej *r, const secp256k1_zkp_scalar *inp_g_sc, secp256k1_zkp_ecmult_multi_callback cb, void *cbdata, size_t n) { + size_t i; + + int (*f)(const secp256k1_zkp_ecmult_context*, secp256k1_zkp_scratch*, secp256k1_zkp_gej*, const secp256k1_zkp_scalar*, secp256k1_zkp_ecmult_multi_callback cb, void*, size_t, size_t); + size_t max_points; + size_t n_batches; + size_t n_batch_points; + + secp256k1_zkp_gej_set_infinity(r); + if (inp_g_sc == NULL && n == 0) { + return 1; + } else if (n == 0) { + secp256k1_zkp_scalar szero; + secp256k1_zkp_scalar_set_int(&szero, 0); + secp256k1_zkp_ecmult(ctx, r, r, &szero, inp_g_sc); + return 1; + } + if (scratch == NULL) { + return secp256k1_zkp_ecmult_multi_var_simple(ctx, r, inp_g_sc, cb, cbdata, n); + } + + max_points = secp256k1_zkp_pippenger_max_points(scratch); + if (max_points == 0) { + return 0; + } else if (max_points > ECMULT_MAX_POINTS_PER_BATCH) { + max_points = ECMULT_MAX_POINTS_PER_BATCH; + } + n_batches = (n+max_points-1)/max_points; + n_batch_points = (n+n_batches-1)/n_batches; + + if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) { + f = secp256k1_zkp_ecmult_pippenger_batch; + } else { + max_points = secp256k1_zkp_strauss_max_points(scratch); + if (max_points == 0) { + return 0; + } + n_batches = (n+max_points-1)/max_points; + n_batch_points = (n+n_batches-1)/n_batches; + f = secp256k1_zkp_ecmult_strauss_batch; + } + for(i = 0; i < n_batches; i++) { + size_t nbp = n < n_batch_points ? n : n_batch_points; + size_t offset = n_batch_points*i; + secp256k1_zkp_gej tmp; + if (!f(ctx, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) { + return 0; + } + secp256k1_zkp_gej_add_var(r, r, &tmp, NULL); + n -= nbp; + } + return 1; +} + +#endif /* SECP256K1_ECMULT_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field.h new file mode 100644 index 00000000..69b38b4e --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field.h @@ -0,0 +1,132 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_FIELD_H +#define SECP256K1_FIELD_H + +/** Field element module. + * + * Field elements can be represented in several ways, but code accessing + * it (and implementations) need to take certain properties into account: + * - Each field element can be normalized or not. + * - Each field element has a magnitude, which represents how far away + * its representation is away from normalization. Normalized elements + * always have a magnitude of 1, but a magnitude of 1 doesn't imply + * normality. + */ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#if defined(USE_FIELD_10X26) +#include "field_10x26.h" +#elif defined(USE_FIELD_5X52) +#include "field_5x52.h" +#else +#error "Please select field implementation" +#endif + +#include "util.h" + +/** Normalize a field element. */ +static void secp256k1_zkp_fe_normalize(secp256k1_zkp_fe *r); + +/** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */ +static void secp256k1_zkp_fe_normalize_weak(secp256k1_zkp_fe *r); + +/** Normalize a field element, without constant-time guarantee. */ +static void secp256k1_zkp_fe_normalize_var(secp256k1_zkp_fe *r); + +/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field + * implementation may optionally normalize the input, but this should not be relied upon. */ +static int secp256k1_zkp_fe_normalizes_to_zero(secp256k1_zkp_fe *r); + +/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field + * implementation may optionally normalize the input, but this should not be relied upon. */ +static int secp256k1_zkp_fe_normalizes_to_zero_var(secp256k1_zkp_fe *r); + +/** Set a field element equal to a small integer. Resulting field element is normalized. */ +static void secp256k1_zkp_fe_set_int(secp256k1_zkp_fe *r, int a); + +/** Sets a field element equal to zero, initializing all fields. */ +static void secp256k1_zkp_fe_clear(secp256k1_zkp_fe *a); + +/** Verify whether a field element is zero. Requires the input to be normalized. */ +static int secp256k1_zkp_fe_is_zero(const secp256k1_zkp_fe *a); + +/** Check the "oddness" of a field element. Requires the input to be normalized. */ +static int secp256k1_zkp_fe_is_odd(const secp256k1_zkp_fe *a); + +/** Compare two field elements. Requires magnitude-1 inputs. */ +static int secp256k1_zkp_fe_equal(const secp256k1_zkp_fe *a, const secp256k1_zkp_fe *b); + +/** Same as secp256k1_zkp_fe_equal, but may be variable time. */ +static int secp256k1_zkp_fe_equal_var(const secp256k1_zkp_fe *a, const secp256k1_zkp_fe *b); + +/** Compare two field elements. Requires both inputs to be normalized */ +static int secp256k1_zkp_fe_cmp_var(const secp256k1_zkp_fe *a, const secp256k1_zkp_fe *b); + +/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */ +static int secp256k1_zkp_fe_set_b32(secp256k1_zkp_fe *r, const unsigned char *a); + +/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +static void secp256k1_zkp_fe_get_b32(unsigned char *r, const secp256k1_zkp_fe *a); + +/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input + * as an argument. The magnitude of the output is one higher. */ +static void secp256k1_zkp_fe_negate(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a, int m); + +/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that + * small integer. */ +static void secp256k1_zkp_fe_mul_int(secp256k1_zkp_fe *r, int a); + +/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ +static void secp256k1_zkp_fe_add(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a); + +/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. + * The output magnitude is 1 (but not guaranteed to be normalized). */ +static void secp256k1_zkp_fe_mul(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a, const secp256k1_zkp_fe * SECP256K1_RESTRICT b); + +/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. + * The output magnitude is 1 (but not guaranteed to be normalized). */ +static void secp256k1_zkp_fe_sqr(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a); + +/** If a has a square root, it is computed in r and 1 is returned. If a does not + * have a square root, the root of its negation is computed and 0 is returned. + * The input's magnitude can be at most 8. The output magnitude is 1 (but not + * guaranteed to be normalized). The result in r will always be a square + * itself. */ +static int secp256k1_zkp_fe_sqrt(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a); + +/** Checks whether a field element is a quadratic residue. */ +static int secp256k1_zkp_fe_is_quad_var(const secp256k1_zkp_fe *a); + +/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be + * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ +static void secp256k1_zkp_fe_inv(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a); + +/** Potentially faster version of secp256k1_zkp_fe_inv, without constant-time guarantee. */ +static void secp256k1_zkp_fe_inv_var(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a); + +/** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be + * at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and + * outputs must not overlap in memory. */ +static void secp256k1_zkp_fe_inv_all_var(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a, size_t len); + +/** Convert a field element to the storage type. */ +static void secp256k1_zkp_fe_to_storage(secp256k1_zkp_fe_storage *r, const secp256k1_zkp_fe *a); + +/** Convert a field element back from the storage type. */ +static void secp256k1_zkp_fe_from_storage(secp256k1_zkp_fe *r, const secp256k1_zkp_fe_storage *a); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +static void secp256k1_zkp_fe_storage_cmov(secp256k1_zkp_fe_storage *r, const secp256k1_zkp_fe_storage *a, int flag); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +static void secp256k1_zkp_fe_cmov(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a, int flag); + +#endif /* SECP256K1_FIELD_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_10x26.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_10x26.h new file mode 100644 index 00000000..3c71992c --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_10x26.h @@ -0,0 +1,48 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_FIELD_REPR_H +#define SECP256K1_FIELD_REPR_H + +#include + +typedef struct { + /* X = sum(i=0..9, elem[i]*2^26) mod n */ + uint32_t n[10]; +#ifdef VERIFY + int magnitude; + int normalized; +#endif +} secp256k1_zkp_fe; + +/* Unpacks a constant into a overlapping multi-limbed FE element. */ +#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ + (d0) & 0x3FFFFFFUL, \ + (((uint32_t)d0) >> 26) | (((uint32_t)(d1) & 0xFFFFFUL) << 6), \ + (((uint32_t)d1) >> 20) | (((uint32_t)(d2) & 0x3FFFUL) << 12), \ + (((uint32_t)d2) >> 14) | (((uint32_t)(d3) & 0xFFUL) << 18), \ + (((uint32_t)d3) >> 8) | (((uint32_t)(d4) & 0x3UL) << 24), \ + (((uint32_t)d4) >> 2) & 0x3FFFFFFUL, \ + (((uint32_t)d4) >> 28) | (((uint32_t)(d5) & 0x3FFFFFUL) << 4), \ + (((uint32_t)d5) >> 22) | (((uint32_t)(d6) & 0xFFFFUL) << 10), \ + (((uint32_t)d6) >> 16) | (((uint32_t)(d7) & 0x3FFUL) << 16), \ + (((uint32_t)d7) >> 10) \ +} + +#ifdef VERIFY +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} +#else +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} +#endif + +typedef struct { + uint32_t n[8]; +} secp256k1_zkp_fe_storage; + +#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }} +#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0] + +#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_10x26_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_10x26_impl.h new file mode 100644 index 00000000..762a9394 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_10x26_impl.h @@ -0,0 +1,1161 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_FIELD_REPR_IMPL_H +#define SECP256K1_FIELD_REPR_IMPL_H + +#include "util.h" +#include "num.h" +#include "field.h" + +#ifdef VERIFY +static void secp256k1_zkp_fe_verify(const secp256k1_zkp_fe *a) { + const uint32_t *d = a->n; + int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; + r &= (d[0] <= 0x3FFFFFFUL * m); + r &= (d[1] <= 0x3FFFFFFUL * m); + r &= (d[2] <= 0x3FFFFFFUL * m); + r &= (d[3] <= 0x3FFFFFFUL * m); + r &= (d[4] <= 0x3FFFFFFUL * m); + r &= (d[5] <= 0x3FFFFFFUL * m); + r &= (d[6] <= 0x3FFFFFFUL * m); + r &= (d[7] <= 0x3FFFFFFUL * m); + r &= (d[8] <= 0x3FFFFFFUL * m); + r &= (d[9] <= 0x03FFFFFUL * m); + r &= (a->magnitude >= 0); + r &= (a->magnitude <= 32); + if (a->normalized) { + r &= (a->magnitude <= 1); + if (r && (d[9] == 0x03FFFFFUL)) { + uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2]; + if (mid == 0x3FFFFFFUL) { + r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); + } + } + } + VERIFY_CHECK(r == 1); +} +#endif + +static void secp256k1_zkp_fe_normalize(secp256k1_zkp_fe *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t m; + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; m = t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; m &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; m &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; m &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; m &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; m &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; m &= t8; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t9 >> 22) | ((t9 == 0x03FFFFFUL) & (m == 0x3FFFFFFUL) + & ((t1 + 0x40UL + ((t0 + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); + + /* Apply the final reduction (for constant-time behaviour, we do it always) */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; + + /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */ + VERIFY_CHECK(t9 >> 22 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t9 &= 0x03FFFFFUL; + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_zkp_fe_verify(r); +#endif +} + +static void secp256k1_zkp_fe_normalize_weak(secp256k1_zkp_fe *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; + +#ifdef VERIFY + r->magnitude = 1; + secp256k1_zkp_fe_verify(r); +#endif +} + +static void secp256k1_zkp_fe_normalize_var(secp256k1_zkp_fe *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t m; + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; m = t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; m &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; m &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; m &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; m &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; m &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; m &= t8; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t9 >> 22) | ((t9 == 0x03FFFFFUL) & (m == 0x3FFFFFFUL) + & ((t1 + 0x40UL + ((t0 + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); + + if (x) { + t0 += 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; + + /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */ + VERIFY_CHECK(t9 >> 22 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t9 &= 0x03FFFFFUL; + } + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_zkp_fe_verify(r); +#endif +} + +static int secp256k1_zkp_fe_normalizes_to_zero(secp256k1_zkp_fe *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint32_t z0, z1; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; z0 = t0; z1 = t0 ^ 0x3D0UL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; + z0 |= t9; z1 &= t9 ^ 0x3C00000UL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + return (z0 == 0) | (z1 == 0x3FFFFFFUL); +} + +static int secp256k1_zkp_fe_normalizes_to_zero_var(secp256k1_zkp_fe *r) { + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t z0, z1; + uint32_t x; + + t0 = r->n[0]; + t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + x = t9 >> 22; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + z0 = t0 & 0x3FFFFFFUL; + z1 = z0 ^ 0x3D0UL; + + /* Fast return path should catch the majority of cases */ + if ((z0 != 0UL) & (z1 != 0x3FFFFFFUL)) { + return 0; + } + + t1 = r->n[1]; + t2 = r->n[2]; + t3 = r->n[3]; + t4 = r->n[4]; + t5 = r->n[5]; + t6 = r->n[6]; + t7 = r->n[7]; + t8 = r->n[8]; + + t9 &= 0x03FFFFFUL; + t1 += (x << 6); + + t1 += (t0 >> 26); + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; + z0 |= t9; z1 &= t9 ^ 0x3C00000UL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + return (z0 == 0) | (z1 == 0x3FFFFFFUL); +} + +SECP256K1_INLINE static void secp256k1_zkp_fe_set_int(secp256k1_zkp_fe *r, int a) { + r->n[0] = a; + r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_zkp_fe_verify(r); +#endif +} + +SECP256K1_INLINE static int secp256k1_zkp_fe_is_zero(const secp256k1_zkp_fe *a) { + const uint32_t *t = a->n; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_zkp_fe_verify(a); +#endif + return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; +} + +SECP256K1_INLINE static int secp256k1_zkp_fe_is_odd(const secp256k1_zkp_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_zkp_fe_verify(a); +#endif + return a->n[0] & 1; +} + +SECP256K1_INLINE static void secp256k1_zkp_fe_clear(secp256k1_zkp_fe *a) { + int i; +#ifdef VERIFY + a->magnitude = 0; + a->normalized = 1; +#endif + for (i=0; i<10; i++) { + a->n[i] = 0; + } +} + +static int secp256k1_zkp_fe_cmp_var(const secp256k1_zkp_fe *a, const secp256k1_zkp_fe *b) { + int i; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + VERIFY_CHECK(b->normalized); + secp256k1_zkp_fe_verify(a); + secp256k1_zkp_fe_verify(b); +#endif + for (i = 9; i >= 0; i--) { + if (a->n[i] > b->n[i]) { + return 1; + } + if (a->n[i] < b->n[i]) { + return -1; + } + } + return 0; +} + +static int secp256k1_zkp_fe_set_b32(secp256k1_zkp_fe *r, const unsigned char *a) { + r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24); + r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22); + r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20); + r->n[3] = (uint32_t)((a[22] >> 6) & 0x3) | ((uint32_t)a[21] << 2) | ((uint32_t)a[20] << 10) | ((uint32_t)a[19] << 18); + r->n[4] = (uint32_t)a[18] | ((uint32_t)a[17] << 8) | ((uint32_t)a[16] << 16) | ((uint32_t)(a[15] & 0x3) << 24); + r->n[5] = (uint32_t)((a[15] >> 2) & 0x3f) | ((uint32_t)a[14] << 6) | ((uint32_t)a[13] << 14) | ((uint32_t)(a[12] & 0xf) << 22); + r->n[6] = (uint32_t)((a[12] >> 4) & 0xf) | ((uint32_t)a[11] << 4) | ((uint32_t)a[10] << 12) | ((uint32_t)(a[9] & 0x3f) << 20); + r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18); + r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24); + r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14); + + if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) { + return 0; + } +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_zkp_fe_verify(r); +#endif + return 1; +} + +/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +static void secp256k1_zkp_fe_get_b32(unsigned char *r, const secp256k1_zkp_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_zkp_fe_verify(a); +#endif + r[0] = (a->n[9] >> 14) & 0xff; + r[1] = (a->n[9] >> 6) & 0xff; + r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3); + r[3] = (a->n[8] >> 16) & 0xff; + r[4] = (a->n[8] >> 8) & 0xff; + r[5] = a->n[8] & 0xff; + r[6] = (a->n[7] >> 18) & 0xff; + r[7] = (a->n[7] >> 10) & 0xff; + r[8] = (a->n[7] >> 2) & 0xff; + r[9] = ((a->n[7] & 0x3) << 6) | ((a->n[6] >> 20) & 0x3f); + r[10] = (a->n[6] >> 12) & 0xff; + r[11] = (a->n[6] >> 4) & 0xff; + r[12] = ((a->n[6] & 0xf) << 4) | ((a->n[5] >> 22) & 0xf); + r[13] = (a->n[5] >> 14) & 0xff; + r[14] = (a->n[5] >> 6) & 0xff; + r[15] = ((a->n[5] & 0x3f) << 2) | ((a->n[4] >> 24) & 0x3); + r[16] = (a->n[4] >> 16) & 0xff; + r[17] = (a->n[4] >> 8) & 0xff; + r[18] = a->n[4] & 0xff; + r[19] = (a->n[3] >> 18) & 0xff; + r[20] = (a->n[3] >> 10) & 0xff; + r[21] = (a->n[3] >> 2) & 0xff; + r[22] = ((a->n[3] & 0x3) << 6) | ((a->n[2] >> 20) & 0x3f); + r[23] = (a->n[2] >> 12) & 0xff; + r[24] = (a->n[2] >> 4) & 0xff; + r[25] = ((a->n[2] & 0xf) << 4) | ((a->n[1] >> 22) & 0xf); + r[26] = (a->n[1] >> 14) & 0xff; + r[27] = (a->n[1] >> 6) & 0xff; + r[28] = ((a->n[1] & 0x3f) << 2) | ((a->n[0] >> 24) & 0x3); + r[29] = (a->n[0] >> 16) & 0xff; + r[30] = (a->n[0] >> 8) & 0xff; + r[31] = a->n[0] & 0xff; +} + +SECP256K1_INLINE static void secp256k1_zkp_fe_negate(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a, int m) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= m); + secp256k1_zkp_fe_verify(a); +#endif + r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0]; + r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1]; + r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2]; + r->n[3] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[3]; + r->n[4] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[4]; + r->n[5] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[5]; + r->n[6] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[6]; + r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7]; + r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8]; + r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9]; +#ifdef VERIFY + r->magnitude = m + 1; + r->normalized = 0; + secp256k1_zkp_fe_verify(r); +#endif +} + +SECP256K1_INLINE static void secp256k1_zkp_fe_mul_int(secp256k1_zkp_fe *r, int a) { + r->n[0] *= a; + r->n[1] *= a; + r->n[2] *= a; + r->n[3] *= a; + r->n[4] *= a; + r->n[5] *= a; + r->n[6] *= a; + r->n[7] *= a; + r->n[8] *= a; + r->n[9] *= a; +#ifdef VERIFY + r->magnitude *= a; + r->normalized = 0; + secp256k1_zkp_fe_verify(r); +#endif +} + +SECP256K1_INLINE static void secp256k1_zkp_fe_add(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a) { +#ifdef VERIFY + secp256k1_zkp_fe_verify(a); +#endif + r->n[0] += a->n[0]; + r->n[1] += a->n[1]; + r->n[2] += a->n[2]; + r->n[3] += a->n[3]; + r->n[4] += a->n[4]; + r->n[5] += a->n[5]; + r->n[6] += a->n[6]; + r->n[7] += a->n[7]; + r->n[8] += a->n[8]; + r->n[9] += a->n[9]; +#ifdef VERIFY + r->magnitude += a->magnitude; + r->normalized = 0; + secp256k1_zkp_fe_verify(r); +#endif +} + +#if defined(USE_EXTERNAL_ASM) + +/* External assembler implementation */ +void secp256k1_zkp_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b); +void secp256k1_zkp_fe_sqr_inner(uint32_t *r, const uint32_t *a); + +#else + +#ifdef VERIFY +#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) +#else +#define VERIFY_BITS(x, n) do { } while(0) +#endif + +SECP256K1_INLINE static void secp256k1_zkp_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) { + uint64_t c, d; + uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; + uint32_t t9, t1, t0, t2, t3, t4, t5, t6, t7; + const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; + + VERIFY_BITS(a[0], 30); + VERIFY_BITS(a[1], 30); + VERIFY_BITS(a[2], 30); + VERIFY_BITS(a[3], 30); + VERIFY_BITS(a[4], 30); + VERIFY_BITS(a[5], 30); + VERIFY_BITS(a[6], 30); + VERIFY_BITS(a[7], 30); + VERIFY_BITS(a[8], 30); + VERIFY_BITS(a[9], 26); + VERIFY_BITS(b[0], 30); + VERIFY_BITS(b[1], 30); + VERIFY_BITS(b[2], 30); + VERIFY_BITS(b[3], 30); + VERIFY_BITS(b[4], 30); + VERIFY_BITS(b[5], 30); + VERIFY_BITS(b[6], 30); + VERIFY_BITS(b[7], 30); + VERIFY_BITS(b[8], 30); + VERIFY_BITS(b[9], 26); + + /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. + * px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. + */ + + d = (uint64_t)a[0] * b[9] + + (uint64_t)a[1] * b[8] + + (uint64_t)a[2] * b[7] + + (uint64_t)a[3] * b[6] + + (uint64_t)a[4] * b[5] + + (uint64_t)a[5] * b[4] + + (uint64_t)a[6] * b[3] + + (uint64_t)a[7] * b[2] + + (uint64_t)a[8] * b[1] + + (uint64_t)a[9] * b[0]; + /* VERIFY_BITS(d, 64); */ + /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ + t9 = d & M; d >>= 26; + VERIFY_BITS(t9, 26); + VERIFY_BITS(d, 38); + /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ + + c = (uint64_t)a[0] * b[0]; + VERIFY_BITS(c, 60); + /* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */ + d += (uint64_t)a[1] * b[9] + + (uint64_t)a[2] * b[8] + + (uint64_t)a[3] * b[7] + + (uint64_t)a[4] * b[6] + + (uint64_t)a[5] * b[5] + + (uint64_t)a[6] * b[4] + + (uint64_t)a[7] * b[3] + + (uint64_t)a[8] * b[2] + + (uint64_t)a[9] * b[1]; + VERIFY_BITS(d, 63); + /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + u0 = d & M; d >>= 26; c += u0 * R0; + VERIFY_BITS(u0, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 61); + /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + t0 = c & M; c >>= 26; c += u0 * R1; + VERIFY_BITS(t0, 26); + VERIFY_BITS(c, 37); + /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + + c += (uint64_t)a[0] * b[1] + + (uint64_t)a[1] * b[0]; + VERIFY_BITS(c, 62); + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */ + d += (uint64_t)a[2] * b[9] + + (uint64_t)a[3] * b[8] + + (uint64_t)a[4] * b[7] + + (uint64_t)a[5] * b[6] + + (uint64_t)a[6] * b[5] + + (uint64_t)a[7] * b[4] + + (uint64_t)a[8] * b[3] + + (uint64_t)a[9] * b[2]; + VERIFY_BITS(d, 63); + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + u1 = d & M; d >>= 26; c += u1 * R0; + VERIFY_BITS(u1, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 63); + /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + t1 = c & M; c >>= 26; c += u1 * R1; + VERIFY_BITS(t1, 26); + VERIFY_BITS(c, 38); + /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + + c += (uint64_t)a[0] * b[2] + + (uint64_t)a[1] * b[1] + + (uint64_t)a[2] * b[0]; + VERIFY_BITS(c, 62); + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + d += (uint64_t)a[3] * b[9] + + (uint64_t)a[4] * b[8] + + (uint64_t)a[5] * b[7] + + (uint64_t)a[6] * b[6] + + (uint64_t)a[7] * b[5] + + (uint64_t)a[8] * b[4] + + (uint64_t)a[9] * b[3]; + VERIFY_BITS(d, 63); + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + u2 = d & M; d >>= 26; c += u2 * R0; + VERIFY_BITS(u2, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 63); + /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + t2 = c & M; c >>= 26; c += u2 * R1; + VERIFY_BITS(t2, 26); + VERIFY_BITS(c, 38); + /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[3] + + (uint64_t)a[1] * b[2] + + (uint64_t)a[2] * b[1] + + (uint64_t)a[3] * b[0]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + d += (uint64_t)a[4] * b[9] + + (uint64_t)a[5] * b[8] + + (uint64_t)a[6] * b[7] + + (uint64_t)a[7] * b[6] + + (uint64_t)a[8] * b[5] + + (uint64_t)a[9] * b[4]; + VERIFY_BITS(d, 63); + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + u3 = d & M; d >>= 26; c += u3 * R0; + VERIFY_BITS(u3, 26); + VERIFY_BITS(d, 37); + /* VERIFY_BITS(c, 64); */ + /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + t3 = c & M; c >>= 26; c += u3 * R1; + VERIFY_BITS(t3, 26); + VERIFY_BITS(c, 39); + /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[4] + + (uint64_t)a[1] * b[3] + + (uint64_t)a[2] * b[2] + + (uint64_t)a[3] * b[1] + + (uint64_t)a[4] * b[0]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[5] * b[9] + + (uint64_t)a[6] * b[8] + + (uint64_t)a[7] * b[7] + + (uint64_t)a[8] * b[6] + + (uint64_t)a[9] * b[5]; + VERIFY_BITS(d, 62); + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + u4 = d & M; d >>= 26; c += u4 * R0; + VERIFY_BITS(u4, 26); + VERIFY_BITS(d, 36); + /* VERIFY_BITS(c, 64); */ + /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + t4 = c & M; c >>= 26; c += u4 * R1; + VERIFY_BITS(t4, 26); + VERIFY_BITS(c, 39); + /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[5] + + (uint64_t)a[1] * b[4] + + (uint64_t)a[2] * b[3] + + (uint64_t)a[3] * b[2] + + (uint64_t)a[4] * b[1] + + (uint64_t)a[5] * b[0]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[6] * b[9] + + (uint64_t)a[7] * b[8] + + (uint64_t)a[8] * b[7] + + (uint64_t)a[9] * b[6]; + VERIFY_BITS(d, 62); + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + u5 = d & M; d >>= 26; c += u5 * R0; + VERIFY_BITS(u5, 26); + VERIFY_BITS(d, 36); + /* VERIFY_BITS(c, 64); */ + /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + t5 = c & M; c >>= 26; c += u5 * R1; + VERIFY_BITS(t5, 26); + VERIFY_BITS(c, 39); + /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[6] + + (uint64_t)a[1] * b[5] + + (uint64_t)a[2] * b[4] + + (uint64_t)a[3] * b[3] + + (uint64_t)a[4] * b[2] + + (uint64_t)a[5] * b[1] + + (uint64_t)a[6] * b[0]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[7] * b[9] + + (uint64_t)a[8] * b[8] + + (uint64_t)a[9] * b[7]; + VERIFY_BITS(d, 61); + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + u6 = d & M; d >>= 26; c += u6 * R0; + VERIFY_BITS(u6, 26); + VERIFY_BITS(d, 35); + /* VERIFY_BITS(c, 64); */ + /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + t6 = c & M; c >>= 26; c += u6 * R1; + VERIFY_BITS(t6, 26); + VERIFY_BITS(c, 39); + /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[7] + + (uint64_t)a[1] * b[6] + + (uint64_t)a[2] * b[5] + + (uint64_t)a[3] * b[4] + + (uint64_t)a[4] * b[3] + + (uint64_t)a[5] * b[2] + + (uint64_t)a[6] * b[1] + + (uint64_t)a[7] * b[0]; + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x8000007C00000007ULL); + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[8] * b[9] + + (uint64_t)a[9] * b[8]; + VERIFY_BITS(d, 58); + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + u7 = d & M; d >>= 26; c += u7 * R0; + VERIFY_BITS(u7, 26); + VERIFY_BITS(d, 32); + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL); + /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + t7 = c & M; c >>= 26; c += u7 * R1; + VERIFY_BITS(t7, 26); + VERIFY_BITS(c, 38); + /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[8] + + (uint64_t)a[1] * b[7] + + (uint64_t)a[2] * b[6] + + (uint64_t)a[3] * b[5] + + (uint64_t)a[4] * b[4] + + (uint64_t)a[5] * b[3] + + (uint64_t)a[6] * b[2] + + (uint64_t)a[7] * b[1] + + (uint64_t)a[8] * b[0]; + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x9000007B80000008ULL); + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[9] * b[9]; + VERIFY_BITS(d, 57); + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + u8 = d & M; d >>= 26; c += u8 * R0; + VERIFY_BITS(u8, 26); + VERIFY_BITS(d, 31); + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x9000016FBFFFC2F8ULL); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[3] = t3; + VERIFY_BITS(r[3], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = t4; + VERIFY_BITS(r[4], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[5] = t5; + VERIFY_BITS(r[5], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[6] = t6; + VERIFY_BITS(r[6], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[7] = t7; + VERIFY_BITS(r[7], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[8] = c & M; c >>= 26; c += u8 * R1; + VERIFY_BITS(r[8], 26); + VERIFY_BITS(c, 39); + /* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += d * R0 + t9; + VERIFY_BITS(c, 45); + /* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[9] = c & (M >> 4); c >>= 22; c += d * (R1 << 4); + VERIFY_BITS(r[9], 22); + VERIFY_BITS(c, 46); + /* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + d = c * (R0 >> 4) + t0; + VERIFY_BITS(d, 56); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[0] = d & M; d >>= 26; + VERIFY_BITS(r[0], 26); + VERIFY_BITS(d, 30); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += c * (R1 >> 4) + t1; + VERIFY_BITS(d, 53); + VERIFY_CHECK(d <= 0x10000003FFFFBFULL); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[1] = d & M; d >>= 26; + VERIFY_BITS(r[1], 26); + VERIFY_BITS(d, 27); + VERIFY_CHECK(d <= 0x4000000ULL); + /* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += t2; + VERIFY_BITS(d, 27); + /* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = d; + VERIFY_BITS(r[2], 27); + /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + +SECP256K1_INLINE static void secp256k1_zkp_fe_sqr_inner(uint32_t *r, const uint32_t *a) { + uint64_t c, d; + uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; + uint32_t t9, t0, t1, t2, t3, t4, t5, t6, t7; + const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; + + VERIFY_BITS(a[0], 30); + VERIFY_BITS(a[1], 30); + VERIFY_BITS(a[2], 30); + VERIFY_BITS(a[3], 30); + VERIFY_BITS(a[4], 30); + VERIFY_BITS(a[5], 30); + VERIFY_BITS(a[6], 30); + VERIFY_BITS(a[7], 30); + VERIFY_BITS(a[8], 30); + VERIFY_BITS(a[9], 26); + + /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. + * px is a shorthand for sum(a[i]*a[x-i], i=0..x). + * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. + */ + + d = (uint64_t)(a[0]*2) * a[9] + + (uint64_t)(a[1]*2) * a[8] + + (uint64_t)(a[2]*2) * a[7] + + (uint64_t)(a[3]*2) * a[6] + + (uint64_t)(a[4]*2) * a[5]; + /* VERIFY_BITS(d, 64); */ + /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ + t9 = d & M; d >>= 26; + VERIFY_BITS(t9, 26); + VERIFY_BITS(d, 38); + /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ + + c = (uint64_t)a[0] * a[0]; + VERIFY_BITS(c, 60); + /* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */ + d += (uint64_t)(a[1]*2) * a[9] + + (uint64_t)(a[2]*2) * a[8] + + (uint64_t)(a[3]*2) * a[7] + + (uint64_t)(a[4]*2) * a[6] + + (uint64_t)a[5] * a[5]; + VERIFY_BITS(d, 63); + /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + u0 = d & M; d >>= 26; c += u0 * R0; + VERIFY_BITS(u0, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 61); + /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + t0 = c & M; c >>= 26; c += u0 * R1; + VERIFY_BITS(t0, 26); + VERIFY_BITS(c, 37); + /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + + c += (uint64_t)(a[0]*2) * a[1]; + VERIFY_BITS(c, 62); + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */ + d += (uint64_t)(a[2]*2) * a[9] + + (uint64_t)(a[3]*2) * a[8] + + (uint64_t)(a[4]*2) * a[7] + + (uint64_t)(a[5]*2) * a[6]; + VERIFY_BITS(d, 63); + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + u1 = d & M; d >>= 26; c += u1 * R0; + VERIFY_BITS(u1, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 63); + /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + t1 = c & M; c >>= 26; c += u1 * R1; + VERIFY_BITS(t1, 26); + VERIFY_BITS(c, 38); + /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[2] + + (uint64_t)a[1] * a[1]; + VERIFY_BITS(c, 62); + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + d += (uint64_t)(a[3]*2) * a[9] + + (uint64_t)(a[4]*2) * a[8] + + (uint64_t)(a[5]*2) * a[7] + + (uint64_t)a[6] * a[6]; + VERIFY_BITS(d, 63); + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + u2 = d & M; d >>= 26; c += u2 * R0; + VERIFY_BITS(u2, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 63); + /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + t2 = c & M; c >>= 26; c += u2 * R1; + VERIFY_BITS(t2, 26); + VERIFY_BITS(c, 38); + /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[3] + + (uint64_t)(a[1]*2) * a[2]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + d += (uint64_t)(a[4]*2) * a[9] + + (uint64_t)(a[5]*2) * a[8] + + (uint64_t)(a[6]*2) * a[7]; + VERIFY_BITS(d, 63); + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + u3 = d & M; d >>= 26; c += u3 * R0; + VERIFY_BITS(u3, 26); + VERIFY_BITS(d, 37); + /* VERIFY_BITS(c, 64); */ + /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + t3 = c & M; c >>= 26; c += u3 * R1; + VERIFY_BITS(t3, 26); + VERIFY_BITS(c, 39); + /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[4] + + (uint64_t)(a[1]*2) * a[3] + + (uint64_t)a[2] * a[2]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + d += (uint64_t)(a[5]*2) * a[9] + + (uint64_t)(a[6]*2) * a[8] + + (uint64_t)a[7] * a[7]; + VERIFY_BITS(d, 62); + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + u4 = d & M; d >>= 26; c += u4 * R0; + VERIFY_BITS(u4, 26); + VERIFY_BITS(d, 36); + /* VERIFY_BITS(c, 64); */ + /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + t4 = c & M; c >>= 26; c += u4 * R1; + VERIFY_BITS(t4, 26); + VERIFY_BITS(c, 39); + /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[5] + + (uint64_t)(a[1]*2) * a[4] + + (uint64_t)(a[2]*2) * a[3]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)(a[6]*2) * a[9] + + (uint64_t)(a[7]*2) * a[8]; + VERIFY_BITS(d, 62); + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + u5 = d & M; d >>= 26; c += u5 * R0; + VERIFY_BITS(u5, 26); + VERIFY_BITS(d, 36); + /* VERIFY_BITS(c, 64); */ + /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + t5 = c & M; c >>= 26; c += u5 * R1; + VERIFY_BITS(t5, 26); + VERIFY_BITS(c, 39); + /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[6] + + (uint64_t)(a[1]*2) * a[5] + + (uint64_t)(a[2]*2) * a[4] + + (uint64_t)a[3] * a[3]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)(a[7]*2) * a[9] + + (uint64_t)a[8] * a[8]; + VERIFY_BITS(d, 61); + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + u6 = d & M; d >>= 26; c += u6 * R0; + VERIFY_BITS(u6, 26); + VERIFY_BITS(d, 35); + /* VERIFY_BITS(c, 64); */ + /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + t6 = c & M; c >>= 26; c += u6 * R1; + VERIFY_BITS(t6, 26); + VERIFY_BITS(c, 39); + /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[7] + + (uint64_t)(a[1]*2) * a[6] + + (uint64_t)(a[2]*2) * a[5] + + (uint64_t)(a[3]*2) * a[4]; + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x8000007C00000007ULL); + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)(a[8]*2) * a[9]; + VERIFY_BITS(d, 58); + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + u7 = d & M; d >>= 26; c += u7 * R0; + VERIFY_BITS(u7, 26); + VERIFY_BITS(d, 32); + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL); + /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + t7 = c & M; c >>= 26; c += u7 * R1; + VERIFY_BITS(t7, 26); + VERIFY_BITS(c, 38); + /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[8] + + (uint64_t)(a[1]*2) * a[7] + + (uint64_t)(a[2]*2) * a[6] + + (uint64_t)(a[3]*2) * a[5] + + (uint64_t)a[4] * a[4]; + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x9000007B80000008ULL); + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[9] * a[9]; + VERIFY_BITS(d, 57); + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + u8 = d & M; d >>= 26; c += u8 * R0; + VERIFY_BITS(u8, 26); + VERIFY_BITS(d, 31); + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x9000016FBFFFC2F8ULL); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[3] = t3; + VERIFY_BITS(r[3], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = t4; + VERIFY_BITS(r[4], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[5] = t5; + VERIFY_BITS(r[5], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[6] = t6; + VERIFY_BITS(r[6], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[7] = t7; + VERIFY_BITS(r[7], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[8] = c & M; c >>= 26; c += u8 * R1; + VERIFY_BITS(r[8], 26); + VERIFY_BITS(c, 39); + /* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += d * R0 + t9; + VERIFY_BITS(c, 45); + /* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[9] = c & (M >> 4); c >>= 22; c += d * (R1 << 4); + VERIFY_BITS(r[9], 22); + VERIFY_BITS(c, 46); + /* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + d = c * (R0 >> 4) + t0; + VERIFY_BITS(d, 56); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[0] = d & M; d >>= 26; + VERIFY_BITS(r[0], 26); + VERIFY_BITS(d, 30); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += c * (R1 >> 4) + t1; + VERIFY_BITS(d, 53); + VERIFY_CHECK(d <= 0x10000003FFFFBFULL); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[1] = d & M; d >>= 26; + VERIFY_BITS(r[1], 26); + VERIFY_BITS(d, 27); + VERIFY_CHECK(d <= 0x4000000ULL); + /* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += t2; + VERIFY_BITS(d, 27); + /* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = d; + VERIFY_BITS(r[2], 27); + /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} +#endif + +static void secp256k1_zkp_fe_mul(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a, const secp256k1_zkp_fe * SECP256K1_RESTRICT b) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= 8); + VERIFY_CHECK(b->magnitude <= 8); + secp256k1_zkp_fe_verify(a); + secp256k1_zkp_fe_verify(b); + VERIFY_CHECK(r != b); +#endif + secp256k1_zkp_fe_mul_inner(r->n, a->n, b->n); +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 0; + secp256k1_zkp_fe_verify(r); +#endif +} + +static void secp256k1_zkp_fe_sqr(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= 8); + secp256k1_zkp_fe_verify(a); +#endif + secp256k1_zkp_fe_sqr_inner(r->n, a->n); +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 0; + secp256k1_zkp_fe_verify(r); +#endif +} + +static SECP256K1_INLINE void secp256k1_zkp_fe_cmov(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a, int flag) { + uint32_t mask0, mask1; + mask0 = flag + ~((uint32_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); + r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); + r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1); + r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1); + r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); + r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); + r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); +#ifdef VERIFY + if (a->magnitude > r->magnitude) { + r->magnitude = a->magnitude; + } + r->normalized &= a->normalized; +#endif +} + +static SECP256K1_INLINE void secp256k1_zkp_fe_storage_cmov(secp256k1_zkp_fe_storage *r, const secp256k1_zkp_fe_storage *a, int flag) { + uint32_t mask0, mask1; + mask0 = flag + ~((uint32_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); + r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); + r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1); + r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1); + r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); +} + +static void secp256k1_zkp_fe_to_storage(secp256k1_zkp_fe_storage *r, const secp256k1_zkp_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); +#endif + r->n[0] = a->n[0] | a->n[1] << 26; + r->n[1] = a->n[1] >> 6 | a->n[2] << 20; + r->n[2] = a->n[2] >> 12 | a->n[3] << 14; + r->n[3] = a->n[3] >> 18 | a->n[4] << 8; + r->n[4] = a->n[4] >> 24 | a->n[5] << 2 | a->n[6] << 28; + r->n[5] = a->n[6] >> 4 | a->n[7] << 22; + r->n[6] = a->n[7] >> 10 | a->n[8] << 16; + r->n[7] = a->n[8] >> 16 | a->n[9] << 10; +} + +static SECP256K1_INLINE void secp256k1_zkp_fe_from_storage(secp256k1_zkp_fe *r, const secp256k1_zkp_fe_storage *a) { + r->n[0] = a->n[0] & 0x3FFFFFFUL; + r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL); + r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL); + r->n[3] = a->n[2] >> 14 | ((a->n[3] << 18) & 0x3FFFFFFUL); + r->n[4] = a->n[3] >> 8 | ((a->n[4] << 24) & 0x3FFFFFFUL); + r->n[5] = (a->n[4] >> 2) & 0x3FFFFFFUL; + r->n[6] = a->n[4] >> 28 | ((a->n[5] << 4) & 0x3FFFFFFUL); + r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL); + r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL); + r->n[9] = a->n[7] >> 10; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; +#endif +} + +#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_5x52.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_5x52.h new file mode 100644 index 00000000..9c5d65f5 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_5x52.h @@ -0,0 +1,47 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_FIELD_REPR_H +#define SECP256K1_FIELD_REPR_H + +#include + +typedef struct { + /* X = sum(i=0..4, elem[i]*2^52) mod n */ + uint64_t n[5]; +#ifdef VERIFY + int magnitude; + int normalized; +#endif +} secp256k1_zkp_fe; + +/* Unpacks a constant into a overlapping multi-limbed FE element. */ +#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ + (d0) | (((uint64_t)(d1) & 0xFFFFFUL) << 32), \ + ((uint64_t)(d1) >> 20) | (((uint64_t)(d2)) << 12) | (((uint64_t)(d3) & 0xFFUL) << 44), \ + ((uint64_t)(d3) >> 8) | (((uint64_t)(d4) & 0xFFFFFFFUL) << 24), \ + ((uint64_t)(d4) >> 28) | (((uint64_t)(d5)) << 4) | (((uint64_t)(d6) & 0xFFFFUL) << 36), \ + ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \ +} + +#ifdef VERIFY +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} +#else +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} +#endif + +typedef struct { + uint64_t n[4]; +} secp256k1_zkp_fe_storage; + +#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \ + (d0) | (((uint64_t)(d1)) << 32), \ + (d2) | (((uint64_t)(d3)) << 32), \ + (d4) | (((uint64_t)(d5)) << 32), \ + (d6) | (((uint64_t)(d7)) << 32) \ +}} + +#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_5x52_asm_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_5x52_asm_impl.h new file mode 100644 index 00000000..446b3d72 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_5x52_asm_impl.h @@ -0,0 +1,502 @@ +/********************************************************************** + * Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/** + * Changelog: + * - March 2013, Diederik Huys: original version + * - November 2014, Pieter Wuille: updated to use Peter Dettman's parallel multiplication algorithm + * - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly + */ + +#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H +#define SECP256K1_FIELD_INNER5X52_IMPL_H + +SECP256K1_INLINE static void secp256k1_zkp_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { +/** + * Registers: rdx:rax = multiplication accumulator + * r9:r8 = c + * r15:rcx = d + * r10-r14 = a0-a4 + * rbx = b + * rdi = r + * rsi = a / t? + */ + uint64_t tmp1, tmp2, tmp3; +__asm__ __volatile__( + "movq 0(%%rsi),%%r10\n" + "movq 8(%%rsi),%%r11\n" + "movq 16(%%rsi),%%r12\n" + "movq 24(%%rsi),%%r13\n" + "movq 32(%%rsi),%%r14\n" + + /* d += a3 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r13\n" + "movq %%rax,%%rcx\n" + "movq %%rdx,%%r15\n" + /* d += a2 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a1 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d = a0 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c = a4 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r14\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += (c & M) * R */ + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* t3 (tmp1) = d & M */ + "movq %%rcx,%%rsi\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rsi\n" + "movq %%rsi,%q1\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* d += a4 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a2 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a1 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a0 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += c * R */ + "movq %%r8,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* t4 = d & M (%%rsi) */ + "movq %%rcx,%%rsi\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* tx = t4 >> 48 (tmp3) */ + "movq %%rsi,%%rax\n" + "shrq $48,%%rax\n" + "movq %%rax,%q3\n" + /* t4 &= (M >> 4) (tmp2) */ + "movq $0xffffffffffff,%%rax\n" + "andq %%rax,%%rsi\n" + "movq %%rsi,%q2\n" + /* c = a0 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r10\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += a4 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a2 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a1 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* u0 = d & M (%%rsi) */ + "movq %%rcx,%%rsi\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* u0 = (u0 << 4) | tx (%%rsi) */ + "shlq $4,%%rsi\n" + "movq %q3,%%rax\n" + "orq %%rax,%%rsi\n" + /* c += u0 * (R >> 4) */ + "movq $0x1000003d1,%%rax\n" + "mulq %%rsi\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[0] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,0(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += a1 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* c += a0 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d += a4 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a2 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c += (d & M) * R */ + "movq %%rcx,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* r[1] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,8(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += a2 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* c += a1 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* c += a0 * b2 (last use of %%r10 = a0) */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* fetch t3 (%%r10, overwrites a0), t4 (%%rsi) */ + "movq %q2,%%rsi\n" + "movq %q1,%%r10\n" + /* d += a4 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c += (d & M) * R */ + "movq %%rcx,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 (%%rcx only) */ + "shrdq $52,%%r15,%%rcx\n" + /* r[2] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,16(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += t3 */ + "addq %%r10,%%r8\n" + /* c += d * R */ + "movq %%rcx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[3] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,24(%%rdi)\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* c += t4 (%%r8 only) */ + "addq %%rsi,%%r8\n" + /* r[4] = c */ + "movq %%r8,32(%%rdi)\n" +: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) +: "b"(b), "D"(r) +: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" +); +} + +SECP256K1_INLINE static void secp256k1_zkp_fe_sqr_inner(uint64_t *r, const uint64_t *a) { +/** + * Registers: rdx:rax = multiplication accumulator + * r9:r8 = c + * rcx:rbx = d + * r10-r14 = a0-a4 + * r15 = M (0xfffffffffffff) + * rdi = r + * rsi = a / t? + */ + uint64_t tmp1, tmp2, tmp3; +__asm__ __volatile__( + "movq 0(%%rsi),%%r10\n" + "movq 8(%%rsi),%%r11\n" + "movq 16(%%rsi),%%r12\n" + "movq 24(%%rsi),%%r13\n" + "movq 32(%%rsi),%%r14\n" + "movq $0xfffffffffffff,%%r15\n" + + /* d = (a0*2) * a3 */ + "leaq (%%r10,%%r10,1),%%rax\n" + "mulq %%r13\n" + "movq %%rax,%%rbx\n" + "movq %%rdx,%%rcx\n" + /* d += (a1*2) * a2 */ + "leaq (%%r11,%%r11,1),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c = a4 * a4 */ + "movq %%r14,%%rax\n" + "mulq %%r14\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += (c & M) * R */ + "andq %%r15,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* t3 (tmp1) = d & M */ + "movq %%rbx,%%rsi\n" + "andq %%r15,%%rsi\n" + "movq %%rsi,%q1\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* a4 *= 2 */ + "addq %%r14,%%r14\n" + /* d += a0 * a4 */ + "movq %%r10,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d+= (a1*2) * a3 */ + "leaq (%%r11,%%r11,1),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += a2 * a2 */ + "movq %%r12,%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += c * R */ + "movq %%r8,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* t4 = d & M (%%rsi) */ + "movq %%rbx,%%rsi\n" + "andq %%r15,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* tx = t4 >> 48 (tmp3) */ + "movq %%rsi,%%rax\n" + "shrq $48,%%rax\n" + "movq %%rax,%q3\n" + /* t4 &= (M >> 4) (tmp2) */ + "movq $0xffffffffffff,%%rax\n" + "andq %%rax,%%rsi\n" + "movq %%rsi,%q2\n" + /* c = a0 * a0 */ + "movq %%r10,%%rax\n" + "mulq %%r10\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += a1 * a4 */ + "movq %%r11,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += (a2*2) * a3 */ + "leaq (%%r12,%%r12,1),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* u0 = d & M (%%rsi) */ + "movq %%rbx,%%rsi\n" + "andq %%r15,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* u0 = (u0 << 4) | tx (%%rsi) */ + "shlq $4,%%rsi\n" + "movq %q3,%%rax\n" + "orq %%rax,%%rsi\n" + /* c += u0 * (R >> 4) */ + "movq $0x1000003d1,%%rax\n" + "mulq %%rsi\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[0] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,0(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* a0 *= 2 */ + "addq %%r10,%%r10\n" + /* c += a0 * a1 */ + "movq %%r10,%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d += a2 * a4 */ + "movq %%r12,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += a3 * a3 */ + "movq %%r13,%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c += (d & M) * R */ + "movq %%rbx,%%rax\n" + "andq %%r15,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* r[1] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,8(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += a0 * a2 (last use of %%r10) */ + "movq %%r10,%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* fetch t3 (%%r10, overwrites a0),t4 (%%rsi) */ + "movq %q2,%%rsi\n" + "movq %q1,%%r10\n" + /* c += a1 * a1 */ + "movq %%r11,%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d += a3 * a4 */ + "movq %%r13,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c += (d & M) * R */ + "movq %%rbx,%%rax\n" + "andq %%r15,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 (%%rbx only) */ + "shrdq $52,%%rcx,%%rbx\n" + /* r[2] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,16(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += t3 */ + "addq %%r10,%%r8\n" + /* c += d * R */ + "movq %%rbx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[3] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,24(%%rdi)\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* c += t4 (%%r8 only) */ + "addq %%rsi,%%r8\n" + /* r[4] = c */ + "movq %%r8,32(%%rdi)\n" +: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) +: "D"(r) +: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" +); +} + +#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_5x52_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_5x52_impl.h new file mode 100644 index 00000000..76b2b4ea --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_5x52_impl.h @@ -0,0 +1,496 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_FIELD_REPR_IMPL_H +#define SECP256K1_FIELD_REPR_IMPL_H + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include "util.h" +#include "num.h" +#include "field.h" + +#if defined(USE_ASM_X86_64) +#include "field_5x52_asm_impl.h" +#else +#include "field_5x52_int128_impl.h" +#endif + +/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, + * represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular, + * each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element + * is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations + * accept any input with magnitude at most M, and have different rules for propagating magnitude to their + * output. + */ + +#ifdef VERIFY +static void secp256k1_zkp_fe_verify(const secp256k1_zkp_fe *a) { + const uint64_t *d = a->n; + int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; + /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m); + r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m); + r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m); + r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m); + r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m); + r &= (a->magnitude >= 0); + r &= (a->magnitude <= 2048); + if (a->normalized) { + r &= (a->magnitude <= 1); + if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { + r &= (d[0] < 0xFFFFEFFFFFC2FULL); + } + } + VERIFY_CHECK(r == 1); +} +#endif + +static void secp256k1_zkp_fe_normalize(secp256k1_zkp_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t m; + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL) + & (t0 >= 0xFFFFEFFFFFC2FULL)); + + /* Apply the final reduction (for constant-time behaviour, we do it always) */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */ + VERIFY_CHECK(t4 >> 48 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t4 &= 0x0FFFFFFFFFFFFULL; + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_zkp_fe_verify(r); +#endif +} + +static void secp256k1_zkp_fe_normalize_weak(secp256k1_zkp_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + +#ifdef VERIFY + r->magnitude = 1; + secp256k1_zkp_fe_verify(r); +#endif +} + +static void secp256k1_zkp_fe_normalize_var(secp256k1_zkp_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t m; + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL) + & (t0 >= 0xFFFFEFFFFFC2FULL)); + + if (x) { + t0 += 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */ + VERIFY_CHECK(t4 >> 48 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t4 &= 0x0FFFFFFFFFFFFULL; + } + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_zkp_fe_verify(r); +#endif +} + +static int secp256k1_zkp_fe_normalizes_to_zero(secp256k1_zkp_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint64_t z0, z1; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; z0 = t0; z1 = t0 ^ 0x1000003D0ULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; + z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); +} + +static int secp256k1_zkp_fe_normalizes_to_zero_var(secp256k1_zkp_fe *r) { + uint64_t t0, t1, t2, t3, t4; + uint64_t z0, z1; + uint64_t x; + + t0 = r->n[0]; + t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + x = t4 >> 48; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + z0 = t0 & 0xFFFFFFFFFFFFFULL; + z1 = z0 ^ 0x1000003D0ULL; + + /* Fast return path should catch the majority of cases */ + if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL)) { + return 0; + } + + t1 = r->n[1]; + t2 = r->n[2]; + t3 = r->n[3]; + + t4 &= 0x0FFFFFFFFFFFFULL; + + t1 += (t0 >> 52); + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; + z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); +} + +SECP256K1_INLINE static void secp256k1_zkp_fe_set_int(secp256k1_zkp_fe *r, int a) { + r->n[0] = a; + r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_zkp_fe_verify(r); +#endif +} + +SECP256K1_INLINE static int secp256k1_zkp_fe_is_zero(const secp256k1_zkp_fe *a) { + const uint64_t *t = a->n; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_zkp_fe_verify(a); +#endif + return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; +} + +SECP256K1_INLINE static int secp256k1_zkp_fe_is_odd(const secp256k1_zkp_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_zkp_fe_verify(a); +#endif + return a->n[0] & 1; +} + +SECP256K1_INLINE static void secp256k1_zkp_fe_clear(secp256k1_zkp_fe *a) { + int i; +#ifdef VERIFY + a->magnitude = 0; + a->normalized = 1; +#endif + for (i=0; i<5; i++) { + a->n[i] = 0; + } +} + +static int secp256k1_zkp_fe_cmp_var(const secp256k1_zkp_fe *a, const secp256k1_zkp_fe *b) { + int i; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + VERIFY_CHECK(b->normalized); + secp256k1_zkp_fe_verify(a); + secp256k1_zkp_fe_verify(b); +#endif + for (i = 4; i >= 0; i--) { + if (a->n[i] > b->n[i]) { + return 1; + } + if (a->n[i] < b->n[i]) { + return -1; + } + } + return 0; +} + +static int secp256k1_zkp_fe_set_b32(secp256k1_zkp_fe *r, const unsigned char *a) { + r->n[0] = (uint64_t)a[31] + | ((uint64_t)a[30] << 8) + | ((uint64_t)a[29] << 16) + | ((uint64_t)a[28] << 24) + | ((uint64_t)a[27] << 32) + | ((uint64_t)a[26] << 40) + | ((uint64_t)(a[25] & 0xF) << 48); + r->n[1] = (uint64_t)((a[25] >> 4) & 0xF) + | ((uint64_t)a[24] << 4) + | ((uint64_t)a[23] << 12) + | ((uint64_t)a[22] << 20) + | ((uint64_t)a[21] << 28) + | ((uint64_t)a[20] << 36) + | ((uint64_t)a[19] << 44); + r->n[2] = (uint64_t)a[18] + | ((uint64_t)a[17] << 8) + | ((uint64_t)a[16] << 16) + | ((uint64_t)a[15] << 24) + | ((uint64_t)a[14] << 32) + | ((uint64_t)a[13] << 40) + | ((uint64_t)(a[12] & 0xF) << 48); + r->n[3] = (uint64_t)((a[12] >> 4) & 0xF) + | ((uint64_t)a[11] << 4) + | ((uint64_t)a[10] << 12) + | ((uint64_t)a[9] << 20) + | ((uint64_t)a[8] << 28) + | ((uint64_t)a[7] << 36) + | ((uint64_t)a[6] << 44); + r->n[4] = (uint64_t)a[5] + | ((uint64_t)a[4] << 8) + | ((uint64_t)a[3] << 16) + | ((uint64_t)a[2] << 24) + | ((uint64_t)a[1] << 32) + | ((uint64_t)a[0] << 40); + if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) { + return 0; + } +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_zkp_fe_verify(r); +#endif + return 1; +} + +/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +static void secp256k1_zkp_fe_get_b32(unsigned char *r, const secp256k1_zkp_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_zkp_fe_verify(a); +#endif + r[0] = (a->n[4] >> 40) & 0xFF; + r[1] = (a->n[4] >> 32) & 0xFF; + r[2] = (a->n[4] >> 24) & 0xFF; + r[3] = (a->n[4] >> 16) & 0xFF; + r[4] = (a->n[4] >> 8) & 0xFF; + r[5] = a->n[4] & 0xFF; + r[6] = (a->n[3] >> 44) & 0xFF; + r[7] = (a->n[3] >> 36) & 0xFF; + r[8] = (a->n[3] >> 28) & 0xFF; + r[9] = (a->n[3] >> 20) & 0xFF; + r[10] = (a->n[3] >> 12) & 0xFF; + r[11] = (a->n[3] >> 4) & 0xFF; + r[12] = ((a->n[2] >> 48) & 0xF) | ((a->n[3] & 0xF) << 4); + r[13] = (a->n[2] >> 40) & 0xFF; + r[14] = (a->n[2] >> 32) & 0xFF; + r[15] = (a->n[2] >> 24) & 0xFF; + r[16] = (a->n[2] >> 16) & 0xFF; + r[17] = (a->n[2] >> 8) & 0xFF; + r[18] = a->n[2] & 0xFF; + r[19] = (a->n[1] >> 44) & 0xFF; + r[20] = (a->n[1] >> 36) & 0xFF; + r[21] = (a->n[1] >> 28) & 0xFF; + r[22] = (a->n[1] >> 20) & 0xFF; + r[23] = (a->n[1] >> 12) & 0xFF; + r[24] = (a->n[1] >> 4) & 0xFF; + r[25] = ((a->n[0] >> 48) & 0xF) | ((a->n[1] & 0xF) << 4); + r[26] = (a->n[0] >> 40) & 0xFF; + r[27] = (a->n[0] >> 32) & 0xFF; + r[28] = (a->n[0] >> 24) & 0xFF; + r[29] = (a->n[0] >> 16) & 0xFF; + r[30] = (a->n[0] >> 8) & 0xFF; + r[31] = a->n[0] & 0xFF; +} + +SECP256K1_INLINE static void secp256k1_zkp_fe_negate(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a, int m) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= m); + secp256k1_zkp_fe_verify(a); +#endif + r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0]; + r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1]; + r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2]; + r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3]; + r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4]; +#ifdef VERIFY + r->magnitude = m + 1; + r->normalized = 0; + secp256k1_zkp_fe_verify(r); +#endif +} + +SECP256K1_INLINE static void secp256k1_zkp_fe_mul_int(secp256k1_zkp_fe *r, int a) { + r->n[0] *= a; + r->n[1] *= a; + r->n[2] *= a; + r->n[3] *= a; + r->n[4] *= a; +#ifdef VERIFY + r->magnitude *= a; + r->normalized = 0; + secp256k1_zkp_fe_verify(r); +#endif +} + +SECP256K1_INLINE static void secp256k1_zkp_fe_add(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a) { +#ifdef VERIFY + secp256k1_zkp_fe_verify(a); +#endif + r->n[0] += a->n[0]; + r->n[1] += a->n[1]; + r->n[2] += a->n[2]; + r->n[3] += a->n[3]; + r->n[4] += a->n[4]; +#ifdef VERIFY + r->magnitude += a->magnitude; + r->normalized = 0; + secp256k1_zkp_fe_verify(r); +#endif +} + +static void secp256k1_zkp_fe_mul(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a, const secp256k1_zkp_fe * SECP256K1_RESTRICT b) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= 8); + VERIFY_CHECK(b->magnitude <= 8); + secp256k1_zkp_fe_verify(a); + secp256k1_zkp_fe_verify(b); + VERIFY_CHECK(r != b); +#endif + secp256k1_zkp_fe_mul_inner(r->n, a->n, b->n); +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 0; + secp256k1_zkp_fe_verify(r); +#endif +} + +static void secp256k1_zkp_fe_sqr(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= 8); + secp256k1_zkp_fe_verify(a); +#endif + secp256k1_zkp_fe_sqr_inner(r->n, a->n); +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 0; + secp256k1_zkp_fe_verify(r); +#endif +} + +static SECP256K1_INLINE void secp256k1_zkp_fe_cmov(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a, int flag) { + uint64_t mask0, mask1; + mask0 = flag + ~((uint64_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); + r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); +#ifdef VERIFY + if (a->magnitude > r->magnitude) { + r->magnitude = a->magnitude; + } + r->normalized &= a->normalized; +#endif +} + +static SECP256K1_INLINE void secp256k1_zkp_fe_storage_cmov(secp256k1_zkp_fe_storage *r, const secp256k1_zkp_fe_storage *a, int flag) { + uint64_t mask0, mask1; + mask0 = flag + ~((uint64_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); +} + +static void secp256k1_zkp_fe_to_storage(secp256k1_zkp_fe_storage *r, const secp256k1_zkp_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); +#endif + r->n[0] = a->n[0] | a->n[1] << 52; + r->n[1] = a->n[1] >> 12 | a->n[2] << 40; + r->n[2] = a->n[2] >> 24 | a->n[3] << 28; + r->n[3] = a->n[3] >> 36 | a->n[4] << 16; +} + +static SECP256K1_INLINE void secp256k1_zkp_fe_from_storage(secp256k1_zkp_fe *r, const secp256k1_zkp_fe_storage *a) { + r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL; + r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL); + r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL); + r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL); + r->n[4] = a->n[3] >> 16; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; +#endif +} + +#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_5x52_int128_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_5x52_int128_impl.h new file mode 100644 index 00000000..797555bf --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_5x52_int128_impl.h @@ -0,0 +1,277 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H +#define SECP256K1_FIELD_INNER5X52_IMPL_H + +#include + +#ifdef VERIFY +#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) +#else +#define VERIFY_BITS(x, n) do { } while(0) +#endif + +SECP256K1_INLINE static void secp256k1_zkp_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { + uint128_t c, d; + uint64_t t3, t4, tx, u0; + uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; + const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; + + VERIFY_BITS(a[0], 56); + VERIFY_BITS(a[1], 56); + VERIFY_BITS(a[2], 56); + VERIFY_BITS(a[3], 56); + VERIFY_BITS(a[4], 52); + VERIFY_BITS(b[0], 56); + VERIFY_BITS(b[1], 56); + VERIFY_BITS(b[2], 56); + VERIFY_BITS(b[3], 56); + VERIFY_BITS(b[4], 52); + VERIFY_CHECK(r != b); + + /* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. + * px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * Note that [x 0 0 0 0 0] = [x*R]. + */ + + d = (uint128_t)a0 * b[3] + + (uint128_t)a1 * b[2] + + (uint128_t)a2 * b[1] + + (uint128_t)a3 * b[0]; + VERIFY_BITS(d, 114); + /* [d 0 0 0] = [p3 0 0 0] */ + c = (uint128_t)a4 * b[4]; + VERIFY_BITS(c, 112); + /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + d += (c & M) * R; c >>= 52; + VERIFY_BITS(d, 115); + VERIFY_BITS(c, 60); + /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + t3 = d & M; d >>= 52; + VERIFY_BITS(t3, 52); + VERIFY_BITS(d, 63); + /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + + d += (uint128_t)a0 * b[4] + + (uint128_t)a1 * b[3] + + (uint128_t)a2 * b[2] + + (uint128_t)a3 * b[1] + + (uint128_t)a4 * b[0]; + VERIFY_BITS(d, 115); + /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + d += c * R; + VERIFY_BITS(d, 116); + /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + t4 = d & M; d >>= 52; + VERIFY_BITS(t4, 52); + VERIFY_BITS(d, 64); + /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + tx = (t4 >> 48); t4 &= (M >> 4); + VERIFY_BITS(tx, 4); + VERIFY_BITS(t4, 48); + /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + + c = (uint128_t)a0 * b[0]; + VERIFY_BITS(c, 112); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ + d += (uint128_t)a1 * b[4] + + (uint128_t)a2 * b[3] + + (uint128_t)a3 * b[2] + + (uint128_t)a4 * b[1]; + VERIFY_BITS(d, 115); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = d & M; d >>= 52; + VERIFY_BITS(u0, 52); + VERIFY_BITS(d, 63); + /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = (u0 << 4) | tx; + VERIFY_BITS(u0, 56); + /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + c += (uint128_t)u0 * (R >> 4); + VERIFY_BITS(c, 115); + /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + r[0] = c & M; c >>= 52; + VERIFY_BITS(r[0], 52); + VERIFY_BITS(c, 61); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ + + c += (uint128_t)a0 * b[1] + + (uint128_t)a1 * b[0]; + VERIFY_BITS(c, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ + d += (uint128_t)a2 * b[4] + + (uint128_t)a3 * b[3] + + (uint128_t)a4 * b[2]; + VERIFY_BITS(d, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + c += (d & M) * R; d >>= 52; + VERIFY_BITS(c, 115); + VERIFY_BITS(d, 62); + /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + r[1] = c & M; c >>= 52; + VERIFY_BITS(r[1], 52); + VERIFY_BITS(c, 63); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + + c += (uint128_t)a0 * b[2] + + (uint128_t)a1 * b[1] + + (uint128_t)a2 * b[0]; + VERIFY_BITS(c, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint128_t)a3 * b[4] + + (uint128_t)a4 * b[3]; + VERIFY_BITS(d, 114); + /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += (d & M) * R; d >>= 52; + VERIFY_BITS(c, 115); + VERIFY_BITS(d, 62); + /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = c & M; c >>= 52; + VERIFY_BITS(r[2], 52); + VERIFY_BITS(c, 63); + /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += d * R + t3; + VERIFY_BITS(c, 100); + /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[3] = c & M; c >>= 52; + VERIFY_BITS(r[3], 52); + VERIFY_BITS(c, 48); + /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += t4; + VERIFY_BITS(c, 49); + /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = c; + VERIFY_BITS(r[4], 49); + /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + +SECP256K1_INLINE static void secp256k1_zkp_fe_sqr_inner(uint64_t *r, const uint64_t *a) { + uint128_t c, d; + uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; + int64_t t3, t4, tx, u0; + const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; + + VERIFY_BITS(a[0], 56); + VERIFY_BITS(a[1], 56); + VERIFY_BITS(a[2], 56); + VERIFY_BITS(a[3], 56); + VERIFY_BITS(a[4], 52); + + /** [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. + * px is a shorthand for sum(a[i]*a[x-i], i=0..x). + * Note that [x 0 0 0 0 0] = [x*R]. + */ + + d = (uint128_t)(a0*2) * a3 + + (uint128_t)(a1*2) * a2; + VERIFY_BITS(d, 114); + /* [d 0 0 0] = [p3 0 0 0] */ + c = (uint128_t)a4 * a4; + VERIFY_BITS(c, 112); + /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + d += (c & M) * R; c >>= 52; + VERIFY_BITS(d, 115); + VERIFY_BITS(c, 60); + /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + t3 = d & M; d >>= 52; + VERIFY_BITS(t3, 52); + VERIFY_BITS(d, 63); + /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + + a4 *= 2; + d += (uint128_t)a0 * a4 + + (uint128_t)(a1*2) * a3 + + (uint128_t)a2 * a2; + VERIFY_BITS(d, 115); + /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + d += c * R; + VERIFY_BITS(d, 116); + /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + t4 = d & M; d >>= 52; + VERIFY_BITS(t4, 52); + VERIFY_BITS(d, 64); + /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + tx = (t4 >> 48); t4 &= (M >> 4); + VERIFY_BITS(tx, 4); + VERIFY_BITS(t4, 48); + /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + + c = (uint128_t)a0 * a0; + VERIFY_BITS(c, 112); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ + d += (uint128_t)a1 * a4 + + (uint128_t)(a2*2) * a3; + VERIFY_BITS(d, 114); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = d & M; d >>= 52; + VERIFY_BITS(u0, 52); + VERIFY_BITS(d, 62); + /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = (u0 << 4) | tx; + VERIFY_BITS(u0, 56); + /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + c += (uint128_t)u0 * (R >> 4); + VERIFY_BITS(c, 113); + /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + r[0] = c & M; c >>= 52; + VERIFY_BITS(r[0], 52); + VERIFY_BITS(c, 61); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ + + a0 *= 2; + c += (uint128_t)a0 * a1; + VERIFY_BITS(c, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ + d += (uint128_t)a2 * a4 + + (uint128_t)a3 * a3; + VERIFY_BITS(d, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + c += (d & M) * R; d >>= 52; + VERIFY_BITS(c, 115); + VERIFY_BITS(d, 62); + /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + r[1] = c & M; c >>= 52; + VERIFY_BITS(r[1], 52); + VERIFY_BITS(c, 63); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + + c += (uint128_t)a0 * a2 + + (uint128_t)a1 * a1; + VERIFY_BITS(c, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint128_t)a3 * a4; + VERIFY_BITS(d, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += (d & M) * R; d >>= 52; + VERIFY_BITS(c, 115); + VERIFY_BITS(d, 62); + /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = c & M; c >>= 52; + VERIFY_BITS(r[2], 52); + VERIFY_BITS(c, 63); + /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + c += d * R + t3; + VERIFY_BITS(c, 100); + /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[3] = c & M; c >>= 52; + VERIFY_BITS(r[3], 52); + VERIFY_BITS(c, 48); + /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += t4; + VERIFY_BITS(c, 49); + /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = c; + VERIFY_BITS(r[4], 49); + /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + +#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_impl.h new file mode 100644 index 00000000..4de88a5c --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/field_impl.h @@ -0,0 +1,315 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_FIELD_IMPL_H +#define SECP256K1_FIELD_IMPL_H + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include "util.h" + +#if defined(USE_FIELD_10X26) +#include "field_10x26_impl.h" +#elif defined(USE_FIELD_5X52) +#include "field_5x52_impl.h" +#else +#error "Please select field implementation" +#endif + +SECP256K1_INLINE static int secp256k1_zkp_fe_equal(const secp256k1_zkp_fe *a, const secp256k1_zkp_fe *b) { + secp256k1_zkp_fe na; + secp256k1_zkp_fe_negate(&na, a, 1); + secp256k1_zkp_fe_add(&na, b); + return secp256k1_zkp_fe_normalizes_to_zero(&na); +} + +SECP256K1_INLINE static int secp256k1_zkp_fe_equal_var(const secp256k1_zkp_fe *a, const secp256k1_zkp_fe *b) { + secp256k1_zkp_fe na; + secp256k1_zkp_fe_negate(&na, a, 1); + secp256k1_zkp_fe_add(&na, b); + return secp256k1_zkp_fe_normalizes_to_zero_var(&na); +} + +static int secp256k1_zkp_fe_sqrt(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a) { + /** Given that p is congruent to 3 mod 4, we can compute the square root of + * a mod p as the (p+1)/4'th power of a. + * + * As (p+1)/4 is an even number, it will have the same result for a and for + * (-a). Only one of these two numbers actually has a square root however, + * so we test at the end by squaring and comparing to the input. + * Also because (p+1)/4 is an even number, the computed square root is + * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). + */ + secp256k1_zkp_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; + int j; + + /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in + * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: + * 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] + */ + + secp256k1_zkp_fe_sqr(&x2, a); + secp256k1_zkp_fe_mul(&x2, &x2, a); + + secp256k1_zkp_fe_sqr(&x3, &x2); + secp256k1_zkp_fe_mul(&x3, &x3, a); + + x6 = x3; + for (j=0; j<3; j++) { + secp256k1_zkp_fe_sqr(&x6, &x6); + } + secp256k1_zkp_fe_mul(&x6, &x6, &x3); + + x9 = x6; + for (j=0; j<3; j++) { + secp256k1_zkp_fe_sqr(&x9, &x9); + } + secp256k1_zkp_fe_mul(&x9, &x9, &x3); + + x11 = x9; + for (j=0; j<2; j++) { + secp256k1_zkp_fe_sqr(&x11, &x11); + } + secp256k1_zkp_fe_mul(&x11, &x11, &x2); + + x22 = x11; + for (j=0; j<11; j++) { + secp256k1_zkp_fe_sqr(&x22, &x22); + } + secp256k1_zkp_fe_mul(&x22, &x22, &x11); + + x44 = x22; + for (j=0; j<22; j++) { + secp256k1_zkp_fe_sqr(&x44, &x44); + } + secp256k1_zkp_fe_mul(&x44, &x44, &x22); + + x88 = x44; + for (j=0; j<44; j++) { + secp256k1_zkp_fe_sqr(&x88, &x88); + } + secp256k1_zkp_fe_mul(&x88, &x88, &x44); + + x176 = x88; + for (j=0; j<88; j++) { + secp256k1_zkp_fe_sqr(&x176, &x176); + } + secp256k1_zkp_fe_mul(&x176, &x176, &x88); + + x220 = x176; + for (j=0; j<44; j++) { + secp256k1_zkp_fe_sqr(&x220, &x220); + } + secp256k1_zkp_fe_mul(&x220, &x220, &x44); + + x223 = x220; + for (j=0; j<3; j++) { + secp256k1_zkp_fe_sqr(&x223, &x223); + } + secp256k1_zkp_fe_mul(&x223, &x223, &x3); + + /* The final result is then assembled using a sliding window over the blocks. */ + + t1 = x223; + for (j=0; j<23; j++) { + secp256k1_zkp_fe_sqr(&t1, &t1); + } + secp256k1_zkp_fe_mul(&t1, &t1, &x22); + for (j=0; j<6; j++) { + secp256k1_zkp_fe_sqr(&t1, &t1); + } + secp256k1_zkp_fe_mul(&t1, &t1, &x2); + secp256k1_zkp_fe_sqr(&t1, &t1); + secp256k1_zkp_fe_sqr(r, &t1); + + /* Check that a square root was actually calculated */ + + secp256k1_zkp_fe_sqr(&t1, r); + return secp256k1_zkp_fe_equal(&t1, a); +} + +static void secp256k1_zkp_fe_inv(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a) { + secp256k1_zkp_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; + int j; + + /** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in + * { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: + * [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] + */ + + secp256k1_zkp_fe_sqr(&x2, a); + secp256k1_zkp_fe_mul(&x2, &x2, a); + + secp256k1_zkp_fe_sqr(&x3, &x2); + secp256k1_zkp_fe_mul(&x3, &x3, a); + + x6 = x3; + for (j=0; j<3; j++) { + secp256k1_zkp_fe_sqr(&x6, &x6); + } + secp256k1_zkp_fe_mul(&x6, &x6, &x3); + + x9 = x6; + for (j=0; j<3; j++) { + secp256k1_zkp_fe_sqr(&x9, &x9); + } + secp256k1_zkp_fe_mul(&x9, &x9, &x3); + + x11 = x9; + for (j=0; j<2; j++) { + secp256k1_zkp_fe_sqr(&x11, &x11); + } + secp256k1_zkp_fe_mul(&x11, &x11, &x2); + + x22 = x11; + for (j=0; j<11; j++) { + secp256k1_zkp_fe_sqr(&x22, &x22); + } + secp256k1_zkp_fe_mul(&x22, &x22, &x11); + + x44 = x22; + for (j=0; j<22; j++) { + secp256k1_zkp_fe_sqr(&x44, &x44); + } + secp256k1_zkp_fe_mul(&x44, &x44, &x22); + + x88 = x44; + for (j=0; j<44; j++) { + secp256k1_zkp_fe_sqr(&x88, &x88); + } + secp256k1_zkp_fe_mul(&x88, &x88, &x44); + + x176 = x88; + for (j=0; j<88; j++) { + secp256k1_zkp_fe_sqr(&x176, &x176); + } + secp256k1_zkp_fe_mul(&x176, &x176, &x88); + + x220 = x176; + for (j=0; j<44; j++) { + secp256k1_zkp_fe_sqr(&x220, &x220); + } + secp256k1_zkp_fe_mul(&x220, &x220, &x44); + + x223 = x220; + for (j=0; j<3; j++) { + secp256k1_zkp_fe_sqr(&x223, &x223); + } + secp256k1_zkp_fe_mul(&x223, &x223, &x3); + + /* The final result is then assembled using a sliding window over the blocks. */ + + t1 = x223; + for (j=0; j<23; j++) { + secp256k1_zkp_fe_sqr(&t1, &t1); + } + secp256k1_zkp_fe_mul(&t1, &t1, &x22); + for (j=0; j<5; j++) { + secp256k1_zkp_fe_sqr(&t1, &t1); + } + secp256k1_zkp_fe_mul(&t1, &t1, a); + for (j=0; j<3; j++) { + secp256k1_zkp_fe_sqr(&t1, &t1); + } + secp256k1_zkp_fe_mul(&t1, &t1, &x2); + for (j=0; j<2; j++) { + secp256k1_zkp_fe_sqr(&t1, &t1); + } + secp256k1_zkp_fe_mul(r, a, &t1); +} + +static void secp256k1_zkp_fe_inv_var(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a) { +#if defined(USE_FIELD_INV_BUILTIN) + secp256k1_zkp_fe_inv(r, a); +#elif defined(USE_FIELD_INV_NUM) + secp256k1_zkp_num n, m; + static const secp256k1_zkp_fe negone = SECP256K1_FE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xFFFFFC2EUL + ); + /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + static const unsigned char prime[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F + }; + unsigned char b[32]; + int res; + secp256k1_zkp_fe c = *a; + secp256k1_zkp_fe_normalize_var(&c); + secp256k1_zkp_fe_get_b32(b, &c); + secp256k1_zkp_num_set_bin(&n, b, 32); + secp256k1_zkp_num_set_bin(&m, prime, 32); + secp256k1_zkp_num_mod_inverse(&n, &n, &m); + secp256k1_zkp_num_get_bin(b, 32, &n); + res = secp256k1_zkp_fe_set_b32(r, b); + (void)res; + VERIFY_CHECK(res); + /* Verify the result is the (unique) valid inverse using non-GMP code. */ + secp256k1_zkp_fe_mul(&c, &c, r); + secp256k1_zkp_fe_add(&c, &negone); + CHECK(secp256k1_zkp_fe_normalizes_to_zero_var(&c)); +#else +#error "Please select field inverse implementation" +#endif +} + +static void secp256k1_zkp_fe_inv_all_var(secp256k1_zkp_fe *r, const secp256k1_zkp_fe *a, size_t len) { + secp256k1_zkp_fe u; + size_t i; + if (len < 1) { + return; + } + + VERIFY_CHECK((r + len <= a) || (a + len <= r)); + + r[0] = a[0]; + + i = 0; + while (++i < len) { + secp256k1_zkp_fe_mul(&r[i], &r[i - 1], &a[i]); + } + + secp256k1_zkp_fe_inv_var(&u, &r[--i]); + + while (i > 0) { + size_t j = i--; + secp256k1_zkp_fe_mul(&r[j], &r[i], &u); + secp256k1_zkp_fe_mul(&u, &u, &a[j]); + } + + r[0] = u; +} + +static int secp256k1_zkp_fe_is_quad_var(const secp256k1_zkp_fe *a) { +#ifndef USE_NUM_NONE + unsigned char b[32]; + secp256k1_zkp_num n; + secp256k1_zkp_num m; + /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + static const unsigned char prime[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F + }; + + secp256k1_zkp_fe c = *a; + secp256k1_zkp_fe_normalize_var(&c); + secp256k1_zkp_fe_get_b32(b, &c); + secp256k1_zkp_num_set_bin(&n, b, 32); + secp256k1_zkp_num_set_bin(&m, prime, 32); + return secp256k1_zkp_num_jacobi(&n, &m) >= 0; +#else + secp256k1_zkp_fe r; + return secp256k1_zkp_fe_sqrt(&r, a); +#endif +} + +#endif /* SECP256K1_FIELD_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/gen_context.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/gen_context.c new file mode 100644 index 00000000..d060b918 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/gen_context.c @@ -0,0 +1,79 @@ +/********************************************************************** + * Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#define USE_BASIC_CONFIG 1 + +#include "basic-config.h" +#include "include/secp256k1.h" +#include "util.h" +#include "field_impl.h" +#include "scalar_impl.h" +#include "group_impl.h" +#include "ecmult_gen_impl.h" + +static void default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} + +static const secp256k1_zkp_callback default_error_callback = { + default_error_callback_fn, + NULL +}; + +int main(int argc, char **argv) { + secp256k1_zkp_ecmult_gen_context ctx; + void *prealloc, *base; + int inner; + int outer; + FILE* fp; + + (void)argc; + (void)argv; + + fp = fopen("src/ecmult_static_context.h","w"); + if (fp == NULL) { + fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n"); + return -1; + } + + fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); + fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); + fprintf(fp, "#include \"src/group.h\"\n"); + fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n"); + fprintf(fp, "static const secp256k1_zkp_ge_storage secp256k1_zkp_ecmult_static_context[64][16] = {\n"); + + base = checked_malloc(&default_error_callback, SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE); + prealloc = base; + secp256k1_zkp_ecmult_gen_context_init(&ctx); + secp256k1_zkp_ecmult_gen_context_build(&ctx, &prealloc); + for(outer = 0; outer != 64; outer++) { + fprintf(fp,"{\n"); + for(inner = 0; inner != 16; inner++) { + fprintf(fp," SC(%uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu)", SECP256K1_GE_STORAGE_CONST_GET((*ctx.prec)[outer][inner])); + if (inner != 15) { + fprintf(fp,",\n"); + } else { + fprintf(fp,"\n"); + } + } + if (outer != 63) { + fprintf(fp,"},\n"); + } else { + fprintf(fp,"}\n"); + } + } + fprintf(fp,"};\n"); + secp256k1_zkp_ecmult_gen_context_clear(&ctx); + free(base); + + fprintf(fp, "#undef SC\n"); + fprintf(fp, "#endif\n"); + fclose(fp); + + return 0; +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/group.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/group.h new file mode 100644 index 00000000..8d8385f5 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/group.h @@ -0,0 +1,142 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_GROUP_H +#define SECP256K1_GROUP_H + +#include "num.h" +#include "field.h" + +/** A group element of the secp256k1 curve, in affine coordinates. */ +typedef struct { + secp256k1_zkp_fe x; + secp256k1_zkp_fe y; + int infinity; /* whether this represents the point at infinity */ +} secp256k1_zkp_ge; + +#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0} +#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} + +/** A group element of the secp256k1 curve, in jacobian coordinates. */ +typedef struct { + secp256k1_zkp_fe x; /* actual X: x/z^2 */ + secp256k1_zkp_fe y; /* actual Y: y/z^3 */ + secp256k1_zkp_fe z; + int infinity; /* whether this represents the point at infinity */ +} secp256k1_zkp_gej; + +#define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0} +#define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} + +typedef struct { + secp256k1_zkp_fe_storage x; + secp256k1_zkp_fe_storage y; +} secp256k1_zkp_ge_storage; + +#define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))} + +#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) + +/** Set a group element equal to the point with given X and Y coordinates */ +static void secp256k1_zkp_ge_set_xy(secp256k1_zkp_ge *r, const secp256k1_zkp_fe *x, const secp256k1_zkp_fe *y); + +/** Set a group element (affine) equal to the point with the given X coordinate + * and a Y coordinate that is a quadratic residue modulo p. The return value + * is true iff a coordinate with the given X coordinate exists. + */ +static int secp256k1_zkp_ge_set_xquad(secp256k1_zkp_ge *r, const secp256k1_zkp_fe *x); + +/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness + * for Y. Return value indicates whether the result is valid. */ +static int secp256k1_zkp_ge_set_xo_var(secp256k1_zkp_ge *r, const secp256k1_zkp_fe *x, int odd); + +/** Check whether a group element is the point at infinity. */ +static int secp256k1_zkp_ge_is_infinity(const secp256k1_zkp_ge *a); + +/** Check whether a group element is valid (i.e., on the curve). */ +static int secp256k1_zkp_ge_is_valid_var(const secp256k1_zkp_ge *a); + +static void secp256k1_zkp_ge_neg(secp256k1_zkp_ge *r, const secp256k1_zkp_ge *a); + +/** Set a group element equal to another which is given in jacobian coordinates */ +static void secp256k1_zkp_ge_set_gej(secp256k1_zkp_ge *r, secp256k1_zkp_gej *a); + +/** Set a batch of group elements equal to the inputs given in jacobian coordinates */ +static void secp256k1_zkp_ge_set_all_gej_var(secp256k1_zkp_ge *r, const secp256k1_zkp_gej *a, size_t len); + +/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to + * the same global z "denominator". zr must contain the known z-ratios such + * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y + * coordinates of the result are stored in r, the common z coordinate is + * stored in globalz. */ +static void secp256k1_zkp_ge_globalz_set_table_gej(size_t len, secp256k1_zkp_ge *r, secp256k1_zkp_fe *globalz, const secp256k1_zkp_gej *a, const secp256k1_zkp_fe *zr); + +/** Set a group element (affine) equal to the point at infinity. */ +static void secp256k1_zkp_ge_set_infinity(secp256k1_zkp_ge *r); + +/** Set a group element (jacobian) equal to the point at infinity. */ +static void secp256k1_zkp_gej_set_infinity(secp256k1_zkp_gej *r); + +/** Set a group element (jacobian) equal to another which is given in affine coordinates. */ +static void secp256k1_zkp_gej_set_ge(secp256k1_zkp_gej *r, const secp256k1_zkp_ge *a); + +/** Compare the X coordinate of a group element (jacobian). */ +static int secp256k1_zkp_gej_eq_x_var(const secp256k1_zkp_fe *x, const secp256k1_zkp_gej *a); + +/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ +static void secp256k1_zkp_gej_neg(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a); + +/** Check whether a group element is the point at infinity. */ +static int secp256k1_zkp_gej_is_infinity(const secp256k1_zkp_gej *a); + +/** Check whether a group element's y coordinate is a quadratic residue. */ +static int secp256k1_zkp_gej_has_quad_y_var(const secp256k1_zkp_gej *a); + +/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). + * a may not be zero. Constant time. */ +static void secp256k1_zkp_gej_double_nonzero(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, secp256k1_zkp_fe *rzr); + +/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). */ +static void secp256k1_zkp_gej_double_var(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, secp256k1_zkp_fe *rzr); + +/** Set r equal to the sum of a and b. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */ +static void secp256k1_zkp_gej_add_var(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, const secp256k1_zkp_gej *b, secp256k1_zkp_fe *rzr); + +/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */ +static void secp256k1_zkp_gej_add_ge(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, const secp256k1_zkp_ge *b); + +/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient + than secp256k1_zkp_gej_add_var. It is identical to secp256k1_zkp_gej_add_ge but without constant-time + guarantee, and b is allowed to be infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */ +static void secp256k1_zkp_gej_add_ge_var(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, const secp256k1_zkp_ge *b, secp256k1_zkp_fe *rzr); + +/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */ +static void secp256k1_zkp_gej_add_zinv_var(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, const secp256k1_zkp_ge *b, const secp256k1_zkp_fe *bzinv); + +#ifdef USE_ENDOMORPHISM +/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ +static void secp256k1_zkp_ge_mul_lambda(secp256k1_zkp_ge *r, const secp256k1_zkp_ge *a); +#endif + +/** Clear a secp256k1_zkp_gej to prevent leaking sensitive information. */ +static void secp256k1_zkp_gej_clear(secp256k1_zkp_gej *r); + +/** Clear a secp256k1_zkp_ge to prevent leaking sensitive information. */ +static void secp256k1_zkp_ge_clear(secp256k1_zkp_ge *r); + +/** Convert a group element to the storage type. */ +static void secp256k1_zkp_ge_to_storage(secp256k1_zkp_ge_storage *r, const secp256k1_zkp_ge *a); + +/** Convert a group element back from the storage type. */ +static void secp256k1_zkp_ge_from_storage(secp256k1_zkp_ge *r, const secp256k1_zkp_ge_storage *a); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +static void secp256k1_zkp_ge_storage_cmov(secp256k1_zkp_ge_storage *r, const secp256k1_zkp_ge_storage *a, int flag); + +/** Rescale a jacobian point by b which must be non-zero. Constant-time. */ +static void secp256k1_zkp_gej_rescale(secp256k1_zkp_gej *r, const secp256k1_zkp_fe *b); + +#endif /* SECP256K1_GROUP_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/group_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/group_impl.h new file mode 100644 index 00000000..0d584caa --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/group_impl.h @@ -0,0 +1,703 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_GROUP_IMPL_H +#define SECP256K1_GROUP_IMPL_H + +#include "num.h" +#include "field.h" +#include "group.h" + +/* These points can be generated in sage as follows: + * + * 0. Setup a worksheet with the following parameters. + * b = 4 # whatever CURVE_B will be set to + * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) + * C = EllipticCurve ([F (0), F (b)]) + * + * 1. Determine all the small orders available to you. (If there are + * no satisfactory ones, go back and change b.) + * print C.order().factor(limit=1000) + * + * 2. Choose an order as one of the prime factors listed in the above step. + * (You can also multiply some to get a composite order, though the + * tests will crash trying to invert scalars during signing.) We take a + * random point and scale it to drop its order to the desired value. + * There is some probability this won't work; just try again. + * order = 199 + * P = C.random_point() + * P = (int(P.order()) / int(order)) * P + * assert(P.order() == order) + * + * 3. Print the values. You'll need to use a vim macro or something to + * split the hex output into 4-byte chunks. + * print "%x %x" % P.xy() + */ +#if defined(EXHAUSTIVE_TEST_ORDER) +# if EXHAUSTIVE_TEST_ORDER == 199 +const secp256k1_zkp_ge secp256k1_zkp_ge_const_g = SECP256K1_GE_CONST( + 0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069, + 0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18, + 0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868, + 0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED +); + +static const int CURVE_B = 4; +# elif EXHAUSTIVE_TEST_ORDER == 13 +const secp256k1_zkp_ge secp256k1_zkp_ge_const_g = SECP256K1_GE_CONST( + 0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0, + 0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15, + 0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e, + 0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac +); +static const int CURVE_B = 2; +# else +# error No known generator for the specified exhaustive test group order. +# endif +#else +/** Generator for secp256k1, value 'g' defined in + * "Standards for Efficient Cryptography" (SEC2) 2.7.1. + */ +static const secp256k1_zkp_ge secp256k1_zkp_ge_const_g = SECP256K1_GE_CONST( + 0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL, + 0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL, + 0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL, + 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL +); + +static const int CURVE_B = 7; +#endif + +static void secp256k1_zkp_ge_set_gej_zinv(secp256k1_zkp_ge *r, const secp256k1_zkp_gej *a, const secp256k1_zkp_fe *zi) { + secp256k1_zkp_fe zi2; + secp256k1_zkp_fe zi3; + secp256k1_zkp_fe_sqr(&zi2, zi); + secp256k1_zkp_fe_mul(&zi3, &zi2, zi); + secp256k1_zkp_fe_mul(&r->x, &a->x, &zi2); + secp256k1_zkp_fe_mul(&r->y, &a->y, &zi3); + r->infinity = a->infinity; +} + +static void secp256k1_zkp_ge_set_xy(secp256k1_zkp_ge *r, const secp256k1_zkp_fe *x, const secp256k1_zkp_fe *y) { + r->infinity = 0; + r->x = *x; + r->y = *y; +} + +static int secp256k1_zkp_ge_is_infinity(const secp256k1_zkp_ge *a) { + return a->infinity; +} + +static void secp256k1_zkp_ge_neg(secp256k1_zkp_ge *r, const secp256k1_zkp_ge *a) { + *r = *a; + secp256k1_zkp_fe_normalize_weak(&r->y); + secp256k1_zkp_fe_negate(&r->y, &r->y, 1); +} + +static void secp256k1_zkp_ge_set_gej(secp256k1_zkp_ge *r, secp256k1_zkp_gej *a) { + secp256k1_zkp_fe z2, z3; + r->infinity = a->infinity; + secp256k1_zkp_fe_inv(&a->z, &a->z); + secp256k1_zkp_fe_sqr(&z2, &a->z); + secp256k1_zkp_fe_mul(&z3, &a->z, &z2); + secp256k1_zkp_fe_mul(&a->x, &a->x, &z2); + secp256k1_zkp_fe_mul(&a->y, &a->y, &z3); + secp256k1_zkp_fe_set_int(&a->z, 1); + r->x = a->x; + r->y = a->y; +} + +static void secp256k1_zkp_ge_set_gej_var(secp256k1_zkp_ge *r, secp256k1_zkp_gej *a) { + secp256k1_zkp_fe z2, z3; + r->infinity = a->infinity; + if (a->infinity) { + return; + } + secp256k1_zkp_fe_inv_var(&a->z, &a->z); + secp256k1_zkp_fe_sqr(&z2, &a->z); + secp256k1_zkp_fe_mul(&z3, &a->z, &z2); + secp256k1_zkp_fe_mul(&a->x, &a->x, &z2); + secp256k1_zkp_fe_mul(&a->y, &a->y, &z3); + secp256k1_zkp_fe_set_int(&a->z, 1); + r->x = a->x; + r->y = a->y; +} + +static void secp256k1_zkp_ge_set_all_gej_var(secp256k1_zkp_ge *r, const secp256k1_zkp_gej *a, size_t len) { + secp256k1_zkp_fe u; + size_t i; + size_t last_i = SIZE_MAX; + + for (i = 0; i < len; i++) { + if (!a[i].infinity) { + /* Use destination's x coordinates as scratch space */ + if (last_i == SIZE_MAX) { + r[i].x = a[i].z; + } else { + secp256k1_zkp_fe_mul(&r[i].x, &r[last_i].x, &a[i].z); + } + last_i = i; + } + } + if (last_i == SIZE_MAX) { + return; + } + secp256k1_zkp_fe_inv_var(&u, &r[last_i].x); + + i = last_i; + while (i > 0) { + i--; + if (!a[i].infinity) { + secp256k1_zkp_fe_mul(&r[last_i].x, &r[i].x, &u); + secp256k1_zkp_fe_mul(&u, &u, &a[last_i].z); + last_i = i; + } + } + VERIFY_CHECK(!a[last_i].infinity); + r[last_i].x = u; + + for (i = 0; i < len; i++) { + r[i].infinity = a[i].infinity; + if (!a[i].infinity) { + secp256k1_zkp_ge_set_gej_zinv(&r[i], &a[i], &r[i].x); + } + } +} + +static void secp256k1_zkp_ge_globalz_set_table_gej(size_t len, secp256k1_zkp_ge *r, secp256k1_zkp_fe *globalz, const secp256k1_zkp_gej *a, const secp256k1_zkp_fe *zr) { + size_t i = len - 1; + secp256k1_zkp_fe zs; + + if (len > 0) { + /* The z of the final point gives us the "global Z" for the table. */ + r[i].x = a[i].x; + r[i].y = a[i].y; + *globalz = a[i].z; + r[i].infinity = 0; + zs = zr[i]; + + /* Work our way backwards, using the z-ratios to scale the x/y values. */ + while (i > 0) { + if (i != len - 1) { + secp256k1_zkp_fe_mul(&zs, &zs, &zr[i]); + } + i--; + secp256k1_zkp_ge_set_gej_zinv(&r[i], &a[i], &zs); + } + } +} + +static void secp256k1_zkp_gej_set_infinity(secp256k1_zkp_gej *r) { + r->infinity = 1; + secp256k1_zkp_fe_clear(&r->x); + secp256k1_zkp_fe_clear(&r->y); + secp256k1_zkp_fe_clear(&r->z); +} + +static void secp256k1_zkp_ge_set_infinity(secp256k1_zkp_ge *r) { + r->infinity = 1; + secp256k1_zkp_fe_clear(&r->x); + secp256k1_zkp_fe_clear(&r->y); +} + +static void secp256k1_zkp_gej_clear(secp256k1_zkp_gej *r) { + r->infinity = 0; + secp256k1_zkp_fe_clear(&r->x); + secp256k1_zkp_fe_clear(&r->y); + secp256k1_zkp_fe_clear(&r->z); +} + +static void secp256k1_zkp_ge_clear(secp256k1_zkp_ge *r) { + r->infinity = 0; + secp256k1_zkp_fe_clear(&r->x); + secp256k1_zkp_fe_clear(&r->y); +} + +static int secp256k1_zkp_ge_set_xquad(secp256k1_zkp_ge *r, const secp256k1_zkp_fe *x) { + secp256k1_zkp_fe x2, x3, c; + r->x = *x; + secp256k1_zkp_fe_sqr(&x2, x); + secp256k1_zkp_fe_mul(&x3, x, &x2); + r->infinity = 0; + secp256k1_zkp_fe_set_int(&c, CURVE_B); + secp256k1_zkp_fe_add(&c, &x3); + return secp256k1_zkp_fe_sqrt(&r->y, &c); +} + +static int secp256k1_zkp_ge_set_xo_var(secp256k1_zkp_ge *r, const secp256k1_zkp_fe *x, int odd) { + if (!secp256k1_zkp_ge_set_xquad(r, x)) { + return 0; + } + secp256k1_zkp_fe_normalize_var(&r->y); + if (secp256k1_zkp_fe_is_odd(&r->y) != odd) { + secp256k1_zkp_fe_negate(&r->y, &r->y, 1); + } + return 1; + +} + +static void secp256k1_zkp_gej_set_ge(secp256k1_zkp_gej *r, const secp256k1_zkp_ge *a) { + r->infinity = a->infinity; + r->x = a->x; + r->y = a->y; + secp256k1_zkp_fe_set_int(&r->z, 1); +} + +static int secp256k1_zkp_gej_eq_x_var(const secp256k1_zkp_fe *x, const secp256k1_zkp_gej *a) { + secp256k1_zkp_fe r, r2; + VERIFY_CHECK(!a->infinity); + secp256k1_zkp_fe_sqr(&r, &a->z); secp256k1_zkp_fe_mul(&r, &r, x); + r2 = a->x; secp256k1_zkp_fe_normalize_weak(&r2); + return secp256k1_zkp_fe_equal_var(&r, &r2); +} + +static void secp256k1_zkp_gej_neg(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a) { + r->infinity = a->infinity; + r->x = a->x; + r->y = a->y; + r->z = a->z; + secp256k1_zkp_fe_normalize_weak(&r->y); + secp256k1_zkp_fe_negate(&r->y, &r->y, 1); +} + +static int secp256k1_zkp_gej_is_infinity(const secp256k1_zkp_gej *a) { + return a->infinity; +} + +static int secp256k1_zkp_gej_is_valid_var(const secp256k1_zkp_gej *a) { + secp256k1_zkp_fe y2, x3, z2, z6; + if (a->infinity) { + return 0; + } + /** y^2 = x^3 + 7 + * (Y/Z^3)^2 = (X/Z^2)^3 + 7 + * Y^2 / Z^6 = X^3 / Z^6 + 7 + * Y^2 = X^3 + 7*Z^6 + */ + secp256k1_zkp_fe_sqr(&y2, &a->y); + secp256k1_zkp_fe_sqr(&x3, &a->x); secp256k1_zkp_fe_mul(&x3, &x3, &a->x); + secp256k1_zkp_fe_sqr(&z2, &a->z); + secp256k1_zkp_fe_sqr(&z6, &z2); secp256k1_zkp_fe_mul(&z6, &z6, &z2); + secp256k1_zkp_fe_mul_int(&z6, CURVE_B); + secp256k1_zkp_fe_add(&x3, &z6); + secp256k1_zkp_fe_normalize_weak(&x3); + return secp256k1_zkp_fe_equal_var(&y2, &x3); +} + +static int secp256k1_zkp_ge_is_valid_var(const secp256k1_zkp_ge *a) { + secp256k1_zkp_fe y2, x3, c; + if (a->infinity) { + return 0; + } + /* y^2 = x^3 + 7 */ + secp256k1_zkp_fe_sqr(&y2, &a->y); + secp256k1_zkp_fe_sqr(&x3, &a->x); secp256k1_zkp_fe_mul(&x3, &x3, &a->x); + secp256k1_zkp_fe_set_int(&c, CURVE_B); + secp256k1_zkp_fe_add(&x3, &c); + secp256k1_zkp_fe_normalize_weak(&x3); + return secp256k1_zkp_fe_equal_var(&y2, &x3); +} + +static void secp256k1_zkp_gej_double_var(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, secp256k1_zkp_fe *rzr) { + /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate. + * + * Note that there is an implementation described at + * https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + * which trades a multiply for a square, but in practice this is actually slower, + * mainly because it requires more normalizations. + */ + secp256k1_zkp_fe t1,t2,t3,t4; + /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, + * Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have + * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. + * + * Having said this, if this function receives a point on a sextic twist, e.g. by + * a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6, + * since -6 does have a cube root mod p. For this point, this function will not set + * the infinity flag even though the point doubles to infinity, and the result + * point will be gibberish (z = 0 but infinity = 0). + */ + r->infinity = a->infinity; + if (r->infinity) { + if (rzr != NULL) { + secp256k1_zkp_fe_set_int(rzr, 1); + } + return; + } + + if (rzr != NULL) { + *rzr = a->y; + secp256k1_zkp_fe_normalize_weak(rzr); + secp256k1_zkp_fe_mul_int(rzr, 2); + } + + secp256k1_zkp_fe_mul(&r->z, &a->z, &a->y); + secp256k1_zkp_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */ + secp256k1_zkp_fe_sqr(&t1, &a->x); + secp256k1_zkp_fe_mul_int(&t1, 3); /* T1 = 3*X^2 (3) */ + secp256k1_zkp_fe_sqr(&t2, &t1); /* T2 = 9*X^4 (1) */ + secp256k1_zkp_fe_sqr(&t3, &a->y); + secp256k1_zkp_fe_mul_int(&t3, 2); /* T3 = 2*Y^2 (2) */ + secp256k1_zkp_fe_sqr(&t4, &t3); + secp256k1_zkp_fe_mul_int(&t4, 2); /* T4 = 8*Y^4 (2) */ + secp256k1_zkp_fe_mul(&t3, &t3, &a->x); /* T3 = 2*X*Y^2 (1) */ + r->x = t3; + secp256k1_zkp_fe_mul_int(&r->x, 4); /* X' = 8*X*Y^2 (4) */ + secp256k1_zkp_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */ + secp256k1_zkp_fe_add(&r->x, &t2); /* X' = 9*X^4 - 8*X*Y^2 (6) */ + secp256k1_zkp_fe_negate(&t2, &t2, 1); /* T2 = -9*X^4 (2) */ + secp256k1_zkp_fe_mul_int(&t3, 6); /* T3 = 12*X*Y^2 (6) */ + secp256k1_zkp_fe_add(&t3, &t2); /* T3 = 12*X*Y^2 - 9*X^4 (8) */ + secp256k1_zkp_fe_mul(&r->y, &t1, &t3); /* Y' = 36*X^3*Y^2 - 27*X^6 (1) */ + secp256k1_zkp_fe_negate(&t2, &t4, 2); /* T2 = -8*Y^4 (3) */ + secp256k1_zkp_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */ +} + +static SECP256K1_INLINE void secp256k1_zkp_gej_double_nonzero(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, secp256k1_zkp_fe *rzr) { + VERIFY_CHECK(!secp256k1_zkp_gej_is_infinity(a)); + secp256k1_zkp_gej_double_var(r, a, rzr); +} + +static void secp256k1_zkp_gej_add_var(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, const secp256k1_zkp_gej *b, secp256k1_zkp_fe *rzr) { + /* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */ + secp256k1_zkp_fe z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + + if (a->infinity) { + VERIFY_CHECK(rzr == NULL); + *r = *b; + return; + } + + if (b->infinity) { + if (rzr != NULL) { + secp256k1_zkp_fe_set_int(rzr, 1); + } + *r = *a; + return; + } + + r->infinity = 0; + secp256k1_zkp_fe_sqr(&z22, &b->z); + secp256k1_zkp_fe_sqr(&z12, &a->z); + secp256k1_zkp_fe_mul(&u1, &a->x, &z22); + secp256k1_zkp_fe_mul(&u2, &b->x, &z12); + secp256k1_zkp_fe_mul(&s1, &a->y, &z22); secp256k1_zkp_fe_mul(&s1, &s1, &b->z); + secp256k1_zkp_fe_mul(&s2, &b->y, &z12); secp256k1_zkp_fe_mul(&s2, &s2, &a->z); + secp256k1_zkp_fe_negate(&h, &u1, 1); secp256k1_zkp_fe_add(&h, &u2); + secp256k1_zkp_fe_negate(&i, &s1, 1); secp256k1_zkp_fe_add(&i, &s2); + if (secp256k1_zkp_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_zkp_fe_normalizes_to_zero_var(&i)) { + secp256k1_zkp_gej_double_var(r, a, rzr); + } else { + if (rzr != NULL) { + secp256k1_zkp_fe_set_int(rzr, 0); + } + r->infinity = 1; + } + return; + } + secp256k1_zkp_fe_sqr(&i2, &i); + secp256k1_zkp_fe_sqr(&h2, &h); + secp256k1_zkp_fe_mul(&h3, &h, &h2); + secp256k1_zkp_fe_mul(&h, &h, &b->z); + if (rzr != NULL) { + *rzr = h; + } + secp256k1_zkp_fe_mul(&r->z, &a->z, &h); + secp256k1_zkp_fe_mul(&t, &u1, &h2); + r->x = t; secp256k1_zkp_fe_mul_int(&r->x, 2); secp256k1_zkp_fe_add(&r->x, &h3); secp256k1_zkp_fe_negate(&r->x, &r->x, 3); secp256k1_zkp_fe_add(&r->x, &i2); + secp256k1_zkp_fe_negate(&r->y, &r->x, 5); secp256k1_zkp_fe_add(&r->y, &t); secp256k1_zkp_fe_mul(&r->y, &r->y, &i); + secp256k1_zkp_fe_mul(&h3, &h3, &s1); secp256k1_zkp_fe_negate(&h3, &h3, 1); + secp256k1_zkp_fe_add(&r->y, &h3); +} + +static void secp256k1_zkp_gej_add_ge_var(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, const secp256k1_zkp_ge *b, secp256k1_zkp_fe *rzr) { + /* 8 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ + secp256k1_zkp_fe z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + if (a->infinity) { + VERIFY_CHECK(rzr == NULL); + secp256k1_zkp_gej_set_ge(r, b); + return; + } + if (b->infinity) { + if (rzr != NULL) { + secp256k1_zkp_fe_set_int(rzr, 1); + } + *r = *a; + return; + } + r->infinity = 0; + + secp256k1_zkp_fe_sqr(&z12, &a->z); + u1 = a->x; secp256k1_zkp_fe_normalize_weak(&u1); + secp256k1_zkp_fe_mul(&u2, &b->x, &z12); + s1 = a->y; secp256k1_zkp_fe_normalize_weak(&s1); + secp256k1_zkp_fe_mul(&s2, &b->y, &z12); secp256k1_zkp_fe_mul(&s2, &s2, &a->z); + secp256k1_zkp_fe_negate(&h, &u1, 1); secp256k1_zkp_fe_add(&h, &u2); + secp256k1_zkp_fe_negate(&i, &s1, 1); secp256k1_zkp_fe_add(&i, &s2); + if (secp256k1_zkp_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_zkp_fe_normalizes_to_zero_var(&i)) { + secp256k1_zkp_gej_double_var(r, a, rzr); + } else { + if (rzr != NULL) { + secp256k1_zkp_fe_set_int(rzr, 0); + } + r->infinity = 1; + } + return; + } + secp256k1_zkp_fe_sqr(&i2, &i); + secp256k1_zkp_fe_sqr(&h2, &h); + secp256k1_zkp_fe_mul(&h3, &h, &h2); + if (rzr != NULL) { + *rzr = h; + } + secp256k1_zkp_fe_mul(&r->z, &a->z, &h); + secp256k1_zkp_fe_mul(&t, &u1, &h2); + r->x = t; secp256k1_zkp_fe_mul_int(&r->x, 2); secp256k1_zkp_fe_add(&r->x, &h3); secp256k1_zkp_fe_negate(&r->x, &r->x, 3); secp256k1_zkp_fe_add(&r->x, &i2); + secp256k1_zkp_fe_negate(&r->y, &r->x, 5); secp256k1_zkp_fe_add(&r->y, &t); secp256k1_zkp_fe_mul(&r->y, &r->y, &i); + secp256k1_zkp_fe_mul(&h3, &h3, &s1); secp256k1_zkp_fe_negate(&h3, &h3, 1); + secp256k1_zkp_fe_add(&r->y, &h3); +} + +static void secp256k1_zkp_gej_add_zinv_var(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, const secp256k1_zkp_ge *b, const secp256k1_zkp_fe *bzinv) { + /* 9 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ + secp256k1_zkp_fe az, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + + if (b->infinity) { + *r = *a; + return; + } + if (a->infinity) { + secp256k1_zkp_fe bzinv2, bzinv3; + r->infinity = b->infinity; + secp256k1_zkp_fe_sqr(&bzinv2, bzinv); + secp256k1_zkp_fe_mul(&bzinv3, &bzinv2, bzinv); + secp256k1_zkp_fe_mul(&r->x, &b->x, &bzinv2); + secp256k1_zkp_fe_mul(&r->y, &b->y, &bzinv3); + secp256k1_zkp_fe_set_int(&r->z, 1); + return; + } + r->infinity = 0; + + /** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to + * secp256k1's isomorphism we can multiply the Z coordinates on both sides + * by bzinv, and get: (rx,ry,rz*bzinv) = (ax,ay,az*bzinv) + (bx,by,1). + * This means that (rx,ry,rz) can be calculated as + * (ax,ay,az*bzinv) + (bx,by,1), when not applying the bzinv factor to rz. + * The variable az below holds the modified Z coordinate for a, which is used + * for the computation of rx and ry, but not for rz. + */ + secp256k1_zkp_fe_mul(&az, &a->z, bzinv); + + secp256k1_zkp_fe_sqr(&z12, &az); + u1 = a->x; secp256k1_zkp_fe_normalize_weak(&u1); + secp256k1_zkp_fe_mul(&u2, &b->x, &z12); + s1 = a->y; secp256k1_zkp_fe_normalize_weak(&s1); + secp256k1_zkp_fe_mul(&s2, &b->y, &z12); secp256k1_zkp_fe_mul(&s2, &s2, &az); + secp256k1_zkp_fe_negate(&h, &u1, 1); secp256k1_zkp_fe_add(&h, &u2); + secp256k1_zkp_fe_negate(&i, &s1, 1); secp256k1_zkp_fe_add(&i, &s2); + if (secp256k1_zkp_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_zkp_fe_normalizes_to_zero_var(&i)) { + secp256k1_zkp_gej_double_var(r, a, NULL); + } else { + r->infinity = 1; + } + return; + } + secp256k1_zkp_fe_sqr(&i2, &i); + secp256k1_zkp_fe_sqr(&h2, &h); + secp256k1_zkp_fe_mul(&h3, &h, &h2); + r->z = a->z; secp256k1_zkp_fe_mul(&r->z, &r->z, &h); + secp256k1_zkp_fe_mul(&t, &u1, &h2); + r->x = t; secp256k1_zkp_fe_mul_int(&r->x, 2); secp256k1_zkp_fe_add(&r->x, &h3); secp256k1_zkp_fe_negate(&r->x, &r->x, 3); secp256k1_zkp_fe_add(&r->x, &i2); + secp256k1_zkp_fe_negate(&r->y, &r->x, 5); secp256k1_zkp_fe_add(&r->y, &t); secp256k1_zkp_fe_mul(&r->y, &r->y, &i); + secp256k1_zkp_fe_mul(&h3, &h3, &s1); secp256k1_zkp_fe_negate(&h3, &h3, 1); + secp256k1_zkp_fe_add(&r->y, &h3); +} + + +static void secp256k1_zkp_gej_add_ge(secp256k1_zkp_gej *r, const secp256k1_zkp_gej *a, const secp256k1_zkp_ge *b) { + /* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */ + static const secp256k1_zkp_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_zkp_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; + secp256k1_zkp_fe m_alt, rr_alt; + int infinity, degenerate; + VERIFY_CHECK(!b->infinity); + VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); + + /** In: + * Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks. + * In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002. + * we find as solution for a unified addition/doubling formula: + * lambda = ((x1 + x2)^2 - x1 * x2 + a) / (y1 + y2), with a = 0 for secp256k1's curve equation. + * x3 = lambda^2 - (x1 + x2) + * 2*y3 = lambda * (x1 + x2 - 2 * x3) - (y1 + y2). + * + * Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives: + * U1 = X1*Z2^2, U2 = X2*Z1^2 + * S1 = Y1*Z2^3, S2 = Y2*Z1^3 + * Z = Z1*Z2 + * T = U1+U2 + * M = S1+S2 + * Q = T*M^2 + * R = T^2-U1*U2 + * X3 = 4*(R^2-Q) + * Y3 = 4*(R*(3*Q-2*R^2)-M^4) + * Z3 = 2*M*Z + * (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.) + * + * This formula has the benefit of being the same for both addition + * of distinct points and doubling. However, it breaks down in the + * case that either point is infinity, or that y1 = -y2. We handle + * these cases in the following ways: + * + * - If b is infinity we simply bail by means of a VERIFY_CHECK. + * + * - If a is infinity, we detect this, and at the end of the + * computation replace the result (which will be meaningless, + * but we compute to be constant-time) with b.x : b.y : 1. + * + * - If a = -b, we have y1 = -y2, which is a degenerate case. + * But here the answer is infinity, so we simply set the + * infinity flag of the result, overriding the computed values + * without even needing to cmov. + * + * - If y1 = -y2 but x1 != x2, which does occur thanks to certain + * properties of our curve (specifically, 1 has nontrivial cube + * roots in our field, and the curve equation has no x coefficient) + * then the answer is not infinity but also not given by the above + * equation. In this case, we cmov in place an alternate expression + * for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these + * expressions for lambda are defined, they are equal, and can be + * obtained from each other by multiplication by (y1 + y2)/(y1 + y2) + * then substitution of x^3 + 7 for y^2 (using the curve equation). + * For all pairs of nonzero points (a, b) at least one is defined, + * so this covers everything. + */ + + secp256k1_zkp_fe_sqr(&zz, &a->z); /* z = Z1^2 */ + u1 = a->x; secp256k1_zkp_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */ + secp256k1_zkp_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ + s1 = a->y; secp256k1_zkp_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ + secp256k1_zkp_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */ + secp256k1_zkp_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ + t = u1; secp256k1_zkp_fe_add(&t, &u2); /* t = T = U1+U2 (2) */ + m = s1; secp256k1_zkp_fe_add(&m, &s2); /* m = M = S1+S2 (2) */ + secp256k1_zkp_fe_sqr(&rr, &t); /* rr = T^2 (1) */ + secp256k1_zkp_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */ + secp256k1_zkp_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */ + secp256k1_zkp_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */ + /** If lambda = R/M = 0/0 we have a problem (except in the "trivial" + * case that Z = z1z2 = 0, and this is special-cased later on). */ + degenerate = secp256k1_zkp_fe_normalizes_to_zero(&m) & + secp256k1_zkp_fe_normalizes_to_zero(&rr); + /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. + * This means either x1 == beta*x2 or beta*x1 == x2, where beta is + * a nontrivial cube root of one. In either case, an alternate + * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2), + * so we set R/M equal to this. */ + rr_alt = s1; + secp256k1_zkp_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */ + secp256k1_zkp_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */ + + secp256k1_zkp_fe_cmov(&rr_alt, &rr, !degenerate); + secp256k1_zkp_fe_cmov(&m_alt, &m, !degenerate); + /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0. + * From here on out Ralt and Malt represent the numerator + * and denominator of lambda; R and M represent the explicit + * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ + secp256k1_zkp_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */ + secp256k1_zkp_fe_mul(&q, &n, &t); /* q = Q = T*Malt^2 (1) */ + /* These two lines use the observation that either M == Malt or M == 0, + * so M^3 * Malt is either Malt^4 (which is computed by squaring), or + * zero (which is "computed" by cmov). So the cost is one squaring + * versus two multiplications. */ + secp256k1_zkp_fe_sqr(&n, &n); + secp256k1_zkp_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */ + secp256k1_zkp_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ + secp256k1_zkp_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */ + infinity = secp256k1_zkp_fe_normalizes_to_zero(&r->z) * (1 - a->infinity); + secp256k1_zkp_fe_mul_int(&r->z, 2); /* r->z = Z3 = 2*Malt*Z (2) */ + secp256k1_zkp_fe_negate(&q, &q, 1); /* q = -Q (2) */ + secp256k1_zkp_fe_add(&t, &q); /* t = Ralt^2-Q (3) */ + secp256k1_zkp_fe_normalize_weak(&t); + r->x = t; /* r->x = Ralt^2-Q (1) */ + secp256k1_zkp_fe_mul_int(&t, 2); /* t = 2*x3 (2) */ + secp256k1_zkp_fe_add(&t, &q); /* t = 2*x3 - Q: (4) */ + secp256k1_zkp_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*x3 - Q) (1) */ + secp256k1_zkp_fe_add(&t, &n); /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */ + secp256k1_zkp_fe_negate(&r->y, &t, 3); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */ + secp256k1_zkp_fe_normalize_weak(&r->y); + secp256k1_zkp_fe_mul_int(&r->x, 4); /* r->x = X3 = 4*(Ralt^2-Q) */ + secp256k1_zkp_fe_mul_int(&r->y, 4); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */ + + /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */ + secp256k1_zkp_fe_cmov(&r->x, &b->x, a->infinity); + secp256k1_zkp_fe_cmov(&r->y, &b->y, a->infinity); + secp256k1_zkp_fe_cmov(&r->z, &fe_1, a->infinity); + r->infinity = infinity; +} + +static void secp256k1_zkp_gej_rescale(secp256k1_zkp_gej *r, const secp256k1_zkp_fe *s) { + /* Operations: 4 mul, 1 sqr */ + secp256k1_zkp_fe zz; + VERIFY_CHECK(!secp256k1_zkp_fe_is_zero(s)); + secp256k1_zkp_fe_sqr(&zz, s); + secp256k1_zkp_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ + secp256k1_zkp_fe_mul(&r->y, &r->y, &zz); + secp256k1_zkp_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ + secp256k1_zkp_fe_mul(&r->z, &r->z, s); /* r->z *= s */ +} + +static void secp256k1_zkp_ge_to_storage(secp256k1_zkp_ge_storage *r, const secp256k1_zkp_ge *a) { + secp256k1_zkp_fe x, y; + VERIFY_CHECK(!a->infinity); + x = a->x; + secp256k1_zkp_fe_normalize(&x); + y = a->y; + secp256k1_zkp_fe_normalize(&y); + secp256k1_zkp_fe_to_storage(&r->x, &x); + secp256k1_zkp_fe_to_storage(&r->y, &y); +} + +static void secp256k1_zkp_ge_from_storage(secp256k1_zkp_ge *r, const secp256k1_zkp_ge_storage *a) { + secp256k1_zkp_fe_from_storage(&r->x, &a->x); + secp256k1_zkp_fe_from_storage(&r->y, &a->y); + r->infinity = 0; +} + +static SECP256K1_INLINE void secp256k1_zkp_ge_storage_cmov(secp256k1_zkp_ge_storage *r, const secp256k1_zkp_ge_storage *a, int flag) { + secp256k1_zkp_fe_storage_cmov(&r->x, &a->x, flag); + secp256k1_zkp_fe_storage_cmov(&r->y, &a->y, flag); +} + +#ifdef USE_ENDOMORPHISM +static void secp256k1_zkp_ge_mul_lambda(secp256k1_zkp_ge *r, const secp256k1_zkp_ge *a) { + static const secp256k1_zkp_fe beta = SECP256K1_FE_CONST( + 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, + 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul + ); + *r = *a; + secp256k1_zkp_fe_mul(&r->x, &r->x, &beta); +} +#endif + +static int secp256k1_zkp_gej_has_quad_y_var(const secp256k1_zkp_gej *a) { + secp256k1_zkp_fe yz; + + if (a->infinity) { + return 0; + } + + /* We rely on the fact that the Jacobi symbol of 1 / a->z^3 is the same as + * that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z + is */ + secp256k1_zkp_fe_mul(&yz, &a->y, &a->z); + return secp256k1_zkp_fe_is_quad_var(&yz); +} + +#endif /* SECP256K1_GROUP_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/hash.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/hash.h new file mode 100644 index 00000000..2af9b7c6 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/hash.h @@ -0,0 +1,41 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_HASH_H +#define SECP256K1_HASH_H + +#include +#include + +typedef struct { + uint32_t s[8]; + uint32_t buf[16]; /* In big endian */ + size_t bytes; +} secp256k1_zkp_sha256; + +static void secp256k1_zkp_sha256_initialize(secp256k1_zkp_sha256 *hash); +static void secp256k1_zkp_sha256_write(secp256k1_zkp_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_zkp_sha256_finalize(secp256k1_zkp_sha256 *hash, unsigned char *out32); + +typedef struct { + secp256k1_zkp_sha256 inner, outer; +} secp256k1_zkp_hmac_sha256; + +static void secp256k1_zkp_hmac_sha256_initialize(secp256k1_zkp_hmac_sha256 *hash, const unsigned char *key, size_t size); +static void secp256k1_zkp_hmac_sha256_write(secp256k1_zkp_hmac_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_zkp_hmac_sha256_finalize(secp256k1_zkp_hmac_sha256 *hash, unsigned char *out32); + +typedef struct { + unsigned char v[32]; + unsigned char k[32]; + int retry; +} secp256k1_zkp_rfc6979_hmac_sha256; + +static void secp256k1_zkp_rfc6979_hmac_sha256_initialize(secp256k1_zkp_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen); +static void secp256k1_zkp_rfc6979_hmac_sha256_generate(secp256k1_zkp_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen); +static void secp256k1_zkp_rfc6979_hmac_sha256_finalize(secp256k1_zkp_rfc6979_hmac_sha256 *rng); + +#endif /* SECP256K1_HASH_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/hash_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/hash_impl.h new file mode 100644 index 00000000..169f5587 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/hash_impl.h @@ -0,0 +1,282 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_HASH_IMPL_H +#define SECP256K1_HASH_IMPL_H + +#include "hash.h" + +#include +#include +#include + +#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10)) +#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7)) +#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3)) +#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10)) + +#define Round(a,b,c,d,e,f,g,h,k,w) do { \ + uint32_t t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \ + uint32_t t2 = Sigma0(a) + Maj((a), (b), (c)); \ + (d) += t1; \ + (h) = t1 + t2; \ +} while(0) + +#ifdef WORDS_BIGENDIAN +#define BE32(x) (x) +#else +#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#endif + +static void secp256k1_zkp_sha256_initialize(secp256k1_zkp_sha256 *hash) { + hash->s[0] = 0x6a09e667ul; + hash->s[1] = 0xbb67ae85ul; + hash->s[2] = 0x3c6ef372ul; + hash->s[3] = 0xa54ff53aul; + hash->s[4] = 0x510e527ful; + hash->s[5] = 0x9b05688cul; + hash->s[6] = 0x1f83d9abul; + hash->s[7] = 0x5be0cd19ul; + hash->bytes = 0; +} + +/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */ +static void secp256k1_zkp_sha256_transform(uint32_t* s, const uint32_t* chunk) { + uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; + uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; + + Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = BE32(chunk[0])); + Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1])); + Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2])); + Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3])); + Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4])); + Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5])); + Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6])); + Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7])); + Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8])); + Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9])); + Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10])); + Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11])); + Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12])); + Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13])); + Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14])); + Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15])); + + Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0)); + + s[0] += a; + s[1] += b; + s[2] += c; + s[3] += d; + s[4] += e; + s[5] += f; + s[6] += g; + s[7] += h; +} + +static void secp256k1_zkp_sha256_write(secp256k1_zkp_sha256 *hash, const unsigned char *data, size_t len) { + size_t bufsize = hash->bytes & 0x3F; + hash->bytes += len; + while (bufsize + len >= 64) { + /* Fill the buffer, and process it. */ + size_t chunk_len = 64 - bufsize; + memcpy(((unsigned char*)hash->buf) + bufsize, data, chunk_len); + data += chunk_len; + len -= chunk_len; + secp256k1_zkp_sha256_transform(hash->s, hash->buf); + bufsize = 0; + } + if (len) { + /* Fill the buffer with what remains. */ + memcpy(((unsigned char*)hash->buf) + bufsize, data, len); + } +} + +static void secp256k1_zkp_sha256_finalize(secp256k1_zkp_sha256 *hash, unsigned char *out32) { + static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint32_t sizedesc[2]; + uint32_t out[8]; + int i = 0; + sizedesc[0] = BE32(hash->bytes >> 29); + sizedesc[1] = BE32(hash->bytes << 3); + secp256k1_zkp_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64)); + secp256k1_zkp_sha256_write(hash, (const unsigned char*)sizedesc, 8); + for (i = 0; i < 8; i++) { + out[i] = BE32(hash->s[i]); + hash->s[i] = 0; + } + memcpy(out32, (const unsigned char*)out, 32); +} + +static void secp256k1_zkp_hmac_sha256_initialize(secp256k1_zkp_hmac_sha256 *hash, const unsigned char *key, size_t keylen) { + size_t n; + unsigned char rkey[64]; + if (keylen <= sizeof(rkey)) { + memcpy(rkey, key, keylen); + memset(rkey + keylen, 0, sizeof(rkey) - keylen); + } else { + secp256k1_zkp_sha256 sha256; + secp256k1_zkp_sha256_initialize(&sha256); + secp256k1_zkp_sha256_write(&sha256, key, keylen); + secp256k1_zkp_sha256_finalize(&sha256, rkey); + memset(rkey + 32, 0, 32); + } + + secp256k1_zkp_sha256_initialize(&hash->outer); + for (n = 0; n < sizeof(rkey); n++) { + rkey[n] ^= 0x5c; + } + secp256k1_zkp_sha256_write(&hash->outer, rkey, sizeof(rkey)); + + secp256k1_zkp_sha256_initialize(&hash->inner); + for (n = 0; n < sizeof(rkey); n++) { + rkey[n] ^= 0x5c ^ 0x36; + } + secp256k1_zkp_sha256_write(&hash->inner, rkey, sizeof(rkey)); + memset(rkey, 0, sizeof(rkey)); +} + +static void secp256k1_zkp_hmac_sha256_write(secp256k1_zkp_hmac_sha256 *hash, const unsigned char *data, size_t size) { + secp256k1_zkp_sha256_write(&hash->inner, data, size); +} + +static void secp256k1_zkp_hmac_sha256_finalize(secp256k1_zkp_hmac_sha256 *hash, unsigned char *out32) { + unsigned char temp[32]; + secp256k1_zkp_sha256_finalize(&hash->inner, temp); + secp256k1_zkp_sha256_write(&hash->outer, temp, 32); + memset(temp, 0, 32); + secp256k1_zkp_sha256_finalize(&hash->outer, out32); +} + + +static void secp256k1_zkp_rfc6979_hmac_sha256_initialize(secp256k1_zkp_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) { + secp256k1_zkp_hmac_sha256 hmac; + static const unsigned char zero[1] = {0x00}; + static const unsigned char one[1] = {0x01}; + + memset(rng->v, 0x01, 32); /* RFC6979 3.2.b. */ + memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */ + + /* RFC6979 3.2.d. */ + secp256k1_zkp_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_zkp_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_zkp_hmac_sha256_write(&hmac, zero, 1); + secp256k1_zkp_hmac_sha256_write(&hmac, key, keylen); + secp256k1_zkp_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_zkp_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_zkp_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_zkp_hmac_sha256_finalize(&hmac, rng->v); + + /* RFC6979 3.2.f. */ + secp256k1_zkp_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_zkp_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_zkp_hmac_sha256_write(&hmac, one, 1); + secp256k1_zkp_hmac_sha256_write(&hmac, key, keylen); + secp256k1_zkp_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_zkp_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_zkp_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_zkp_hmac_sha256_finalize(&hmac, rng->v); + rng->retry = 0; +} + +static void secp256k1_zkp_rfc6979_hmac_sha256_generate(secp256k1_zkp_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) { + /* RFC6979 3.2.h. */ + static const unsigned char zero[1] = {0x00}; + if (rng->retry) { + secp256k1_zkp_hmac_sha256 hmac; + secp256k1_zkp_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_zkp_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_zkp_hmac_sha256_write(&hmac, zero, 1); + secp256k1_zkp_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_zkp_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_zkp_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_zkp_hmac_sha256_finalize(&hmac, rng->v); + } + + while (outlen > 0) { + secp256k1_zkp_hmac_sha256 hmac; + int now = outlen; + secp256k1_zkp_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_zkp_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_zkp_hmac_sha256_finalize(&hmac, rng->v); + if (now > 32) { + now = 32; + } + memcpy(out, rng->v, now); + out += now; + outlen -= now; + } + + rng->retry = 1; +} + +static void secp256k1_zkp_rfc6979_hmac_sha256_finalize(secp256k1_zkp_rfc6979_hmac_sha256 *rng) { + memset(rng->k, 0, 32); + memset(rng->v, 0, 32); + rng->retry = 0; +} + +#undef BE32 +#undef Round +#undef sigma1 +#undef sigma0 +#undef Sigma1 +#undef Sigma0 +#undef Maj +#undef Ch + +#endif /* SECP256K1_HASH_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org/bitcoin/NativeSecp256k1.java b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org/bitcoin/NativeSecp256k1.java new file mode 100644 index 00000000..2863cc42 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org/bitcoin/NativeSecp256k1.java @@ -0,0 +1,446 @@ +/* + * Copyright 2013 Google Inc. + * Copyright 2014-2016 the libsecp256k1 contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bitcoin; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import java.math.BigInteger; +import com.google.common.base.Preconditions; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import static org.bitcoin.NativeSecp256k1Util.*; + +/** + *

This class holds native methods to handle ECDSA verification.

+ * + *

You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1

+ * + *

To build secp256k1 for use with bitcoinj, run + * `./configure --enable-jni --enable-experimental --enable-module-ecdh` + * and `make` then copy `.libs/libsecp256k1.so` to your system library path + * or point the JVM to the folder containing it with -Djava.library.path + *

+ */ +public class NativeSecp256k1 { + + private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + private static final Lock r = rwl.readLock(); + private static final Lock w = rwl.writeLock(); + private static ThreadLocal nativeECDSABuffer = new ThreadLocal(); + /** + * Verifies the given secp256k1 signature in native code. + * Calling when enabled == false is undefined (probably library not loaded) + * + * @param data The data which was signed, must be exactly 32 bytes + * @param signature The signature + * @param pub The public key which did the signing + */ + public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{ + Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 520) { + byteBuff = ByteBuffer.allocateDirect(520); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(data); + byteBuff.put(signature); + byteBuff.put(pub); + + byte[][] retByteArray; + + r.lock(); + try { + return secp256k1_zkp_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1; + } finally { + r.unlock(); + } + } + + /** + * libsecp256k1 Create an ECDSA signature. + * + * @param data Message hash, 32 bytes + * @param key Secret key, 32 bytes + * + * Return values + * @param sig byte array of signature + */ + public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{ + Preconditions.checkArgument(data.length == 32 && sec.length <= 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 32 + 32) { + byteBuff = ByteBuffer.allocateDirect(32 + 32); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(data); + byteBuff.put(sec); + + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_zkp_ecdsa_sign(byteBuff, Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] sigArr = retByteArray[0]; + int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(sigArr.length, sigLen, "Got bad signature length."); + + return retVal == 0 ? new byte[0] : sigArr; + } + + /** + * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid + * + * @param seckey ECDSA Secret key, 32 bytes + */ + public static boolean secKeyVerify(byte[] seckey) { + Preconditions.checkArgument(seckey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seckey.length) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + + r.lock(); + try { + return secp256k1_zkp_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1; + } finally { + r.unlock(); + } + } + + + /** + * libsecp256k1 Compute Pubkey - computes public key from secret key + * + * @param seckey ECDSA Secret key, 32 bytes + * + * Return values + * @param pubkey ECDSA Public key, 33 or 65 bytes + */ + //TODO add a 'compressed' arg + public static byte[] computePubkey(byte[] seckey) throws AssertFailException{ + Preconditions.checkArgument(seckey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seckey.length) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_zkp_ec_pubkey_create(byteBuff, Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + return retVal == 0 ? new byte[0]: pubArr; + } + + /** + * libsecp256k1 Cleanup - This destroys the secp256k1 context object + * This should be called at the end of the program for proper cleanup of the context. + */ + public static synchronized void cleanup() { + w.lock(); + try { + secp256k1_zkp_destroy_context(Secp256k1Context.getContext()); + } finally { + w.unlock(); + } + } + + public static long cloneContext() { + r.lock(); + try { + return secp256k1_zkp_ctx_clone(Secp256k1Context.getContext()); + } finally { r.unlock(); } + } + + /** + * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it + * + * @param tweak some bytes to tweak with + * @param seckey 32-byte seckey + */ + public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_zkp_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] privArr = retByteArray[0]; + + int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(privArr.length, privLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return privArr; + } + + /** + * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it + * + * @param tweak some bytes to tweak with + * @param seckey 32-byte seckey + */ + public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_zkp_privkey_tweak_add(byteBuff,Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] privArr = retByteArray[0]; + + int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(privArr.length, privLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return privArr; + } + + /** + * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it + * + * @param tweak some bytes to tweak with + * @param pubkey 32-byte seckey + */ + public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_zkp_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + + int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return pubArr; + } + + /** + * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it + * + * @param tweak some bytes to tweak with + * @param pubkey 32-byte seckey + */ + public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_zkp_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + + int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return pubArr; + } + + /** + * libsecp256k1 create ECDH secret - constant time ECDH calculation + * + * @param seckey byte array of secret key used in exponentiaion + * @param pubkey byte array of public key used in exponentiaion + */ + public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{ + Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) { + byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + byteBuff.put(pubkey); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_zkp_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] resArr = retByteArray[0]; + int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + + assertEquals(resArr.length, 32, "Got bad result length."); + assertEquals(retVal, 1, "Failed return value check."); + + return resArr; + } + + /** + * libsecp256k1 randomize - updates the context randomization + * + * @param seed 32-byte random seed + */ + public static synchronized boolean randomize(byte[] seed) throws AssertFailException{ + Preconditions.checkArgument(seed.length == 32 || seed == null); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seed.length) { + byteBuff = ByteBuffer.allocateDirect(seed.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seed); + + w.lock(); + try { + return secp256k1_zkp_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1; + } finally { + w.unlock(); + } + } + + private static native long secp256k1_zkp_ctx_clone(long context); + + private static native int secp256k1_zkp_context_randomize(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_zkp_privkey_tweak_add(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_zkp_privkey_tweak_mul(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_zkp_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen); + + private static native byte[][] secp256k1_zkp_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen); + + private static native void secp256k1_zkp_destroy_context(long context); + + private static native int secp256k1_zkp_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen); + + private static native byte[][] secp256k1_zkp_ecdsa_sign(ByteBuffer byteBuff, long context); + + private static native int secp256k1_zkp_ec_seckey_verify(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_zkp_ec_pubkey_create(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_zkp_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen); + + private static native byte[][] secp256k1_zkp_ecdh(ByteBuffer byteBuff, long context, int inputLen); + +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org/bitcoin/NativeSecp256k1Test.java b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org/bitcoin/NativeSecp256k1Test.java new file mode 100644 index 00000000..d766a102 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -0,0 +1,226 @@ +package org.bitcoin; + +import com.google.common.io.BaseEncoding; +import java.util.Arrays; +import java.math.BigInteger; +import javax.xml.bind.DatatypeConverter; +import static org.bitcoin.NativeSecp256k1Util.*; + +/** + * This class holds test cases defined for testing this library. + */ +public class NativeSecp256k1Test { + + //TODO improve comments/add more tests + /** + * This tests verify() for a valid signature + */ + public static void testVerifyPos() throws AssertFailException{ + boolean result = false; + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + result = NativeSecp256k1.verify( data, sig, pub); + assertEquals( result, true , "testVerifyPos"); + } + + /** + * This tests verify() for a non-valid signature + */ + public static void testVerifyNeg() throws AssertFailException{ + boolean result = false; + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" + byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + result = NativeSecp256k1.verify( data, sig, pub); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testVerifyNeg"); + } + + /** + * This tests secret key verify() for a valid secretkey + */ + public static void testSecKeyVerifyPos() throws AssertFailException{ + boolean result = false; + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + result = NativeSecp256k1.secKeyVerify( sec ); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, true , "testSecKeyVerifyPos"); + } + + /** + * This tests secret key verify() for an invalid secretkey + */ + public static void testSecKeyVerifyNeg() throws AssertFailException{ + boolean result = false; + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + result = NativeSecp256k1.secKeyVerify( sec ); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testSecKeyVerifyNeg"); + } + + /** + * This tests public key create() for a valid secretkey + */ + public static void testPubKeyCreatePos() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.computePubkey( sec); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos"); + } + + /** + * This tests public key create() for a invalid secretkey + */ + public static void testPubKeyCreateNeg() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.computePubkey( sec); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString, "" , "testPubKeyCreateNeg"); + } + + /** + * This tests sign() for a valid secretkey + */ + public static void testSignPos() throws AssertFailException{ + + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos"); + } + + /** + * This tests sign() for a invalid secretkey + */ + public static void testSignNeg() throws AssertFailException{ + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString, "" , "testSignNeg"); + } + + /** + * This tests private key tweak-add + */ + public static void testPrivKeyTweakAdd_1() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1"); + } + + /** + * This tests private key tweak-mul + */ + public static void testPrivKeyTweakMul_1() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1"); + } + + /** + * This tests private key tweak-add uncompressed + */ + public static void testPrivKeyTweakAdd_2() throws AssertFailException { + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2"); + } + + /** + * This tests private key tweak-mul uncompressed + */ + public static void testPrivKeyTweakMul_2() throws AssertFailException { + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2"); + } + + /** + * This tests seed randomization + */ + public static void testRandomize() throws AssertFailException { + byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random" + boolean result = NativeSecp256k1.randomize(seed); + assertEquals( result, true, "testRandomize"); + } + + public static void testCreateECDHSecret() throws AssertFailException{ + + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub); + String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret"); + } + + public static void main(String[] args) throws AssertFailException{ + + + System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n"); + + assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" ); + + //Test verify() success/fail + testVerifyPos(); + testVerifyNeg(); + + //Test secKeyVerify() success/fail + testSecKeyVerifyPos(); + testSecKeyVerifyNeg(); + + //Test computePubkey() success/fail + testPubKeyCreatePos(); + testPubKeyCreateNeg(); + + //Test sign() success/fail + testSignPos(); + testSignNeg(); + + //Test privKeyTweakAdd() 1 + testPrivKeyTweakAdd_1(); + + //Test privKeyTweakMul() 2 + testPrivKeyTweakMul_1(); + + //Test privKeyTweakAdd() 3 + testPrivKeyTweakAdd_2(); + + //Test privKeyTweakMul() 4 + testPrivKeyTweakMul_2(); + + //Test randomize() + testRandomize(); + + //Test ECDH + testCreateECDHSecret(); + + NativeSecp256k1.cleanup(); + + System.out.println(" All tests passed." ); + + } +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org/bitcoin/NativeSecp256k1Util.java b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org/bitcoin/NativeSecp256k1Util.java new file mode 100644 index 00000000..04732ba0 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org/bitcoin/NativeSecp256k1Util.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014-2016 the libsecp256k1 contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bitcoin; + +public class NativeSecp256k1Util{ + + public static void assertEquals( int val, int val2, String message ) throws AssertFailException{ + if( val != val2 ) + throw new AssertFailException("FAIL: " + message); + } + + public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{ + if( val != val2 ) + throw new AssertFailException("FAIL: " + message); + else + System.out.println("PASS: " + message); + } + + public static void assertEquals( String val, String val2, String message ) throws AssertFailException{ + if( !val.equals(val2) ) + throw new AssertFailException("FAIL: " + message); + else + System.out.println("PASS: " + message); + } + + public static class AssertFailException extends Exception { + public AssertFailException(String message) { + super( message ); + } + } +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org/bitcoin/Secp256k1Context.java b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org/bitcoin/Secp256k1Context.java new file mode 100644 index 00000000..fc725df9 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org/bitcoin/Secp256k1Context.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014-2016 the libsecp256k1 contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bitcoin; + +/** + * This class holds the context reference used in native methods + * to handle ECDSA operations. + */ +public class Secp256k1Context { + private static final boolean enabled; //true if the library is loaded + private static final long context; //ref to pointer to context obj + + static { //static initializer + boolean isEnabled = true; + long contextRef = -1; + try { + System.loadLibrary("secp256k1"); + contextRef = secp256k1_zkp_init_context(); + } catch (UnsatisfiedLinkError e) { + System.out.println("UnsatisfiedLinkError: " + e.toString()); + isEnabled = false; + } + enabled = isEnabled; + context = contextRef; + } + + public static boolean isEnabled() { + return enabled; + } + + public static long getContext() { + if(!enabled) return -1; //sanity check + return context; + } + + private static native long secp256k1_zkp_init_context(); +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org_bitcoin_NativeSecp256k1.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org_bitcoin_NativeSecp256k1.c new file mode 100644 index 00000000..0a747384 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org_bitcoin_NativeSecp256k1.c @@ -0,0 +1,379 @@ +#include +#include +#include +#include "org_bitcoin_NativeSecp256k1.h" +#include "include/secp256k1.h" +#include "include/secp256k1_ecdh.h" +#include "include/secp256k1_recovery.h" + + +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ctx_1clone + (JNIEnv* env, jclass classObject, jlong ctx_l) +{ + const secp256k1_zkp_context *ctx = (secp256k1_zkp_context*)(uintptr_t)ctx_l; + + jlong ctx_clone_l = (uintptr_t) secp256k1_zkp_context_clone(ctx); + + (void)classObject;(void)env; + + return ctx_clone_l; + +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1context_1randomize + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_zkp_context *ctx = (secp256k1_zkp_context*)(uintptr_t)ctx_l; + + const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_zkp_context_randomize(ctx, seed); + +} + +SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1destroy_1context + (JNIEnv* env, jclass classObject, jlong ctx_l) +{ + secp256k1_zkp_context *ctx = (secp256k1_zkp_context*)(uintptr_t)ctx_l; + + secp256k1_zkp_context_destroy(ctx); + + (void)classObject;(void)env; +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ecdsa_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen) +{ + secp256k1_zkp_context *ctx = (secp256k1_zkp_context*)(uintptr_t)ctx_l; + + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* sigdata = { (unsigned char*) (data + 32) }; + const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) }; + + secp256k1_zkp_ecdsa_signature sig; + secp256k1_zkp_pubkey pubkey; + + int ret = secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen); + + if( ret ) { + ret = secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); + + if( ret ) { + ret = secp256k1_zkp_ecdsa_verify(ctx, &sig, data, &pubkey); + } + } + + (void)classObject; + + return ret; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ecdsa_1sign + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_zkp_context *ctx = (secp256k1_zkp_context*)(uintptr_t)ctx_l; + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + unsigned char* secKey = (unsigned char*) (data + 32); + + jobjectArray retArray; + jbyteArray sigArray, intsByteArray; + unsigned char intsarray[2]; + + secp256k1_zkp_ecdsa_signature sig[72]; + + int ret = secp256k1_zkp_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL); + + unsigned char outputSer[72]; + size_t outputLen = 72; + + if( ret ) { + int ret2 = secp256k1_zkp_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + sigArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, sigArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ec_1seckey_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_zkp_context *ctx = (secp256k1_zkp_context*)(uintptr_t)ctx_l; + unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_zkp_ec_seckey_verify(ctx, secKey); +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ec_1pubkey_1create + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_zkp_context *ctx = (secp256k1_zkp_context*)(uintptr_t)ctx_l; + const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + secp256k1_zkp_pubkey pubkey; + + jobjectArray retArray; + jbyteArray pubkeyArray, intsByteArray; + unsigned char intsarray[2]; + + int ret = secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, secKey); + + unsigned char outputSer[65]; + size_t outputLen = 65; + + if( ret ) { + int ret2 = secp256k1_zkp_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubkeyArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; + +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1privkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_zkp_context *ctx = (secp256k1_zkp_context*)(uintptr_t)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_zkp_ec_privkey_tweak_add(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1privkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_zkp_context *ctx = (secp256k1_zkp_context*)(uintptr_t)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_zkp_ec_privkey_tweak_mul(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1pubkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_zkp_context *ctx = (secp256k1_zkp_context*)(uintptr_t)ctx_l; +/* secp256k1_zkp_pubkey* pubkey = (secp256k1_zkp_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/ + unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + unsigned char outputSer[65]; + size_t outputLen = 65; + + secp256k1_zkp_pubkey pubkey; + int ret = secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, pkey, publen); + + if( ret ) { + ret = secp256k1_zkp_ec_pubkey_tweak_add(ctx, &pubkey, tweak); + } + + if( ret ) { + int ret2 = secp256k1_zkp_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1pubkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_zkp_context *ctx = (secp256k1_zkp_context*)(uintptr_t)ctx_l; + unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + unsigned char outputSer[65]; + size_t outputLen = 65; + + secp256k1_zkp_pubkey pubkey; + int ret = secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, pkey, publen); + + if ( ret ) { + ret = secp256k1_zkp_ec_pubkey_tweak_mul(ctx, &pubkey, tweak); + } + + if( ret ) { + int ret2 = secp256k1_zkp_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ecdsa_1pubkey_1combine + (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys) +{ + (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys; + + return 0; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ecdh + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_zkp_context *ctx = (secp256k1_zkp_context*)(uintptr_t)ctx_l; + const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* pubdata = (const unsigned char*) (secdata + 32); + + jobjectArray retArray; + jbyteArray outArray, intsByteArray; + unsigned char intsarray[1]; + secp256k1_zkp_pubkey pubkey; + unsigned char nonce_res[32]; + size_t outputLen = 32; + + int ret = secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); + + if (ret) { + ret = secp256k1_zkp_ecdh( + ctx, + nonce_res, + &pubkey, + secdata, + NULL, + NULL + ); + } + + intsarray[0] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + outArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res); + (*env)->SetObjectArrayElement(env, retArray, 0, outArray); + + intsByteArray = (*env)->NewByteArray(env, 1); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org_bitcoin_NativeSecp256k1.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org_bitcoin_NativeSecp256k1.h new file mode 100644 index 00000000..e660b7bc --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org_bitcoin_NativeSecp256k1.h @@ -0,0 +1,119 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +#include "include/secp256k1.h" +/* Header for class org_bitcoin_NativeSecp256k1 */ + +#ifndef _Included_org_bitcoin_NativeSecp256k1 +#define _Included_org_bitcoin_NativeSecp256k1 +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_zkp_ctx_clone + * Signature: (J)J + */ +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ctx_1clone + (JNIEnv *, jclass, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_zkp_context_randomize + * Signature: (Ljava/nio/ByteBuffer;J)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1context_1randomize + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_zkp_privkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1privkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_zkp_privkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1privkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_zkp_pubkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1pubkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_zkp_pubkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1pubkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_zkp_destroy_context + * Signature: (J)V + */ +SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1destroy_1context + (JNIEnv *, jclass, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_zkp_ecdsa_verify + * Signature: (Ljava/nio/ByteBuffer;JII)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ecdsa_1verify + (JNIEnv *, jclass, jobject, jlong, jint, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_zkp_ecdsa_sign + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ecdsa_1sign + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_zkp_ec_seckey_verify + * Signature: (Ljava/nio/ByteBuffer;J)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ec_1seckey_1verify + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_zkp_ec_pubkey_create + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ec_1pubkey_1create + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_zkp_ec_pubkey_parse + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ec_1pubkey_1parse + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_zkp_ecdh + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_zkp_1ecdh + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org_bitcoin_Secp256k1Context.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org_bitcoin_Secp256k1Context.c new file mode 100644 index 00000000..93661f57 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org_bitcoin_Secp256k1Context.c @@ -0,0 +1,15 @@ +#include +#include +#include "org_bitcoin_Secp256k1Context.h" +#include "include/secp256k1.h" + +SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_zkp_1init_1context + (JNIEnv* env, jclass classObject) +{ + secp256k1_zkp_context *ctx = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + (void)classObject;(void)env; + + return (uintptr_t)ctx; +} + diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org_bitcoin_Secp256k1Context.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org_bitcoin_Secp256k1Context.h new file mode 100644 index 00000000..6358205e --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/java/org_bitcoin_Secp256k1Context.h @@ -0,0 +1,22 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +#include "include/secp256k1.h" +/* Header for class org_bitcoin_Secp256k1Context */ + +#ifndef _Included_org_bitcoin_Secp256k1Context +#define _Included_org_bitcoin_Secp256k1Context +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_bitcoin_Secp256k1Context + * Method: secp256k1_zkp_init_context + * Signature: ()J + */ +SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_zkp_1init_1context + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/ecdh/Makefile.am.include b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/ecdh/Makefile.am.include new file mode 100644 index 00000000..40973dfa --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/ecdh/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_zkp_ecdh.h +noinst_HEADERS += src/modules/ecdh/main_impl.h +noinst_HEADERS += src/modules/ecdh/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_ecdh +bench_ecdh_SOURCES = src/bench_ecdh.c +bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/ecdh/main_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/ecdh/main_impl.h new file mode 100644 index 00000000..7bc9b6a0 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/ecdh/main_impl.h @@ -0,0 +1,67 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_MAIN_H +#define SECP256K1_MODULE_ECDH_MAIN_H + +#include "include/secp256k1_ecdh.h" +#include "ecmult_const_impl.h" + +static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + unsigned char version = (y[31] & 0x01) | 0x02; + secp256k1_zkp_sha256 sha; + (void)data; + + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_sha256_write(&sha, &version, 1); + secp256k1_zkp_sha256_write(&sha, x, 32); + secp256k1_zkp_sha256_finalize(&sha, output); + + return 1; +} + +const secp256k1_zkp_ecdh_hash_function secp256k1_zkp_ecdh_hash_function_sha256 = ecdh_hash_function_sha256; +const secp256k1_zkp_ecdh_hash_function secp256k1_zkp_ecdh_hash_function_default = ecdh_hash_function_sha256; + +int secp256k1_zkp_ecdh(const secp256k1_zkp_context* ctx, unsigned char *output, const secp256k1_zkp_pubkey *point, const unsigned char *scalar, secp256k1_zkp_ecdh_hash_function hashfp, void *data) { + int ret = 0; + int overflow = 0; + secp256k1_zkp_gej res; + secp256k1_zkp_ge pt; + secp256k1_zkp_scalar s; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(point != NULL); + ARG_CHECK(scalar != NULL); + if (hashfp == NULL) { + hashfp = secp256k1_zkp_ecdh_hash_function_default; + } + + secp256k1_zkp_pubkey_load(ctx, &pt, point); + secp256k1_zkp_scalar_set_b32(&s, scalar, &overflow); + if (overflow || secp256k1_zkp_scalar_is_zero(&s)) { + ret = 0; + } else { + unsigned char x[32]; + unsigned char y[32]; + + secp256k1_zkp_ecmult_const(&res, &pt, &s, 256); + secp256k1_zkp_ge_set_gej(&pt, &res); + + /* Compute a hash of the point */ + secp256k1_zkp_fe_normalize(&pt.x); + secp256k1_zkp_fe_normalize(&pt.y); + secp256k1_zkp_fe_get_b32(x, &pt.x); + secp256k1_zkp_fe_get_b32(y, &pt.y); + + ret = hashfp(output, x, y, data); + } + + secp256k1_zkp_scalar_clear(&s); + return ret; +} + +#endif /* SECP256K1_MODULE_ECDH_MAIN_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/ecdh/tests_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/ecdh/tests_impl.h new file mode 100644 index 00000000..644ef9c0 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/ecdh/tests_impl.h @@ -0,0 +1,132 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_TESTS_H +#define SECP256K1_MODULE_ECDH_TESTS_H + +int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + (void)output; + (void)x; + (void)y; + (void)data; + return 0; +} + +int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { + (void)data; + /* Save x and y as uncompressed public key */ + output[0] = 0x04; + memcpy(output + 1, x, 32); + memcpy(output + 33, y, 32); + return 1; +} + +void test_ecdh_api(void) { + /* Setup context that just counts errors */ + secp256k1_zkp_context *tctx = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_zkp_pubkey point; + unsigned char res[32]; + unsigned char s_one[32] = { 0 }; + int32_t ecount = 0; + s_one[31] = 1; + + secp256k1_zkp_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount); + CHECK(secp256k1_zkp_ec_pubkey_create(tctx, &point, s_one) == 1); + + /* Check all NULLs are detected */ + CHECK(secp256k1_zkp_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_ecdh(tctx, res, NULL, s_one, NULL, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ecdh(tctx, res, &point, NULL, NULL, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1); + CHECK(ecount == 3); + + /* Cleanup */ + secp256k1_zkp_context_destroy(tctx); +} + +void test_ecdh_generator_basepoint(void) { + unsigned char s_one[32] = { 0 }; + secp256k1_zkp_pubkey point[2]; + int i; + + s_one[31] = 1; + /* Check against pubkey creation when the basepoint is the generator */ + for (i = 0; i < 100; ++i) { + secp256k1_zkp_sha256 sha; + unsigned char s_b32[32]; + unsigned char output_ecdh[65]; + unsigned char output_ser[32]; + unsigned char point_ser[65]; + size_t point_ser_len = sizeof(point_ser); + secp256k1_zkp_scalar s; + + random_scalar_order(&s); + secp256k1_zkp_scalar_get_b32(s_b32, &s); + + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &point[0], s_one) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &point[1], s_b32) == 1); + + /* compute using ECDH function with custom hash function */ + CHECK(secp256k1_zkp_ecdh(ctx, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1); + /* compute "explicitly" */ + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1); + /* compare */ + CHECK(memcmp(output_ecdh, point_ser, 65) == 0); + + /* compute using ECDH function with default hash function */ + CHECK(secp256k1_zkp_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1); + /* compute "explicitly" */ + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_sha256_write(&sha, point_ser, point_ser_len); + secp256k1_zkp_sha256_finalize(&sha, output_ser); + /* compare */ + CHECK(memcmp(output_ecdh, output_ser, 32) == 0); + } +} + +void test_bad_scalar(void) { + unsigned char s_zero[32] = { 0 }; + unsigned char s_overflow[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + unsigned char s_rand[32] = { 0 }; + unsigned char output[32]; + secp256k1_zkp_scalar rand; + secp256k1_zkp_pubkey point; + + /* Create random point */ + random_scalar_order(&rand); + secp256k1_zkp_scalar_get_b32(s_rand, &rand); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &point, s_rand) == 1); + + /* Try to multiply it by bad values */ + CHECK(secp256k1_zkp_ecdh(ctx, output, &point, s_zero, NULL, NULL) == 0); + CHECK(secp256k1_zkp_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 0); + /* ...and a good one */ + s_overflow[31] -= 1; + CHECK(secp256k1_zkp_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 1); + + /* Hash function failure results in ecdh failure */ + CHECK(secp256k1_zkp_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0); +} + +void run_ecdh_tests(void) { + test_ecdh_api(); + test_ecdh_generator_basepoint(); + test_bad_scalar(); +} + +#endif /* SECP256K1_MODULE_ECDH_TESTS_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/generator/Makefile.am.include b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/generator/Makefile.am.include new file mode 100644 index 00000000..dccbb395 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/generator/Makefile.am.include @@ -0,0 +1,9 @@ +include_HEADERS += include/secp256k1_zkp_generator.h +noinst_HEADERS += src/modules/generator/main_impl.h +noinst_HEADERS += src/modules/generator/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_generator +bench_generator_SOURCES = src/bench_generator.c +bench_generator_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_generator_LDFLAGS = -static +endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/generator/main_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/generator/main_impl.h new file mode 100644 index 00000000..0b893dfa --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/generator/main_impl.h @@ -0,0 +1,222 @@ +/********************************************************************** + * Copyright (c) 2016 Andrew Poelstra & Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_GENERATOR_MAIN +#define SECP256K1_MODULE_GENERATOR_MAIN + +#include + +#include "field.h" +#include "group.h" +#include "hash.h" +#include "scalar.h" + +static void secp256k1_zkp_generator_load(secp256k1_zkp_ge* ge, const secp256k1_zkp_generator* gen) { + int succeed; + succeed = secp256k1_zkp_fe_set_b32(&ge->x, &gen->data[0]); + VERIFY_CHECK(succeed != 0); + succeed = secp256k1_zkp_fe_set_b32(&ge->y, &gen->data[32]); + VERIFY_CHECK(succeed != 0); + ge->infinity = 0; + (void) succeed; +} + +static void secp256k1_zkp_generator_save(secp256k1_zkp_generator *gen, secp256k1_zkp_ge* ge) { + VERIFY_CHECK(!secp256k1_zkp_ge_is_infinity(ge)); + secp256k1_zkp_fe_normalize_var(&ge->x); + secp256k1_zkp_fe_normalize_var(&ge->y); + secp256k1_zkp_fe_get_b32(&gen->data[0], &ge->x); + secp256k1_zkp_fe_get_b32(&gen->data[32], &ge->y); +} + +int secp256k1_zkp_generator_parse(const secp256k1_zkp_context* ctx, secp256k1_zkp_generator* gen, const unsigned char *input) { + secp256k1_zkp_fe x; + secp256k1_zkp_ge ge; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(gen != NULL); + ARG_CHECK(input != NULL); + + if ((input[0] & 0xFE) != 10 || + !secp256k1_zkp_fe_set_b32(&x, &input[1]) || + !secp256k1_zkp_ge_set_xquad(&ge, &x)) { + return 0; + } + if (input[0] & 1) { + secp256k1_zkp_ge_neg(&ge, &ge); + } + secp256k1_zkp_generator_save(gen, &ge); + return 1; +} + +int secp256k1_zkp_generator_serialize(const secp256k1_zkp_context* ctx, unsigned char *output, const secp256k1_zkp_generator* gen) { + secp256k1_zkp_ge ge; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(gen != NULL); + + secp256k1_zkp_generator_load(&ge, gen); + + output[0] = 11 ^ secp256k1_zkp_fe_is_quad_var(&ge.y); + secp256k1_zkp_fe_normalize_var(&ge.x); + secp256k1_zkp_fe_get_b32(&output[1], &ge.x); + return 1; +} + +static void shallue_van_de_woestijne(secp256k1_zkp_ge* ge, const secp256k1_zkp_fe* t) { + /* Implements the algorithm from: + * Indifferentiable Hashing to Barreto-Naehrig Curves + * Pierre-Alain Fouque and Mehdi Tibouchi + * Latincrypt 2012 + */ + + /* Basic algorithm: + + c = sqrt(-3) + d = (c - 1)/2 + + w = c * t / (1 + b + t^2) [with b = 7] + x1 = d - t*w + x2 = -(x1 + 1) + x3 = 1 + 1/w^2 + + To avoid the 2 divisions, compute the above in numerator/denominator form: + wn = c * t + wd = 1 + 7 + t^2 + x1n = d*wd - t*wn + x1d = wd + x2n = -(x1n + wd) + x2d = wd + x3n = wd^2 + c^2 + t^2 + x3d = (c * t)^2 + + The joint denominator j = wd * c^2 * t^2, and + 1 / x1d = 1/j * c^2 * t^2 + 1 / x2d = x3d = 1/j * wd + */ + + static const secp256k1_zkp_fe c = SECP256K1_FE_CONST(0x0a2d2ba9, 0x3507f1df, 0x233770c2, 0xa797962c, 0xc61f6d15, 0xda14ecd4, 0x7d8d27ae, 0x1cd5f852); + static const secp256k1_zkp_fe d = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40); + static const secp256k1_zkp_fe b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 7); + static const secp256k1_zkp_fe b_plus_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 8); + + secp256k1_zkp_fe wn, wd, x1n, x2n, x3n, x3d, jinv, tmp, x1, x2, x3, alphain, betain, gammain, y1, y2, y3; + int alphaquad, betaquad; + + secp256k1_zkp_fe_mul(&wn, &c, t); /* mag 1 */ + secp256k1_zkp_fe_sqr(&wd, t); /* mag 1 */ + secp256k1_zkp_fe_add(&wd, &b_plus_one); /* mag 2 */ + secp256k1_zkp_fe_mul(&tmp, t, &wn); /* mag 1 */ + secp256k1_zkp_fe_negate(&tmp, &tmp, 1); /* mag 2 */ + secp256k1_zkp_fe_mul(&x1n, &d, &wd); /* mag 1 */ + secp256k1_zkp_fe_add(&x1n, &tmp); /* mag 3 */ + x2n = x1n; /* mag 3 */ + secp256k1_zkp_fe_add(&x2n, &wd); /* mag 5 */ + secp256k1_zkp_fe_negate(&x2n, &x2n, 5); /* mag 6 */ + secp256k1_zkp_fe_mul(&x3d, &c, t); /* mag 1 */ + secp256k1_zkp_fe_sqr(&x3d, &x3d); /* mag 1 */ + secp256k1_zkp_fe_sqr(&x3n, &wd); /* mag 1 */ + secp256k1_zkp_fe_add(&x3n, &x3d); /* mag 2 */ + secp256k1_zkp_fe_mul(&jinv, &x3d, &wd); /* mag 1 */ + secp256k1_zkp_fe_inv(&jinv, &jinv); /* mag 1 */ + secp256k1_zkp_fe_mul(&x1, &x1n, &x3d); /* mag 1 */ + secp256k1_zkp_fe_mul(&x1, &x1, &jinv); /* mag 1 */ + secp256k1_zkp_fe_mul(&x2, &x2n, &x3d); /* mag 1 */ + secp256k1_zkp_fe_mul(&x2, &x2, &jinv); /* mag 1 */ + secp256k1_zkp_fe_mul(&x3, &x3n, &wd); /* mag 1 */ + secp256k1_zkp_fe_mul(&x3, &x3, &jinv); /* mag 1 */ + + secp256k1_zkp_fe_sqr(&alphain, &x1); /* mag 1 */ + secp256k1_zkp_fe_mul(&alphain, &alphain, &x1); /* mag 1 */ + secp256k1_zkp_fe_add(&alphain, &b); /* mag 2 */ + secp256k1_zkp_fe_sqr(&betain, &x2); /* mag 1 */ + secp256k1_zkp_fe_mul(&betain, &betain, &x2); /* mag 1 */ + secp256k1_zkp_fe_add(&betain, &b); /* mag 2 */ + secp256k1_zkp_fe_sqr(&gammain, &x3); /* mag 1 */ + secp256k1_zkp_fe_mul(&gammain, &gammain, &x3); /* mag 1 */ + secp256k1_zkp_fe_add(&gammain, &b); /* mag 2 */ + + alphaquad = secp256k1_zkp_fe_sqrt(&y1, &alphain); + betaquad = secp256k1_zkp_fe_sqrt(&y2, &betain); + secp256k1_zkp_fe_sqrt(&y3, &gammain); + + secp256k1_zkp_fe_cmov(&x1, &x2, (!alphaquad) & betaquad); + secp256k1_zkp_fe_cmov(&y1, &y2, (!alphaquad) & betaquad); + secp256k1_zkp_fe_cmov(&x1, &x3, (!alphaquad) & !betaquad); + secp256k1_zkp_fe_cmov(&y1, &y3, (!alphaquad) & !betaquad); + + secp256k1_zkp_ge_set_xy(ge, &x1, &y1); + + /* The linked algorithm from the paper uses the Jacobi symbol of t to + * determine the Jacobi symbol of the produced y coordinate. Since the + * rest of the algorithm only uses t^2, we can safely use another criterion + * as long as negation of t results in negation of the y coordinate. Here + * we choose to use t's oddness, as it is faster to determine. */ + secp256k1_zkp_fe_negate(&tmp, &ge->y, 1); + secp256k1_zkp_fe_cmov(&ge->y, &tmp, secp256k1_zkp_fe_is_odd(t)); +} + +static int secp256k1_zkp_generator_generate_internal(const secp256k1_zkp_context* ctx, secp256k1_zkp_generator* gen, const unsigned char *key32, const unsigned char *blind32) { + static const unsigned char prefix1[17] = "1st generation: "; + static const unsigned char prefix2[17] = "2nd generation: "; + secp256k1_zkp_fe t = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 4); + secp256k1_zkp_ge add; + secp256k1_zkp_gej accum; + int overflow; + secp256k1_zkp_sha256 sha256; + unsigned char b32[32]; + int ret = 1; + + if (blind32) { + secp256k1_zkp_scalar blind; + secp256k1_zkp_scalar_set_b32(&blind, blind32, &overflow); + ret = !overflow; + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &accum, &blind); + } + + secp256k1_zkp_sha256_initialize(&sha256); + secp256k1_zkp_sha256_write(&sha256, prefix1, 16); + secp256k1_zkp_sha256_write(&sha256, key32, 32); + secp256k1_zkp_sha256_finalize(&sha256, b32); + ret &= secp256k1_zkp_fe_set_b32(&t, b32); + shallue_van_de_woestijne(&add, &t); + if (blind32) { + secp256k1_zkp_gej_add_ge(&accum, &accum, &add); + } else { + secp256k1_zkp_gej_set_ge(&accum, &add); + } + + secp256k1_zkp_sha256_initialize(&sha256); + secp256k1_zkp_sha256_write(&sha256, prefix2, 16); + secp256k1_zkp_sha256_write(&sha256, key32, 32); + secp256k1_zkp_sha256_finalize(&sha256, b32); + ret &= secp256k1_zkp_fe_set_b32(&t, b32); + shallue_van_de_woestijne(&add, &t); + secp256k1_zkp_gej_add_ge(&accum, &accum, &add); + + secp256k1_zkp_ge_set_gej(&add, &accum); + secp256k1_zkp_generator_save(gen, &add); + return ret; +} + +int secp256k1_zkp_generator_generate(const secp256k1_zkp_context* ctx, secp256k1_zkp_generator* gen, const unsigned char *key32) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(gen != NULL); + ARG_CHECK(key32 != NULL); + return secp256k1_zkp_generator_generate_internal(ctx, gen, key32, NULL); +} + +int secp256k1_zkp_generator_generate_blinded(const secp256k1_zkp_context* ctx, secp256k1_zkp_generator* gen, const unsigned char *key32, const unsigned char *blind32) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(gen != NULL); + ARG_CHECK(key32 != NULL); + ARG_CHECK(blind32 != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + return secp256k1_zkp_generator_generate_internal(ctx, gen, key32, blind32); +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/generator/tests_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/generator/tests_impl.h new file mode 100644 index 00000000..15bb434e --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/generator/tests_impl.h @@ -0,0 +1,227 @@ +/********************************************************************** + * Copyright (c) 2016 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_GENERATOR_TESTS +#define SECP256K1_MODULE_GENERATOR_TESTS + +#include +#include + +#include "group.h" +#include "scalar.h" +#include "testrand.h" +#include "util.h" + +#include "include/secp256k1_generator.h" + +void test_generator_api(void) { + unsigned char key[32]; + unsigned char blind[32]; + unsigned char sergen[33]; + secp256k1_zkp_context *none = secp256k1_zkp_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_zkp_context *sign = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_zkp_context *vrfy = secp256k1_zkp_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_zkp_generator gen; + int32_t ecount = 0; + + secp256k1_zkp_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_rand256(key); + secp256k1_zkp_rand256(blind); + + CHECK(secp256k1_zkp_generator_generate(none, &gen, key) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_generator_generate(none, NULL, key) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_generator_generate(none, &gen, NULL) == 0); + CHECK(ecount == 2); + + CHECK(secp256k1_zkp_generator_generate_blinded(sign, &gen, key, blind) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_generator_generate_blinded(vrfy, &gen, key, blind) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_generator_generate_blinded(none, &gen, key, blind) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_generator_generate_blinded(vrfy, NULL, key, blind) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_zkp_generator_generate_blinded(vrfy, &gen, NULL, blind) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_zkp_generator_generate_blinded(vrfy, &gen, key, NULL) == 0); + CHECK(ecount == 7); + + CHECK(secp256k1_zkp_generator_serialize(none, sergen, &gen) == 1); + CHECK(ecount == 7); + CHECK(secp256k1_zkp_generator_serialize(none, NULL, &gen) == 0); + CHECK(ecount == 8); + CHECK(secp256k1_zkp_generator_serialize(none, sergen, NULL) == 0); + CHECK(ecount == 9); + + CHECK(secp256k1_zkp_generator_serialize(none, sergen, &gen) == 1); + CHECK(secp256k1_zkp_generator_parse(none, &gen, sergen) == 1); + CHECK(ecount == 9); + CHECK(secp256k1_zkp_generator_parse(none, NULL, sergen) == 0); + CHECK(ecount == 10); + CHECK(secp256k1_zkp_generator_parse(none, &gen, NULL) == 0); + CHECK(ecount == 11); + + secp256k1_zkp_context_destroy(none); + secp256k1_zkp_context_destroy(sign); + secp256k1_zkp_context_destroy(vrfy); +} + +void test_shallue_van_de_woestijne(void) { + /* Matches with the output of the shallue_van_de_woestijne.sage SAGE program */ + static const secp256k1_zkp_ge_storage results[32] = { + SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0x0225f529, 0xee75acaf, 0xccfc4560, 0x26c5e46b, 0xf80237a3, 0x3924655a, 0x16f90e88, 0x085ed52a), + SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0xfdda0ad6, 0x118a5350, 0x3303ba9f, 0xd93a1b94, 0x07fdc85c, 0xc6db9aa5, 0xe906f176, 0xf7a12705), + SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0x56716069, 0x6818286b, 0x72f01a3e, 0x5e8caca7, 0x36249160, 0xc7ded69d, 0xd51913c3, 0x03a2fa97), + SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0xa98e9f96, 0x97e7d794, 0x8d0fe5c1, 0xa1735358, 0xc9db6e9f, 0x38212962, 0x2ae6ec3b, 0xfc5d0198), + SECP256K1_GE_STORAGE_CONST(0x531f7239, 0xaebc780e, 0x179fbf8d, 0x412a1b01, 0x511f0abc, 0xe0c46151, 0x8b38db84, 0xcc2467f3, 0x82387d45, 0xec7bd5cc, 0x61fcb9df, 0x41cddd7b, 0x217d8114, 0x3577dc8f, 0x23de356a, 0x7e97704e), + SECP256K1_GE_STORAGE_CONST(0x531f7239, 0xaebc780e, 0x179fbf8d, 0x412a1b01, 0x511f0abc, 0xe0c46151, 0x8b38db84, 0xcc2467f3, 0x7dc782ba, 0x13842a33, 0x9e034620, 0xbe322284, 0xde827eeb, 0xca882370, 0xdc21ca94, 0x81688be1), + SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0x56716069, 0x6818286b, 0x72f01a3e, 0x5e8caca7, 0x36249160, 0xc7ded69d, 0xd51913c3, 0x03a2fa97), + SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0xa98e9f96, 0x97e7d794, 0x8d0fe5c1, 0xa1735358, 0xc9db6e9f, 0x38212962, 0x2ae6ec3b, 0xfc5d0198), + SECP256K1_GE_STORAGE_CONST(0x5e5936b1, 0x81db0b65, 0x8e33a8c6, 0x1aa687dd, 0x31d11e15, 0x85e35664, 0x6b4c2071, 0xcde7e942, 0x88bb5332, 0xa8e05654, 0x78d4f60c, 0x0cd979ec, 0x938558f2, 0xcac11216, 0x7c387a56, 0xe3a6d5f3), + SECP256K1_GE_STORAGE_CONST(0x5e5936b1, 0x81db0b65, 0x8e33a8c6, 0x1aa687dd, 0x31d11e15, 0x85e35664, 0x6b4c2071, 0xcde7e942, 0x7744accd, 0x571fa9ab, 0x872b09f3, 0xf3268613, 0x6c7aa70d, 0x353eede9, 0x83c785a8, 0x1c59263c), + SECP256K1_GE_STORAGE_CONST(0x657d438f, 0xfac34a50, 0x463fd07c, 0x3f09f320, 0x4c98e8ed, 0x6927e330, 0xc0c7735f, 0x76d32f6d, 0x577c2b11, 0xcaca2f6f, 0xd60bcaf0, 0x3e7cebe9, 0x5da6e1f4, 0xbb557f12, 0x2a397331, 0x81df897f), + SECP256K1_GE_STORAGE_CONST(0x657d438f, 0xfac34a50, 0x463fd07c, 0x3f09f320, 0x4c98e8ed, 0x6927e330, 0xc0c7735f, 0x76d32f6d, 0xa883d4ee, 0x3535d090, 0x29f4350f, 0xc1831416, 0xa2591e0b, 0x44aa80ed, 0xd5c68ccd, 0x7e2072b0), + SECP256K1_GE_STORAGE_CONST(0xbe0bc11b, 0x2bc639cb, 0xc28f72a8, 0xd07c21cc, 0xbc06cfa7, 0x4c2ff25e, 0x630c9740, 0x23128eab, 0x6f062fc8, 0x75148197, 0xd10375c3, 0xcc3fadb6, 0x20277e9c, 0x00579c55, 0xeddd7f95, 0xe95604db), + SECP256K1_GE_STORAGE_CONST(0xbe0bc11b, 0x2bc639cb, 0xc28f72a8, 0xd07c21cc, 0xbc06cfa7, 0x4c2ff25e, 0x630c9740, 0x23128eab, 0x90f9d037, 0x8aeb7e68, 0x2efc8a3c, 0x33c05249, 0xdfd88163, 0xffa863aa, 0x12228069, 0x16a9f754), + SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0xfdda0ad6, 0x118a5350, 0x3303ba9f, 0xd93a1b94, 0x07fdc85c, 0xc6db9aa5, 0xe906f176, 0xf7a12705), + SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0x0225f529, 0xee75acaf, 0xccfc4560, 0x26c5e46b, 0xf80237a3, 0x3924655a, 0x16f90e88, 0x085ed52a), + SECP256K1_GE_STORAGE_CONST(0xaee172d4, 0xce7c5010, 0xdb20a88f, 0x469598c1, 0xd7f7926f, 0xabb85cb5, 0x339f1403, 0x87e6b494, 0x38065980, 0x4de81b35, 0x098c7190, 0xe3380f9d, 0x95b2ed6c, 0x6c869e85, 0xc772bc5a, 0x7bc3d9d5), + SECP256K1_GE_STORAGE_CONST(0xaee172d4, 0xce7c5010, 0xdb20a88f, 0x469598c1, 0xd7f7926f, 0xabb85cb5, 0x339f1403, 0x87e6b494, 0xc7f9a67f, 0xb217e4ca, 0xf6738e6f, 0x1cc7f062, 0x6a4d1293, 0x9379617a, 0x388d43a4, 0x843c225a), + SECP256K1_GE_STORAGE_CONST(0xc28f5c28, 0xf5c28f5c, 0x28f5c28f, 0x5c28f5c2, 0x8f5c28f5, 0xc28f5c28, 0xf5c28f5b, 0x6666635a, 0x0c4da840, 0x1b2cf5be, 0x4604e6ec, 0xf92b2780, 0x063a5351, 0xe294bf65, 0xbb2f8b61, 0x00902db7), + SECP256K1_GE_STORAGE_CONST(0xc28f5c28, 0xf5c28f5c, 0x28f5c28f, 0x5c28f5c2, 0x8f5c28f5, 0xc28f5c28, 0xf5c28f5b, 0x6666635a, 0xf3b257bf, 0xe4d30a41, 0xb9fb1913, 0x06d4d87f, 0xf9c5acae, 0x1d6b409a, 0x44d0749d, 0xff6fce78), + SECP256K1_GE_STORAGE_CONST(0xecf56be6, 0x9c8fde26, 0x152832c6, 0xe043b3d5, 0xaf9a723f, 0x789854a0, 0xcb1b810d, 0xe2614ece, 0x66127ae4, 0xe4c17a75, 0x60a727e6, 0xffd2ea7f, 0xaed99088, 0xbec465c6, 0xbde56791, 0x37ed5572), + SECP256K1_GE_STORAGE_CONST(0xecf56be6, 0x9c8fde26, 0x152832c6, 0xe043b3d5, 0xaf9a723f, 0x789854a0, 0xcb1b810d, 0xe2614ece, 0x99ed851b, 0x1b3e858a, 0x9f58d819, 0x002d1580, 0x51266f77, 0x413b9a39, 0x421a986d, 0xc812a6bd), + SECP256K1_GE_STORAGE_CONST(0xba72860f, 0x10fcd142, 0x23f71e3c, 0x228deb9a, 0xc46c5ff5, 0x90b884e5, 0xcc60d51e, 0x0629d16e, 0x67999f31, 0x5a74ada3, 0x526832cf, 0x76b9fec3, 0xa348cc97, 0x33c3aa67, 0x02bd2516, 0x7814f635), + SECP256K1_GE_STORAGE_CONST(0xba72860f, 0x10fcd142, 0x23f71e3c, 0x228deb9a, 0xc46c5ff5, 0x90b884e5, 0xcc60d51e, 0x0629d16e, 0x986660ce, 0xa58b525c, 0xad97cd30, 0x8946013c, 0x5cb73368, 0xcc3c5598, 0xfd42dae8, 0x87eb05fa), + SECP256K1_GE_STORAGE_CONST(0x92ef5657, 0xdba51cc7, 0xf3e1b442, 0xa6a0916b, 0x8ce03079, 0x2ef5657d, 0xba51cc7e, 0xab2beb65, 0x782c65d2, 0x3f1e0eb2, 0x9179a994, 0xe5e8ff80, 0x5a0d50d9, 0xdeeaed90, 0xcec96ca5, 0x973e2ad3), + SECP256K1_GE_STORAGE_CONST(0x92ef5657, 0xdba51cc7, 0xf3e1b442, 0xa6a0916b, 0x8ce03079, 0x2ef5657d, 0xba51cc7e, 0xab2beb65, 0x87d39a2d, 0xc0e1f14d, 0x6e86566b, 0x1a17007f, 0xa5f2af26, 0x2115126f, 0x31369359, 0x68c1d15c), + SECP256K1_GE_STORAGE_CONST(0x9468ad22, 0xf921fc78, 0x8de3f1b0, 0x586c58eb, 0x5e6f0270, 0xe950b602, 0x7ada90d9, 0xd71ae323, 0x922a0c6a, 0x9ccc31d9, 0xc3bf87fd, 0x88381739, 0x35fe393f, 0xa64dfdec, 0x29f2846d, 0x12918d86), + SECP256K1_GE_STORAGE_CONST(0x9468ad22, 0xf921fc78, 0x8de3f1b0, 0x586c58eb, 0x5e6f0270, 0xe950b602, 0x7ada90d9, 0xd71ae323, 0x6dd5f395, 0x6333ce26, 0x3c407802, 0x77c7e8c6, 0xca01c6c0, 0x59b20213, 0xd60d7b91, 0xed6e6ea9), + SECP256K1_GE_STORAGE_CONST(0x76ddc7f5, 0xe029e59e, 0x22b0e54f, 0xa811db94, 0x5a209c4f, 0x5e912ca2, 0x8b4da6a7, 0x4c1e00a2, 0x1e8f516c, 0x91c20437, 0x50f6e24e, 0x8c2cf202, 0xacf68291, 0xbf8b66eb, 0xf7335b62, 0xec2c88fe), + SECP256K1_GE_STORAGE_CONST(0x76ddc7f5, 0xe029e59e, 0x22b0e54f, 0xa811db94, 0x5a209c4f, 0x5e912ca2, 0x8b4da6a7, 0x4c1e00a2, 0xe170ae93, 0x6e3dfbc8, 0xaf091db1, 0x73d30dfd, 0x53097d6e, 0x40749914, 0x08cca49c, 0x13d37331), + SECP256K1_GE_STORAGE_CONST(0xf75763bc, 0x2907e79b, 0x125e33c3, 0x9a027f48, 0x0f8c6409, 0x2153432f, 0x967bc2b1, 0x1d1f5cf0, 0xb4a8edc6, 0x36391b39, 0x9bc219c0, 0x3d033128, 0xdbcd463e, 0xd2506394, 0x061b87a5, 0x9e510235), + SECP256K1_GE_STORAGE_CONST(0xf75763bc, 0x2907e79b, 0x125e33c3, 0x9a027f48, 0x0f8c6409, 0x2153432f, 0x967bc2b1, 0x1d1f5cf0, 0x4b571239, 0xc9c6e4c6, 0x643de63f, 0xc2fcced7, 0x2432b9c1, 0x2daf9c6b, 0xf9e47859, 0x61aef9fa), + }; + + secp256k1_zkp_ge ge; + secp256k1_zkp_fe fe; + secp256k1_zkp_ge_storage ges; + int i, s; + for (i = 1; i <= 16; i++) { + secp256k1_zkp_fe_set_int(&fe, i); + + for (s = 0; s < 2; s++) { + if (s) { + secp256k1_zkp_fe_negate(&fe, &fe, 1); + secp256k1_zkp_fe_normalize(&fe); + } + shallue_van_de_woestijne(&ge, &fe); + secp256k1_zkp_ge_to_storage(&ges, &ge); + + CHECK(memcmp(&ges, &results[i * 2 + s - 2], sizeof(secp256k1_zkp_ge_storage)) == 0); + } + } +} + +void test_generator_generate(void) { + static const secp256k1_zkp_ge_storage results[32] = { + SECP256K1_GE_STORAGE_CONST(0x806cd8ed, 0xd6c153e3, 0x4aa9b9a0, 0x8755c4be, 0x4718b1ef, 0xb26cb93f, 0xfdd99e1b, 0x21f2af8e, 0xc7062208, 0xcc649a03, 0x1bdc1a33, 0x9d01f115, 0x4bcd0dca, 0xfe0b875d, 0x62f35f73, 0x28673006), + SECP256K1_GE_STORAGE_CONST(0xd91b15ec, 0x47a811f4, 0xaa189561, 0xd13f5c4d, 0x4e81f10d, 0xc7dc551f, 0x4fea9b84, 0x610314c4, 0x9b0ada1e, 0xb38efd67, 0x8bff0b6c, 0x7d7315f7, 0xb49b8cc5, 0xa679fad4, 0xc94f9dc6, 0x9da66382), + SECP256K1_GE_STORAGE_CONST(0x11c00de6, 0xf885035e, 0x76051430, 0xa3c38b2a, 0x5f86ab8c, 0xf66dae58, 0x04ea7307, 0x348b19bf, 0xe0858ae7, 0x61dcb1ba, 0xff247e37, 0xd38fcd88, 0xf3bd7911, 0xaa4ed6e0, 0x28d792dd, 0x3ee1ac09), + SECP256K1_GE_STORAGE_CONST(0x986b99eb, 0x3130e7f0, 0xe779f674, 0xb85cb514, 0x46a676bf, 0xb1dfb603, 0x4c4bb639, 0x7c406210, 0xdf900609, 0x8b3ef1e0, 0x30e32fb0, 0xd97a4329, 0xff98aed0, 0xcd278c3f, 0xe6078467, 0xfbd12f35), + SECP256K1_GE_STORAGE_CONST(0xae528146, 0x03fdf91e, 0xc592977e, 0x12461dc7, 0xb9e038f8, 0x048dcb62, 0xea264756, 0xd459ae42, 0x80ef658d, 0x92becb84, 0xdba8e4f9, 0x560d7a72, 0xbaf4c393, 0xfbcf6007, 0x11039f1c, 0x224faaad), + SECP256K1_GE_STORAGE_CONST(0x00df3d91, 0x35975eee, 0x91fab903, 0xe3128e4a, 0xca071dde, 0x270814e5, 0xcbda69ec, 0xcad58f46, 0x11b590aa, 0x92d89969, 0x2dbd932f, 0x08013b8b, 0x45afabc6, 0x43677db2, 0x143e0c0f, 0x5865fb03), + SECP256K1_GE_STORAGE_CONST(0x1168155b, 0x987e9bc8, 0x84c5f3f4, 0x92ebf784, 0xcc8c6735, 0x39d8e5e8, 0xa967115a, 0x2949da9b, 0x0858a470, 0xf403ca97, 0xb1827f6f, 0x544c2c67, 0x08f6cb83, 0xc510c317, 0x96c981ed, 0xb9f61780), + SECP256K1_GE_STORAGE_CONST(0xe8d7c0cf, 0x2bb4194c, 0x97bf2a36, 0xbd115ba0, 0x81a9afe8, 0x7663fa3c, 0x9c3cd253, 0x79fe2571, 0x2028ad04, 0xefa00119, 0x5a25d598, 0x67e79502, 0x49de7c61, 0x4751cd9d, 0x4fb317f6, 0xf76f1110), + SECP256K1_GE_STORAGE_CONST(0x9532c491, 0xa64851dd, 0xcd0d3e5a, 0x93e17267, 0xa10aca95, 0xa23781aa, 0x5087f340, 0xc45fecc3, 0xb691ddc2, 0x3143a7b6, 0x09969302, 0x258affb8, 0x5bbf8666, 0xe1192319, 0xeb174d88, 0x308bd57a), + SECP256K1_GE_STORAGE_CONST(0x6b20b6e2, 0x1ba6cc44, 0x3f2c3a0c, 0x5283ba44, 0xbee43a0a, 0x2799a6cf, 0xbecc0f8a, 0xf8c583ac, 0xf7021e76, 0xd51291a6, 0xf9396215, 0x686f25aa, 0xbec36282, 0x5e11eeea, 0x6e51a6e6, 0xd7d7c006), + SECP256K1_GE_STORAGE_CONST(0xde27e6ff, 0x219b3ab1, 0x2b0a9e4e, 0x51fc6092, 0x96e55af6, 0xc6f717d6, 0x12cd6cce, 0x65d6c8f2, 0x48166884, 0x4dc13fd2, 0xed7a7d81, 0x66a0839a, 0x8a960863, 0xfe0001c1, 0x35d206fd, 0x63b87c09), + SECP256K1_GE_STORAGE_CONST(0x79a96fb8, 0xd88a08d3, 0x055d38d1, 0x3346b0d4, 0x47d838ca, 0xfcc8fa40, 0x6d3a7157, 0xef84e7e3, 0x6bab9c45, 0x2871b51d, 0xb0df2369, 0xe7860e01, 0x2e37ffea, 0x6689fd1a, 0x9c6fe9cf, 0xb940acea), + SECP256K1_GE_STORAGE_CONST(0x06c4d4cb, 0xd32c0ddb, 0x67e988c6, 0x2bdbe6ad, 0xa39b80cc, 0x61afb347, 0x234abe27, 0xa689618c, 0x5b355949, 0xf904fe08, 0x569b2313, 0xe8f19f8d, 0xc5b79e27, 0x70da0832, 0x5fb7a229, 0x238ca6b6), + SECP256K1_GE_STORAGE_CONST(0x7027e566, 0x3e727c28, 0x42aa14e5, 0x52c2d2ec, 0x1d8beaa9, 0x8a22ceab, 0x15ccafc3, 0xb4f06249, 0x9b3dffbc, 0xdbd5e045, 0x6931fd03, 0x8b1c6a9b, 0x4c168c6d, 0xa6553897, 0xfe11ce49, 0xac728139), + SECP256K1_GE_STORAGE_CONST(0xee3520c3, 0x9f2b954d, 0xf8e15547, 0xdaeb6cc8, 0x04c8f3b0, 0x9301f53e, 0xe0c11ea1, 0xeace539d, 0x244ff873, 0x7e060c98, 0xe843c353, 0xcd35d2e4, 0x3cd8b082, 0xcffbc9ae, 0x81eafa70, 0x332f9748), + SECP256K1_GE_STORAGE_CONST(0xdaecd756, 0xf5b706a4, 0xc14e1095, 0x3e2f70df, 0xa81276e7, 0x71806b89, 0x4d8a5502, 0xa0ef4998, 0xbac906c0, 0x948b1d48, 0xe023f439, 0xfd3770b8, 0x837f60cc, 0x40552a51, 0x433d0b79, 0x6610da27), + SECP256K1_GE_STORAGE_CONST(0x55e1ca28, 0x750fe2d0, 0x57f7449b, 0x3f49d999, 0x3b9616dd, 0x5387bc2e, 0x6e6698f8, 0xc4ea49f4, 0xe339e0e9, 0xa4c7fa99, 0xd063e062, 0x6582bce2, 0x33c6b1ee, 0x17a5b47f, 0x6d43ecf8, 0x98b40120), + SECP256K1_GE_STORAGE_CONST(0xdd82cac2, 0x9e0e0135, 0x4964d3bc, 0x27469233, 0xf13bbd5e, 0xd7aff24b, 0x4902fca8, 0x17294b12, 0x561ab1d6, 0xcd9bcb6e, 0x805585cf, 0x3df8714c, 0x1bfa6304, 0x5efbf122, 0x1a3d8fd9, 0x3827764a), + SECP256K1_GE_STORAGE_CONST(0xda5cbfb7, 0x3522e9c7, 0xcb594436, 0x83677038, 0x0eaa64a9, 0x2eca3888, 0x0fe4c9d6, 0xdeb22dbf, 0x4f46de68, 0x0447c780, 0xc54a314b, 0x5389a926, 0xbba8910b, 0x869fc6cd, 0x42ee82e8, 0x5895e42a), + SECP256K1_GE_STORAGE_CONST(0x4e09830e, 0xc8894c58, 0x4e6278de, 0x167a96b0, 0x20d60463, 0xee48f788, 0x4974d66e, 0x871e35e9, 0x21259c4d, 0x332ca932, 0x2e187df9, 0xe7afbc23, 0x9d171ebc, 0x7d9e2560, 0x503f50b1, 0x9fe45834), + SECP256K1_GE_STORAGE_CONST(0xabfff6ca, 0x41dcfd17, 0x03cae629, 0x9d127971, 0xf19ee000, 0x2db332e6, 0x5cc209a3, 0xc21b8f54, 0x65991d60, 0xee54f5cc, 0xddf7a732, 0xa76b0303, 0xb9f519a6, 0x22ea0390, 0x8af23ffa, 0x35ae6632), + SECP256K1_GE_STORAGE_CONST(0xc6c9b92c, 0x91e045a5, 0xa1913277, 0x44d6fce2, 0x11b12c7c, 0x9b3112d6, 0xc61e14a6, 0xd6b1ae12, 0x04ab0396, 0xebdc4c6a, 0xc213cc3e, 0x077a2e80, 0xb4ba7b2b, 0x33907d56, 0x2c98ccf7, 0xb82a2e9f), + SECP256K1_GE_STORAGE_CONST(0x66f6e6d9, 0xc4bb9a5f, 0x99085781, 0x83cb9362, 0x2ea437d8, 0xccd31969, 0xffadca3a, 0xff1d3935, 0x50a5b06e, 0x39e039d7, 0x1dfb2723, 0x18db74e5, 0x5af64da1, 0xdfc34586, 0x6aac3bd0, 0x5792a890), + SECP256K1_GE_STORAGE_CONST(0x58ded03c, 0x98e1a890, 0x63fc7793, 0xe3ecd896, 0x235e75c9, 0x82e7008f, 0xddbf3ca8, 0x5b7e9ecb, 0x34594776, 0x58ab6821, 0xaf43a453, 0xa946fda9, 0x13d24999, 0xccf22df8, 0xd291ef59, 0xb08975c0), + SECP256K1_GE_STORAGE_CONST(0x74557864, 0x4f2b0486, 0xd5beea7c, 0x2d258ccb, 0x78a870e1, 0x848982d8, 0xed3f91a4, 0x9db83a36, 0xd84e940e, 0x1d33c28a, 0x62398ec8, 0xc493aee7, 0x7c2ba722, 0x42dee7ae, 0x3c35c256, 0xad00cf42), + SECP256K1_GE_STORAGE_CONST(0x7fc7963a, 0x16abc8fb, 0x5d61eb61, 0x0fc50a68, 0x754470d2, 0xf43df3be, 0x52228f66, 0x522fe61b, 0x499f9e7f, 0x462c6545, 0x29687af4, 0x9f7c732d, 0x48801ce5, 0x21acd546, 0xc6fb903c, 0x7c265032), + SECP256K1_GE_STORAGE_CONST(0xb2f6257c, 0xc58df82f, 0xb9ba4f36, 0x7ededf03, 0xf8ea10f3, 0x104d7ae6, 0x233b7ac4, 0x725e11de, 0x9c7a32df, 0x4842f33d, 0xaad84f0b, 0x62e88b40, 0x46ddcbde, 0xbbeec6f8, 0x93bfde27, 0x0561dc73), + SECP256K1_GE_STORAGE_CONST(0xe2cdfd27, 0x8a8e22be, 0xabf08b79, 0x1bc6ae38, 0x41d22a9a, 0x9472e266, 0x1a7c6e83, 0xa2f74725, 0x0e26c103, 0xe0dd93b2, 0x3724f3b7, 0x8bb7366e, 0x2c245768, 0xd64f3283, 0xd8316e8a, 0x1383b977), + SECP256K1_GE_STORAGE_CONST(0x757c13e7, 0xe866017e, 0xe6af61d7, 0x161d208a, 0xc438f712, 0x242fcd23, 0x63a10e59, 0xd67e41fb, 0xb550c6a9, 0x4ddb15f3, 0xfeea4bfe, 0xd2faa19f, 0x2aa2fbd3, 0x0c6ae785, 0xe357f365, 0xb30d12e0), + SECP256K1_GE_STORAGE_CONST(0x528d525e, 0xac30095b, 0x5e5f83ca, 0x4d3dea63, 0xeb608f2d, 0x18dd25a7, 0x2529c8e5, 0x1ae5f9f1, 0xfde2860b, 0x492a4106, 0x9f356c05, 0x3ebc045e, 0x4ad08b79, 0x3e264935, 0xf25785a9, 0x8690b5ee), + SECP256K1_GE_STORAGE_CONST(0x150df593, 0x5b6956a0, 0x0cfed843, 0xb9d6ffce, 0x4f790022, 0xea18730f, 0xc495111d, 0x91568e55, 0x6700a2ca, 0x9ff4ed32, 0xc1697312, 0x4eb51ce3, 0x5656344b, 0x65a1e3d5, 0xd6c1f7ce, 0x29233f82), + SECP256K1_GE_STORAGE_CONST(0x38e02eaf, 0x2c8774fd, 0x58b8b373, 0x732457f1, 0x16dbe53b, 0xea5683d9, 0xada20dd7, 0x14ce20a6, 0x6ac5362e, 0xbb425416, 0x8250f43f, 0xa4ee2b63, 0x0406324f, 0x1c876d60, 0xebe5be2c, 0x6eb1515b), + }; + secp256k1_zkp_generator gen; + secp256k1_zkp_ge ge; + secp256k1_zkp_ge_storage ges; + int i; + unsigned char v[32]; + unsigned char s[32] = {0}; + secp256k1_zkp_scalar sc; + secp256k1_zkp_scalar_set_b32(&sc, s, NULL); + for (i = 1; i <= 32; i++) { + memset(v, 0, 31); + v[31] = i; + CHECK(secp256k1_zkp_generator_generate_blinded(ctx, &gen, v, s)); + secp256k1_zkp_generator_load(&ge, &gen); + secp256k1_zkp_ge_to_storage(&ges, &ge); + CHECK(memcmp(&ges, &results[i - 1], sizeof(secp256k1_zkp_ge_storage)) == 0); + CHECK(secp256k1_zkp_generator_generate(ctx, &gen, v)); + secp256k1_zkp_generator_load(&ge, &gen); + secp256k1_zkp_ge_to_storage(&ges, &ge); + CHECK(memcmp(&ges, &results[i - 1], sizeof(secp256k1_zkp_ge_storage)) == 0); + } + + /* There is no range restriction on the value, but the blinder must be a + * valid scalar. Check that an invalid blinder causes the call to fail + * but not crash. */ + memset(v, 0xff, 32); + CHECK(secp256k1_zkp_generator_generate(ctx, &gen, v)); + memset(s, 0xff, 32); + CHECK(!secp256k1_zkp_generator_generate_blinded(ctx, &gen, v, s)); +} + +void test_generator_fixed_vector(void) { + const unsigned char two_g[33] = { + 0x0b, + 0xc6, 0x04, 0x7f, 0x94, 0x41, 0xed, 0x7d, 0x6d, 0x30, 0x45, 0x40, 0x6e, 0x95, 0xc0, 0x7c, 0xd8, + 0x5c, 0x77, 0x8e, 0x4b, 0x8c, 0xef, 0x3c, 0xa7, 0xab, 0xac, 0x09, 0xb9, 0x5c, 0x70, 0x9e, 0xe5 + }; + unsigned char result[33]; + secp256k1_zkp_generator parse; + + CHECK(secp256k1_zkp_generator_parse(ctx, &parse, two_g)); + CHECK(secp256k1_zkp_generator_serialize(ctx, result, &parse)); + CHECK(memcmp(two_g, result, 33) == 0); + + result[0] = 0x0a; + CHECK(secp256k1_zkp_generator_parse(ctx, &parse, result)); + result[0] = 0x08; + CHECK(!secp256k1_zkp_generator_parse(ctx, &parse, result)); +} + +void run_generator_tests(void) { + test_shallue_van_de_woestijne(); + test_generator_fixed_vector(); + test_generator_api(); + test_generator_generate(); +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/Makefile.am.include b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/Makefile.am.include new file mode 100644 index 00000000..d9b58798 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/Makefile.am.include @@ -0,0 +1,16 @@ +include_HEADERS += include/secp256k1_zkp_musig.h +noinst_HEADERS += src/modules/musig/main_impl.h +noinst_HEADERS += src/modules/musig/tests_impl.h + +noinst_PROGRAMS += example_musig +example_musig_SOURCES = src/modules/musig/example.c +example_musig_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include $(SECP_INCLUDES) +if !ENABLE_COVERAGE +example_musig_CPPFLAGS += -DVERIFY +endif +example_musig_LDADD = libsecp256k1.la $(SECP_LIBS) +example_musig_LDFLAGS = -static + +if USE_TESTS +TESTS += example_musig +endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/example.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/example.c new file mode 100644 index 00000000..9a906f3a --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/example.c @@ -0,0 +1,165 @@ +/********************************************************************** + * Copyright (c) 2018 Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/** + * This file demonstrates how to use the MuSig module to create a multisignature. + * Additionally, see the documentation in include/secp256k1_zkp_musig.h. + */ + +#include +#include +#include +#include +#include + + /* Number of public keys involved in creating the aggregate signature */ +#define N_SIGNERS 3 + /* Create a key pair and store it in seckey and pubkey */ +int create_key(const secp256k1_zkp_context* ctx, unsigned char* seckey, secp256k1_zkp_pubkey* pubkey) { + int ret; + FILE *frand = fopen("/dev/urandom", "r"); + if (frand == NULL) { + return 0; + } + do { + if(!fread(seckey, 32, 1, frand)) { + fclose(frand); + return 0; + } + /* The probability that this not a valid secret key is approximately 2^-128 */ + } while (!secp256k1_zkp_ec_seckey_verify(ctx, seckey)); + fclose(frand); + ret = secp256k1_zkp_ec_pubkey_create(ctx, pubkey, seckey); + return ret; +} + +/* Sign a message hash with the given key pairs and store the result in sig */ +int sign(const secp256k1_zkp_context* ctx, unsigned char seckeys[][32], const secp256k1_zkp_pubkey* pubkeys, const unsigned char* msg32, secp256k1_zkp_schnorrsig *sig) { + secp256k1_zkp_musig_session musig_session[N_SIGNERS]; + unsigned char nonce_commitment[N_SIGNERS][32]; + const unsigned char *nonce_commitment_ptr[N_SIGNERS]; + secp256k1_zkp_musig_session_signer_data signer_data[N_SIGNERS][N_SIGNERS]; + secp256k1_zkp_pubkey nonce[N_SIGNERS]; + int i, j; + secp256k1_zkp_musig_partial_signature partial_sig[N_SIGNERS]; + + for (i = 0; i < N_SIGNERS; i++) { + FILE *frand; + unsigned char session_id32[32]; + unsigned char pk_hash[32]; + secp256k1_zkp_pubkey combined_pk; + + /* Create combined pubkey and initialize signer data */ + if (!secp256k1_zkp_musig_pubkey_combine(ctx, NULL, &combined_pk, pk_hash, pubkeys, N_SIGNERS)) { + return 0; + } + /* Create random session ID. It is absolutely necessary that the session ID + * is unique for every call of secp256k1_zkp_musig_session_initialize. Otherwise + * it's trivial for an attacker to extract the secret key! */ + frand = fopen("/dev/urandom", "r"); + if(frand == NULL) { + return 0; + } + if (!fread(session_id32, 32, 1, frand)) { + fclose(frand); + return 0; + } + fclose(frand); + /* Initialize session */ + if (!secp256k1_zkp_musig_session_initialize(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, pk_hash, N_SIGNERS, i, seckeys[i])) { + return 0; + } + nonce_commitment_ptr[i] = &nonce_commitment[i][0]; + } + /* Communication round 1: Exchange nonce commitments */ + for (i = 0; i < N_SIGNERS; i++) { + /* Set nonce commitments in the signer data and get the own public nonce */ + if (!secp256k1_zkp_musig_session_get_public_nonce(ctx, &musig_session[i], signer_data[i], &nonce[i], nonce_commitment_ptr, N_SIGNERS)) { + return 0; + } + } + /* Communication round 2: Exchange nonces */ + for (i = 0; i < N_SIGNERS; i++) { + for (j = 0; j < N_SIGNERS; j++) { + if (!secp256k1_zkp_musig_set_nonce(ctx, &signer_data[i][j], &nonce[j])) { + /* Signer j's nonce does not match the nonce commitment. In this case + * abort the protocol. If you make another attempt at finishing the + * protocol, create a new session (with a fresh session ID!). */ + return 0; + } + } + if (!secp256k1_zkp_musig_session_combine_nonces(ctx, &musig_session[i], signer_data[i], N_SIGNERS, NULL, NULL)) { + return 0; + } + } + for (i = 0; i < N_SIGNERS; i++) { + if (!secp256k1_zkp_musig_partial_sign(ctx, &musig_session[i], &partial_sig[i])) { + return 0; + } + } + /* Communication round 3: Exchange partial signatures */ + for (i = 0; i < N_SIGNERS; i++) { + for (j = 0; j < N_SIGNERS; j++) { + /* To check whether signing was successful, it suffices to either verify + * the the combined signature with the combined public key using + * secp256k1_zkp_schnorrsig_verify, or verify all partial signatures of all + * signers individually. Verifying the combined signature is cheaper but + * verifying the individual partial signatures has the advantage that it + * can be used to determine which of the partial signatures are invalid + * (if any), i.e., which of the partial signatures cause the combined + * signature to be invalid and thus the protocol run to fail. It's also + * fine to first verify the combined sig, and only verify the individual + * sigs if it does not work. + */ + if (!secp256k1_zkp_musig_partial_sig_verify(ctx, &musig_session[i], &signer_data[i][j], &partial_sig[j], &pubkeys[j])) { + return 0; + } + } + } + return secp256k1_zkp_musig_partial_sig_combine(ctx, &musig_session[0], sig, partial_sig, N_SIGNERS); +} + + int main(void) { + secp256k1_zkp_context* ctx; + int i; + unsigned char seckeys[N_SIGNERS][32]; + secp256k1_zkp_pubkey pubkeys[N_SIGNERS]; + secp256k1_zkp_pubkey combined_pk; + unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!"; + secp256k1_zkp_schnorrsig sig; + + /* Create a context for signing and verification */ + ctx = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + printf("Creating key pairs......"); + for (i = 0; i < N_SIGNERS; i++) { + if (!create_key(ctx, seckeys[i], &pubkeys[i])) { + printf("FAILED\n"); + return 1; + } + } + printf("ok\n"); + printf("Combining public keys..."); + if (!secp256k1_zkp_musig_pubkey_combine(ctx, NULL, &combined_pk, NULL, pubkeys, N_SIGNERS)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + printf("Signing message........."); + if (!sign(ctx, seckeys, pubkeys, msg, &sig)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + printf("Verifying signature....."); + if (!secp256k1_zkp_schnorrsig_verify(ctx, &sig, msg, &combined_pk)) { + printf("FAILED\n"); + return 1; + } + printf("ok\n"); + secp256k1_zkp_context_destroy(ctx); + return 0; +} + diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/main_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/main_impl.h new file mode 100644 index 00000000..693b7f5d --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/main_impl.h @@ -0,0 +1,629 @@ +/********************************************************************** + * Copyright (c) 2018 Andrew Poelstra, Jonas Nick * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_MUSIG_MAIN_ +#define _SECP256K1_MODULE_MUSIG_MAIN_ + +#include "include/secp256k1.h" +#include "include/secp256k1_musig.h" +#include "hash.h" + +/* Computes ell = SHA256(pk[0], ..., pk[np-1]) */ +static int secp256k1_zkp_musig_compute_ell(const secp256k1_zkp_context *ctx, unsigned char *ell, const secp256k1_zkp_pubkey *pk, size_t np) { + secp256k1_zkp_sha256 sha; + size_t i; + + secp256k1_zkp_sha256_initialize(&sha); + for (i = 0; i < np; i++) { + unsigned char ser[33]; + size_t serlen = sizeof(ser); + if (!secp256k1_zkp_ec_pubkey_serialize(ctx, ser, &serlen, &pk[i], SECP256K1_EC_COMPRESSED)) { + return 0; + } + secp256k1_zkp_sha256_write(&sha, ser, serlen); + } + secp256k1_zkp_sha256_finalize(&sha, ell); + return 1; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("MuSig coefficient")||SHA256("MuSig coefficient"). */ +static void secp256k1_zkp_musig_sha256_init_tagged(secp256k1_zkp_sha256 *sha) { + secp256k1_zkp_sha256_initialize(sha); + + sha->s[0] = 0x0fd0690cul; + sha->s[1] = 0xfefeae97ul; + sha->s[2] = 0x996eac7ful; + sha->s[3] = 0x5c30d864ul; + sha->s[4] = 0x8c4a0573ul; + sha->s[5] = 0xaca1a22ful; + sha->s[6] = 0x6f43b801ul; + sha->s[7] = 0x85ce27cdul; + sha->bytes = 64; +} + +/* Compute r = SHA256(ell, idx). The four bytes of idx are serialized least significant byte first. */ +static void secp256k1_zkp_musig_coefficient(secp256k1_zkp_scalar *r, const unsigned char *ell, uint32_t idx) { + secp256k1_zkp_sha256 sha; + unsigned char buf[32]; + size_t i; + + secp256k1_zkp_musig_sha256_init_tagged(&sha); + secp256k1_zkp_sha256_write(&sha, ell, 32); + /* We're hashing the index of the signer instead of its public key as specified + * in the MuSig paper. This reduces the total amount of data that needs to be + * hashed. + * Additionally, it prevents creating identical musig_coefficients for identical + * public keys. A participant Bob could choose his public key to be the same as + * Alice's, then replay Alice's messages (nonce and partial signature) to create + * a valid partial signature. This is not a problem for MuSig per se, but could + * result in subtle issues with protocols building on threshold signatures. + * With the assumption that public keys are unique, hashing the index is + * equivalent to hashing the public key. Because the public key can be + * identified by the index given the ordered list of public keys (included in + * ell), the index is just a different encoding of the public key.*/ + for (i = 0; i < sizeof(uint32_t); i++) { + unsigned char c = idx; + secp256k1_zkp_sha256_write(&sha, &c, 1); + idx >>= 8; + } + secp256k1_zkp_sha256_finalize(&sha, buf); + secp256k1_zkp_scalar_set_b32(r, buf, NULL); +} + +typedef struct { + const secp256k1_zkp_context *ctx; + unsigned char ell[32]; + const secp256k1_zkp_pubkey *pks; +} secp256k1_zkp_musig_pubkey_combine_ecmult_data; + +/* Callback for batch EC multiplication to compute ell_0*P0 + ell_1*P1 + ... */ +static int secp256k1_zkp_musig_pubkey_combine_callback(secp256k1_zkp_scalar *sc, secp256k1_zkp_ge *pt, size_t idx, void *data) { + secp256k1_zkp_musig_pubkey_combine_ecmult_data *ctx = (secp256k1_zkp_musig_pubkey_combine_ecmult_data *) data; + secp256k1_zkp_musig_coefficient(sc, ctx->ell, idx); + return secp256k1_zkp_pubkey_load(ctx->ctx, pt, &ctx->pks[idx]); +} + + +static void secp256k1_zkp_musig_signers_init(secp256k1_zkp_musig_session_signer_data *signers, uint32_t n_signers) { + uint32_t i; + for (i = 0; i < n_signers; i++) { + memset(&signers[i], 0, sizeof(signers[i])); + signers[i].index = i; + signers[i].present = 0; + } +} + +int secp256k1_zkp_musig_pubkey_combine(const secp256k1_zkp_context* ctx, secp256k1_zkp_scratch_space *scratch, secp256k1_zkp_pubkey *combined_pk, unsigned char *pk_hash32, const secp256k1_zkp_pubkey *pubkeys, size_t n_pubkeys) { + secp256k1_zkp_musig_pubkey_combine_ecmult_data ecmult_data; + secp256k1_zkp_gej pkj; + secp256k1_zkp_ge pkp; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(combined_pk != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(pubkeys != NULL); + ARG_CHECK(n_pubkeys > 0); + + ecmult_data.ctx = ctx; + ecmult_data.pks = pubkeys; + if (!secp256k1_zkp_musig_compute_ell(ctx, ecmult_data.ell, pubkeys, n_pubkeys)) { + return 0; + } + if (!secp256k1_zkp_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &pkj, NULL, secp256k1_zkp_musig_pubkey_combine_callback, (void *) &ecmult_data, n_pubkeys)) { + return 0; + } + secp256k1_zkp_ge_set_gej(&pkp, &pkj); + secp256k1_zkp_pubkey_save(combined_pk, &pkp); + + if (pk_hash32 != NULL) { + memcpy(pk_hash32, ecmult_data.ell, 32); + } + return 1; +} + +int secp256k1_zkp_musig_session_initialize(const secp256k1_zkp_context* ctx, secp256k1_zkp_musig_session *session, secp256k1_zkp_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_zkp_pubkey *combined_pk, const unsigned char *pk_hash32, size_t n_signers, size_t my_index, const unsigned char *seckey) { + unsigned char combined_ser[33]; + size_t combined_ser_size = sizeof(combined_ser); + int overflow; + secp256k1_zkp_scalar secret; + secp256k1_zkp_scalar mu; + secp256k1_zkp_sha256 sha; + secp256k1_zkp_gej rj; + secp256k1_zkp_ge rp; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(session != NULL); + ARG_CHECK(signers != NULL); + ARG_CHECK(nonce_commitment32 != NULL); + ARG_CHECK(session_id32 != NULL); + ARG_CHECK(combined_pk != NULL); + ARG_CHECK(pk_hash32 != NULL); + ARG_CHECK(seckey != NULL); + + memset(session, 0, sizeof(*session)); + + if (msg32 != NULL) { + memcpy(session->msg, msg32, 32); + session->msg_is_set = 1; + } else { + session->msg_is_set = 0; + } + memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk)); + memcpy(session->pk_hash, pk_hash32, 32); + session->nonce_is_set = 0; + session->has_secret_data = 1; + if (n_signers == 0 || my_index >= n_signers) { + return 0; + } + if (n_signers > UINT32_MAX) { + return 0; + } + session->n_signers = (uint32_t) n_signers; + secp256k1_zkp_musig_signers_init(signers, session->n_signers); + session->nonce_commitments_hash_is_set = 0; + + /* Compute secret key */ + secp256k1_zkp_scalar_set_b32(&secret, seckey, &overflow); + if (overflow) { + secp256k1_zkp_scalar_clear(&secret); + return 0; + } + secp256k1_zkp_musig_coefficient(&mu, pk_hash32, (uint32_t) my_index); + secp256k1_zkp_scalar_mul(&secret, &secret, &mu); + secp256k1_zkp_scalar_get_b32(session->seckey, &secret); + + /* Compute secret nonce */ + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_sha256_write(&sha, session_id32, 32); + if (session->msg_is_set) { + secp256k1_zkp_sha256_write(&sha, msg32, 32); + } + secp256k1_zkp_ec_pubkey_serialize(ctx, combined_ser, &combined_ser_size, combined_pk, SECP256K1_EC_COMPRESSED); + secp256k1_zkp_sha256_write(&sha, combined_ser, combined_ser_size); + secp256k1_zkp_sha256_write(&sha, seckey, 32); + secp256k1_zkp_sha256_finalize(&sha, session->secnonce); + secp256k1_zkp_scalar_set_b32(&secret, session->secnonce, &overflow); + if (overflow) { + secp256k1_zkp_scalar_clear(&secret); + return 0; + } + + /* Compute public nonce and commitment */ + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &secret); + secp256k1_zkp_ge_set_gej(&rp, &rj); + secp256k1_zkp_pubkey_save(&session->nonce, &rp); + + if (nonce_commitment32 != NULL) { + unsigned char commit[33]; + size_t commit_size = sizeof(commit); + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_ec_pubkey_serialize(ctx, commit, &commit_size, &session->nonce, SECP256K1_EC_COMPRESSED); + secp256k1_zkp_sha256_write(&sha, commit, commit_size); + secp256k1_zkp_sha256_finalize(&sha, nonce_commitment32); + } + + secp256k1_zkp_scalar_clear(&secret); + return 1; +} + +int secp256k1_zkp_musig_session_get_public_nonce(const secp256k1_zkp_context* ctx, secp256k1_zkp_musig_session *session, secp256k1_zkp_musig_session_signer_data *signers, secp256k1_zkp_pubkey *nonce, const unsigned char *const *commitments, size_t n_commitments) { + secp256k1_zkp_sha256 sha; + unsigned char nonce_commitments_hash[32]; + size_t i; + (void) ctx; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(session != NULL); + ARG_CHECK(signers != NULL); + ARG_CHECK(nonce != NULL); + ARG_CHECK(commitments != NULL); + + if (!session->has_secret_data || n_commitments != session->n_signers) { + return 0; + } + for (i = 0; i < n_commitments; i++) { + ARG_CHECK(commitments[i] != NULL); + } + + secp256k1_zkp_sha256_initialize(&sha); + for (i = 0; i < n_commitments; i++) { + memcpy(signers[i].nonce_commitment, commitments[i], 32); + secp256k1_zkp_sha256_write(&sha, commitments[i], 32); + } + secp256k1_zkp_sha256_finalize(&sha, nonce_commitments_hash); + if (session->nonce_commitments_hash_is_set + && memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) { + /* Abort if get_public_nonce has been called before with a different array of + * commitments. */ + return 0; + } + memcpy(session->nonce_commitments_hash, nonce_commitments_hash, 32); + session->nonce_commitments_hash_is_set = 1; + memcpy(nonce, &session->nonce, sizeof(*nonce)); + return 1; +} + +int secp256k1_zkp_musig_session_initialize_verifier(const secp256k1_zkp_context* ctx, secp256k1_zkp_musig_session *session, secp256k1_zkp_musig_session_signer_data *signers, const unsigned char *msg32, const secp256k1_zkp_pubkey *combined_pk, const unsigned char *pk_hash32, const unsigned char *const *commitments, size_t n_signers) { + size_t i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(session != NULL); + ARG_CHECK(signers != NULL); + ARG_CHECK(combined_pk != NULL); + ARG_CHECK(pk_hash32 != NULL); + ARG_CHECK(commitments != NULL); + /* Check n_signers before checking commitments to allow testing the case where + * n_signers is big without allocating the space. */ + if (n_signers > UINT32_MAX) { + return 0; + } + for (i = 0; i < n_signers; i++) { + ARG_CHECK(commitments[i] != NULL); + } + (void) ctx; + + memset(session, 0, sizeof(*session)); + + memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk)); + if (n_signers == 0) { + return 0; + } + session->n_signers = (uint32_t) n_signers; + secp256k1_zkp_musig_signers_init(signers, session->n_signers); + + memcpy(session->pk_hash, pk_hash32, 32); + session->nonce_is_set = 0; + session->msg_is_set = 0; + if (msg32 != NULL) { + memcpy(session->msg, msg32, 32); + session->msg_is_set = 1; + } + session->has_secret_data = 0; + session->nonce_commitments_hash_is_set = 0; + + for (i = 0; i < n_signers; i++) { + memcpy(signers[i].nonce_commitment, commitments[i], 32); + } + return 1; +} + +int secp256k1_zkp_musig_set_nonce(const secp256k1_zkp_context* ctx, secp256k1_zkp_musig_session_signer_data *signer, const secp256k1_zkp_pubkey *nonce) { + unsigned char commit[33]; + size_t commit_size = sizeof(commit); + secp256k1_zkp_sha256 sha; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(signer != NULL); + ARG_CHECK(nonce != NULL); + + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_ec_pubkey_serialize(ctx, commit, &commit_size, nonce, SECP256K1_EC_COMPRESSED); + secp256k1_zkp_sha256_write(&sha, commit, commit_size); + secp256k1_zkp_sha256_finalize(&sha, commit); + + if (memcmp(commit, signer->nonce_commitment, 32) != 0) { + return 0; + } + memcpy(&signer->nonce, nonce, sizeof(*nonce)); + signer->present = 1; + return 1; +} + +int secp256k1_zkp_musig_session_combine_nonces(const secp256k1_zkp_context* ctx, secp256k1_zkp_musig_session *session, const secp256k1_zkp_musig_session_signer_data *signers, size_t n_signers, int *nonce_is_negated, const secp256k1_zkp_pubkey *adaptor) { + secp256k1_zkp_gej combined_noncej; + secp256k1_zkp_ge combined_noncep; + secp256k1_zkp_ge noncep; + secp256k1_zkp_sha256 sha; + unsigned char nonce_commitments_hash[32]; + size_t i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(session != NULL); + ARG_CHECK(signers != NULL); + + if (n_signers != session->n_signers) { + return 0; + } + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_gej_set_infinity(&combined_noncej); + for (i = 0; i < n_signers; i++) { + if (!signers[i].present) { + return 0; + } + secp256k1_zkp_sha256_write(&sha, signers[i].nonce_commitment, 32); + secp256k1_zkp_pubkey_load(ctx, &noncep, &signers[i].nonce); + secp256k1_zkp_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL); + } + secp256k1_zkp_sha256_finalize(&sha, nonce_commitments_hash); + /* Either the session is a verifier session or or the nonce_commitments_hash has + * been set in `musig_session_get_public_nonce`. */ + VERIFY_CHECK(!session->has_secret_data || session->nonce_commitments_hash_is_set); + if (session->has_secret_data + && memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) { + /* If the signers' commitments changed between get_public_nonce and now we + * have to abort because in that case they may have seen our nonce before + * creating their commitment. That can happen if the signer_data given to + * this function is different to the signer_data given to get_public_nonce. + * */ + return 0; + } + + /* Add public adaptor to nonce */ + if (adaptor != NULL) { + secp256k1_zkp_pubkey_load(ctx, &noncep, adaptor); + secp256k1_zkp_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL); + } + secp256k1_zkp_ge_set_gej(&combined_noncep, &combined_noncej); + if (secp256k1_zkp_fe_is_quad_var(&combined_noncep.y)) { + session->nonce_is_negated = 0; + } else { + session->nonce_is_negated = 1; + secp256k1_zkp_ge_neg(&combined_noncep, &combined_noncep); + } + if (nonce_is_negated != NULL) { + *nonce_is_negated = session->nonce_is_negated; + } + secp256k1_zkp_pubkey_save(&session->combined_nonce, &combined_noncep); + session->nonce_is_set = 1; + return 1; +} + +int secp256k1_zkp_musig_session_set_msg(const secp256k1_zkp_context* ctx, secp256k1_zkp_musig_session *session, const unsigned char *msg32) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(session != NULL); + ARG_CHECK(msg32 != NULL); + + if (session->msg_is_set) { + return 0; + } + memcpy(session->msg, msg32, 32); + session->msg_is_set = 1; + return 1; +} + +int secp256k1_zkp_musig_partial_signature_serialize(const secp256k1_zkp_context* ctx, unsigned char *out32, const secp256k1_zkp_musig_partial_signature* sig) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out32 != NULL); + ARG_CHECK(sig != NULL); + memcpy(out32, sig->data, 32); + return 1; +} + +int secp256k1_zkp_musig_partial_signature_parse(const secp256k1_zkp_context* ctx, secp256k1_zkp_musig_partial_signature* sig, const unsigned char *in32) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(in32 != NULL); + memcpy(sig->data, in32, 32); + return 1; +} + +/* Compute msghash = SHA256(combined_nonce, combined_pk, msg) */ +static int secp256k1_zkp_musig_compute_messagehash(const secp256k1_zkp_context *ctx, unsigned char *msghash, const secp256k1_zkp_musig_session *session) { + unsigned char buf[33]; + size_t bufsize = 33; + secp256k1_zkp_ge rp; + secp256k1_zkp_sha256 sha; + + secp256k1_zkp_sha256_initialize(&sha); + if (!session->nonce_is_set) { + return 0; + } + secp256k1_zkp_pubkey_load(ctx, &rp, &session->combined_nonce); + secp256k1_zkp_fe_get_b32(buf, &rp.x); + secp256k1_zkp_sha256_write(&sha, buf, 32); + secp256k1_zkp_ec_pubkey_serialize(ctx, buf, &bufsize, &session->combined_pk, SECP256K1_EC_COMPRESSED); + VERIFY_CHECK(bufsize == 33); + secp256k1_zkp_sha256_write(&sha, buf, bufsize); + if (!session->msg_is_set) { + return 0; + } + secp256k1_zkp_sha256_write(&sha, session->msg, 32); + secp256k1_zkp_sha256_finalize(&sha, msghash); + return 1; +} + +int secp256k1_zkp_musig_partial_sign(const secp256k1_zkp_context* ctx, const secp256k1_zkp_musig_session *session, secp256k1_zkp_musig_partial_signature *partial_sig) { + unsigned char msghash[32]; + int overflow; + secp256k1_zkp_scalar sk; + secp256k1_zkp_scalar e, k; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(partial_sig != NULL); + ARG_CHECK(session != NULL); + + if (!session->nonce_is_set || !session->has_secret_data) { + return 0; + } + + /* build message hash */ + if (!secp256k1_zkp_musig_compute_messagehash(ctx, msghash, session)) { + return 0; + } + secp256k1_zkp_scalar_set_b32(&e, msghash, NULL); + + secp256k1_zkp_scalar_set_b32(&sk, session->seckey, &overflow); + if (overflow) { + secp256k1_zkp_scalar_clear(&sk); + return 0; + } + + secp256k1_zkp_scalar_set_b32(&k, session->secnonce, &overflow); + if (overflow || secp256k1_zkp_scalar_is_zero(&k)) { + secp256k1_zkp_scalar_clear(&sk); + secp256k1_zkp_scalar_clear(&k); + return 0; + } + if (session->nonce_is_negated) { + secp256k1_zkp_scalar_negate(&k, &k); + } + + /* Sign */ + secp256k1_zkp_scalar_mul(&e, &e, &sk); + secp256k1_zkp_scalar_add(&e, &e, &k); + secp256k1_zkp_scalar_get_b32(&partial_sig->data[0], &e); + secp256k1_zkp_scalar_clear(&sk); + secp256k1_zkp_scalar_clear(&k); + + return 1; +} + +int secp256k1_zkp_musig_partial_sig_combine(const secp256k1_zkp_context* ctx, const secp256k1_zkp_musig_session *session, secp256k1_zkp_schnorrsig *sig, const secp256k1_zkp_musig_partial_signature *partial_sigs, size_t n_sigs) { + size_t i; + secp256k1_zkp_scalar s; + secp256k1_zkp_ge noncep; + (void) ctx; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(partial_sigs != NULL); + ARG_CHECK(session != NULL); + + if (!session->nonce_is_set) { + return 0; + } + if (n_sigs != session->n_signers) { + return 0; + } + secp256k1_zkp_scalar_clear(&s); + for (i = 0; i < n_sigs; i++) { + int overflow; + secp256k1_zkp_scalar term; + + secp256k1_zkp_scalar_set_b32(&term, partial_sigs[i].data, &overflow); + if (overflow) { + return 0; + } + secp256k1_zkp_scalar_add(&s, &s, &term); + } + + secp256k1_zkp_pubkey_load(ctx, &noncep, &session->combined_nonce); + VERIFY_CHECK(secp256k1_zkp_fe_is_quad_var(&noncep.y)); + secp256k1_zkp_fe_normalize(&noncep.x); + secp256k1_zkp_fe_get_b32(&sig->data[0], &noncep.x); + secp256k1_zkp_scalar_get_b32(&sig->data[32], &s); + + return 1; +} + +int secp256k1_zkp_musig_partial_sig_verify(const secp256k1_zkp_context* ctx, const secp256k1_zkp_musig_session *session, const secp256k1_zkp_musig_session_signer_data *signer, const secp256k1_zkp_musig_partial_signature *partial_sig, const secp256k1_zkp_pubkey *pubkey) { + unsigned char msghash[32]; + secp256k1_zkp_scalar s; + secp256k1_zkp_scalar e; + secp256k1_zkp_scalar mu; + secp256k1_zkp_gej rj; + secp256k1_zkp_ge rp; + int overflow; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(session != NULL); + ARG_CHECK(signer != NULL); + ARG_CHECK(partial_sig != NULL); + ARG_CHECK(pubkey != NULL); + + if (!session->nonce_is_set || !signer->present) { + return 0; + } + secp256k1_zkp_scalar_set_b32(&s, partial_sig->data, &overflow); + if (overflow) { + return 0; + } + if (!secp256k1_zkp_musig_compute_messagehash(ctx, msghash, session)) { + return 0; + } + secp256k1_zkp_scalar_set_b32(&e, msghash, NULL); + + /* Multiplying the messagehash by the musig coefficient is equivalent + * to multiplying the signer's public key by the coefficient, except + * much easier to do. */ + secp256k1_zkp_musig_coefficient(&mu, session->pk_hash, signer->index); + secp256k1_zkp_scalar_mul(&e, &e, &mu); + + if (!secp256k1_zkp_pubkey_load(ctx, &rp, &signer->nonce)) { + return 0; + } + + if (!secp256k1_zkp_schnorrsig_real_verify(ctx, &rj, &s, &e, pubkey)) { + return 0; + } + if (!session->nonce_is_negated) { + secp256k1_zkp_ge_neg(&rp, &rp); + } + secp256k1_zkp_gej_add_ge_var(&rj, &rj, &rp, NULL); + + return secp256k1_zkp_gej_is_infinity(&rj); +} + +int secp256k1_zkp_musig_partial_sig_adapt(const secp256k1_zkp_context* ctx, secp256k1_zkp_musig_partial_signature *adaptor_sig, const secp256k1_zkp_musig_partial_signature *partial_sig, const unsigned char *sec_adaptor32, int nonce_is_negated) { + secp256k1_zkp_scalar s; + secp256k1_zkp_scalar t; + int overflow; + + (void) ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(adaptor_sig != NULL); + ARG_CHECK(partial_sig != NULL); + ARG_CHECK(sec_adaptor32 != NULL); + + secp256k1_zkp_scalar_set_b32(&s, partial_sig->data, &overflow); + if (overflow) { + return 0; + } + secp256k1_zkp_scalar_set_b32(&t, sec_adaptor32, &overflow); + if (overflow) { + secp256k1_zkp_scalar_clear(&t); + return 0; + } + + if (nonce_is_negated) { + secp256k1_zkp_scalar_negate(&t, &t); + } + + secp256k1_zkp_scalar_add(&s, &s, &t); + secp256k1_zkp_scalar_get_b32(adaptor_sig->data, &s); + secp256k1_zkp_scalar_clear(&t); + return 1; +} + +int secp256k1_zkp_musig_extract_secret_adaptor(const secp256k1_zkp_context* ctx, unsigned char *sec_adaptor32, const secp256k1_zkp_schnorrsig *sig, const secp256k1_zkp_musig_partial_signature *partial_sigs, size_t n_partial_sigs, int nonce_is_negated) { + secp256k1_zkp_scalar t; + secp256k1_zkp_scalar s; + int overflow; + size_t i; + + (void) ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sec_adaptor32 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(partial_sigs != NULL); + + secp256k1_zkp_scalar_set_b32(&t, &sig->data[32], &overflow); + if (overflow) { + return 0; + } + secp256k1_zkp_scalar_negate(&t, &t); + + for (i = 0; i < n_partial_sigs; i++) { + secp256k1_zkp_scalar_set_b32(&s, partial_sigs[i].data, &overflow); + if (overflow) { + secp256k1_zkp_scalar_clear(&t); + return 0; + } + secp256k1_zkp_scalar_add(&t, &t, &s); + } + + if (!nonce_is_negated) { + secp256k1_zkp_scalar_negate(&t, &t); + } + secp256k1_zkp_scalar_get_b32(sec_adaptor32, &t); + secp256k1_zkp_scalar_clear(&t); + return 1; +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/musig.md b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/musig.md new file mode 100644 index 00000000..1dce8088 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/musig.md @@ -0,0 +1,199 @@ +MuSig - Rogue-Key-Resistant Multisignatures Module +=========================== + +This module implements the MuSig [1] multisignature scheme. The majority of +the module is an API designed to be used by signing or auditing participants +in a multisignature scheme. This involves a somewhat complex state machine +and significant effort has been taken to prevent accidental misuse of the +API in ways that could lead to accidental signatures or loss of key material. + +The resulting signatures are valid Schnorr signatures as described in [2]. + +# Theory + +In MuSig all signers contribute key material to a single signing key, +using the equation + + P = sum_i µ_i - P_i + +where `P_i` is the public key of the `i`th signer and `µ_i` is a so-called +_MuSig coefficient_ computed according to the following equation + + L = H(P_1 || P_2 || ... || P_n) + µ_i = H(L || i) + +where H is a hash function modelled as a random oracle. + +To produce a multisignature `(s, R)` on a message `m` using verification key +`P`, signers act as follows: + +1. Each computes a nonce, or ephemeral keypair, `(k_i, R_i)`. Every signer + communicates `H(R_i)` to every participant (both signers and auditors). +2. Upon receipt of every `H(R_i)`, each signer communicates `R_i` to every + participant. The recipients check that each `R_i` is consistent with the + previously-communicated hash. +3. Each signer computes a combined nonce + `R = sum_i R_i` + and shared challenge + `e = H(R || P || m)` + and partial signature + `s_i = k_i + µ_i*x_i*e` + where `x_i` is the secret key corresponding to `P_i`. + +The complete signature is then the `(s, R)` where `s = sum_i s_i` and `R = sum_i R_i`. + +# API Usage + +The following sections describe use of our API, and are mirrored in code in `src/modules/musig/example.c`. + +It is essential to security that signers use a unique uniformly random nonce for all +signing sessions, and that they do not reuse these nonces even in the case that a +signing session fails to complete. To that end, all signing state is encapsulated +in the data structure `secp256k1_zkp_musig_session`. The API does not expose any +functionality to serialize or deserialize this structure; it is designed to exist +only in memory. + +Users who need to persist this structure must take additional security measures +which cannot be enforced by a C API. Some guidance is provided in the documentation +for this data structure in `include/secp256k1_zkp_musig.h`. + +## Key Generation + +To use MuSig, users must first compute their combined public key `P`, which is +suitable for use on a blockchain or other public key repository. They do this +by calling `secp256k1_zkp_musig_pubkey_combine`. + +This function takes as input a list of public keys `P_i` in the argument +`pubkeys`. It outputs the combined public key `P` in the out-pointer `combined_pk` +and hash `L` in the out-pointer `pk_hash32`, if this pointer is non-NULL. + +## Signing + +A participant who wishes to sign a message (as opposed to observing/auditing the +signature process, which is also a supported mode) acts as follows. + +### Signing Participant + +1. The signer starts the session by calling `secp256k1_zkp_musig_session_initialize`. + This function outputs + - an initialized session state in the out-pointer `session` + - an array of initialized signer data in the out-pointer `signers` + - a commitment `H(R_i)` to a nonce in the out-pointer `nonce_commitment32` + It takes as input + - a unique session ID `session_id32` + - (optionally) a message to be signed `msg32` + - the combined public key output from `secp256k1_zkp_musig_pubkey_combine` + - the public key hash output from `secp256k1_zkp_musig_pubkey_combine` + - the signer's index `i` `my_index` + - the signer's secret key `seckey` +2. The signer then communicates `H(R_i)` to all other signers, and receives + commitments `H(R_j)` from all other signers `j`. These hashes are simply + length-32 byte arrays which can be communicated however is communicated. +3. Once all signers nonce commitments have been received, the signer records + these commitments with the function `secp256k1_zkp_musig_session_get_public_nonce`. + This function updates in place + - the session state `session` + - the array of signer data `signers` + taking in as input the list of commitments `commitments` and outputting the + signer's public nonce `R_i` in the out-pointer `nonce`. +4. The signer then communicates `R_i` to all other signers, and receives `R_j` + from each signer `j`. On receipt of a nonce `R_j` he calls the function + `secp256k1_zkp_musig_set_nonce` to record this fact. This function checks that + the received nonce is consistent with the previously-received nonce and will + return 0 in this case. The signer must also call this function with his own + nonce and his own index `i`. + These nonces `R_i` are secp256k1 public keys; they should be serialized using + `secp256k1_zkp_ec_pubkey_serialize` and parsed with `secp256k1_zkp_ec_pubkey_parse`. +5. Once all nonces have been exchanged in this way, signers are able to compute + their partial signatures. They do so by calling `secp256k1_zkp_musig_session_combine_nonces` + which updates in place + - the session state `session` + - the array of signer data `signers` + It outputs an auxiliary integer `nonce_is_negated` and has an auxiliary input + `adaptor`. Both of these may be set to NULL for ordinary signing purposes. + If the signer did not provide a message to `secp256k1_zkp_musig_session_initialize`, + a message must be provided now by calling `secp256k1_zkp_musig_session_set_msg` which + updates the session state in place. +6. The signer computes a partial signature `s_i` using the function + `secp256k1_zkp_musig_partial_sign` which takes the session state as input and + partial signature as output. +7. The signer then communicates the partial signature `s_i` to all other signers, or + to a central coordinator. These partial signatures should be serialized using + `musig_partial_signature_serialize` and parsed using `musig_partial_signature_parse`. +8. Each signer calls `secp256k1_zkp_musig_partial_sig_verify` on the other signers' partial + signatures to verify their correctness. If only the validity of the final signature + is important, not assigning blame, this step can be skipped. +9. Any signer, or central coordinator, may combine the partial signatures to obtain + a complete signature using `secp256k1_zkp_musig_partial_sig_combine`. This function takes + a signing session and array of MuSig partial signatures, and outputs a single + Schnorr signature. + +### Non-signing Participant + +A participant who wants to verify the signing process, i.e. check that nonce commitments +are consistent and partial signatures are correct without contributing a partial signature, +may do so using the above instructions except for the following changes: + +1. A signing session should be produced using `musig_session_initialize_verifier` + rather than `musig_session_initialize`; this function takes no secret data or + signer index. +2. The participant receives nonce commitments, public nonces and partial signatures, + but does not produce these values. Therefore `secp256k1_zkp_musig_session_get_public_nonce` + and `secp256k1_zkp_musig_partial_sign` are not called. + +### Verifier + +The final signature is simply a valid Schnorr signature using the combined public key. It +can be verified using the `secp256k1_zkp_schnorrsig_verify` with the correct message and +public key output from `secp256k1_zkp_musig_pubkey_combine`. + +## Atomic Swaps + +The signing API supports the production of "adaptor signatures", modified partial signatures +which are offset by an auxiliary secret known to one party. That is, +1. One party generates a (secret) adaptor `t` with corresponding (public) adaptor `T = t*G`. +2. When combining nonces, each party adds `T` to the total nonce used in the signature. +3. The party who knows `t` must "adapt" their partial signature with `t` to complete the + signature. +4. Any party who sees both the final signature and the original partial signatures + can compute `t`. + +Using these adaptor signatures, two 2-of-2 MuSig signing protocols can be executed in +parallel such that one party's partial signatures are made atomic. That is, when the other +party learns one partial signature, she automatically learns the other. This has applications +in cross-chain atomic swaps. + +Such a protocol can be executed as follows. Consider two participants, Alice and Bob, who +are simultaneously producing 2-of-2 multisignatures for two blockchains A and B. They act +as follows. + +1. Before the protocol begins, Bob chooses a 32-byte auxiliary secret `t` at random and + computes a corresponding public point `T` by calling `secp256k1_zkp_ec_pubkey_create`. + He communicates `T` to Alice. +2. Together, the parties execute steps 1-4 of the signing protocol above. +3. At step 5, when combining the two parties' public nonces, both parties call + `secp256k1_zkp_musig_session_combine_nonces` with `adaptor` set to `T` and `nonce_is_negated` + set to a non-NULL pointer to int. +4. Steps 6 and 7 proceed as before. Step 8, verifying the partial signatures, is now + essential to the security of the protocol and must not be omitted! + +The above steps are executed identically for both signing sessions. However, step 9 will +not work as before, since the partial signatures will not add up to a valid total signature. +Additional steps must be taken, and it is at this point that the two signing sessions +diverge. From here on we consider "Session A" which benefits Alice (e.g. which sends her +coins) and "Session B" which benefits Bob (e.g. which sends him coins). + +5. In Session B, Bob calls `secp256k1_zkp_musig_partial_sig_adapt` with his partial signature + and `t`, to produce an adaptor signature. He can then call `secp256k1_zkp_musig_partial_sig_combine` + with this adaptor signature and Alice's partial signature, to produce a complete + signature for blockchain B. +6. Alice reads this signature from blockchain B. She calls `secp256k1_zkp_musig_extract_secret_adaptor`, + passing the complete signature along with her and Bob's partial signatures from Session B. + This function outputs `t`, which until this point was only known to Bob. +7. In Session A, Alice is now able to replicate Bob's action, calling + `secp256k1_zkp_musig_partial_sig_adapt` with her own partial signature and `t`, ultimately + producing a complete signature on blockchain A. + +[1] https://eprint.iacr.org/2018/068 +[2] https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki + diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/tests_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/tests_impl.h new file mode 100644 index 00000000..69f5ec01 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/musig/tests_impl.h @@ -0,0 +1,757 @@ +/********************************************************************** + * Copyright (c) 2018 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_MUSIG_TESTS_ +#define _SECP256K1_MODULE_MUSIG_TESTS_ + +#include "secp256k1_musig.h" + +void musig_api_tests(secp256k1_zkp_scratch_space *scratch) { + secp256k1_zkp_scratch_space *scratch_small; + secp256k1_zkp_musig_session session[2]; + secp256k1_zkp_musig_session verifier_session; + secp256k1_zkp_musig_session_signer_data signer0[2]; + secp256k1_zkp_musig_session_signer_data signer1[2]; + secp256k1_zkp_musig_session_signer_data verifier_signer_data[2]; + secp256k1_zkp_musig_partial_signature partial_sig[2]; + secp256k1_zkp_musig_partial_signature partial_sig_adapted[2]; + secp256k1_zkp_musig_partial_signature partial_sig_overflow; + secp256k1_zkp_schnorrsig final_sig; + secp256k1_zkp_schnorrsig final_sig_cmp; + + unsigned char buf[32]; + unsigned char sk[2][32]; + unsigned char ones[32]; + unsigned char session_id[2][32]; + unsigned char nonce_commitment[2][32]; + int nonce_is_negated; + const unsigned char *ncs[2]; + unsigned char msg[32]; + unsigned char msghash[32]; + secp256k1_zkp_pubkey combined_pk; + unsigned char pk_hash[32]; + secp256k1_zkp_pubkey pk[2]; + + unsigned char sec_adaptor[32]; + unsigned char sec_adaptor1[32]; + secp256k1_zkp_pubkey adaptor; + + /** setup **/ + secp256k1_zkp_context *none = secp256k1_zkp_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_zkp_context *sign = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_zkp_context *vrfy = secp256k1_zkp_context_create(SECP256K1_CONTEXT_VERIFY); + int ecount; + + secp256k1_zkp_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + + memset(ones, 0xff, 32); + + secp256k1_zkp_rand256(session_id[0]); + secp256k1_zkp_rand256(session_id[1]); + secp256k1_zkp_rand256(sk[0]); + secp256k1_zkp_rand256(sk[1]); + secp256k1_zkp_rand256(msg); + secp256k1_zkp_rand256(sec_adaptor); + + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &adaptor, sec_adaptor) == 1); + + /** main test body **/ + + /* Key combination */ + ecount = 0; + CHECK(secp256k1_zkp_musig_pubkey_combine(none, scratch, &combined_pk, pk_hash, pk, 2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_musig_pubkey_combine(sign, scratch, &combined_pk, pk_hash, pk, 2) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1); + CHECK(ecount == 2); + /* pubkey_combine does not require a scratch space */ + CHECK(secp256k1_zkp_musig_pubkey_combine(vrfy, NULL, &combined_pk, pk_hash, pk, 2) == 1); + CHECK(ecount == 2); + /* If a scratch space is given it shouldn't be too small */ + scratch_small = secp256k1_zkp_scratch_space_create(ctx, 1); + CHECK(secp256k1_zkp_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, pk_hash, pk, 2) == 0); + secp256k1_zkp_scratch_space_destroy(scratch_small); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_pubkey_combine(vrfy, scratch, NULL, pk_hash, pk, 2) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_musig_pubkey_combine(vrfy, scratch, &combined_pk, NULL, pk, 2) == 1); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, NULL, 2) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 0) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_zkp_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, NULL, 0) == 0); + CHECK(ecount == 6); + + CHECK(secp256k1_zkp_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1); + CHECK(secp256k1_zkp_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1); + CHECK(secp256k1_zkp_musig_pubkey_combine(vrfy, scratch, &combined_pk, pk_hash, pk, 2) == 1); + + /** Session creation **/ + ecount = 0; + CHECK(secp256k1_zkp_musig_session_initialize(none, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_musig_session_initialize(vrfy, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_session_initialize(sign, NULL, signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session[0], NULL, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session[0], signer0, NULL, session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], NULL, msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); + CHECK(ecount == 6); + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, NULL, pk_hash, 2, 0, sk[0]) == 0); + CHECK(ecount == 7); + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, NULL, 2, 0, sk[0]) == 0); + CHECK(ecount == 8); + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 0, 0, sk[0]) == 0); + CHECK(ecount == 8); + /* If more than UINT32_MAX fits in a size_t, test that session_initialize + * rejects n_signers that high. */ + if (SIZE_MAX > UINT32_MAX) { + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, ((size_t) UINT32_MAX) + 2, 0, sk[0]) == 0); + } + CHECK(ecount == 8); + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, NULL) == 0); + CHECK(ecount == 9); + /* secret key overflows */ + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, ones) == 0); + CHECK(ecount == 9); + + + { + secp256k1_zkp_musig_session session_without_msg; + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session_without_msg, signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); + CHECK(secp256k1_zkp_musig_session_set_msg(none, &session_without_msg, msg) == 1); + CHECK(secp256k1_zkp_musig_session_set_msg(none, &session_without_msg, msg) == 0); + } + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); + CHECK(secp256k1_zkp_musig_session_initialize(sign, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, pk_hash, 2, 1, sk[1]) == 1); + ncs[0] = nonce_commitment[0]; + ncs[1] = nonce_commitment[1]; + + ecount = 0; + CHECK(secp256k1_zkp_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_musig_session_initialize_verifier(none, NULL, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, NULL, &combined_pk, pk_hash, ncs, 2) == 1); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, NULL, pk_hash, ncs, 2) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, NULL, ncs, 2) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, NULL, 2) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 0) == 0); + CHECK(ecount == 4); + if (SIZE_MAX > UINT32_MAX) { + CHECK(secp256k1_zkp_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, ((size_t) UINT32_MAX) + 2) == 0); + } + CHECK(ecount == 4); + CHECK(secp256k1_zkp_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 1); + + CHECK(secp256k1_zkp_musig_compute_messagehash(none, msghash, &verifier_session) == 0); + CHECK(secp256k1_zkp_musig_compute_messagehash(none, msghash, &session[0]) == 0); + + /** Signing step 0 -- exchange nonce commitments */ + ecount = 0; + { + secp256k1_zkp_pubkey nonce; + + /* Can obtain public nonce after commitments have been exchanged; still can't sign */ + CHECK(secp256k1_zkp_musig_session_get_public_nonce(none, &session[0], signer0, &nonce, ncs, 2) == 1); + CHECK(secp256k1_zkp_musig_partial_sign(none, &session[0], &partial_sig[0]) == 0); + CHECK(ecount == 0); + } + + /** Signing step 1 -- exchange nonces */ + ecount = 0; + { + secp256k1_zkp_pubkey public_nonce[3]; + + CHECK(secp256k1_zkp_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 2) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_musig_session_get_public_nonce(none, NULL, signer0, &public_nonce[0], ncs, 2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_musig_session_get_public_nonce(none, &session[0], NULL, &public_nonce[0], ncs, 2) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_session_get_public_nonce(none, &session[0], signer0, NULL, ncs, 2) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], NULL, 2) == 0); + CHECK(ecount == 4); + /* Number of commitments and number of signers are different */ + CHECK(secp256k1_zkp_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 1) == 0); + CHECK(ecount == 4); + + CHECK(secp256k1_zkp_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 2) == 1); + CHECK(secp256k1_zkp_musig_session_get_public_nonce(none, &session[1], signer1, &public_nonce[1], ncs, 2) == 1); + + CHECK(secp256k1_zkp_musig_set_nonce(none, &signer0[0], &public_nonce[0]) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(none, &signer0[1], &public_nonce[0]) == 0); + CHECK(secp256k1_zkp_musig_set_nonce(none, &signer0[1], &public_nonce[1]) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(none, &signer0[1], &public_nonce[1]) == 1); + CHECK(ecount == 4); + + CHECK(secp256k1_zkp_musig_set_nonce(none, NULL, &public_nonce[0]) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_zkp_musig_set_nonce(none, &signer1[0], NULL) == 0); + CHECK(ecount == 6); + + CHECK(secp256k1_zkp_musig_set_nonce(none, &signer1[0], &public_nonce[0]) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(none, &signer1[1], &public_nonce[1]) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(none, &verifier_signer_data[0], &public_nonce[0]) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(none, &verifier_signer_data[1], &public_nonce[1]) == 1); + + ecount = 0; + CHECK(secp256k1_zkp_musig_session_combine_nonces(none, &session[0], signer0, 2, &nonce_is_negated, &adaptor) == 1); + CHECK(secp256k1_zkp_musig_session_combine_nonces(none, NULL, signer0, 2, &nonce_is_negated, &adaptor) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_musig_session_combine_nonces(none, &session[0], NULL, 2, &nonce_is_negated, &adaptor) == 0); + CHECK(ecount == 2); + /* Number of signers differs from number during intialization */ + CHECK(secp256k1_zkp_musig_session_combine_nonces(none, &session[0], signer0, 1, &nonce_is_negated, &adaptor) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_session_combine_nonces(none, &session[0], signer0, 2, NULL, &adaptor) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_session_combine_nonces(none, &session[0], signer0, 2, &nonce_is_negated, NULL) == 1); + + CHECK(secp256k1_zkp_musig_session_combine_nonces(none, &session[0], signer0, 2, &nonce_is_negated, &adaptor) == 1); + CHECK(secp256k1_zkp_musig_session_combine_nonces(none, &session[1], signer0, 2, &nonce_is_negated, &adaptor) == 1); + CHECK(secp256k1_zkp_musig_session_combine_nonces(none, &verifier_session, verifier_signer_data, 2, &nonce_is_negated, &adaptor) == 1); + } + + /** Signing step 2 -- partial signatures */ + ecount = 0; + CHECK(secp256k1_zkp_musig_partial_sign(none, &session[0], &partial_sig[0]) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_musig_partial_sign(none, NULL, &partial_sig[0]) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_musig_partial_sign(none, &session[0], NULL) == 0); + CHECK(ecount == 2); + + CHECK(secp256k1_zkp_musig_partial_sign(none, &session[0], &partial_sig[0]) == 1); + CHECK(secp256k1_zkp_musig_partial_sign(none, &session[1], &partial_sig[1]) == 1); + /* observer can't sign */ + CHECK(secp256k1_zkp_musig_partial_sign(none, &verifier_session, &partial_sig[2]) == 0); + CHECK(ecount == 2); + + ecount = 0; + CHECK(secp256k1_zkp_musig_partial_signature_serialize(none, buf, &partial_sig[0]) == 1); + CHECK(secp256k1_zkp_musig_partial_signature_serialize(none, NULL, &partial_sig[0]) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_musig_partial_signature_serialize(none, buf, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_partial_signature_parse(none, &partial_sig[0], buf) == 1); + CHECK(secp256k1_zkp_musig_partial_signature_parse(none, NULL, buf) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_musig_partial_signature_parse(none, &partial_sig[0], NULL) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_musig_partial_signature_parse(none, &partial_sig_overflow, ones) == 1); + + /** Partial signature verification */ + ecount = 0; + CHECK(secp256k1_zkp_musig_partial_sig_verify(none, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_musig_partial_sig_verify(sign, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[1], &pk[0]) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_partial_sig_verify(vrfy, NULL, &signer0[0], &partial_sig[0], &pk[0]) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_musig_partial_sig_verify(vrfy, &session[0], NULL, &partial_sig[0], &pk[0]) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], NULL, &pk[0]) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_zkp_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig_overflow, &pk[0]) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_zkp_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], NULL) == 0); + CHECK(ecount == 6); + + CHECK(secp256k1_zkp_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1); + CHECK(secp256k1_zkp_musig_partial_sig_verify(vrfy, &session[1], &signer1[0], &partial_sig[0], &pk[0]) == 1); + CHECK(secp256k1_zkp_musig_partial_sig_verify(vrfy, &session[0], &signer0[1], &partial_sig[1], &pk[1]) == 1); + CHECK(secp256k1_zkp_musig_partial_sig_verify(vrfy, &session[1], &signer1[1], &partial_sig[1], &pk[1]) == 1); + CHECK(secp256k1_zkp_musig_partial_sig_verify(vrfy, &verifier_session, &verifier_signer_data[0], &partial_sig[0], &pk[0]) == 1); + CHECK(secp256k1_zkp_musig_partial_sig_verify(vrfy, &verifier_session, &verifier_signer_data[1], &partial_sig[1], &pk[1]) == 1); + CHECK(ecount == 6); + + /** Adaptor signature verification */ + memcpy(&partial_sig_adapted[1], &partial_sig[1], sizeof(partial_sig_adapted[1])); + ecount = 0; + CHECK(secp256k1_zkp_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], sec_adaptor, nonce_is_negated) == 1); + CHECK(secp256k1_zkp_musig_partial_sig_adapt(none, NULL, &partial_sig[0], sec_adaptor, 0) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_musig_partial_sig_adapt(none, &partial_sig_adapted[0], NULL, sec_adaptor, 0) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig_overflow, sec_adaptor, nonce_is_negated) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], NULL, 0) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], ones, nonce_is_negated) == 0); + CHECK(ecount == 3); + + /** Signing combining and verification */ + ecount = 0; + CHECK(secp256k1_zkp_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 2) == 1); + CHECK(secp256k1_zkp_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2) == 1); + CHECK(memcmp(&final_sig, &final_sig_cmp, sizeof(final_sig)) == 0); + CHECK(secp256k1_zkp_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2) == 1); + CHECK(memcmp(&final_sig, &final_sig_cmp, sizeof(final_sig)) == 0); + + CHECK(secp256k1_zkp_musig_partial_sig_combine(none, NULL, &final_sig, partial_sig_adapted, 2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_musig_partial_sig_combine(none, &session[0], NULL, partial_sig_adapted, 2) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_partial_sig_combine(none, &session[0], &final_sig, NULL, 2) == 0); + CHECK(ecount == 3); + { + secp256k1_zkp_musig_partial_signature partial_sig_tmp[2]; + partial_sig_tmp[0] = partial_sig_adapted[0]; + partial_sig_tmp[1] = partial_sig_overflow; + CHECK(secp256k1_zkp_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_tmp, 2) == 0); + } + CHECK(ecount == 3); + /* Wrong number of partial sigs */ + CHECK(secp256k1_zkp_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 1) == 0); + CHECK(ecount == 3); + + CHECK(secp256k1_zkp_schnorrsig_verify(vrfy, &final_sig, msg, &combined_pk) == 1); + + /** Secret adaptor can be extracted from signature */ + ecount = 0; + CHECK(secp256k1_zkp_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 2, nonce_is_negated) == 1); + CHECK(memcmp(sec_adaptor, sec_adaptor1, 32) == 0); + CHECK(secp256k1_zkp_musig_extract_secret_adaptor(none, NULL, &final_sig, partial_sig, 2, 0) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_musig_extract_secret_adaptor(none, sec_adaptor1, NULL, partial_sig, 2, 0) == 0); + CHECK(ecount == 2); + { + secp256k1_zkp_schnorrsig final_sig_tmp = final_sig; + memcpy(&final_sig_tmp.data[32], ones, 32); + CHECK(secp256k1_zkp_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig_tmp, partial_sig, 2, nonce_is_negated) == 0); + } + CHECK(ecount == 2); + CHECK(secp256k1_zkp_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, NULL, 2, 0) == 0); + CHECK(ecount == 3); + { + secp256k1_zkp_musig_partial_signature partial_sig_tmp[2]; + partial_sig_tmp[0] = partial_sig[0]; + partial_sig_tmp[1] = partial_sig_overflow; + CHECK(secp256k1_zkp_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig_tmp, 2, nonce_is_negated) == 0); + } + CHECK(ecount == 3); + CHECK(secp256k1_zkp_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 0, 0) == 1); + CHECK(secp256k1_zkp_musig_extract_secret_adaptor(none, sec_adaptor1, &final_sig, partial_sig, 2, 1) == 1); + + /** cleanup **/ + memset(&session, 0, sizeof(session)); + secp256k1_zkp_context_destroy(none); + secp256k1_zkp_context_destroy(sign); + secp256k1_zkp_context_destroy(vrfy); +} + +/* Initializes two sessions, one use the given parameters (session_id, + * nonce_commitments, etc.) except that `session_tmp` uses new signers with different + * public keys. The point of this test is to call `musig_session_get_public_nonce` + * with signers from `session_tmp` who have different public keys than the correct + * ones and return the resulting messagehash. This should not result in a different + * messagehash because the public keys of the signers are only used during session + * initialization. */ +int musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp256k1_zkp_pubkey *pks, secp256k1_zkp_pubkey *combined_pk, unsigned char *pk_hash, const unsigned char * const *nonce_commitments, unsigned char *msg, secp256k1_zkp_pubkey *nonce_other, unsigned char *sk, unsigned char *session_id) { + secp256k1_zkp_musig_session session; + secp256k1_zkp_musig_session session_tmp; + unsigned char nonce_commitment[32]; + secp256k1_zkp_musig_session_signer_data signers[2]; + secp256k1_zkp_musig_session_signer_data signers_tmp[2]; + unsigned char sk_dummy[32]; + secp256k1_zkp_pubkey pks_tmp[2]; + secp256k1_zkp_pubkey combined_pk_tmp; + unsigned char pk_hash_tmp[32]; + secp256k1_zkp_pubkey nonce; + + /* Set up signers with different public keys */ + secp256k1_zkp_rand256(sk_dummy); + pks_tmp[0] = pks[0]; + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pks_tmp[1], sk_dummy) == 1); + CHECK(secp256k1_zkp_musig_pubkey_combine(ctx, NULL, &combined_pk_tmp, pk_hash_tmp, pks_tmp, 2) == 1); + CHECK(secp256k1_zkp_musig_session_initialize(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, pk_hash_tmp, 2, 0, sk_dummy) == 1); + + CHECK(secp256k1_zkp_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1); + CHECK(memcmp(nonce_commitment, nonce_commitments[1], 32) == 0); + /* Call get_public_nonce with different signers than the signers the session was + * initialized with. */ + CHECK(secp256k1_zkp_musig_session_get_public_nonce(ctx, &session_tmp, signers, &nonce, nonce_commitments, 2) == 1); + CHECK(secp256k1_zkp_musig_session_get_public_nonce(ctx, &session, signers_tmp, &nonce, nonce_commitments, 2) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers[0], nonce_other) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers[1], &nonce) == 1); + CHECK(secp256k1_zkp_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1); + + return secp256k1_zkp_musig_compute_messagehash(ctx, msghash, &session); +} + +/* Creates a new session (with a different session id) and tries to use that session + * to combine nonces with given signers_other. This should fail, because the nonce + * commitments of signers_other do not match the nonce commitments the new session + * was initialized with. If do_test is 0, the correct signers are being used and + * therefore the function should return 1. */ +int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_zkp_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_zkp_pubkey *nonce_other, unsigned char *msg, unsigned char *sk, secp256k1_zkp_musig_session_signer_data *signers_other, int do_test) { + secp256k1_zkp_musig_session session; + secp256k1_zkp_musig_session_signer_data signers[2]; + secp256k1_zkp_musig_session_signer_data *signers_to_use; + unsigned char nonce_commitment[32]; + unsigned char session_id[32]; + secp256k1_zkp_pubkey nonce; + const unsigned char *ncs[2]; + + /* Initialize new signers */ + secp256k1_zkp_rand256(session_id); + CHECK(secp256k1_zkp_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 1, sk) == 1); + ncs[0] = nonce_commitment_other; + ncs[1] = nonce_commitment; + CHECK(secp256k1_zkp_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers[0], nonce_other) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers[1], &nonce) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers[1], &nonce) == 1); + secp256k1_zkp_musig_session_combine_nonces(ctx, &session, signers_other, 2, NULL, NULL); + if (do_test) { + signers_to_use = signers_other; + } else { + signers_to_use = signers; + } + return secp256k1_zkp_musig_session_combine_nonces(ctx, &session, signers_to_use, 2, NULL, NULL); +} + +/* Recreates a session with the given session_id, signers, pk, msg etc. parameters + * and tries to sign and verify the other signers partial signature. Both should fail + * if msg is NULL. */ +int musig_state_machine_missing_msg_test(secp256k1_zkp_pubkey *pks, secp256k1_zkp_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_zkp_pubkey *nonce_other, secp256k1_zkp_musig_partial_signature *partial_sig_other, unsigned char *sk, unsigned char *session_id, unsigned char *msg) { + secp256k1_zkp_musig_session session; + secp256k1_zkp_musig_session_signer_data signers[2]; + unsigned char nonce_commitment[32]; + const unsigned char *ncs[2]; + secp256k1_zkp_pubkey nonce; + secp256k1_zkp_musig_partial_signature partial_sig; + int partial_sign, partial_verify; + + CHECK(secp256k1_zkp_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1); + ncs[0] = nonce_commitment_other; + ncs[1] = nonce_commitment; + CHECK(secp256k1_zkp_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers[0], nonce_other) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers[1], &nonce) == 1); + + CHECK(secp256k1_zkp_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1); + partial_sign = secp256k1_zkp_musig_partial_sign(ctx, &session, &partial_sig); + partial_verify = secp256k1_zkp_musig_partial_sig_verify(ctx, &session, &signers[0], partial_sig_other, &pks[0]); + if (msg != NULL) { + /* Return 1 if both succeeded */ + return partial_sign && partial_verify; + } + /* Return 0 if both failed */ + return partial_sign || partial_verify; +} + +/* Recreates a session with the given session_id, signers, pk, msg etc. parameters + * and tries to verify and combine partial sigs. If do_combine is 0, the + * combine_nonces step is left out. In that case verify and combine should fail and + * this function should return 0. */ +int musig_state_machine_missing_combine_test(secp256k1_zkp_pubkey *pks, secp256k1_zkp_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_zkp_pubkey *nonce_other, secp256k1_zkp_musig_partial_signature *partial_sig_other, unsigned char *msg, unsigned char *sk, unsigned char *session_id, secp256k1_zkp_musig_partial_signature *partial_sig, int do_combine) { + secp256k1_zkp_musig_session session; + secp256k1_zkp_musig_session_signer_data signers[2]; + unsigned char nonce_commitment[32]; + const unsigned char *ncs[2]; + secp256k1_zkp_pubkey nonce; + secp256k1_zkp_musig_partial_signature partial_sigs[2]; + secp256k1_zkp_schnorrsig sig; + int partial_verify, sig_combine; + + CHECK(secp256k1_zkp_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1); + ncs[0] = nonce_commitment_other; + ncs[1] = nonce_commitment; + CHECK(secp256k1_zkp_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers[0], nonce_other) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers[1], &nonce) == 1); + + partial_sigs[0] = *partial_sig_other; + partial_sigs[1] = *partial_sig; + if (do_combine != 0) { + CHECK(secp256k1_zkp_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1); + } + partial_verify = secp256k1_zkp_musig_partial_sig_verify(ctx, &session, signers, partial_sig_other, &pks[0]); + sig_combine = secp256k1_zkp_musig_partial_sig_combine(ctx, &session, &sig, partial_sigs, 2); + if (do_combine != 0) { + /* Return 1 if both succeeded */ + return partial_verify && sig_combine; + } + /* Return 0 if both failed */ + return partial_verify || sig_combine; +} + +void musig_state_machine_tests(secp256k1_zkp_scratch_space *scratch) { + size_t i; + secp256k1_zkp_musig_session session[2]; + secp256k1_zkp_musig_session_signer_data signers0[2]; + secp256k1_zkp_musig_session_signer_data signers1[2]; + unsigned char nonce_commitment[2][32]; + unsigned char session_id[2][32]; + unsigned char msg[32]; + unsigned char sk[2][32]; + secp256k1_zkp_pubkey pk[2]; + secp256k1_zkp_pubkey combined_pk; + unsigned char pk_hash[32]; + secp256k1_zkp_pubkey nonce[2]; + const unsigned char *ncs[2]; + secp256k1_zkp_musig_partial_signature partial_sig[2]; + unsigned char msghash1[32]; + unsigned char msghash2[32]; + + /* Run state machine with the same objects twice to test that it's allowed to + * reinitialize session and session_signer_data. */ + for (i = 0; i < 2; i++) { + /* Setup */ + secp256k1_zkp_rand256(session_id[0]); + secp256k1_zkp_rand256(session_id[1]); + secp256k1_zkp_rand256(sk[0]); + secp256k1_zkp_rand256(sk[1]); + secp256k1_zkp_rand256(msg); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1); + CHECK(secp256k1_zkp_musig_pubkey_combine(ctx, scratch, &combined_pk, pk_hash, pk, 2) == 1); + CHECK(secp256k1_zkp_musig_session_initialize(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1); + CHECK(secp256k1_zkp_musig_session_initialize(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, &combined_pk, pk_hash, 2, 1, sk[1]) == 1); + + /* Set nonce commitments */ + ncs[0] = nonce_commitment[0]; + ncs[1] = nonce_commitment[1]; + CHECK(secp256k1_zkp_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2) == 1); + /* Changing a nonce commitment is not okay */ + ncs[1] = (unsigned char*) "this isn't a nonce commitment..."; + CHECK(secp256k1_zkp_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2) == 0); + /* Repeating with the same nonce commitments is okay */ + ncs[1] = nonce_commitment[1]; + CHECK(secp256k1_zkp_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2) == 1); + + /* Get nonce for signer 1 */ + CHECK(secp256k1_zkp_musig_session_get_public_nonce(ctx, &session[1], signers1, &nonce[1], ncs, 2) == 1); + + /* Set nonces */ + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers0[0], &nonce[0]) == 1); + /* Can't set nonce that doesn't match nonce commitment */ + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers0[1], &nonce[0]) == 0); + /* Set correct nonce */ + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers0[1], &nonce[1]) == 1); + + /* Combine nonces */ + CHECK(secp256k1_zkp_musig_session_combine_nonces(ctx, &session[0], signers0, 2, NULL, NULL) == 1); + /* Not everyone is present from signer 1's view */ + CHECK(secp256k1_zkp_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 0); + /* Make everyone present */ + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers1[0], &nonce[0]) == 1); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &signers1[1], &nonce[1]) == 1); + + /* Can't combine nonces from signers of a different session */ + CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, pk_hash, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 1) == 0); + CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, pk_hash, nonce_commitment[0], &nonce[0], msg, sk[1], signers1, 0) == 1); + + /* Partially sign */ + CHECK(secp256k1_zkp_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1); + /* Can't verify or sign until nonce is combined */ + CHECK(secp256k1_zkp_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 0); + CHECK(secp256k1_zkp_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 0); + CHECK(secp256k1_zkp_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 1); + CHECK(secp256k1_zkp_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 1); + /* messagehash should be the same as a session whose get_public_nonce was called + * with different signers (i.e. they diff in public keys). This is because the + * public keys of the signers is set in stone when initializing the session. */ + CHECK(secp256k1_zkp_musig_compute_messagehash(ctx, msghash1, &session[1]) == 1); + CHECK(musig_state_machine_diff_signer_msghash_test(msghash2, pk, &combined_pk, pk_hash, ncs, msg, &nonce[0], sk[1], session_id[1]) == 1); + CHECK(memcmp(msghash1, msghash2, 32) == 0); + CHECK(secp256k1_zkp_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1); + CHECK(secp256k1_zkp_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[1], &pk[1]) == 1); + /* Wrong signature */ + CHECK(secp256k1_zkp_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[0], &pk[1]) == 0); + /* Can't sign or verify until msg is set */ + CHECK(musig_state_machine_missing_msg_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], sk[1], session_id[1], NULL) == 0); + CHECK(musig_state_machine_missing_msg_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], sk[1], session_id[1], msg) == 1); + + /* Can't verify and combine partial sigs until nonces are combined */ + CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 0) == 0); + CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 1) == 1); + } +} + +void scriptless_atomic_swap(secp256k1_zkp_scratch_space *scratch) { + /* Throughout this test "a" and "b" refer to two hypothetical blockchains, + * while the indices 0 and 1 refer to the two signers. Here signer 0 is + * sending a-coins to signer 1, while signer 1 is sending b-coins to signer + * 0. Signer 0 produces the adaptor signatures. */ + secp256k1_zkp_schnorrsig final_sig_a; + secp256k1_zkp_schnorrsig final_sig_b; + secp256k1_zkp_musig_partial_signature partial_sig_a[2]; + secp256k1_zkp_musig_partial_signature partial_sig_b_adapted[2]; + secp256k1_zkp_musig_partial_signature partial_sig_b[2]; + unsigned char sec_adaptor[32]; + unsigned char sec_adaptor_extracted[32]; + secp256k1_zkp_pubkey pub_adaptor; + + unsigned char seckey_a[2][32]; + unsigned char seckey_b[2][32]; + secp256k1_zkp_pubkey pk_a[2]; + secp256k1_zkp_pubkey pk_b[2]; + unsigned char pk_hash_a[32]; + unsigned char pk_hash_b[32]; + secp256k1_zkp_pubkey combined_pk_a; + secp256k1_zkp_pubkey combined_pk_b; + secp256k1_zkp_musig_session musig_session_a[2]; + secp256k1_zkp_musig_session musig_session_b[2]; + unsigned char noncommit_a[2][32]; + unsigned char noncommit_b[2][32]; + const unsigned char *noncommit_a_ptr[2]; + const unsigned char *noncommit_b_ptr[2]; + secp256k1_zkp_pubkey pubnon_a[2]; + secp256k1_zkp_pubkey pubnon_b[2]; + int nonce_is_negated_a; + int nonce_is_negated_b; + secp256k1_zkp_musig_session_signer_data data_a[2]; + secp256k1_zkp_musig_session_signer_data data_b[2]; + + const unsigned char seed[32] = "still tired of choosing seeds..."; + const unsigned char msg32_a[32] = "this is the message blockchain a"; + const unsigned char msg32_b[32] = "this is the message blockchain b"; + + /* Step 1: key setup */ + secp256k1_zkp_rand256(seckey_a[0]); + secp256k1_zkp_rand256(seckey_a[1]); + secp256k1_zkp_rand256(seckey_b[0]); + secp256k1_zkp_rand256(seckey_b[1]); + secp256k1_zkp_rand256(sec_adaptor); + + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pk_a[0], seckey_a[0])); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pk_a[1], seckey_a[1])); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pk_b[0], seckey_b[0])); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pk_b[1], seckey_b[1])); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor)); + + CHECK(secp256k1_zkp_musig_pubkey_combine(ctx, scratch, &combined_pk_a, pk_hash_a, pk_a, 2)); + CHECK(secp256k1_zkp_musig_pubkey_combine(ctx, scratch, &combined_pk_b, pk_hash_b, pk_b, 2)); + + CHECK(secp256k1_zkp_musig_session_initialize(ctx, &musig_session_a[0], data_a, noncommit_a[0], seed, msg32_a, &combined_pk_a, pk_hash_a, 2, 0, seckey_a[0])); + CHECK(secp256k1_zkp_musig_session_initialize(ctx, &musig_session_a[1], data_a, noncommit_a[1], seed, msg32_a, &combined_pk_a, pk_hash_a, 2, 1, seckey_a[1])); + noncommit_a_ptr[0] = noncommit_a[0]; + noncommit_a_ptr[1] = noncommit_a[1]; + + CHECK(secp256k1_zkp_musig_session_initialize(ctx, &musig_session_b[0], data_b, noncommit_b[0], seed, msg32_b, &combined_pk_b, pk_hash_b, 2, 0, seckey_b[0])); + CHECK(secp256k1_zkp_musig_session_initialize(ctx, &musig_session_b[1], data_b, noncommit_b[1], seed, msg32_b, &combined_pk_b, pk_hash_b, 2, 1, seckey_b[1])); + noncommit_b_ptr[0] = noncommit_b[0]; + noncommit_b_ptr[1] = noncommit_b[1]; + + /* Step 2: Exchange nonces */ + CHECK(secp256k1_zkp_musig_session_get_public_nonce(ctx, &musig_session_a[0], data_a, &pubnon_a[0], noncommit_a_ptr, 2)); + CHECK(secp256k1_zkp_musig_session_get_public_nonce(ctx, &musig_session_a[1], data_a, &pubnon_a[1], noncommit_a_ptr, 2)); + CHECK(secp256k1_zkp_musig_session_get_public_nonce(ctx, &musig_session_b[0], data_b, &pubnon_b[0], noncommit_b_ptr, 2)); + CHECK(secp256k1_zkp_musig_session_get_public_nonce(ctx, &musig_session_b[1], data_b, &pubnon_b[1], noncommit_b_ptr, 2)); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &data_a[0], &pubnon_a[0])); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &data_a[1], &pubnon_a[1])); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &data_b[0], &pubnon_b[0])); + CHECK(secp256k1_zkp_musig_set_nonce(ctx, &data_b[1], &pubnon_b[1])); + CHECK(secp256k1_zkp_musig_session_combine_nonces(ctx, &musig_session_a[0], data_a, 2, &nonce_is_negated_a, &pub_adaptor)); + CHECK(secp256k1_zkp_musig_session_combine_nonces(ctx, &musig_session_a[1], data_a, 2, NULL, &pub_adaptor)); + CHECK(secp256k1_zkp_musig_session_combine_nonces(ctx, &musig_session_b[0], data_b, 2, &nonce_is_negated_b, &pub_adaptor)); + CHECK(secp256k1_zkp_musig_session_combine_nonces(ctx, &musig_session_b[1], data_b, 2, NULL, &pub_adaptor)); + + /* Step 3: Signer 0 produces partial signatures for both chains. */ + CHECK(secp256k1_zkp_musig_partial_sign(ctx, &musig_session_a[0], &partial_sig_a[0])); + CHECK(secp256k1_zkp_musig_partial_sign(ctx, &musig_session_b[0], &partial_sig_b[0])); + + /* Step 4: Signer 1 receives partial signatures, verifies them and creates a + * partial signature to send B-coins to signer 0. */ + CHECK(secp256k1_zkp_musig_partial_sig_verify(ctx, &musig_session_a[1], data_a, &partial_sig_a[0], &pk_a[0]) == 1); + CHECK(secp256k1_zkp_musig_partial_sig_verify(ctx, &musig_session_b[1], data_b, &partial_sig_b[0], &pk_b[0]) == 1); + CHECK(secp256k1_zkp_musig_partial_sign(ctx, &musig_session_b[1], &partial_sig_b[1])); + + /* Step 5: Signer 0 adapts its own partial signature and combines it with the + * partial signature from signer 1. This results in a complete signature which + * is broadcasted by signer 0 to take B-coins. */ + CHECK(secp256k1_zkp_musig_partial_sig_adapt(ctx, &partial_sig_b_adapted[0], &partial_sig_b[0], sec_adaptor, nonce_is_negated_b)); + memcpy(&partial_sig_b_adapted[1], &partial_sig_b[1], sizeof(partial_sig_b_adapted[1])); + CHECK(secp256k1_zkp_musig_partial_sig_combine(ctx, &musig_session_b[0], &final_sig_b, partial_sig_b_adapted, 2) == 1); + CHECK(secp256k1_zkp_schnorrsig_verify(ctx, &final_sig_b, msg32_b, &combined_pk_b) == 1); + + /* Step 6: Signer 1 extracts adaptor from the published signature, applies it to + * other partial signature, and takes A-coins. */ + CHECK(secp256k1_zkp_musig_extract_secret_adaptor(ctx, sec_adaptor_extracted, &final_sig_b, partial_sig_b, 2, nonce_is_negated_b) == 1); + CHECK(memcmp(sec_adaptor_extracted, sec_adaptor, sizeof(sec_adaptor)) == 0); /* in real life we couldn't check this, of course */ + CHECK(secp256k1_zkp_musig_partial_sig_adapt(ctx, &partial_sig_a[0], &partial_sig_a[0], sec_adaptor_extracted, nonce_is_negated_a)); + CHECK(secp256k1_zkp_musig_partial_sign(ctx, &musig_session_a[1], &partial_sig_a[1])); + CHECK(secp256k1_zkp_musig_partial_sig_combine(ctx, &musig_session_a[1], &final_sig_a, partial_sig_a, 2) == 1); + CHECK(secp256k1_zkp_schnorrsig_verify(ctx, &final_sig_a, msg32_a, &combined_pk_a) == 1); +} + +/* Checks that hash initialized by secp256k1_zkp_musig_sha256_init_tagged has the + * expected state. */ +void sha256_tag_test(void) { + char tag[17] = "MuSig coefficient"; + secp256k1_zkp_sha256 sha; + secp256k1_zkp_sha256 sha_tagged; + unsigned char buf[32]; + unsigned char buf2[32]; + size_t i; + + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_sha256_write(&sha, (unsigned char *) tag, 17); + secp256k1_zkp_sha256_finalize(&sha, buf); + /* buf = SHA256("MuSig coefficient") */ + + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_sha256_write(&sha, buf, 32); + secp256k1_zkp_sha256_write(&sha, buf, 32); + /* Is buffer fully consumed? */ + CHECK((sha.bytes & 0x3F) == 0); + + /* Compare with tagged SHA */ + secp256k1_zkp_musig_sha256_init_tagged(&sha_tagged); + for (i = 0; i < 8; i++) { + CHECK(sha_tagged.s[i] == sha.s[i]); + } + secp256k1_zkp_sha256_write(&sha, buf, 32); + secp256k1_zkp_sha256_write(&sha_tagged, buf, 32); + secp256k1_zkp_sha256_finalize(&sha, buf); + secp256k1_zkp_sha256_finalize(&sha_tagged, buf2); + CHECK(memcmp(buf, buf2, 32) == 0); +} + +void run_musig_tests(void) { + int i; + secp256k1_zkp_scratch_space *scratch = secp256k1_zkp_scratch_space_create(ctx, 1024 * 1024); + + musig_api_tests(scratch); + musig_state_machine_tests(scratch); + for (i = 0; i < count; i++) { + /* Run multiple times to ensure that the nonce is negated in some tests */ + scriptless_atomic_swap(scratch); + } + sha256_tag_test(); + + secp256k1_zkp_scratch_space_destroy(scratch); +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/Makefile.am.include b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/Makefile.am.include new file mode 100644 index 00000000..6b73954f --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/Makefile.am.include @@ -0,0 +1,15 @@ +include_HEADERS += include/secp256k1_zkp_rangeproof.h +noinst_HEADERS += src/modules/rangeproof/main_impl.h +noinst_HEADERS += src/modules/rangeproof/pedersen.h +noinst_HEADERS += src/modules/rangeproof/pedersen_impl.h +noinst_HEADERS += src/modules/rangeproof/borromean.h +noinst_HEADERS += src/modules/rangeproof/borromean_impl.h +noinst_HEADERS += src/modules/rangeproof/rangeproof.h +noinst_HEADERS += src/modules/rangeproof/rangeproof_impl.h +noinst_HEADERS += src/modules/rangeproof/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_rangeproof +bench_rangeproof_SOURCES = src/bench_rangeproof.c +bench_rangeproof_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_rangeproof_LDFLAGS = -static +endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/borromean.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/borromean.h new file mode 100644 index 00000000..ed5dae83 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/borromean.h @@ -0,0 +1,24 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + + +#ifndef _SECP256K1_BORROMEAN_H_ +#define _SECP256K1_BORROMEAN_H_ + +#include "scalar.h" +#include "field.h" +#include "group.h" +#include "ecmult.h" +#include "ecmult_gen.h" + +int secp256k1_zkp_borromean_verify(const secp256k1_zkp_ecmult_context* ecmult_ctx, secp256k1_zkp_scalar *evalues, const unsigned char *e0, const secp256k1_zkp_scalar *s, + const secp256k1_zkp_gej *pubs, const size_t *rsizes, size_t nrings, const unsigned char *m, size_t mlen); + +int secp256k1_zkp_borromean_sign(const secp256k1_zkp_ecmult_context* ecmult_ctx, const secp256k1_zkp_ecmult_gen_context *ecmult_gen_ctx, + unsigned char *e0, secp256k1_zkp_scalar *s, const secp256k1_zkp_gej *pubs, const secp256k1_zkp_scalar *k, const secp256k1_zkp_scalar *sec, + const size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen); + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/borromean_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/borromean_impl.h new file mode 100644 index 00000000..ce3b8a29 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/borromean_impl.h @@ -0,0 +1,204 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + + +#ifndef _SECP256K1_BORROMEAN_IMPL_H_ +#define _SECP256K1_BORROMEAN_IMPL_H_ + +#include "scalar.h" +#include "field.h" +#include "group.h" +#include "hash.h" +#include "eckey.h" +#include "ecmult.h" +#include "ecmult_gen.h" +#include "borromean.h" + +#include +#include + +#ifdef WORDS_BIGENDIAN +#define BE32(x) (x) +#else +#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#endif + +SECP256K1_INLINE static void secp256k1_zkp_borromean_hash(unsigned char *hash, const unsigned char *m, size_t mlen, const unsigned char *e, size_t elen, + size_t ridx, size_t eidx) { + uint32_t ring; + uint32_t epos; + secp256k1_zkp_sha256 sha256_en; + secp256k1_zkp_sha256_initialize(&sha256_en); + ring = BE32((uint32_t)ridx); + epos = BE32((uint32_t)eidx); + secp256k1_zkp_sha256_write(&sha256_en, e, elen); + secp256k1_zkp_sha256_write(&sha256_en, m, mlen); + secp256k1_zkp_sha256_write(&sha256_en, (unsigned char*)&ring, 4); + secp256k1_zkp_sha256_write(&sha256_en, (unsigned char*)&epos, 4); + secp256k1_zkp_sha256_finalize(&sha256_en, hash); +} + +/** "Borromean" ring signature. + * Verifies nrings concurrent ring signatures all sharing a challenge value. + * Signature is one s value per pubkey and a hash. + * Verification equation: + * | m = H(P_{0..}||message) (Message must contain pubkeys or a pubkey commitment) + * | For each ring i: + * | | en = to_scalar(H(e0||m||i||0)) + * | | For each pubkey j: + * | | | r = s_i_j G + en * P_i_j + * | | | e = H(r||m||i||j) + * | | | en = to_scalar(e) + * | | r_i = r + * | return e_0 ==== H(r_{0..i}||m) + */ +int secp256k1_zkp_borromean_verify(const secp256k1_zkp_ecmult_context* ecmult_ctx, secp256k1_zkp_scalar *evalues, const unsigned char *e0, + const secp256k1_zkp_scalar *s, const secp256k1_zkp_gej *pubs, const size_t *rsizes, size_t nrings, const unsigned char *m, size_t mlen) { + secp256k1_zkp_gej rgej; + secp256k1_zkp_ge rge; + secp256k1_zkp_scalar ens; + secp256k1_zkp_sha256 sha256_e0; + unsigned char tmp[33]; + size_t i; + size_t j; + size_t count; + size_t size; + int overflow; + VERIFY_CHECK(ecmult_ctx != NULL); + VERIFY_CHECK(e0 != NULL); + VERIFY_CHECK(s != NULL); + VERIFY_CHECK(pubs != NULL); + VERIFY_CHECK(rsizes != NULL); + VERIFY_CHECK(nrings > 0); + VERIFY_CHECK(m != NULL); + count = 0; + secp256k1_zkp_sha256_initialize(&sha256_e0); + for (i = 0; i < nrings; i++) { + VERIFY_CHECK(INT_MAX - count > rsizes[i]); + secp256k1_zkp_borromean_hash(tmp, m, mlen, e0, 32, i, 0); + secp256k1_zkp_scalar_set_b32(&ens, tmp, &overflow); + for (j = 0; j < rsizes[i]; j++) { + if (overflow || secp256k1_zkp_scalar_is_zero(&s[count]) || secp256k1_zkp_scalar_is_zero(&ens) || secp256k1_zkp_gej_is_infinity(&pubs[count])) { + return 0; + } + if (evalues) { + /*If requested, save the challenges for proof rewind.*/ + evalues[count] = ens; + } + secp256k1_zkp_ecmult(ecmult_ctx, &rgej, &pubs[count], &ens, &s[count]); + if (secp256k1_zkp_gej_is_infinity(&rgej)) { + return 0; + } + /* OPT: loop can be hoisted and split to use batch inversion across all the rings; this would make it much faster. */ + secp256k1_zkp_ge_set_gej_var(&rge, &rgej); + secp256k1_zkp_eckey_pubkey_serialize(&rge, tmp, &size, 1); + if (j != rsizes[i] - 1) { + secp256k1_zkp_borromean_hash(tmp, m, mlen, tmp, 33, i, j + 1); + secp256k1_zkp_scalar_set_b32(&ens, tmp, &overflow); + } else { + secp256k1_zkp_sha256_write(&sha256_e0, tmp, size); + } + count++; + } + } + secp256k1_zkp_sha256_write(&sha256_e0, m, mlen); + secp256k1_zkp_sha256_finalize(&sha256_e0, tmp); + return memcmp(e0, tmp, 32) == 0; +} + +int secp256k1_zkp_borromean_sign(const secp256k1_zkp_ecmult_context* ecmult_ctx, const secp256k1_zkp_ecmult_gen_context *ecmult_gen_ctx, + unsigned char *e0, secp256k1_zkp_scalar *s, const secp256k1_zkp_gej *pubs, const secp256k1_zkp_scalar *k, const secp256k1_zkp_scalar *sec, + const size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen) { + secp256k1_zkp_gej rgej; + secp256k1_zkp_ge rge; + secp256k1_zkp_scalar ens; + secp256k1_zkp_sha256 sha256_e0; + unsigned char tmp[33]; + size_t i; + size_t j; + size_t count; + size_t size; + int overflow; + VERIFY_CHECK(ecmult_ctx != NULL); + VERIFY_CHECK(ecmult_gen_ctx != NULL); + VERIFY_CHECK(e0 != NULL); + VERIFY_CHECK(s != NULL); + VERIFY_CHECK(pubs != NULL); + VERIFY_CHECK(k != NULL); + VERIFY_CHECK(sec != NULL); + VERIFY_CHECK(rsizes != NULL); + VERIFY_CHECK(secidx != NULL); + VERIFY_CHECK(nrings > 0); + VERIFY_CHECK(m != NULL); + secp256k1_zkp_sha256_initialize(&sha256_e0); + count = 0; + for (i = 0; i < nrings; i++) { + VERIFY_CHECK(INT_MAX - count > rsizes[i]); + secp256k1_zkp_ecmult_gen(ecmult_gen_ctx, &rgej, &k[i]); + secp256k1_zkp_ge_set_gej(&rge, &rgej); + if (secp256k1_zkp_gej_is_infinity(&rgej)) { + return 0; + } + secp256k1_zkp_eckey_pubkey_serialize(&rge, tmp, &size, 1); + for (j = secidx[i] + 1; j < rsizes[i]; j++) { + secp256k1_zkp_borromean_hash(tmp, m, mlen, tmp, 33, i, j); + secp256k1_zkp_scalar_set_b32(&ens, tmp, &overflow); + if (overflow || secp256k1_zkp_scalar_is_zero(&ens)) { + return 0; + } + /** The signing algorithm as a whole is not memory uniform so there is likely a cache sidechannel that + * leaks which members are non-forgeries. That the forgeries themselves are variable time may leave + * an additional privacy impacting timing side-channel, but not a key loss one. + */ + secp256k1_zkp_ecmult(ecmult_ctx, &rgej, &pubs[count + j], &ens, &s[count + j]); + if (secp256k1_zkp_gej_is_infinity(&rgej)) { + return 0; + } + secp256k1_zkp_ge_set_gej_var(&rge, &rgej); + secp256k1_zkp_eckey_pubkey_serialize(&rge, tmp, &size, 1); + } + secp256k1_zkp_sha256_write(&sha256_e0, tmp, size); + count += rsizes[i]; + } + secp256k1_zkp_sha256_write(&sha256_e0, m, mlen); + secp256k1_zkp_sha256_finalize(&sha256_e0, e0); + count = 0; + for (i = 0; i < nrings; i++) { + VERIFY_CHECK(INT_MAX - count > rsizes[i]); + secp256k1_zkp_borromean_hash(tmp, m, mlen, e0, 32, i, 0); + secp256k1_zkp_scalar_set_b32(&ens, tmp, &overflow); + if (overflow || secp256k1_zkp_scalar_is_zero(&ens)) { + return 0; + } + for (j = 0; j < secidx[i]; j++) { + secp256k1_zkp_ecmult(ecmult_ctx, &rgej, &pubs[count + j], &ens, &s[count + j]); + if (secp256k1_zkp_gej_is_infinity(&rgej)) { + return 0; + } + secp256k1_zkp_ge_set_gej_var(&rge, &rgej); + secp256k1_zkp_eckey_pubkey_serialize(&rge, tmp, &size, 1); + secp256k1_zkp_borromean_hash(tmp, m, mlen, tmp, 33, i, j + 1); + secp256k1_zkp_scalar_set_b32(&ens, tmp, &overflow); + if (overflow || secp256k1_zkp_scalar_is_zero(&ens)) { + return 0; + } + } + secp256k1_zkp_scalar_mul(&s[count + j], &ens, &sec[i]); + secp256k1_zkp_scalar_negate(&s[count + j], &s[count + j]); + secp256k1_zkp_scalar_add(&s[count + j], &s[count + j], &k[i]); + if (secp256k1_zkp_scalar_is_zero(&s[count + j])) { + return 0; + } + count += rsizes[i]; + } + secp256k1_zkp_scalar_clear(&ens); + secp256k1_zkp_ge_clear(&rge); + secp256k1_zkp_gej_clear(&rgej); + memset(tmp, 0, 33); + return 1; +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/main_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/main_impl.h new file mode 100644 index 00000000..2d958e7c --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/main_impl.h @@ -0,0 +1,295 @@ +/********************************************************************** + * Copyright (c) 2014-2015 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_RANGEPROOF_MAIN +#define SECP256K1_MODULE_RANGEPROOF_MAIN + +#include "group.h" + +#include "modules/rangeproof/pedersen_impl.h" +#include "modules/rangeproof/borromean_impl.h" +#include "modules/rangeproof/rangeproof_impl.h" + +/** Alternative generator for secp256k1. + * This is the sha256 of 'g' after DER encoding (without compression), + * which happens to be a point on the curve. + * sage: G2 = EllipticCurve ([F (0), F (7)]).lift_x(F(int(hashlib.sha256('0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'.decode('hex')).hexdigest(),16))) + * sage: '%x %x' % G2.xy() + */ +static const secp256k1_zkp_generator secp256k1_zkp_generator_h_internal = {{ + 0x50, 0x92, 0x9b, 0x74, 0xc1, 0xa0, 0x49, 0x54, 0xb7, 0x8b, 0x4b, 0x60, 0x35, 0xe9, 0x7a, 0x5e, + 0x07, 0x8a, 0x5a, 0x0f, 0x28, 0xec, 0x96, 0xd5, 0x47, 0xbf, 0xee, 0x9a, 0xce, 0x80, 0x3a, 0xc0, + 0x31, 0xd3, 0xc6, 0x86, 0x39, 0x73, 0x92, 0x6e, 0x04, 0x9e, 0x63, 0x7c, 0xb1, 0xb5, 0xf4, 0x0a, + 0x36, 0xda, 0xc2, 0x8a, 0xf1, 0x76, 0x69, 0x68, 0xc3, 0x0c, 0x23, 0x13, 0xf3, 0xa3, 0x89, 0x04 +}}; + +const secp256k1_zkp_generator *secp256k1_zkp_generator_h = &secp256k1_zkp_generator_h_internal; + +static void secp256k1_zkp_pedersen_commitment_load(secp256k1_zkp_ge* ge, const secp256k1_zkp_pedersen_commitment* commit) { + secp256k1_zkp_fe fe; + secp256k1_zkp_fe_set_b32(&fe, &commit->data[1]); + secp256k1_zkp_ge_set_xquad(ge, &fe); + if (commit->data[0] & 1) { + secp256k1_zkp_ge_neg(ge, ge); + } +} + +static void secp256k1_zkp_pedersen_commitment_save(secp256k1_zkp_pedersen_commitment* commit, secp256k1_zkp_ge* ge) { + secp256k1_zkp_fe_normalize(&ge->x); + secp256k1_zkp_fe_get_b32(&commit->data[1], &ge->x); + commit->data[0] = 9 ^ secp256k1_zkp_fe_is_quad_var(&ge->y); +} + +int secp256k1_zkp_pedersen_commitment_parse(const secp256k1_zkp_context* ctx, secp256k1_zkp_pedersen_commitment* commit, const unsigned char *input) { + secp256k1_zkp_fe x; + secp256k1_zkp_ge ge; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(commit != NULL); + ARG_CHECK(input != NULL); + (void) ctx; + + if ((input[0] & 0xFE) != 8 || + !secp256k1_zkp_fe_set_b32(&x, &input[1]) || + !secp256k1_zkp_ge_set_xquad(&ge, &x)) { + return 0; + } + if (input[0] & 1) { + secp256k1_zkp_ge_neg(&ge, &ge); + } + secp256k1_zkp_pedersen_commitment_save(commit, &ge); + return 1; +} + +int secp256k1_zkp_pedersen_commitment_serialize(const secp256k1_zkp_context* ctx, unsigned char *output, const secp256k1_zkp_pedersen_commitment* commit) { + secp256k1_zkp_ge ge; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(commit != NULL); + + secp256k1_zkp_pedersen_commitment_load(&ge, commit); + + output[0] = 9 ^ secp256k1_zkp_fe_is_quad_var(&ge.y); + secp256k1_zkp_fe_normalize_var(&ge.x); + secp256k1_zkp_fe_get_b32(&output[1], &ge.x); + return 1; +} + +/* Generates a pedersen commitment: *commit = blind * G + value * G2. The blinding factor is 32 bytes.*/ +int secp256k1_zkp_pedersen_commit(const secp256k1_zkp_context* ctx, secp256k1_zkp_pedersen_commitment *commit, const unsigned char *blind, uint64_t value, const secp256k1_zkp_generator* gen) { + secp256k1_zkp_ge genp; + secp256k1_zkp_gej rj; + secp256k1_zkp_ge r; + secp256k1_zkp_scalar sec; + int overflow; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(commit != NULL); + ARG_CHECK(blind != NULL); + ARG_CHECK(gen != NULL); + secp256k1_zkp_generator_load(&genp, gen); + secp256k1_zkp_scalar_set_b32(&sec, blind, &overflow); + if (!overflow) { + secp256k1_zkp_pedersen_ecmult(&ctx->ecmult_gen_ctx, &rj, &sec, value, &genp); + if (!secp256k1_zkp_gej_is_infinity(&rj)) { + secp256k1_zkp_ge_set_gej(&r, &rj); + secp256k1_zkp_pedersen_commitment_save(commit, &r); + ret = 1; + } + secp256k1_zkp_gej_clear(&rj); + secp256k1_zkp_ge_clear(&r); + } + secp256k1_zkp_scalar_clear(&sec); + return ret; +} + +/** Takes a list of n pointers to 32 byte blinding values, the first negs of which are treated with positive sign and the rest + * negative, then calculates an additional blinding value that adds to zero. + */ +int secp256k1_zkp_pedersen_blind_sum(const secp256k1_zkp_context* ctx, unsigned char *blind_out, const unsigned char * const *blinds, size_t n, size_t npositive) { + secp256k1_zkp_scalar acc; + secp256k1_zkp_scalar x; + size_t i; + int overflow; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(blind_out != NULL); + ARG_CHECK(blinds != NULL); + ARG_CHECK(npositive <= n); + (void) ctx; + secp256k1_zkp_scalar_set_int(&acc, 0); + for (i = 0; i < n; i++) { + secp256k1_zkp_scalar_set_b32(&x, blinds[i], &overflow); + if (overflow) { + return 0; + } + if (i >= npositive) { + secp256k1_zkp_scalar_negate(&x, &x); + } + secp256k1_zkp_scalar_add(&acc, &acc, &x); + } + secp256k1_zkp_scalar_get_b32(blind_out, &acc); + secp256k1_zkp_scalar_clear(&acc); + secp256k1_zkp_scalar_clear(&x); + return 1; +} + +/* Takes two lists of commitments and sums the first set and subtracts the second and verifies that they sum to excess. */ +int secp256k1_zkp_pedersen_verify_tally(const secp256k1_zkp_context* ctx, const secp256k1_zkp_pedersen_commitment * const* commits, size_t pcnt, const secp256k1_zkp_pedersen_commitment * const* ncommits, size_t ncnt) { + secp256k1_zkp_gej accj; + secp256k1_zkp_ge add; + size_t i; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(!pcnt || (commits != NULL)); + ARG_CHECK(!ncnt || (ncommits != NULL)); + (void) ctx; + secp256k1_zkp_gej_set_infinity(&accj); + for (i = 0; i < ncnt; i++) { + secp256k1_zkp_pedersen_commitment_load(&add, ncommits[i]); + secp256k1_zkp_gej_add_ge_var(&accj, &accj, &add, NULL); + } + secp256k1_zkp_gej_neg(&accj, &accj); + for (i = 0; i < pcnt; i++) { + secp256k1_zkp_pedersen_commitment_load(&add, commits[i]); + secp256k1_zkp_gej_add_ge_var(&accj, &accj, &add, NULL); + } + return secp256k1_zkp_gej_is_infinity(&accj); +} + +int secp256k1_zkp_pedersen_blind_generator_blind_sum(const secp256k1_zkp_context* ctx, const uint64_t *value, const unsigned char* const* generator_blind, unsigned char* const* blinding_factor, size_t n_total, size_t n_inputs) { + secp256k1_zkp_scalar sum; + secp256k1_zkp_scalar tmp; + size_t i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(n_total == 0 || value != NULL); + ARG_CHECK(n_total == 0 || generator_blind != NULL); + ARG_CHECK(n_total == 0 || blinding_factor != NULL); + ARG_CHECK(n_total > n_inputs); + (void) ctx; + + if (n_total == 0) { + return 1; + } + + secp256k1_zkp_scalar_set_int(&sum, 0); + for (i = 0; i < n_total; i++) { + int overflow = 0; + secp256k1_zkp_scalar addend; + secp256k1_zkp_scalar_set_u64(&addend, value[i]); /* s = v */ + + secp256k1_zkp_scalar_set_b32(&tmp, generator_blind[i], &overflow); + if (overflow == 1) { + secp256k1_zkp_scalar_clear(&tmp); + secp256k1_zkp_scalar_clear(&addend); + secp256k1_zkp_scalar_clear(&sum); + return 0; + } + secp256k1_zkp_scalar_mul(&addend, &addend, &tmp); /* s = vr */ + + secp256k1_zkp_scalar_set_b32(&tmp, blinding_factor[i], &overflow); + if (overflow == 1) { + secp256k1_zkp_scalar_clear(&tmp); + secp256k1_zkp_scalar_clear(&addend); + secp256k1_zkp_scalar_clear(&sum); + return 0; + } + secp256k1_zkp_scalar_add(&addend, &addend, &tmp); /* s = vr + r' */ + secp256k1_zkp_scalar_cond_negate(&addend, i < n_inputs); /* s is negated if it's an input */ + secp256k1_zkp_scalar_add(&sum, &sum, &addend); /* sum += s */ + secp256k1_zkp_scalar_clear(&addend); + } + + /* Right now tmp has the last pedersen blinding factor. Subtract the sum from it. */ + secp256k1_zkp_scalar_negate(&sum, &sum); + secp256k1_zkp_scalar_add(&tmp, &tmp, &sum); + secp256k1_zkp_scalar_get_b32(blinding_factor[n_total - 1], &tmp); + + secp256k1_zkp_scalar_clear(&tmp); + secp256k1_zkp_scalar_clear(&sum); + return 1; +} + +int secp256k1_zkp_rangeproof_info(const secp256k1_zkp_context* ctx, int *exp, int *mantissa, + uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, size_t plen) { + size_t offset; + uint64_t scale; + ARG_CHECK(exp != NULL); + ARG_CHECK(mantissa != NULL); + ARG_CHECK(min_value != NULL); + ARG_CHECK(max_value != NULL); + ARG_CHECK(proof != NULL); + offset = 0; + scale = 1; + (void)ctx; + return secp256k1_zkp_rangeproof_getheader_impl(&offset, exp, mantissa, &scale, min_value, max_value, proof, plen); +} + +int secp256k1_zkp_rangeproof_rewind(const secp256k1_zkp_context* ctx, + unsigned char *blind_out, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce, + uint64_t *min_value, uint64_t *max_value, + const secp256k1_zkp_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_zkp_generator* gen) { + secp256k1_zkp_ge commitp; + secp256k1_zkp_ge genp; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(commit != NULL); + ARG_CHECK(proof != NULL); + ARG_CHECK(min_value != NULL); + ARG_CHECK(max_value != NULL); + ARG_CHECK(message_out != NULL || outlen == NULL); + ARG_CHECK(nonce != NULL); + ARG_CHECK(extra_commit != NULL || extra_commit_len == 0); + ARG_CHECK(gen != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(secp256k1_zkp_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + secp256k1_zkp_pedersen_commitment_load(&commitp, commit); + secp256k1_zkp_generator_load(&genp, gen); + return secp256k1_zkp_rangeproof_verify_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, + blind_out, value_out, message_out, outlen, nonce, min_value, max_value, &commitp, proof, plen, extra_commit, extra_commit_len, &genp); +} + +int secp256k1_zkp_rangeproof_verify(const secp256k1_zkp_context* ctx, uint64_t *min_value, uint64_t *max_value, + const secp256k1_zkp_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_zkp_generator* gen) { + secp256k1_zkp_ge commitp; + secp256k1_zkp_ge genp; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(commit != NULL); + ARG_CHECK(proof != NULL); + ARG_CHECK(min_value != NULL); + ARG_CHECK(max_value != NULL); + ARG_CHECK(extra_commit != NULL || extra_commit_len == 0); + ARG_CHECK(gen != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + secp256k1_zkp_pedersen_commitment_load(&commitp, commit); + secp256k1_zkp_generator_load(&genp, gen); + return secp256k1_zkp_rangeproof_verify_impl(&ctx->ecmult_ctx, NULL, + NULL, NULL, NULL, NULL, NULL, min_value, max_value, &commitp, proof, plen, extra_commit, extra_commit_len, &genp); +} + +int secp256k1_zkp_rangeproof_sign(const secp256k1_zkp_context* ctx, unsigned char *proof, size_t *plen, uint64_t min_value, + const secp256k1_zkp_pedersen_commitment *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value, + const unsigned char *message, size_t msg_len, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_zkp_generator* gen){ + secp256k1_zkp_ge commitp; + secp256k1_zkp_ge genp; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(proof != NULL); + ARG_CHECK(plen != NULL); + ARG_CHECK(commit != NULL); + ARG_CHECK(blind != NULL); + ARG_CHECK(nonce != NULL); + ARG_CHECK(message != NULL || msg_len == 0); + ARG_CHECK(extra_commit != NULL || extra_commit_len == 0); + ARG_CHECK(gen != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(secp256k1_zkp_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + secp256k1_zkp_pedersen_commitment_load(&commitp, commit); + secp256k1_zkp_generator_load(&genp, gen); + return secp256k1_zkp_rangeproof_sign_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, + proof, plen, min_value, &commitp, blind, nonce, exp, min_bits, value, message, msg_len, extra_commit, extra_commit_len, &genp); +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/pedersen.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/pedersen.h new file mode 100644 index 00000000..e43652b1 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/pedersen.h @@ -0,0 +1,22 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_PEDERSEN_H_ +#define _SECP256K1_PEDERSEN_H_ + +#include "ecmult_gen.h" +#include "group.h" +#include "scalar.h" + +#include + +/** Multiply a small number with the generator: r = gn*G2 */ +static void secp256k1_zkp_pedersen_ecmult_small(secp256k1_zkp_gej *r, uint64_t gn, const secp256k1_zkp_ge* genp); + +/* sec * G + value * G2. */ +static void secp256k1_zkp_pedersen_ecmult(const secp256k1_zkp_ecmult_gen_context *ecmult_gen_ctx, secp256k1_zkp_gej *rj, const secp256k1_zkp_scalar *sec, uint64_t value, const secp256k1_zkp_ge* genp); + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/pedersen_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/pedersen_impl.h new file mode 100644 index 00000000..2919841d --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/pedersen_impl.h @@ -0,0 +1,51 @@ +/*********************************************************************** + * Copyright (c) 2015 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php. * + ***********************************************************************/ + +#ifndef _SECP256K1_PEDERSEN_IMPL_H_ +#define _SECP256K1_PEDERSEN_IMPL_H_ + +#include + +#include "eckey.h" +#include "ecmult_const.h" +#include "ecmult_gen.h" +#include "group.h" +#include "field.h" +#include "scalar.h" +#include "util.h" + +static void secp256k1_zkp_pedersen_scalar_set_u64(secp256k1_zkp_scalar *sec, uint64_t value) { + unsigned char data[32]; + int i; + for (i = 0; i < 24; i++) { + data[i] = 0; + } + for (; i < 32; i++) { + data[i] = value >> 56; + value <<= 8; + } + secp256k1_zkp_scalar_set_b32(sec, data, NULL); + memset(data, 0, 32); +} + +static void secp256k1_zkp_pedersen_ecmult_small(secp256k1_zkp_gej *r, uint64_t gn, const secp256k1_zkp_ge* genp) { + secp256k1_zkp_scalar s; + secp256k1_zkp_pedersen_scalar_set_u64(&s, gn); + secp256k1_zkp_ecmult_const(r, genp, &s, 64); + secp256k1_zkp_scalar_clear(&s); +} + +/* sec * G + value * G2. */ +SECP256K1_INLINE static void secp256k1_zkp_pedersen_ecmult(const secp256k1_zkp_ecmult_gen_context *ecmult_gen_ctx, secp256k1_zkp_gej *rj, const secp256k1_zkp_scalar *sec, uint64_t value, const secp256k1_zkp_ge* genp) { + secp256k1_zkp_gej vj; + secp256k1_zkp_ecmult_gen(ecmult_gen_ctx, rj, sec); + secp256k1_zkp_pedersen_ecmult_small(&vj, value, genp); + /* FIXME: constant time. */ + secp256k1_zkp_gej_add_var(rj, rj, &vj, NULL); + secp256k1_zkp_gej_clear(&vj); +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/rangeproof.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/rangeproof.h new file mode 100644 index 00000000..1eee4a85 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/rangeproof.h @@ -0,0 +1,21 @@ +/********************************************************************** + * Copyright (c) 2015 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_RANGEPROOF_H_ +#define _SECP256K1_RANGEPROOF_H_ + +#include "scalar.h" +#include "group.h" +#include "ecmult.h" +#include "ecmult_gen.h" + +static int secp256k1_zkp_rangeproof_verify_impl(const secp256k1_zkp_ecmult_context* ecmult_ctx, + const secp256k1_zkp_ecmult_gen_context* ecmult_gen_ctx, + unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce, + uint64_t *min_value, uint64_t *max_value, const secp256k1_zkp_ge *commit, const unsigned char *proof, size_t plen, + const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_zkp_ge* genp); + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/rangeproof_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/rangeproof_impl.h new file mode 100644 index 00000000..95cd4b97 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/rangeproof_impl.h @@ -0,0 +1,685 @@ +/********************************************************************** + * Copyright (c) 2015 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_RANGEPROOF_IMPL_H_ +#define _SECP256K1_RANGEPROOF_IMPL_H_ + +#include "eckey.h" +#include "scalar.h" +#include "group.h" +#include "rangeproof.h" +#include "hash_impl.h" +#include "pedersen_impl.h" +#include "util.h" + +#include "modules/rangeproof/pedersen.h" +#include "modules/rangeproof/borromean.h" + +SECP256K1_INLINE static void secp256k1_zkp_rangeproof_pub_expand(secp256k1_zkp_gej *pubs, + int exp, size_t *rsizes, size_t rings, const secp256k1_zkp_ge* genp) { + secp256k1_zkp_gej base; + size_t i; + size_t j; + size_t npub; + VERIFY_CHECK(exp < 19); + if (exp < 0) { + exp = 0; + } + secp256k1_zkp_gej_set_ge(&base, genp); + secp256k1_zkp_gej_neg(&base, &base); + while (exp--) { + /* Multiplication by 10 */ + secp256k1_zkp_gej tmp; + secp256k1_zkp_gej_double_var(&tmp, &base, NULL); + secp256k1_zkp_gej_double_var(&base, &tmp, NULL); + secp256k1_zkp_gej_double_var(&base, &base, NULL); + secp256k1_zkp_gej_add_var(&base, &base, &tmp, NULL); + } + npub = 0; + for (i = 0; i < rings; i++) { + for (j = 1; j < rsizes[i]; j++) { + secp256k1_zkp_gej_add_var(&pubs[npub + j], &pubs[npub + j - 1], &base, NULL); + } + if (i < rings - 1) { + secp256k1_zkp_gej_double_var(&base, &base, NULL); + secp256k1_zkp_gej_double_var(&base, &base, NULL); + } + npub += rsizes[i]; + } +} + +SECP256K1_INLINE static void secp256k1_zkp_rangeproof_serialize_point(unsigned char* data, const secp256k1_zkp_ge *point) { + secp256k1_zkp_fe pointx; + pointx = point->x; + secp256k1_zkp_fe_normalize(&pointx); + data[0] = !secp256k1_zkp_fe_is_quad_var(&point->y); + secp256k1_zkp_fe_get_b32(data + 1, &pointx); +} + +SECP256K1_INLINE static int secp256k1_zkp_rangeproof_genrand(secp256k1_zkp_scalar *sec, secp256k1_zkp_scalar *s, unsigned char *message, + size_t *rsizes, size_t rings, const unsigned char *nonce, const secp256k1_zkp_ge *commit, const unsigned char *proof, size_t len, const secp256k1_zkp_ge* genp) { + unsigned char tmp[32]; + unsigned char rngseed[32 + 33 + 33 + 10]; + secp256k1_zkp_rfc6979_hmac_sha256 rng; + secp256k1_zkp_scalar acc; + int overflow; + int ret; + size_t i; + size_t j; + int b; + size_t npub; + VERIFY_CHECK(len <= 10); + memcpy(rngseed, nonce, 32); + secp256k1_zkp_rangeproof_serialize_point(rngseed + 32, commit); + secp256k1_zkp_rangeproof_serialize_point(rngseed + 32 + 33, genp); + memcpy(rngseed + 33 + 33 + 32, proof, len); + secp256k1_zkp_rfc6979_hmac_sha256_initialize(&rng, rngseed, 32 + 33 + 33 + len); + secp256k1_zkp_scalar_clear(&acc); + npub = 0; + ret = 1; + for (i = 0; i < rings; i++) { + if (i < rings - 1) { + secp256k1_zkp_rfc6979_hmac_sha256_generate(&rng, tmp, 32); + do { + secp256k1_zkp_rfc6979_hmac_sha256_generate(&rng, tmp, 32); + secp256k1_zkp_scalar_set_b32(&sec[i], tmp, &overflow); + } while (overflow || secp256k1_zkp_scalar_is_zero(&sec[i])); + secp256k1_zkp_scalar_add(&acc, &acc, &sec[i]); + } else { + secp256k1_zkp_scalar_negate(&acc, &acc); + sec[i] = acc; + } + for (j = 0; j < rsizes[i]; j++) { + secp256k1_zkp_rfc6979_hmac_sha256_generate(&rng, tmp, 32); + if (message) { + for (b = 0; b < 32; b++) { + tmp[b] ^= message[(i * 4 + j) * 32 + b]; + message[(i * 4 + j) * 32 + b] = tmp[b]; + } + } + secp256k1_zkp_scalar_set_b32(&s[npub], tmp, &overflow); + ret &= !(overflow || secp256k1_zkp_scalar_is_zero(&s[npub])); + npub++; + } + } + secp256k1_zkp_rfc6979_hmac_sha256_finalize(&rng); + secp256k1_zkp_scalar_clear(&acc); + memset(tmp, 0, 32); + return ret; +} + +SECP256K1_INLINE static int secp256k1_zkp_range_proveparams(uint64_t *v, size_t *rings, size_t *rsizes, size_t *npub, size_t *secidx, uint64_t *min_value, + int *mantissa, uint64_t *scale, int *exp, int *min_bits, uint64_t value) { + size_t i; + *rings = 1; + rsizes[0] = 1; + secidx[0] = 0; + *scale = 1; + *mantissa = 0; + *npub = 0; + if (*min_value == UINT64_MAX) { + /* If the minimum value is the maximal representable value, then we cannot code a range. */ + *exp = -1; + } + if (*exp >= 0) { + int max_bits; + uint64_t v2; + if ((*min_value && value > INT64_MAX) || (value && *min_value >= INT64_MAX)) { + /* If either value or min_value is >= 2^63-1 then the other must by zero to avoid overflowing the proven range. */ + return 0; + } + max_bits = *min_value ? secp256k1_zkp_clz64_var(*min_value) : 64; + if (*min_bits > max_bits) { + *min_bits = max_bits; + } + if (*min_bits > 61 || value > INT64_MAX) { + /** Ten is not a power of two, so dividing by ten and then representing in base-2 times ten + * expands the representable range. The verifier requires the proven range is within 0..2**64. + * For very large numbers (all over 2**63) we must change our exponent to compensate. + * Rather than handling it precisely, this just disables use of the exponent for big values. + */ + *exp = 0; + } + /* Mask off the least significant digits, as requested. */ + *v = value - *min_value; + /* If the user has asked for more bits of proof then there is room for in the exponent, reduce the exponent. */ + v2 = *min_bits ? (UINT64_MAX>>(64-*min_bits)) : 0; + for (i = 0; (int) i < *exp && (v2 <= UINT64_MAX / 10); i++) { + *v /= 10; + v2 *= 10; + } + *exp = i; + v2 = *v; + for (i = 0; (int) i < *exp; i++) { + v2 *= 10; + *scale *= 10; + } + /* If the masked number isn't precise, compute the public offset. */ + *min_value = value - v2; + /* How many bits do we need to represent our value? */ + *mantissa = *v ? 64 - secp256k1_zkp_clz64_var(*v) : 1; + if (*min_bits > *mantissa) { + /* If the user asked for more precision, give it to them. */ + *mantissa = *min_bits; + } + /* Digits in radix-4, except for the last digit if our mantissa length is odd. */ + *rings = (*mantissa + 1) >> 1; + for (i = 0; i < *rings; i++) { + rsizes[i] = ((i < *rings - 1) | (!(*mantissa&1))) ? 4 : 2; + *npub += rsizes[i]; + secidx[i] = (*v >> (i*2)) & 3; + } + VERIFY_CHECK(*mantissa>0); + VERIFY_CHECK((*v & ~(UINT64_MAX>>(64-*mantissa))) == 0); /* Did this get all the bits? */ + } else { + /* A proof for an exact value. */ + *exp = 0; + *min_value = value; + *v = 0; + *npub = 2; + } + VERIFY_CHECK(*v * *scale + *min_value == value); + VERIFY_CHECK(*rings > 0); + VERIFY_CHECK(*rings <= 32); + VERIFY_CHECK(*npub <= 128); + return 1; +} + +/* strawman interface, writes proof in proof, a buffer of plen, proves with respect to min_value the range for commit which has the provided blinding factor and value. */ +SECP256K1_INLINE static int secp256k1_zkp_rangeproof_sign_impl(const secp256k1_zkp_ecmult_context* ecmult_ctx, + const secp256k1_zkp_ecmult_gen_context* ecmult_gen_ctx, + unsigned char *proof, size_t *plen, uint64_t min_value, + const secp256k1_zkp_ge *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value, + const unsigned char *message, size_t msg_len, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_zkp_ge* genp){ + secp256k1_zkp_gej pubs[128]; /* Candidate digits for our proof, most inferred. */ + secp256k1_zkp_scalar s[128]; /* Signatures in our proof, most forged. */ + secp256k1_zkp_scalar sec[32]; /* Blinding factors for the correct digits. */ + secp256k1_zkp_scalar k[32]; /* Nonces for our non-forged signatures. */ + secp256k1_zkp_scalar stmp; + secp256k1_zkp_sha256 sha256_m; + unsigned char prep[4096]; + unsigned char tmp[33]; + unsigned char *signs; /* Location of sign flags in the proof. */ + uint64_t v; + uint64_t scale; /* scale = 10^exp. */ + int mantissa; /* Number of bits proven in the blinded value. */ + size_t rings; /* How many digits will our proof cover. */ + size_t rsizes[32]; /* How many possible values there are for each place. */ + size_t secidx[32]; /* Which digit is the correct one. */ + size_t len; /* Number of bytes used so far. */ + size_t i; + int overflow; + size_t npub; + len = 0; + if (*plen < 65 || min_value > value || min_bits > 64 || min_bits < 0 || exp < -1 || exp > 18) { + return 0; + } + if (!secp256k1_zkp_range_proveparams(&v, &rings, rsizes, &npub, secidx, &min_value, &mantissa, &scale, &exp, &min_bits, value)) { + return 0; + } + proof[len] = (rsizes[0] > 1 ? (64 | exp) : 0) | (min_value ? 32 : 0); + len++; + if (rsizes[0] > 1) { + VERIFY_CHECK(mantissa > 0 && mantissa <= 64); + proof[len] = mantissa - 1; + len++; + } + if (min_value) { + for (i = 0; i < 8; i++) { + proof[len + i] = (min_value >> ((7-i) * 8)) & 255; + } + len += 8; + } + /* Do we have enough room in the proof for the message? Each ring gives us 128 bytes, but the + * final ring is used to encode the blinding factor and the value, so we can't use that. (Well, + * technically there are 64 bytes available if we avoided the other data, but this is difficult + * because it's not always in the same place. */ + if (msg_len > 0 && msg_len > 128 * (rings - 1)) { + return 0; + } + /* Do we have enough room for the proof? */ + if (*plen - len < 32 * (npub + rings - 1) + 32 + ((rings+6) >> 3)) { + return 0; + } + secp256k1_zkp_sha256_initialize(&sha256_m); + secp256k1_zkp_rangeproof_serialize_point(tmp, commit); + secp256k1_zkp_sha256_write(&sha256_m, tmp, 33); + secp256k1_zkp_rangeproof_serialize_point(tmp, genp); + secp256k1_zkp_sha256_write(&sha256_m, tmp, 33); + secp256k1_zkp_sha256_write(&sha256_m, proof, len); + + memset(prep, 0, 4096); + if (message != NULL) { + memcpy(prep, message, msg_len); + } + /* Note, the data corresponding to the blinding factors must be zero. */ + if (rsizes[rings - 1] > 1) { + size_t idx; + /* Value encoding sidechannel. */ + idx = rsizes[rings - 1] - 1; + idx -= secidx[rings - 1] == idx; + idx = ((rings - 1) * 4 + idx) * 32; + for (i = 0; i < 8; i++) { + prep[8 + i + idx] = prep[16 + i + idx] = prep[24 + i + idx] = (v >> (56 - i * 8)) & 255; + prep[i + idx] = 0; + } + prep[idx] = 128; + } + if (!secp256k1_zkp_rangeproof_genrand(sec, s, prep, rsizes, rings, nonce, commit, proof, len, genp)) { + return 0; + } + memset(prep, 0, 4096); + for (i = 0; i < rings; i++) { + /* Sign will overwrite the non-forged signature, move that random value into the nonce. */ + k[i] = s[i * 4 + secidx[i]]; + secp256k1_zkp_scalar_clear(&s[i * 4 + secidx[i]]); + } + /** Genrand returns the last blinding factor as -sum(rest), + * adding in the blinding factor for our commitment, results in the blinding factor for + * the commitment to the last digit that the verifier can compute for itself by subtracting + * all the digits in the proof from the commitment. This lets the prover skip sending the + * blinded value for one digit. + */ + secp256k1_zkp_scalar_set_b32(&stmp, blind, &overflow); + secp256k1_zkp_scalar_add(&sec[rings - 1], &sec[rings - 1], &stmp); + if (overflow || secp256k1_zkp_scalar_is_zero(&sec[rings - 1])) { + return 0; + } + signs = &proof[len]; + /* We need one sign bit for each blinded value we send. */ + for (i = 0; i < (rings + 6) >> 3; i++) { + signs[i] = 0; + len++; + } + npub = 0; + for (i = 0; i < rings; i++) { + /*OPT: Use the precomputed gen2 basis?*/ + secp256k1_zkp_pedersen_ecmult(ecmult_gen_ctx, &pubs[npub], &sec[i], ((uint64_t)secidx[i] * scale) << (i*2), genp); + if (secp256k1_zkp_gej_is_infinity(&pubs[npub])) { + return 0; + } + if (i < rings - 1) { + unsigned char tmpc[33]; + secp256k1_zkp_ge c; + unsigned char quadness; + /*OPT: split loop and batch invert.*/ + /*OPT: do not compute full pubs[npub] in ge form; we only need x */ + secp256k1_zkp_ge_set_gej_var(&c, &pubs[npub]); + secp256k1_zkp_rangeproof_serialize_point(tmpc, &c); + quadness = tmpc[0]; + secp256k1_zkp_sha256_write(&sha256_m, tmpc, 33); + signs[i>>3] |= quadness << (i&7); + memcpy(&proof[len], tmpc + 1, 32); + len += 32; + } + npub += rsizes[i]; + } + secp256k1_zkp_rangeproof_pub_expand(pubs, exp, rsizes, rings, genp); + if (extra_commit != NULL) { + secp256k1_zkp_sha256_write(&sha256_m, extra_commit, extra_commit_len); + } + secp256k1_zkp_sha256_finalize(&sha256_m, tmp); + if (!secp256k1_zkp_borromean_sign(ecmult_ctx, ecmult_gen_ctx, &proof[len], s, pubs, k, sec, rsizes, secidx, rings, tmp, 32)) { + return 0; + } + len += 32; + for (i = 0; i < npub; i++) { + secp256k1_zkp_scalar_get_b32(&proof[len],&s[i]); + len += 32; + } + VERIFY_CHECK(len <= *plen); + *plen = len; + memset(prep, 0, 4096); + return 1; +} + +/* Computes blinding factor x given k, s, and the challenge e. */ +SECP256K1_INLINE static void secp256k1_zkp_rangeproof_recover_x(secp256k1_zkp_scalar *x, const secp256k1_zkp_scalar *k, const secp256k1_zkp_scalar *e, + const secp256k1_zkp_scalar *s) { + secp256k1_zkp_scalar stmp; + secp256k1_zkp_scalar_negate(x, s); + secp256k1_zkp_scalar_add(x, x, k); + secp256k1_zkp_scalar_inverse(&stmp, e); + secp256k1_zkp_scalar_mul(x, x, &stmp); +} + +/* Computes ring's nonce given the blinding factor x, the challenge e, and the signature s. */ +SECP256K1_INLINE static void secp256k1_zkp_rangeproof_recover_k(secp256k1_zkp_scalar *k, const secp256k1_zkp_scalar *x, const secp256k1_zkp_scalar *e, + const secp256k1_zkp_scalar *s) { + secp256k1_zkp_scalar stmp; + secp256k1_zkp_scalar_mul(&stmp, x, e); + secp256k1_zkp_scalar_add(k, s, &stmp); +} + +SECP256K1_INLINE static void secp256k1_zkp_rangeproof_ch32xor(unsigned char *x, const unsigned char *y) { + int i; + for (i = 0; i < 32; i++) { + x[i] ^= y[i]; + } +} + +SECP256K1_INLINE static int secp256k1_zkp_rangeproof_rewind_inner(secp256k1_zkp_scalar *blind, uint64_t *v, + unsigned char *m, size_t *mlen, secp256k1_zkp_scalar *ev, secp256k1_zkp_scalar *s, + size_t *rsizes, size_t rings, const unsigned char *nonce, const secp256k1_zkp_ge *commit, const unsigned char *proof, size_t len, const secp256k1_zkp_ge *genp) { + secp256k1_zkp_scalar s_orig[128]; + secp256k1_zkp_scalar sec[32]; + secp256k1_zkp_scalar stmp; + unsigned char prep[4096]; + unsigned char tmp[32]; + uint64_t value; + size_t offset; + size_t i; + size_t j; + int b; + size_t skip1; + size_t skip2; + size_t npub; + npub = ((rings - 1) << 2) + rsizes[rings-1]; + VERIFY_CHECK(npub <= 128); + VERIFY_CHECK(npub >= 1); + memset(prep, 0, 4096); + /* Reconstruct the provers random values. */ + secp256k1_zkp_rangeproof_genrand(sec, s_orig, prep, rsizes, rings, nonce, commit, proof, len, genp); + *v = UINT64_MAX; + secp256k1_zkp_scalar_clear(blind); + if (rings == 1 && rsizes[0] == 1) { + /* With only a single proof, we can only recover the blinding factor. */ + secp256k1_zkp_rangeproof_recover_x(blind, &s_orig[0], &ev[0], &s[0]); + if (v) { + *v = 0; + } + if (mlen) { + *mlen = 0; + } + return 1; + } + npub = (rings - 1) << 2; + for (j = 0; j < 2; j++) { + size_t idx; + /* Look for a value encoding in the last ring. */ + idx = npub + rsizes[rings - 1] - 1 - j; + secp256k1_zkp_scalar_get_b32(tmp, &s[idx]); + secp256k1_zkp_rangeproof_ch32xor(tmp, &prep[idx * 32]); + if ((tmp[0] & 128) && (memcmp(&tmp[16], &tmp[24], 8) == 0) && (memcmp(&tmp[8], &tmp[16], 8) == 0)) { + value = 0; + for (i = 0; i < 8; i++) { + value = (value << 8) + tmp[24 + i]; + } + if (v) { + *v = value; + } + memcpy(&prep[idx * 32], tmp, 32); + break; + } + } + if (j > 1) { + /* Couldn't extract a value. */ + if (mlen) { + *mlen = 0; + } + return 0; + } + skip1 = rsizes[rings - 1] - 1 - j; + skip2 = ((value >> ((rings - 1) << 1)) & 3); + if (skip1 == skip2) { + /*Value is in wrong position.*/ + if (mlen) { + *mlen = 0; + } + return 0; + } + skip1 += (rings - 1) << 2; + skip2 += (rings - 1) << 2; + /* Like in the rsize[] == 1 case, Having figured out which s is the one which was not forged, we can recover the blinding factor. */ + secp256k1_zkp_rangeproof_recover_x(&stmp, &s_orig[skip2], &ev[skip2], &s[skip2]); + secp256k1_zkp_scalar_negate(&sec[rings - 1], &sec[rings - 1]); + secp256k1_zkp_scalar_add(blind, &stmp, &sec[rings - 1]); + if (!m || !mlen || *mlen == 0) { + if (mlen) { + *mlen = 0; + } + /* FIXME: cleanup in early out/failure cases. */ + return 1; + } + offset = 0; + npub = 0; + for (i = 0; i < rings; i++) { + size_t idx; + idx = (value >> (i << 1)) & 3; + for (j = 0; j < rsizes[i]; j++) { + if (npub == skip1 || npub == skip2) { + npub++; + continue; + } + if (idx == j) { + /** For the non-forged signatures the signature is calculated instead of random, instead we recover the prover's nonces. + * this could just as well recover the blinding factors and messages could be put there as is done for recovering the + * blinding factor in the last ring, but it takes an inversion to recover x so it's faster to put the message data in k. + */ + secp256k1_zkp_rangeproof_recover_k(&stmp, &sec[i], &ev[npub], &s[npub]); + } else { + stmp = s[npub]; + } + secp256k1_zkp_scalar_get_b32(tmp, &stmp); + secp256k1_zkp_rangeproof_ch32xor(tmp, &prep[npub * 32]); + for (b = 0; b < 32 && offset < *mlen; b++) { + m[offset] = tmp[b]; + offset++; + } + npub++; + } + } + *mlen = offset; + memset(prep, 0, 4096); + for (i = 0; i < 128; i++) { + secp256k1_zkp_scalar_clear(&s_orig[i]); + } + for (i = 0; i < 32; i++) { + secp256k1_zkp_scalar_clear(&sec[i]); + } + secp256k1_zkp_scalar_clear(&stmp); + return 1; +} + +SECP256K1_INLINE static int secp256k1_zkp_rangeproof_getheader_impl(size_t *offset, int *exp, int *mantissa, uint64_t *scale, + uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, size_t plen) { + int i; + int has_nz_range; + int has_min; + if (plen < 65 || ((proof[*offset] & 128) != 0)) { + return 0; + } + has_nz_range = proof[*offset] & 64; + has_min = proof[*offset] & 32; + *exp = -1; + *mantissa = 0; + if (has_nz_range) { + *exp = proof[*offset] & 31; + *offset += 1; + if (*exp > 18) { + return 0; + } + *mantissa = proof[*offset] + 1; + if (*mantissa > 64) { + return 0; + } + *max_value = UINT64_MAX>>(64-*mantissa); + } else { + *max_value = 0; + } + *offset += 1; + *scale = 1; + for (i = 0; i < *exp; i++) { + if (*max_value > UINT64_MAX / 10) { + return 0; + } + *max_value *= 10; + *scale *= 10; + } + *min_value = 0; + if (has_min) { + if(plen - *offset < 8) { + return 0; + } + /*FIXME: Compact minvalue encoding?*/ + for (i = 0; i < 8; i++) { + *min_value = (*min_value << 8) | proof[*offset + i]; + } + *offset += 8; + } + if (*max_value > UINT64_MAX - *min_value) { + return 0; + } + *max_value += *min_value; + return 1; +} + +/* Verifies range proof (len plen) for commit, the min/max values proven are put in the min/max arguments; returns 0 on failure 1 on success.*/ +SECP256K1_INLINE static int secp256k1_zkp_rangeproof_verify_impl(const secp256k1_zkp_ecmult_context* ecmult_ctx, + const secp256k1_zkp_ecmult_gen_context* ecmult_gen_ctx, + unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce, + uint64_t *min_value, uint64_t *max_value, const secp256k1_zkp_ge *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_zkp_ge* genp) { + secp256k1_zkp_gej accj; + secp256k1_zkp_gej pubs[128]; + secp256k1_zkp_ge c; + secp256k1_zkp_scalar s[128]; + secp256k1_zkp_scalar evalues[128]; /* Challenges, only used during proof rewind. */ + secp256k1_zkp_sha256 sha256_m; + size_t rsizes[32]; + int ret; + size_t i; + int exp; + int mantissa; + size_t offset; + size_t rings; + int overflow; + size_t npub; + int offset_post_header; + uint64_t scale; + unsigned char signs[31]; + unsigned char m[33]; + const unsigned char *e0; + offset = 0; + if (!secp256k1_zkp_rangeproof_getheader_impl(&offset, &exp, &mantissa, &scale, min_value, max_value, proof, plen)) { + return 0; + } + offset_post_header = offset; + rings = 1; + rsizes[0] = 1; + npub = 1; + if (mantissa != 0) { + rings = (mantissa >> 1); + for (i = 0; i < rings; i++) { + rsizes[i] = 4; + } + npub = (mantissa >> 1) << 2; + if (mantissa & 1) { + rsizes[rings] = 2; + npub += rsizes[rings]; + rings++; + } + } + VERIFY_CHECK(rings <= 32); + if (plen - offset < 32 * (npub + rings - 1) + 32 + ((rings+6) >> 3)) { + return 0; + } + secp256k1_zkp_sha256_initialize(&sha256_m); + secp256k1_zkp_rangeproof_serialize_point(m, commit); + secp256k1_zkp_sha256_write(&sha256_m, m, 33); + secp256k1_zkp_rangeproof_serialize_point(m, genp); + secp256k1_zkp_sha256_write(&sha256_m, m, 33); + secp256k1_zkp_sha256_write(&sha256_m, proof, offset); + for(i = 0; i < rings - 1; i++) { + signs[i] = (proof[offset + ( i>> 3)] & (1 << (i & 7))) != 0; + } + offset += (rings + 6) >> 3; + if ((rings - 1) & 7) { + /* Number of coded blinded points is not a multiple of 8, force extra sign bits to 0 to reject mutation. */ + if ((proof[offset - 1] >> ((rings - 1) & 7)) != 0) { + return 0; + } + } + npub = 0; + secp256k1_zkp_gej_set_infinity(&accj); + if (*min_value) { + secp256k1_zkp_pedersen_ecmult_small(&accj, *min_value, genp); + } + for(i = 0; i < rings - 1; i++) { + secp256k1_zkp_fe fe; + if (!secp256k1_zkp_fe_set_b32(&fe, &proof[offset]) || + !secp256k1_zkp_ge_set_xquad(&c, &fe)) { + return 0; + } + if (signs[i]) { + secp256k1_zkp_ge_neg(&c, &c); + } + /* Not using secp256k1_zkp_rangeproof_serialize_point as we almost have it + * serialized form already. */ + secp256k1_zkp_sha256_write(&sha256_m, &signs[i], 1); + secp256k1_zkp_sha256_write(&sha256_m, &proof[offset], 32); + secp256k1_zkp_gej_set_ge(&pubs[npub], &c); + secp256k1_zkp_gej_add_ge_var(&accj, &accj, &c, NULL); + offset += 32; + npub += rsizes[i]; + } + secp256k1_zkp_gej_neg(&accj, &accj); + secp256k1_zkp_gej_add_ge_var(&pubs[npub], &accj, commit, NULL); + if (secp256k1_zkp_gej_is_infinity(&pubs[npub])) { + return 0; + } + secp256k1_zkp_rangeproof_pub_expand(pubs, exp, rsizes, rings, genp); + npub += rsizes[rings - 1]; + e0 = &proof[offset]; + offset += 32; + for (i = 0; i < npub; i++) { + secp256k1_zkp_scalar_set_b32(&s[i], &proof[offset], &overflow); + if (overflow) { + return 0; + } + offset += 32; + } + if (offset != plen) { + /*Extra data found, reject.*/ + return 0; + } + if (extra_commit != NULL) { + secp256k1_zkp_sha256_write(&sha256_m, extra_commit, extra_commit_len); + } + secp256k1_zkp_sha256_finalize(&sha256_m, m); + ret = secp256k1_zkp_borromean_verify(ecmult_ctx, nonce ? evalues : NULL, e0, s, pubs, rsizes, rings, m, 32); + if (ret && nonce) { + /* Given the nonce, try rewinding the witness to recover its initial state. */ + secp256k1_zkp_scalar blind; + uint64_t vv; + if (!ecmult_gen_ctx) { + return 0; + } + if (!secp256k1_zkp_rangeproof_rewind_inner(&blind, &vv, message_out, outlen, evalues, s, rsizes, rings, nonce, commit, proof, offset_post_header, genp)) { + return 0; + } + /* Unwind apparently successful, see if the commitment can be reconstructed. */ + /* FIXME: should check vv is in the mantissa's range. */ + vv = (vv * scale) + *min_value; + secp256k1_zkp_pedersen_ecmult(ecmult_gen_ctx, &accj, &blind, vv, genp); + if (secp256k1_zkp_gej_is_infinity(&accj)) { + return 0; + } + secp256k1_zkp_gej_neg(&accj, &accj); + secp256k1_zkp_gej_add_ge_var(&accj, &accj, commit, NULL); + if (!secp256k1_zkp_gej_is_infinity(&accj)) { + return 0; + } + if (blindout) { + secp256k1_zkp_scalar_get_b32(blindout, &blind); + } + if (value_out) { + *value_out = vv; + } + } + return ret; +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/tests_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/tests_impl.h new file mode 100644 index 00000000..e89b13b2 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/rangeproof/tests_impl.h @@ -0,0 +1,709 @@ +/********************************************************************** + * Copyright (c) 2015 Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_RANGEPROOF_TESTS +#define SECP256K1_MODULE_RANGEPROOF_TESTS + +#include + +#include "group.h" +#include "scalar.h" +#include "testrand.h" +#include "util.h" + +#include "include/secp256k1_rangeproof.h" + +static void test_pedersen_api(const secp256k1_zkp_context *none, const secp256k1_zkp_context *sign, const secp256k1_zkp_context *vrfy, const int32_t *ecount) { + secp256k1_zkp_pedersen_commitment commit; + const secp256k1_zkp_pedersen_commitment *commit_ptr = &commit; + unsigned char blind[32]; + unsigned char blind_out[32]; + const unsigned char *blind_ptr = blind; + unsigned char *blind_out_ptr = blind_out; + uint64_t val = secp256k1_zkp_rand32(); + + secp256k1_zkp_rand256(blind); + CHECK(secp256k1_zkp_pedersen_commit(none, &commit, blind, val, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 1); + CHECK(secp256k1_zkp_pedersen_commit(vrfy, &commit, blind, val, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 2); + CHECK(secp256k1_zkp_pedersen_commit(sign, &commit, blind, val, secp256k1_zkp_generator_h) != 0); + CHECK(*ecount == 2); + + CHECK(secp256k1_zkp_pedersen_commit(sign, NULL, blind, val, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 3); + CHECK(secp256k1_zkp_pedersen_commit(sign, &commit, NULL, val, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 4); + CHECK(secp256k1_zkp_pedersen_commit(sign, &commit, blind, val, NULL) == 0); + CHECK(*ecount == 5); + + CHECK(secp256k1_zkp_pedersen_blind_sum(none, blind_out, &blind_ptr, 1, 1) != 0); + CHECK(*ecount == 5); + CHECK(secp256k1_zkp_pedersen_blind_sum(none, NULL, &blind_ptr, 1, 1) == 0); + CHECK(*ecount == 6); + CHECK(secp256k1_zkp_pedersen_blind_sum(none, blind_out, NULL, 1, 1) == 0); + CHECK(*ecount == 7); + CHECK(secp256k1_zkp_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 1) == 0); + CHECK(*ecount == 8); + CHECK(secp256k1_zkp_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 0) != 0); + CHECK(*ecount == 8); + + CHECK(secp256k1_zkp_pedersen_commit(sign, &commit, blind, val, secp256k1_zkp_generator_h) != 0); + CHECK(secp256k1_zkp_pedersen_verify_tally(none, &commit_ptr, 1, &commit_ptr, 1) != 0); + CHECK(secp256k1_zkp_pedersen_verify_tally(none, NULL, 0, &commit_ptr, 1) == 0); + CHECK(secp256k1_zkp_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 0) == 0); + CHECK(secp256k1_zkp_pedersen_verify_tally(none, NULL, 0, NULL, 0) != 0); + CHECK(*ecount == 8); + CHECK(secp256k1_zkp_pedersen_verify_tally(none, NULL, 1, &commit_ptr, 1) == 0); + CHECK(*ecount == 9); + CHECK(secp256k1_zkp_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 1) == 0); + CHECK(*ecount == 10); + + CHECK(secp256k1_zkp_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 0) != 0); + CHECK(*ecount == 10); + CHECK(secp256k1_zkp_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0); + CHECK(*ecount == 11); + CHECK(secp256k1_zkp_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0); + CHECK(*ecount == 12); + CHECK(secp256k1_zkp_pedersen_blind_generator_blind_sum(none, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0); + CHECK(*ecount == 13); + CHECK(secp256k1_zkp_pedersen_blind_generator_blind_sum(none, &val, NULL, &blind_out_ptr, 1, 0) == 0); + CHECK(*ecount == 14); + CHECK(secp256k1_zkp_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0); + CHECK(*ecount == 15); +} + +static void test_rangeproof_api(const secp256k1_zkp_context *none, const secp256k1_zkp_context *sign, const secp256k1_zkp_context *vrfy, const secp256k1_zkp_context *both, const int32_t *ecount) { + unsigned char proof[5134]; + unsigned char blind[32]; + secp256k1_zkp_pedersen_commitment commit; + uint64_t vmin = secp256k1_zkp_rand32(); + uint64_t val = vmin + secp256k1_zkp_rand32(); + size_t len = sizeof(proof); + /* we'll switch to dylan thomas for this one */ + const unsigned char message[68] = "My tears are like the quiet drift / Of petals from some magic rose;"; + size_t mlen = sizeof(message); + const unsigned char ext_commit[72] = "And all my grief flows from the rift / Of unremembered skies and snows."; + size_t ext_commit_len = sizeof(ext_commit); + + secp256k1_zkp_rand256(blind); + CHECK(secp256k1_zkp_pedersen_commit(ctx, &commit, blind, val, secp256k1_zkp_generator_h)); + + CHECK(secp256k1_zkp_rangeproof_sign(none, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 1); + CHECK(secp256k1_zkp_rangeproof_sign(sign, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 2); + CHECK(secp256k1_zkp_rangeproof_sign(vrfy, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 3); + CHECK(secp256k1_zkp_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) != 0); + CHECK(*ecount == 3); + + CHECK(secp256k1_zkp_rangeproof_sign(both, NULL, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 4); + CHECK(secp256k1_zkp_rangeproof_sign(both, proof, NULL, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 5); + CHECK(secp256k1_zkp_rangeproof_sign(both, proof, &len, vmin, NULL, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 6); + CHECK(secp256k1_zkp_rangeproof_sign(both, proof, &len, vmin, &commit, NULL, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 7); + CHECK(secp256k1_zkp_rangeproof_sign(both, proof, &len, vmin, &commit, blind, NULL, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 8); + CHECK(secp256k1_zkp_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, vmin - 1, message, mlen, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 8); + CHECK(secp256k1_zkp_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, mlen, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 9); + CHECK(secp256k1_zkp_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) != 0); + CHECK(*ecount == 9); + CHECK(secp256k1_zkp_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 10); + CHECK(secp256k1_zkp_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, 0, secp256k1_zkp_generator_h) != 0); + CHECK(*ecount == 10); + CHECK(secp256k1_zkp_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, 0, NULL) == 0); + CHECK(*ecount == 11); + + CHECK(secp256k1_zkp_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) != 0); + { + int exp; + int mantissa; + uint64_t min_value; + uint64_t max_value; + CHECK(secp256k1_zkp_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, proof, len) != 0); + CHECK(exp == 0); + CHECK(((uint64_t) 1 << mantissa) > val - vmin); + CHECK(((uint64_t) 1 << (mantissa - 1)) <= val - vmin); + CHECK(min_value == vmin); + CHECK(max_value >= val); + + CHECK(secp256k1_zkp_rangeproof_info(none, NULL, &mantissa, &min_value, &max_value, proof, len) == 0); + CHECK(*ecount == 12); + CHECK(secp256k1_zkp_rangeproof_info(none, &exp, NULL, &min_value, &max_value, proof, len) == 0); + CHECK(*ecount == 13); + CHECK(secp256k1_zkp_rangeproof_info(none, &exp, &mantissa, NULL, &max_value, proof, len) == 0); + CHECK(*ecount == 14); + CHECK(secp256k1_zkp_rangeproof_info(none, &exp, &mantissa, &min_value, NULL, proof, len) == 0); + CHECK(*ecount == 15); + CHECK(secp256k1_zkp_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, NULL, len) == 0); + CHECK(*ecount == 16); + CHECK(secp256k1_zkp_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, proof, 0) == 0); + CHECK(*ecount == 16); + } + { + uint64_t min_value; + uint64_t max_value; + CHECK(secp256k1_zkp_rangeproof_verify(none, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 17); + CHECK(secp256k1_zkp_rangeproof_verify(sign, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 18); + CHECK(secp256k1_zkp_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) != 0); + CHECK(*ecount == 18); + + CHECK(secp256k1_zkp_rangeproof_verify(vrfy, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 19); + CHECK(secp256k1_zkp_rangeproof_verify(vrfy, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 20); + CHECK(secp256k1_zkp_rangeproof_verify(vrfy, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 21); + CHECK(secp256k1_zkp_rangeproof_verify(vrfy, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 22); + CHECK(secp256k1_zkp_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, 0, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 22); + CHECK(secp256k1_zkp_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 23); + CHECK(secp256k1_zkp_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, 0, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 23); + CHECK(secp256k1_zkp_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL) == 0); + CHECK(*ecount == 24); + } + { + unsigned char blind_out[32]; + unsigned char message_out[68]; + uint64_t value_out; + uint64_t min_value; + uint64_t max_value; + size_t message_len = sizeof(message_out); + + CHECK(secp256k1_zkp_rangeproof_rewind(none, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 25); + CHECK(secp256k1_zkp_rangeproof_rewind(sign, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 26); + CHECK(secp256k1_zkp_rangeproof_rewind(vrfy, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 27); + CHECK(secp256k1_zkp_rangeproof_rewind(both, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) != 0); + CHECK(*ecount == 27); + + CHECK(min_value == vmin); + CHECK(max_value >= val); + CHECK(value_out == val); + CHECK(message_len == sizeof(message_out)); + CHECK(memcmp(message, message_out, sizeof(message_out)) == 0); + + CHECK(secp256k1_zkp_rangeproof_rewind(both, NULL, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) != 0); + CHECK(*ecount == 27); /* blindout may be NULL */ + CHECK(secp256k1_zkp_rangeproof_rewind(both, blind_out, NULL, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) != 0); + CHECK(*ecount == 27); /* valueout may be NULL */ + CHECK(secp256k1_zkp_rangeproof_rewind(both, blind_out, &value_out, NULL, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 28); + CHECK(secp256k1_zkp_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) != 0); + CHECK(*ecount == 28); + CHECK(secp256k1_zkp_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, NULL, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 29); + CHECK(secp256k1_zkp_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 30); + CHECK(secp256k1_zkp_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 31); + CHECK(secp256k1_zkp_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 32); + CHECK(secp256k1_zkp_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 33); + CHECK(secp256k1_zkp_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, 0, ext_commit, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 33); + CHECK(secp256k1_zkp_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 34); + CHECK(secp256k1_zkp_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, secp256k1_zkp_generator_h) == 0); + CHECK(*ecount == 34); + CHECK(secp256k1_zkp_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL) == 0); + CHECK(*ecount == 35); + } +} + +static void test_api(void) { + secp256k1_zkp_context *none = secp256k1_zkp_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_zkp_context *sign = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_zkp_context *vrfy = secp256k1_zkp_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_zkp_context *both = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + int32_t ecount; + int i; + + secp256k1_zkp_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); + + for (i = 0; i < count; i++) { + ecount = 0; + test_pedersen_api(none, sign, vrfy, &ecount); + ecount = 0; + test_rangeproof_api(none, sign, vrfy, both, &ecount); + } + + secp256k1_zkp_context_destroy(none); + secp256k1_zkp_context_destroy(sign); + secp256k1_zkp_context_destroy(vrfy); + secp256k1_zkp_context_destroy(both); +} + +static void test_pedersen(void) { + secp256k1_zkp_pedersen_commitment commits[19]; + const secp256k1_zkp_pedersen_commitment *cptr[19]; + unsigned char blinds[32*19]; + const unsigned char *bptr[19]; + secp256k1_zkp_scalar s; + uint64_t values[19]; + int64_t totalv; + int i; + int inputs; + int outputs; + int total; + inputs = (secp256k1_zkp_rand32() & 7) + 1; + outputs = (secp256k1_zkp_rand32() & 7) + 2; + total = inputs + outputs; + for (i = 0; i < 19; i++) { + cptr[i] = &commits[i]; + bptr[i] = &blinds[i * 32]; + } + totalv = 0; + for (i = 0; i < inputs; i++) { + values[i] = secp256k1_zkp_rands64(0, INT64_MAX - totalv); + totalv += values[i]; + } + for (i = 0; i < outputs - 1; i++) { + values[i + inputs] = secp256k1_zkp_rands64(0, totalv); + totalv -= values[i + inputs]; + } + values[total - 1] = totalv; + + for (i = 0; i < total - 1; i++) { + random_scalar_order(&s); + secp256k1_zkp_scalar_get_b32(&blinds[i * 32], &s); + } + CHECK(secp256k1_zkp_pedersen_blind_sum(ctx, &blinds[(total - 1) * 32], bptr, total - 1, inputs)); + for (i = 0; i < total; i++) { + CHECK(secp256k1_zkp_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_zkp_generator_h)); + } + CHECK(secp256k1_zkp_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs)); + CHECK(secp256k1_zkp_pedersen_verify_tally(ctx, &cptr[inputs], outputs, cptr, inputs)); + if (inputs > 0 && values[0] > 0) { + CHECK(!secp256k1_zkp_pedersen_verify_tally(ctx, cptr, inputs - 1, &cptr[inputs], outputs)); + } + random_scalar_order(&s); + for (i = 0; i < 4; i++) { + secp256k1_zkp_scalar_get_b32(&blinds[i * 32], &s); + } + values[0] = INT64_MAX; + values[1] = 0; + values[2] = 1; + for (i = 0; i < 3; i++) { + CHECK(secp256k1_zkp_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_zkp_generator_h)); + } + CHECK(secp256k1_zkp_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1)); + CHECK(secp256k1_zkp_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1)); +} + +static void test_borromean(void) { + unsigned char e0[32]; + secp256k1_zkp_scalar s[64]; + secp256k1_zkp_gej pubs[64]; + secp256k1_zkp_scalar k[8]; + secp256k1_zkp_scalar sec[8]; + secp256k1_zkp_ge ge; + secp256k1_zkp_scalar one; + unsigned char m[32]; + size_t rsizes[8]; + size_t secidx[8]; + size_t nrings; + size_t i; + size_t j; + int c; + secp256k1_zkp_rand256_test(m); + nrings = 1 + (secp256k1_zkp_rand32()&7); + c = 0; + secp256k1_zkp_scalar_set_int(&one, 1); + if (secp256k1_zkp_rand32()&1) { + secp256k1_zkp_scalar_negate(&one, &one); + } + for (i = 0; i < nrings; i++) { + rsizes[i] = 1 + (secp256k1_zkp_rand32()&7); + secidx[i] = secp256k1_zkp_rand32() % rsizes[i]; + random_scalar_order(&sec[i]); + random_scalar_order(&k[i]); + if(secp256k1_zkp_rand32()&7) { + sec[i] = one; + } + if(secp256k1_zkp_rand32()&7) { + k[i] = one; + } + for (j = 0; j < rsizes[i]; j++) { + random_scalar_order(&s[c + j]); + if(secp256k1_zkp_rand32()&7) { + s[i] = one; + } + if (j == secidx[i]) { + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &pubs[c + j], &sec[i]); + } else { + random_group_element_test(&ge); + random_group_element_jacobian_test(&pubs[c + j],&ge); + } + } + c += rsizes[i]; + } + CHECK(secp256k1_zkp_borromean_sign(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, e0, s, pubs, k, sec, rsizes, secidx, nrings, m, 32)); + CHECK(secp256k1_zkp_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32)); + i = secp256k1_zkp_rand32() % c; + secp256k1_zkp_scalar_negate(&s[i],&s[i]); + CHECK(!secp256k1_zkp_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32)); + secp256k1_zkp_scalar_negate(&s[i],&s[i]); + secp256k1_zkp_scalar_set_int(&one, 1); + for(j = 0; j < 4; j++) { + i = secp256k1_zkp_rand32() % c; + if (secp256k1_zkp_rand32() & 1) { + secp256k1_zkp_gej_double_var(&pubs[i],&pubs[i], NULL); + } else { + secp256k1_zkp_scalar_add(&s[i],&s[i],&one); + } + CHECK(!secp256k1_zkp_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32)); + } +} + +static void test_rangeproof(void) { + const uint64_t testvs[11] = {0, 1, 5, 11, 65535, 65537, INT32_MAX, UINT32_MAX, INT64_MAX - 1, INT64_MAX, UINT64_MAX}; + secp256k1_zkp_pedersen_commitment commit; + secp256k1_zkp_pedersen_commitment commit2; + unsigned char proof[5134 + 1]; /* One additional byte to test if trailing bytes are rejected */ + unsigned char blind[32]; + unsigned char blindout[32]; + unsigned char message[4096]; + size_t mlen; + uint64_t v; + uint64_t vout; + uint64_t vmin; + uint64_t minv; + uint64_t maxv; + size_t len; + size_t i; + size_t j; + size_t k; + /* Short message is a Simone de Beauvoir quote */ + const unsigned char message_short[120] = "When I see my own likeness in the depths of someone else's consciousness, I always experience a moment of panic."; + /* Long message is 0xA5 with a bunch of this quote in the middle */ + unsigned char message_long[3968]; + memset(message_long, 0xa5, sizeof(message_long)); + for (i = 1200; i < 3600; i += 120) { + memcpy(&message_long[i], message_short, sizeof(message_short)); + } + + secp256k1_zkp_rand256(blind); + for (i = 0; i < 11; i++) { + v = testvs[i]; + CHECK(secp256k1_zkp_pedersen_commit(ctx, &commit, blind, v, secp256k1_zkp_generator_h)); + for (vmin = 0; vmin < (i<9 && i > 0 ? 2 : 1); vmin++) { + const unsigned char *input_message = NULL; + size_t input_message_len = 0; + /* vmin is always either 0 or 1; if it is 1, then we have no room for a message. + * If it's 0, we use "minimum encoding" and only have room for a small message when + * `testvs[i]` is >= 4; for a large message when it's >= 2^32. */ + if (vmin == 0 && i > 2) { + input_message = message_short; + input_message_len = sizeof(message_short); + } + if (vmin == 0 && i > 7) { + input_message = message_long; + input_message_len = sizeof(message_long); + } + len = 5134; + CHECK(secp256k1_zkp_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, 0, 0, v, input_message, input_message_len, NULL, 0, secp256k1_zkp_generator_h)); + CHECK(len <= 5134); + mlen = 4096; + CHECK(secp256k1_zkp_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_zkp_generator_h)); + if (input_message != NULL) { + CHECK(memcmp(message, input_message, input_message_len) == 0); + } + for (j = input_message_len; j < mlen; j++) { + CHECK(message[j] == 0); + } + CHECK(mlen <= 4096); + CHECK(memcmp(blindout, blind, 32) == 0); + CHECK(vout == v); + CHECK(minv <= v); + CHECK(maxv >= v); + len = 5134; + CHECK(secp256k1_zkp_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v, NULL, 0, NULL, 0, secp256k1_zkp_generator_h)); + CHECK(len <= 73); + CHECK(secp256k1_zkp_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_zkp_generator_h)); + CHECK(memcmp(blindout, blind, 32) == 0); + CHECK(vout == v); + CHECK(minv == v); + CHECK(maxv == v); + + /* Check with a committed message */ + len = 5134; + CHECK(secp256k1_zkp_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v, NULL, 0, message_short, sizeof(message_short), secp256k1_zkp_generator_h)); + CHECK(len <= 73); + CHECK(!secp256k1_zkp_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_zkp_generator_h)); + CHECK(!secp256k1_zkp_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, message_long, sizeof(message_long), secp256k1_zkp_generator_h)); + CHECK(secp256k1_zkp_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, message_short, sizeof(message_short), secp256k1_zkp_generator_h)); + CHECK(memcmp(blindout, blind, 32) == 0); + CHECK(vout == v); + CHECK(minv == v); + CHECK(maxv == v); + } + } + secp256k1_zkp_rand256(blind); + v = INT64_MAX - 1; + CHECK(secp256k1_zkp_pedersen_commit(ctx, &commit, blind, v, secp256k1_zkp_generator_h)); + for (i = 0; i < 19; i++) { + len = 5134; + CHECK(secp256k1_zkp_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, i, 0, v, NULL, 0, NULL, 0, secp256k1_zkp_generator_h)); + CHECK(secp256k1_zkp_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_zkp_generator_h)); + CHECK(len <= 5134); + CHECK(minv <= v); + CHECK(maxv >= v); + /* Make sure it fails when validating with a committed message */ + CHECK(!secp256k1_zkp_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, message_short, sizeof(message_short), secp256k1_zkp_generator_h)); + } + secp256k1_zkp_rand256(blind); + { + /*Malleability test.*/ + v = secp256k1_zkp_rands64(0, 255); + CHECK(secp256k1_zkp_pedersen_commit(ctx, &commit, blind, v, secp256k1_zkp_generator_h)); + len = 5134; + CHECK(secp256k1_zkp_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, 0, 3, v, NULL, 0, NULL, 0, secp256k1_zkp_generator_h)); + CHECK(len <= 5134); + /* Test if trailing bytes are rejected. */ + proof[len] = v; + CHECK(!secp256k1_zkp_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len + 1, NULL, 0, secp256k1_zkp_generator_h)); + for (i = 0; i < len*8; i++) { + proof[i >> 3] ^= 1 << (i & 7); + CHECK(!secp256k1_zkp_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_zkp_generator_h)); + proof[i >> 3] ^= 1 << (i & 7); + } + CHECK(secp256k1_zkp_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_zkp_generator_h)); + CHECK(minv <= v); + CHECK(maxv >= v); + } + memcpy(&commit2, &commit, sizeof(commit)); + for (i = 0; i < (size_t) 2*count; i++) { + int exp; + int min_bits; + v = secp256k1_zkp_rands64(0, UINT64_MAX >> (secp256k1_zkp_rand32()&63)); + vmin = 0; + if ((v < INT64_MAX) && (secp256k1_zkp_rand32()&1)) { + vmin = secp256k1_zkp_rands64(0, v); + } + secp256k1_zkp_rand256(blind); + CHECK(secp256k1_zkp_pedersen_commit(ctx, &commit, blind, v, secp256k1_zkp_generator_h)); + len = 5134; + exp = (int)secp256k1_zkp_rands64(0,18)-(int)secp256k1_zkp_rands64(0,18); + if (exp < 0) { + exp = -exp; + } + min_bits = (int)secp256k1_zkp_rands64(0,64)-(int)secp256k1_zkp_rands64(0,64); + if (min_bits < 0) { + min_bits = -min_bits; + } + CHECK(secp256k1_zkp_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, exp, min_bits, v, NULL, 0, NULL, 0, secp256k1_zkp_generator_h)); + CHECK(len <= 5134); + mlen = 4096; + CHECK(secp256k1_zkp_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_zkp_generator_h)); + for (j = 0; j < mlen; j++) { + CHECK(message[j] == 0); + } + CHECK(mlen <= 4096); + CHECK(memcmp(blindout, blind, 32) == 0); + + CHECK(minv <= v); + CHECK(maxv >= v); + CHECK(secp256k1_zkp_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_zkp_generator_h)); + memcpy(&commit2, &commit, sizeof(commit)); + } + for (j = 0; j < 5; j++) { + for (i = 0; i < 96; i++) { + secp256k1_zkp_rand256(&proof[i * 32]); + } + for (k = 0; k < 128; k++) { + len = k; + CHECK(!secp256k1_zkp_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, NULL, 0, secp256k1_zkp_generator_h)); + } + len = secp256k1_zkp_rands64(0, 3072); + CHECK(!secp256k1_zkp_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, NULL, 0, secp256k1_zkp_generator_h)); + } +} + +#define MAX_N_GENS 30 +void test_multiple_generators(void) { + const size_t n_inputs = (secp256k1_zkp_rand32() % (MAX_N_GENS / 2)) + 1; + const size_t n_outputs = (secp256k1_zkp_rand32() % (MAX_N_GENS / 2)) + 1; + const size_t n_generators = n_inputs + n_outputs; + unsigned char *generator_blind[MAX_N_GENS]; + unsigned char *pedersen_blind[MAX_N_GENS]; + secp256k1_zkp_generator generator[MAX_N_GENS]; + secp256k1_zkp_pedersen_commitment commit[MAX_N_GENS]; + const secp256k1_zkp_pedersen_commitment *commit_ptr[MAX_N_GENS]; + size_t i; + int64_t total_value; + uint64_t value[MAX_N_GENS]; + + secp256k1_zkp_scalar s; + + unsigned char generator_seed[32]; + random_scalar_order(&s); + secp256k1_zkp_scalar_get_b32(generator_seed, &s); + /* Create all the needed generators */ + for (i = 0; i < n_generators; i++) { + generator_blind[i] = (unsigned char*) malloc(32); + pedersen_blind[i] = (unsigned char*) malloc(32); + + random_scalar_order(&s); + secp256k1_zkp_scalar_get_b32(generator_blind[i], &s); + random_scalar_order(&s); + secp256k1_zkp_scalar_get_b32(pedersen_blind[i], &s); + + CHECK(secp256k1_zkp_generator_generate_blinded(ctx, &generator[i], generator_seed, generator_blind[i])); + + commit_ptr[i] = &commit[i]; + } + + /* Compute all the values -- can be positive or negative */ + total_value = 0; + for (i = 0; i < n_outputs; i++) { + value[n_inputs + i] = secp256k1_zkp_rands64(0, INT64_MAX - total_value); + total_value += value[n_inputs + i]; + } + for (i = 0; i < n_inputs - 1; i++) { + value[i] = secp256k1_zkp_rands64(0, total_value); + total_value -= value[i]; + } + value[i] = total_value; + + /* Correct for blinding factors and do the commitments */ + CHECK(secp256k1_zkp_pedersen_blind_generator_blind_sum(ctx, value, (const unsigned char * const *) generator_blind, pedersen_blind, n_generators, n_inputs)); + for (i = 0; i < n_generators; i++) { + CHECK(secp256k1_zkp_pedersen_commit(ctx, &commit[i], pedersen_blind[i], value[i], &generator[i])); + } + + /* Verify */ + CHECK(secp256k1_zkp_pedersen_verify_tally(ctx, &commit_ptr[0], n_inputs, &commit_ptr[n_inputs], n_outputs)); + + /* Cleanup */ + for (i = 0; i < n_generators; i++) { + free(generator_blind[i]); + free(pedersen_blind[i]); + } +} + +void test_rangeproof_fixed_vectors(void) { + const unsigned char vector_1[] = { + 0x62, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x02, 0x2a, 0x5c, 0x42, 0x0e, 0x1d, + 0x51, 0xe1, 0xb7, 0xf3, 0x69, 0x04, 0xb5, 0xbb, 0x9b, 0x41, 0x66, 0x14, 0xf3, 0x64, 0x42, 0x26, + 0xe3, 0xa7, 0x6a, 0x06, 0xbb, 0xa8, 0x5a, 0x49, 0x6f, 0x19, 0x76, 0xfb, 0xe5, 0x75, 0x77, 0x88, + 0xab, 0xa9, 0x66, 0x44, 0x80, 0xea, 0x29, 0x95, 0x7f, 0xdf, 0x72, 0x4a, 0xaf, 0x02, 0xbe, 0xdd, + 0x5d, 0x15, 0xd8, 0xae, 0xff, 0x74, 0xc9, 0x8c, 0x1a, 0x67, 0x0e, 0xb2, 0x57, 0x22, 0x99, 0xc3, + 0x21, 0x46, 0x6f, 0x15, 0x58, 0x0e, 0xdb, 0xe6, 0x6e, 0xc4, 0x0d, 0xfe, 0x6f, 0x04, 0x6b, 0x0d, + 0x18, 0x3d, 0x78, 0x40, 0x98, 0x56, 0x4e, 0xe4, 0x4a, 0x74, 0x90, 0xa7, 0xac, 0x9c, 0x16, 0xe0, + 0x3e, 0x81, 0xaf, 0x0f, 0xe3, 0x4f, 0x34, 0x99, 0x52, 0xf7, 0xa7, 0xf6, 0xd3, 0x83, 0xa0, 0x17, + 0x4b, 0x2d, 0xa7, 0xd4, 0xfd, 0xf7, 0x84, 0x45, 0xc4, 0x11, 0x71, 0x3d, 0x4a, 0x22, 0x34, 0x09, + 0x9c, 0xa7, 0xe5, 0xc8, 0xba, 0x04, 0xbf, 0xfd, 0x25, 0x11, 0x7d, 0xa4, 0x43, 0x45, 0xc7, 0x62, + 0x9e, 0x7b, 0x80, 0xf6, 0x09, 0xbb, 0x1b, 0x2e, 0xf3, 0xcd, 0x23, 0xe0, 0xed, 0x81, 0x43, 0x42, + 0xbe, 0xc4, 0x9f, 0x58, 0x8a, 0x0d, 0x66, 0x79, 0x09, 0x70, 0x11, 0x68, 0x3d, 0x87, 0x38, 0x1c, + 0x3c, 0x85, 0x52, 0x5b, 0x62, 0xf7, 0x3e, 0x7e, 0x87, 0xa2, 0x99, 0x24, 0xd0, 0x7d, 0x18, 0x63, + 0x56, 0x48, 0xa4, 0x3a, 0xfe, 0x65, 0xfa, 0xa4, 0xd0, 0x67, 0xaa, 0x98, 0x65, 0x4d, 0xe4, 0x22, + 0x75, 0x45, 0x52, 0xe8, 0x41, 0xc7, 0xed, 0x38, 0xeb, 0xf5, 0x02, 0x90, 0xc9, 0x45, 0xa3, 0xb0, + 0x4d, 0x03, 0xd7, 0xab, 0x43, 0xe4, 0x21, 0xfc, 0x83, 0xd6, 0x12, 0x1d, 0x76, 0xb1, 0x3c, 0x67, + 0x63, 0x1f, 0x52, 0x9d, 0xc3, 0x23, 0x5c, 0x4e, 0xa6, 0x8d, 0x01, 0x4a, 0xba, 0x9a, 0xf4, 0x16, + 0x5b, 0x67, 0xc8, 0xe1, 0xd2, 0x42, 0x6d, 0xdf, 0xcd, 0x08, 0x6a, 0x73, 0x41, 0x6a, 0xc2, 0x84, + 0xc6, 0x31, 0xbe, 0x57, 0xcb, 0x0e, 0xde, 0xbf, 0x71, 0xd5, 0x8a, 0xf7, 0x24, 0xb2, 0xa7, 0x89, + 0x96, 0x62, 0x4f, 0xd9, 0xf7, 0xc3, 0xde, 0x4c, 0xab, 0x13, 0x72, 0xb4, 0xb3, 0x35, 0x04, 0x82, + 0xa8, 0x75, 0x1d, 0xde, 0x46, 0xa8, 0x0d, 0xb8, 0x23, 0x44, 0x00, 0x44, 0xfa, 0x53, 0x6c, 0x2d, + 0xce, 0xd3, 0xa6, 0x80, 0xa1, 0x20, 0xca, 0xd1, 0x63, 0xbb, 0xbe, 0x39, 0x5f, 0x9d, 0x27, 0x69, + 0xb3, 0x33, 0x1f, 0xdb, 0xda, 0x67, 0x05, 0x37, 0xbe, 0x65, 0xe9, 0x7e, 0xa9, 0xc3, 0xff, 0x37, + 0x8a, 0xb4, 0x2d, 0xfe, 0xf2, 0x16, 0x85, 0xc7, 0x0f, 0xd9, 0xbe, 0x14, 0xd1, 0x80, 0x14, 0x9f, + 0x58, 0x56, 0x98, 0x41, 0xf6, 0x26, 0xf7, 0xa2, 0x71, 0x66, 0xb4, 0x7a, 0x9c, 0x12, 0x73, 0xd3, + 0xdf, 0x77, 0x2b, 0x49, 0xe5, 0xca, 0x50, 0x57, 0x44, 0x6e, 0x3f, 0x58, 0x56, 0xbc, 0x21, 0x70, + 0x4f, 0xc6, 0xaa, 0x12, 0xff, 0x7c, 0xa7, 0x3d, 0xed, 0x46, 0xc1, 0x40, 0xe6, 0x58, 0x09, 0x2a, + 0xda, 0xb3, 0x76, 0xab, 0x44, 0xb5, 0x4e, 0xb3, 0x12, 0xe0, 0x26, 0x8a, 0x52, 0xac, 0x49, 0x1d, + 0xe7, 0x06, 0x53, 0x3a, 0x01, 0x35, 0x21, 0x2e, 0x86, 0x48, 0xc5, 0x75, 0xc1, 0xa2, 0x7d, 0x22, + 0x53, 0xf6, 0x3f, 0x41, 0xc5, 0xb3, 0x08, 0x7d, 0xa3, 0x67, 0xc0, 0xbb, 0xb6, 0x8d, 0xf0, 0xd3, + 0x01, 0x72, 0xd3, 0x63, 0x82, 0x01, 0x1a, 0xe7, 0x1d, 0x22, 0xfa, 0x95, 0x33, 0xf6, 0xf2, 0xde, + 0xa2, 0x53, 0x86, 0x55, 0x5a, 0xb4, 0x2e, 0x75, 0x75, 0xc6, 0xd5, 0x93, 0x9c, 0x57, 0xa9, 0x1f, + 0xb9, 0x3e, 0xe8, 0x1c, 0xbf, 0xac, 0x1c, 0x54, 0x6f, 0xf5, 0xab, 0x41, 0xee, 0xb3, 0x0e, 0xd0, + 0x76, 0xc4, 0x1a, 0x45, 0xcd, 0xf1, 0xd6, 0xcc, 0xb0, 0x83, 0x70, 0x73, 0xbc, 0x88, 0x74, 0xa0, + 0x5b, 0xe7, 0x98, 0x10, 0x36, 0xbf, 0xec, 0x23, 0x1c, 0xc2, 0xb5, 0xba, 0x4b, 0x9d, 0x7f, 0x8c, + 0x8a, 0xe2, 0xda, 0x18, 0xdd, 0xab, 0x27, 0x8a, 0x15, 0xeb, 0xb0, 0xd4, 0x3a, 0x8b, 0x77, 0x00, + 0xc7, 0xbb, 0xcc, 0xfa, 0xba, 0xa4, 0x6a, 0x17, 0x5c, 0xf8, 0x51, 0x5d, 0x8d, 0x16, 0xcd, 0xa7, + 0x0e, 0x71, 0x97, 0x98, 0x78, 0x5a, 0x41, 0xb3, 0xf0, 0x1f, 0x87, 0x2d, 0x65, 0xcd, 0x29, 0x49, + 0xd2, 0x87, 0x2c, 0x91, 0xa9, 0x5f, 0xcc, 0xa9, 0xd8, 0xbb, 0x53, 0x18, 0xe7, 0xd6, 0xec, 0x65, + 0xa6, 0x45, 0xf6, 0xce, 0xcf, 0x48, 0xf6, 0x1e, 0x3d, 0xd2, 0xcf, 0xcb, 0x3a, 0xcd, 0xbb, 0x92, + 0x29, 0x24, 0x16, 0x7f, 0x8a, 0xa8, 0x5c, 0x0c, 0x45, 0x71, 0x33 + }; + const unsigned char commit_1[] = { + 0x08, + 0xf5, 0x1e, 0x0d, 0xc5, 0x86, 0x78, 0x51, 0xa9, 0x00, 0x00, 0xef, 0x4d, 0xe2, 0x94, 0x60, 0x89, + 0x83, 0x04, 0xb4, 0x0e, 0x90, 0x10, 0x05, 0x1c, 0x7f, 0xd7, 0x33, 0x92, 0x1f, 0xe7, 0x74, 0x59 + }; + uint64_t min_value_1; + uint64_t max_value_1; + secp256k1_zkp_pedersen_commitment pc; + + CHECK(secp256k1_zkp_pedersen_commitment_parse(ctx, &pc, commit_1)); + + CHECK(secp256k1_zkp_rangeproof_verify( + ctx, + &min_value_1, &max_value_1, + &pc, + vector_1, sizeof(vector_1), + NULL, 0, + secp256k1_zkp_generator_h + )); +} + +void test_pedersen_commitment_fixed_vector(void) { + const unsigned char two_g[33] = { + 0x09, + 0xc6, 0x04, 0x7f, 0x94, 0x41, 0xed, 0x7d, 0x6d, 0x30, 0x45, 0x40, 0x6e, 0x95, 0xc0, 0x7c, 0xd8, + 0x5c, 0x77, 0x8e, 0x4b, 0x8c, 0xef, 0x3c, 0xa7, 0xab, 0xac, 0x09, 0xb9, 0x5c, 0x70, 0x9e, 0xe5 + }; + unsigned char result[33]; + secp256k1_zkp_pedersen_commitment parse; + + CHECK(secp256k1_zkp_pedersen_commitment_parse(ctx, &parse, two_g)); + CHECK(secp256k1_zkp_pedersen_commitment_serialize(ctx, result, &parse)); + CHECK(memcmp(two_g, result, 33) == 0); + + result[0] = 0x08; + CHECK(secp256k1_zkp_pedersen_commitment_parse(ctx, &parse, result)); + result[0] = 0x0c; + CHECK(!secp256k1_zkp_pedersen_commitment_parse(ctx, &parse, result)); +} + +void run_rangeproof_tests(void) { + int i; + test_api(); + test_rangeproof_fixed_vectors(); + test_pedersen_commitment_fixed_vector(); + for (i = 0; i < 10*count; i++) { + test_pedersen(); + } + for (i = 0; i < 10*count; i++) { + test_borromean(); + } + test_rangeproof(); + test_multiple_generators(); +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/recovery/Makefile.am.include b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/recovery/Makefile.am.include new file mode 100644 index 00000000..1ca33e0f --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/recovery/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_zkp_recovery.h +noinst_HEADERS += src/modules/recovery/main_impl.h +noinst_HEADERS += src/modules/recovery/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_recover +bench_recover_SOURCES = src/bench_recover.c +bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/recovery/main_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/recovery/main_impl.h new file mode 100755 index 00000000..f6c16dd6 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/recovery/main_impl.h @@ -0,0 +1,193 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H +#define SECP256K1_MODULE_RECOVERY_MAIN_H + +#include "include/secp256k1_recovery.h" + +static void secp256k1_zkp_ecdsa_recoverable_signature_load(const secp256k1_zkp_context* ctx, secp256k1_zkp_scalar* r, secp256k1_zkp_scalar* s, int* recid, const secp256k1_zkp_ecdsa_recoverable_signature* sig) { + (void)ctx; + if (sizeof(secp256k1_zkp_scalar) == 32) { + /* When the secp256k1_zkp_scalar type is exactly 32 byte, use its + * representation inside secp256k1_zkp_ecdsa_signature, as conversion is very fast. + * Note that secp256k1_zkp_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + secp256k1_zkp_scalar_set_b32(r, &sig->data[0], NULL); + secp256k1_zkp_scalar_set_b32(s, &sig->data[32], NULL); + } + *recid = sig->data[64]; +} + +static void secp256k1_zkp_ecdsa_recoverable_signature_save(secp256k1_zkp_ecdsa_recoverable_signature* sig, const secp256k1_zkp_scalar* r, const secp256k1_zkp_scalar* s, int recid) { + if (sizeof(secp256k1_zkp_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + secp256k1_zkp_scalar_get_b32(&sig->data[0], r); + secp256k1_zkp_scalar_get_b32(&sig->data[32], s); + } + sig->data[64] = recid; +} + +int secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(const secp256k1_zkp_context* ctx, secp256k1_zkp_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) { + secp256k1_zkp_scalar r, s; + int ret = 1; + int overflow = 0; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + ARG_CHECK(recid >= 0 && recid <= 3); + + secp256k1_zkp_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_zkp_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + secp256k1_zkp_ecdsa_recoverable_signature_save(sig, &r, &s, recid); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int secp256k1_zkp_ecdsa_recoverable_signature_serialize_compact(const secp256k1_zkp_context* ctx, unsigned char *output64, int *recid, const secp256k1_zkp_ecdsa_recoverable_signature* sig) { + secp256k1_zkp_scalar r, s; + + (void)ctx; + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(recid != NULL); + + secp256k1_zkp_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig); + secp256k1_zkp_scalar_get_b32(&output64[0], &r); + secp256k1_zkp_scalar_get_b32(&output64[32], &s); + return 1; +} + +int secp256k1_zkp_ecdsa_recoverable_signature_convert(const secp256k1_zkp_context* ctx, secp256k1_zkp_ecdsa_signature* sig, const secp256k1_zkp_ecdsa_recoverable_signature* sigin) { + secp256k1_zkp_scalar r, s; + int recid; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_zkp_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin); + secp256k1_zkp_ecdsa_signature_save(sig, &r, &s); + return 1; +} + +static int secp256k1_zkp_ecdsa_sig_recover(const secp256k1_zkp_ecmult_context *ctx, const secp256k1_zkp_scalar *sigr, const secp256k1_zkp_scalar* sigs, secp256k1_zkp_ge *pubkey, const secp256k1_zkp_scalar *message, int recid) { + unsigned char brx[32]; + secp256k1_zkp_fe fx; + secp256k1_zkp_ge x; + secp256k1_zkp_gej xj; + secp256k1_zkp_scalar rn, u1, u2; + secp256k1_zkp_gej qj; + int r; + + if (secp256k1_zkp_scalar_is_zero(sigr) || secp256k1_zkp_scalar_is_zero(sigs)) { + return 0; + } + + secp256k1_zkp_scalar_get_b32(brx, sigr); + r = secp256k1_zkp_fe_set_b32(&fx, brx); + (void)r; + VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */ + if (recid & 2) { + if (secp256k1_zkp_fe_cmp_var(&fx, &secp256k1_zkp_ecdsa_const_p_minus_order) >= 0) { + return 0; + } + secp256k1_zkp_fe_add(&fx, &secp256k1_zkp_ecdsa_const_order_as_fe); + } + if (!secp256k1_zkp_ge_set_xo_var(&x, &fx, recid & 1)) { + return 0; + } + secp256k1_zkp_gej_set_ge(&xj, &x); + secp256k1_zkp_scalar_inverse_var(&rn, sigr); + secp256k1_zkp_scalar_mul(&u1, &rn, message); + secp256k1_zkp_scalar_negate(&u1, &u1); + secp256k1_zkp_scalar_mul(&u2, &rn, sigs); + secp256k1_zkp_ecmult(ctx, &qj, &xj, &u2, &u1); + secp256k1_zkp_ge_set_gej_var(pubkey, &qj); + return !secp256k1_zkp_gej_is_infinity(&qj); +} + +int secp256k1_zkp_ecdsa_sign_recoverable(const secp256k1_zkp_context* ctx, secp256k1_zkp_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_zkp_nonce_function noncefp, const void* noncedata) { + secp256k1_zkp_scalar r, s; + secp256k1_zkp_scalar sec, non, msg; + int recid; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_zkp_nonce_function_default; + } + + secp256k1_zkp_scalar_set_b32(&sec, seckey, &overflow); + /* Fail if the secret key is invalid. */ + if (!overflow && !secp256k1_zkp_scalar_is_zero(&sec)) { + unsigned char nonce32[32]; + unsigned int count = 0; + secp256k1_zkp_scalar_set_b32(&msg, msg32, NULL); + while (1) { + ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_zkp_scalar_set_b32(&non, nonce32, &overflow); + if (!secp256k1_zkp_scalar_is_zero(&non) && !overflow) { + if (secp256k1_zkp_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) { + break; + } + } + count++; + } + memset(nonce32, 0, 32); + secp256k1_zkp_scalar_clear(&msg); + secp256k1_zkp_scalar_clear(&non); + secp256k1_zkp_scalar_clear(&sec); + } + if (ret) { + secp256k1_zkp_ecdsa_recoverable_signature_save(signature, &r, &s, recid); + } else { + memset(signature, 0, sizeof(*signature)); + } + return ret; +} + +int secp256k1_zkp_ecdsa_recover(const secp256k1_zkp_context* ctx, secp256k1_zkp_pubkey *pubkey, const secp256k1_zkp_ecdsa_recoverable_signature *signature, const unsigned char *msg32) { + secp256k1_zkp_ge q; + secp256k1_zkp_scalar r, s; + secp256k1_zkp_scalar m; + int recid; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_zkp_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature); + VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */ + secp256k1_zkp_scalar_set_b32(&m, msg32, NULL); + if (secp256k1_zkp_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) { + secp256k1_zkp_pubkey_save(pubkey, &q); + return 1; + } else { + memset(pubkey, 0, sizeof(*pubkey)); + return 0; + } +} + +#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/recovery/tests_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/recovery/tests_impl.h new file mode 100644 index 00000000..a719865a --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/recovery/tests_impl.h @@ -0,0 +1,393 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H +#define SECP256K1_MODULE_RECOVERY_TESTS_H + +static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void) msg32; + (void) key32; + (void) algo16; + (void) data; + + /* On the first run, return 0 to force a second run */ + if (counter == 0) { + memset(nonce32, 0, 32); + return 1; + } + /* On the second run, return an overflow to force a third run */ + if (counter == 1) { + memset(nonce32, 0xff, 32); + return 1; + } + /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */ + memset(nonce32, 1, 32); + return secp256k1_zkp_rand_bits(1); +} + +void test_ecdsa_recovery_api(void) { + /* Setup contexts that just count errors */ + secp256k1_zkp_context *none = secp256k1_zkp_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_zkp_context *sign = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_zkp_context *vrfy = secp256k1_zkp_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_zkp_context *both = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_zkp_pubkey pubkey; + secp256k1_zkp_pubkey recpubkey; + secp256k1_zkp_ecdsa_signature normal_sig; + secp256k1_zkp_ecdsa_recoverable_signature recsig; + unsigned char privkey[32] = { 1 }; + unsigned char message[32] = { 2 }; + int32_t ecount = 0; + int recid = 0; + unsigned char sig[74]; + unsigned char zero_privkey[32] = { 0 }; + unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + secp256k1_zkp_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Check bad contexts and NULLs for signing */ + ecount = 0; + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0); + CHECK(ecount == 5); + /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */ + secp256k1_zkp_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL); + CHECK(ecount == 5); + /* These will all fail, but not in ARG_CHECK way */ + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0); + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0); + /* This one will succeed. */ + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(ecount == 5); + + /* Check signing with a goofy nonce function */ + + /* Check bad contexts and NULLs for recovery */ + ecount = 0; + CHECK(secp256k1_zkp_ecdsa_recover(none, &recpubkey, &recsig, message) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ecdsa_recover(both, &recpubkey, &recsig, message) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ecdsa_recover(both, NULL, &recsig, message) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_ecdsa_recover(both, &recpubkey, NULL, message) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0); + CHECK(ecount == 5); + + /* Check NULLs for conversion */ + CHECK(secp256k1_zkp_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1); + ecount = 0; + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1); + + /* Check NULLs for de/serialization */ + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + ecount = 0; + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1); + + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0); + CHECK(ecount == 7); + /* overflow in signature will fail but not affect ecount */ + memcpy(sig, over_privkey, 32); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0); + CHECK(ecount == 7); + + /* cleanup */ + secp256k1_zkp_context_destroy(none); + secp256k1_zkp_context_destroy(sign); + secp256k1_zkp_context_destroy(vrfy); + secp256k1_zkp_context_destroy(both); +} + +void test_ecdsa_recovery_end_to_end(void) { + unsigned char extra[32] = {0x00}; + unsigned char privkey[32]; + unsigned char message[32]; + secp256k1_zkp_ecdsa_signature signature[5]; + secp256k1_zkp_ecdsa_recoverable_signature rsignature[5]; + unsigned char sig[74]; + secp256k1_zkp_pubkey pubkey; + secp256k1_zkp_pubkey recpubkey; + int recid = 0; + + /* Generate a random key and message. */ + { + secp256k1_zkp_scalar msg, key; + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_zkp_scalar_get_b32(privkey, &key); + secp256k1_zkp_scalar_get_b32(message, &msg); + } + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Serialize/parse compact and verify/recover. */ + extra[0] = 0; + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1); + extra[31] = 1; + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1); + extra[31] = 0; + extra[0] = 1; + CHECK(secp256k1_zkp_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(memcmp(&signature[4], &signature[0], 64) == 0); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); + memset(&rsignature[4], 0, sizeof(rsignature[4])); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); + /* Parse compact (with recovery id) and recover. */ + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_zkp_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1); + CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + /* Serialize/destroy/parse signature and verify again. */ + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); + sig[secp256k1_zkp_rand_bits(6)] += 1 + secp256k1_zkp_rand_int(255); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0); + /* Recover again */ + CHECK(secp256k1_zkp_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 || + memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); +} + +/* Tests several edge cases. */ +void test_ecdsa_recovery_edge_cases(void) { + const unsigned char msg32[32] = { + 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', + 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', + 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', + 's', 's', 'a', 'g', 'e', '.', '.', '.' + }; + const unsigned char sig64[64] = { + /* Generated by signing the above message with nonce 'This is the nonce we will use...' + * and secret key 0 (which is not valid), resulting in recid 0. */ + 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, + 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, + 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, + 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, + 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, + 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, + 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, + 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 + }; + secp256k1_zkp_pubkey pubkey; + /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ + const unsigned char sigb64[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + secp256k1_zkp_pubkey pubkeyb; + secp256k1_zkp_ecdsa_recoverable_signature rsig; + secp256k1_zkp_ecdsa_signature sig; + int recid; + + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0)); + CHECK(!secp256k1_zkp_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1)); + CHECK(secp256k1_zkp_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2)); + CHECK(!secp256k1_zkp_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3)); + CHECK(!secp256k1_zkp_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + + for (recid = 0; recid < 4; recid++) { + int i; + int recid2; + /* (4,4) encoded in DER. */ + unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; + unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; + unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; + unsigned char sigbderalt1[39] = { + 0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt2[39] = { + 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + unsigned char sigbderalt3[40] = { + 0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt4[40] = { + 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + }; + /* (order + r,4) encoded in DER. */ + unsigned char sigbderlong[40] = { + 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, + 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, + 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 + }; + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1); + CHECK(secp256k1_zkp_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); + for (recid2 = 0; recid2 < 4; recid2++) { + secp256k1_zkp_pubkey pubkey2b; + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1); + CHECK(secp256k1_zkp_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1); + /* Verifying with (order + r,4) should always fail. */ + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + } + /* DER parsing tests. */ + /* Zero length r/s. */ + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); + /* Leading zeros. */ + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); + sigbderalt3[4] = 1; + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + sigbderalt4[7] = 1; + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + /* Damage signature. */ + sigbder[7]++; + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + sigbder[7]--; + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0); + for(i = 0; i < 8; i++) { + int c; + unsigned char orig = sigbder[i]; + /*Try every single-byte change.*/ + for (c = 0; c < 256; c++) { + if (c == orig ) { + continue; + } + sigbder[i] = c; + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_zkp_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + } + sigbder[i] = orig; + } + } + + /* Test r/s equal to zero */ + { + /* (1,1) encoded in DER. */ + unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; + unsigned char sigc64[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + secp256k1_zkp_pubkey pubkeyc; + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_zkp_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1); + sigcder[4] = 0; + sigc64[31] = 0; + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_zkp_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); + sigcder[4] = 1; + sigcder[7] = 0; + sigc64[31] = 1; + sigc64[63] = 0; + CHECK(secp256k1_zkp_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_zkp_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); + } +} + +void run_recovery_tests(void) { + int i; + for (i = 0; i < count; i++) { + test_ecdsa_recovery_api(); + } + for (i = 0; i < 64*count; i++) { + test_ecdsa_recovery_end_to_end(); + } + test_ecdsa_recovery_edge_cases(); +} + +#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/schnorrsig/Makefile.am.include b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/schnorrsig/Makefile.am.include new file mode 100644 index 00000000..ac29e6d2 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/schnorrsig/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_zkp_schnorrsig.h +noinst_HEADERS += src/modules/schnorrsig/main_impl.h +noinst_HEADERS += src/modules/schnorrsig/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_schnorrsig +bench_schnorrsig_SOURCES = src/bench_schnorrsig.c +bench_schnorrsig_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/schnorrsig/main_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/schnorrsig/main_impl.h new file mode 100644 index 00000000..43ba02d3 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/schnorrsig/main_impl.h @@ -0,0 +1,338 @@ +/********************************************************************** + * Copyright (c) 2018 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_SCHNORRSIG_MAIN_ +#define _SECP256K1_MODULE_SCHNORRSIG_MAIN_ + +#include "include/secp256k1.h" +#include "include/secp256k1_schnorrsig.h" +#include "hash.h" + +int secp256k1_zkp_schnorrsig_serialize(const secp256k1_zkp_context* ctx, unsigned char *out64, const secp256k1_zkp_schnorrsig* sig) { + (void) ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(out64 != NULL); + ARG_CHECK(sig != NULL); + memcpy(out64, sig->data, 64); + return 1; +} + +int secp256k1_zkp_schnorrsig_parse(const secp256k1_zkp_context* ctx, secp256k1_zkp_schnorrsig* sig, const unsigned char *in64) { + (void) ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(in64 != NULL); + memcpy(sig->data, in64, 64); + return 1; +} + +int secp256k1_zkp_schnorrsig_sign(const secp256k1_zkp_context* ctx, secp256k1_zkp_schnorrsig *sig, int *nonce_is_negated, const unsigned char *msg32, const unsigned char *seckey, secp256k1_zkp_nonce_function noncefp, void *ndata) { + secp256k1_zkp_scalar x; + secp256k1_zkp_scalar e; + secp256k1_zkp_scalar k; + secp256k1_zkp_gej pkj; + secp256k1_zkp_gej rj; + secp256k1_zkp_ge pk; + secp256k1_zkp_ge r; + secp256k1_zkp_sha256 sha; + int overflow; + unsigned char buf[33]; + size_t buflen = sizeof(buf); + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(sig != NULL); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(seckey != NULL); + + if (noncefp == NULL) { + noncefp = secp256k1_zkp_nonce_function_bipschnorr; + } + secp256k1_zkp_scalar_set_b32(&x, seckey, &overflow); + /* Fail if the secret key is invalid. */ + if (overflow || secp256k1_zkp_scalar_is_zero(&x)) { + memset(sig, 0, sizeof(*sig)); + return 0; + } + + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &pkj, &x); + secp256k1_zkp_ge_set_gej(&pk, &pkj); + + if (!noncefp(buf, msg32, seckey, NULL, (void*)ndata, 0)) { + return 0; + } + secp256k1_zkp_scalar_set_b32(&k, buf, NULL); + if (secp256k1_zkp_scalar_is_zero(&k)) { + return 0; + } + + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k); + secp256k1_zkp_ge_set_gej(&r, &rj); + + if (nonce_is_negated != NULL) { + *nonce_is_negated = 0; + } + if (!secp256k1_zkp_fe_is_quad_var(&r.y)) { + secp256k1_zkp_scalar_negate(&k, &k); + if (nonce_is_negated != NULL) { + *nonce_is_negated = 1; + } + } + secp256k1_zkp_fe_normalize(&r.x); + secp256k1_zkp_fe_get_b32(&sig->data[0], &r.x); + + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_sha256_write(&sha, &sig->data[0], 32); + secp256k1_zkp_eckey_pubkey_serialize(&pk, buf, &buflen, 1); + secp256k1_zkp_sha256_write(&sha, buf, buflen); + secp256k1_zkp_sha256_write(&sha, msg32, 32); + secp256k1_zkp_sha256_finalize(&sha, buf); + + secp256k1_zkp_scalar_set_b32(&e, buf, NULL); + secp256k1_zkp_scalar_mul(&e, &e, &x); + secp256k1_zkp_scalar_add(&e, &e, &k); + + secp256k1_zkp_scalar_get_b32(&sig->data[32], &e); + secp256k1_zkp_scalar_clear(&k); + secp256k1_zkp_scalar_clear(&x); + + return 1; +} + +/* Helper function for verification and batch verification. + * Computes R = sG - eP. */ +static int secp256k1_zkp_schnorrsig_real_verify(const secp256k1_zkp_context* ctx, secp256k1_zkp_gej *rj, const secp256k1_zkp_scalar *s, const secp256k1_zkp_scalar *e, const secp256k1_zkp_pubkey *pk) { + secp256k1_zkp_scalar nege; + secp256k1_zkp_ge pkp; + secp256k1_zkp_gej pkj; + + secp256k1_zkp_scalar_negate(&nege, e); + + if (!secp256k1_zkp_pubkey_load(ctx, &pkp, pk)) { + return 0; + } + secp256k1_zkp_gej_set_ge(&pkj, &pkp); + + /* rj = s*G + (-e)*pkj */ + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, rj, &pkj, &nege, s); + return 1; +} + +int secp256k1_zkp_schnorrsig_verify(const secp256k1_zkp_context* ctx, const secp256k1_zkp_schnorrsig *sig, const unsigned char *msg32, const secp256k1_zkp_pubkey *pk) { + secp256k1_zkp_scalar s; + secp256k1_zkp_scalar e; + secp256k1_zkp_gej rj; + secp256k1_zkp_fe rx; + secp256k1_zkp_sha256 sha; + unsigned char buf[33]; + size_t buflen = sizeof(buf); + int overflow; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(sig != NULL); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(pk != NULL); + + if (!secp256k1_zkp_fe_set_b32(&rx, &sig->data[0])) { + return 0; + } + + secp256k1_zkp_scalar_set_b32(&s, &sig->data[32], &overflow); + if (overflow) { + return 0; + } + + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_sha256_write(&sha, &sig->data[0], 32); + secp256k1_zkp_ec_pubkey_serialize(ctx, buf, &buflen, pk, SECP256K1_EC_COMPRESSED); + secp256k1_zkp_sha256_write(&sha, buf, buflen); + secp256k1_zkp_sha256_write(&sha, msg32, 32); + secp256k1_zkp_sha256_finalize(&sha, buf); + secp256k1_zkp_scalar_set_b32(&e, buf, NULL); + + if (!secp256k1_zkp_schnorrsig_real_verify(ctx, &rj, &s, &e, pk) + || !secp256k1_zkp_gej_has_quad_y_var(&rj) /* fails if rj is infinity */ + || !secp256k1_zkp_gej_eq_x_var(&rx, &rj)) { + return 0; + } + + return 1; +} + +/* Data that is used by the batch verification ecmult callback */ +typedef struct { + const secp256k1_zkp_context *ctx; + /* Seed for the random number generator */ + unsigned char chacha_seed[32]; + /* Caches randomizers generated by the PRNG which returns two randomizers per call. Caching + * avoids having to call the PRNG twice as often. The very first randomizer will be set to 1 and + * the PRNG is called at every odd indexed schnorrsig to fill the cache. */ + secp256k1_zkp_scalar randomizer_cache[2]; + /* Signature, message, public key tuples to verify */ + const secp256k1_zkp_schnorrsig *const *sig; + const unsigned char *const *msg32; + const secp256k1_zkp_pubkey *const *pk; + size_t n_sigs; +} secp256k1_zkp_schnorrsig_verify_ecmult_context; + +/* Callback function which is called by ecmult_multi in order to convert the ecmult_context + * consisting of signature, message and public key tuples into scalars and points. */ +static int secp256k1_zkp_schnorrsig_verify_batch_ecmult_callback(secp256k1_zkp_scalar *sc, secp256k1_zkp_ge *pt, size_t idx, void *data) { + secp256k1_zkp_schnorrsig_verify_ecmult_context *ecmult_context = (secp256k1_zkp_schnorrsig_verify_ecmult_context *) data; + + if (idx % 4 == 2) { + /* Every idx corresponds to a (scalar,point)-tuple. So this callback is called with 4 + * consecutive tuples before we need to call the RNG for new randomizers: + * (-randomizer_cache[0], R1) + * (-randomizer_cache[0]*e1, P1) + * (-randomizer_cache[1], R2) + * (-randomizer_cache[1]*e2, P2) */ + secp256k1_zkp_scalar_chacha20(&ecmult_context->randomizer_cache[0], &ecmult_context->randomizer_cache[1], ecmult_context->chacha_seed, idx / 4); + } + + /* R */ + if (idx % 2 == 0) { + secp256k1_zkp_fe rx; + *sc = ecmult_context->randomizer_cache[(idx / 2) % 2]; + if (!secp256k1_zkp_fe_set_b32(&rx, &ecmult_context->sig[idx / 2]->data[0])) { + return 0; + } + if (!secp256k1_zkp_ge_set_xquad(pt, &rx)) { + return 0; + } + /* eP */ + } else { + unsigned char buf[33]; + size_t buflen = sizeof(buf); + secp256k1_zkp_sha256 sha; + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_sha256_write(&sha, &ecmult_context->sig[idx / 2]->data[0], 32); + secp256k1_zkp_ec_pubkey_serialize(ecmult_context->ctx, buf, &buflen, ecmult_context->pk[idx / 2], SECP256K1_EC_COMPRESSED); + secp256k1_zkp_sha256_write(&sha, buf, buflen); + secp256k1_zkp_sha256_write(&sha, ecmult_context->msg32[idx / 2], 32); + secp256k1_zkp_sha256_finalize(&sha, buf); + + secp256k1_zkp_scalar_set_b32(sc, buf, NULL); + secp256k1_zkp_scalar_mul(sc, sc, &ecmult_context->randomizer_cache[(idx / 2) % 2]); + + if (!secp256k1_zkp_pubkey_load(ecmult_context->ctx, pt, ecmult_context->pk[idx / 2])) { + return 0; + } + } + return 1; +} + +/** Helper function for batch verification. Hashes signature verification data into the + * randomization seed and initializes ecmult_context. + * + * Returns 1 if the randomizer was successfully initialized. + * + * Args: ctx: a secp256k1 context object + * Out: ecmult_context: context for batch_ecmult_callback + * In/Out sha: an initialized sha256 object which hashes the schnorrsig input in order to get a + * seed for the randomizer PRNG + * In: sig: array of signatures, or NULL if there are no signatures + * msg32: array of messages, or NULL if there are no signatures + * pk: array of public keys, or NULL if there are no signatures + * n_sigs: number of signatures in above arrays (must be 0 if they are NULL) + */ +int secp256k1_zkp_schnorrsig_verify_batch_init_randomizer(const secp256k1_zkp_context *ctx, secp256k1_zkp_schnorrsig_verify_ecmult_context *ecmult_context, secp256k1_zkp_sha256 *sha, const secp256k1_zkp_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_zkp_pubkey *const *pk, size_t n_sigs) { + size_t i; + + if (n_sigs > 0) { + ARG_CHECK(sig != NULL); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(pk != NULL); + } + + for (i = 0; i < n_sigs; i++) { + unsigned char buf[33]; + size_t buflen = sizeof(buf); + secp256k1_zkp_sha256_write(sha, sig[i]->data, 64); + secp256k1_zkp_sha256_write(sha, msg32[i], 32); + secp256k1_zkp_ec_pubkey_serialize(ctx, buf, &buflen, pk[i], SECP256K1_EC_COMPRESSED); + secp256k1_zkp_sha256_write(sha, buf, 32); + } + ecmult_context->ctx = ctx; + ecmult_context->sig = sig; + ecmult_context->msg32 = msg32; + ecmult_context->pk = pk; + ecmult_context->n_sigs = n_sigs; + + return 1; +} + +/** Helper function for batch verification. Sums the s part of all signatures multiplied by their + * randomizer. + * + * Returns 1 if s is successfully summed. + * + * In/Out: s: the s part of the input sigs is added to this s argument + * In: chacha_seed: PRNG seed for computing randomizers + * sig: array of signatures, or NULL if there are no signatures + * n_sigs: number of signatures in above array (must be 0 if they are NULL) + */ +int secp256k1_zkp_schnorrsig_verify_batch_sum_s(secp256k1_zkp_scalar *s, unsigned char *chacha_seed, const secp256k1_zkp_schnorrsig *const *sig, size_t n_sigs) { + secp256k1_zkp_scalar randomizer_cache[2]; + size_t i; + + secp256k1_zkp_scalar_set_int(&randomizer_cache[0], 1); + for (i = 0; i < n_sigs; i++) { + int overflow; + secp256k1_zkp_scalar term; + if (i % 2 == 1) { + secp256k1_zkp_scalar_chacha20(&randomizer_cache[0], &randomizer_cache[1], chacha_seed, i / 2); + } + + secp256k1_zkp_scalar_set_b32(&term, &sig[i]->data[32], &overflow); + if (overflow) { + return 0; + } + secp256k1_zkp_scalar_mul(&term, &term, &randomizer_cache[i % 2]); + secp256k1_zkp_scalar_add(s, s, &term); + } + return 1; +} + +/* schnorrsig batch verification. + * Seeds a random number generator with the inputs and derives a random number ai for every + * signature i. Fails if y-coordinate of any R is not a quadratic residue or if + * 0 != -(s1 + a2*s2 + ... + au*su)G + R1 + a2*R2 + ... + au*Ru + e1*P1 + (a2*e2)P2 + ... + (au*eu)Pu. */ +int secp256k1_zkp_schnorrsig_verify_batch(const secp256k1_zkp_context *ctx, secp256k1_zkp_scratch *scratch, const secp256k1_zkp_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_zkp_pubkey *const *pk, size_t n_sigs) { + secp256k1_zkp_schnorrsig_verify_ecmult_context ecmult_context; + secp256k1_zkp_sha256 sha; + secp256k1_zkp_scalar s; + secp256k1_zkp_gej rj; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(scratch != NULL); + /* Check that n_sigs is less than half of the maximum size_t value. This is necessary because + * the number of points given to ecmult_multi is 2*n_sigs. */ + ARG_CHECK(n_sigs <= SIZE_MAX / 2); + /* Check that n_sigs is less than 2^31 to ensure the same behavior of this function on 32-bit + * and 64-bit platforms. */ + ARG_CHECK(n_sigs < (size_t)(1 << 31)); + + secp256k1_zkp_sha256_initialize(&sha); + if (!secp256k1_zkp_schnorrsig_verify_batch_init_randomizer(ctx, &ecmult_context, &sha, sig, msg32, pk, n_sigs)) { + return 0; + } + secp256k1_zkp_sha256_finalize(&sha, ecmult_context.chacha_seed); + secp256k1_zkp_scalar_set_int(&ecmult_context.randomizer_cache[0], 1); + + secp256k1_zkp_scalar_clear(&s); + if (!secp256k1_zkp_schnorrsig_verify_batch_sum_s(&s, ecmult_context.chacha_seed, sig, n_sigs)) { + return 0; + } + secp256k1_zkp_scalar_negate(&s, &s); + + return secp256k1_zkp_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &rj, &s, secp256k1_zkp_schnorrsig_verify_batch_ecmult_callback, (void *) &ecmult_context, 2 * n_sigs) + && secp256k1_zkp_gej_is_infinity(&rj); +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/schnorrsig/tests_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/schnorrsig/tests_impl.h new file mode 100644 index 00000000..285a0d10 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/schnorrsig/tests_impl.h @@ -0,0 +1,726 @@ +/********************************************************************** + * Copyright (c) 2018 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_SCHNORRSIG_TESTS_ +#define _SECP256K1_MODULE_SCHNORRSIG_TESTS_ + +#include "secp256k1_schnorrsig.h" + +void test_schnorrsig_serialize(void) { + secp256k1_zkp_schnorrsig sig; + unsigned char in[64]; + unsigned char out[64]; + + memset(in, 0x12, 64); + CHECK(secp256k1_zkp_schnorrsig_parse(ctx, &sig, in)); + CHECK(secp256k1_zkp_schnorrsig_serialize(ctx, out, &sig)); + CHECK(memcmp(in, out, 64) == 0); +} + +void test_schnorrsig_api(secp256k1_zkp_scratch_space *scratch) { + unsigned char sk1[32]; + unsigned char sk2[32]; + unsigned char sk3[32]; + unsigned char msg[32]; + unsigned char sig64[64]; + secp256k1_zkp_pubkey pk[3]; + secp256k1_zkp_schnorrsig sig; + const secp256k1_zkp_schnorrsig *sigptr = &sig; + const unsigned char *msgptr = msg; + const secp256k1_zkp_pubkey *pkptr = &pk[0]; + int nonce_is_negated; + + /** setup **/ + secp256k1_zkp_context *none = secp256k1_zkp_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_zkp_context *sign = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_zkp_context *vrfy = secp256k1_zkp_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_zkp_context *both = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + int ecount; + + secp256k1_zkp_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); + + secp256k1_zkp_rand256(sk1); + secp256k1_zkp_rand256(sk2); + secp256k1_zkp_rand256(sk3); + secp256k1_zkp_rand256(msg); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pk[0], sk1) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pk[1], sk2) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pk[2], sk3) == 1); + + /** main test body **/ + ecount = 0; + CHECK(secp256k1_zkp_schnorrsig_sign(none, &sig, &nonce_is_negated, msg, sk1, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_schnorrsig_sign(vrfy, &sig, &nonce_is_negated, msg, sk1, NULL, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_schnorrsig_sign(sign, &sig, &nonce_is_negated, msg, sk1, NULL, NULL) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_schnorrsig_sign(sign, NULL, &nonce_is_negated, msg, sk1, NULL, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_schnorrsig_sign(sign, &sig, NULL, msg, sk1, NULL, NULL) == 1); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_schnorrsig_sign(sign, &sig, &nonce_is_negated, NULL, sk1, NULL, NULL) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_schnorrsig_sign(sign, &sig, &nonce_is_negated, msg, NULL, NULL, NULL) == 0); + CHECK(ecount == 5); + + ecount = 0; + CHECK(secp256k1_zkp_schnorrsig_serialize(none, sig64, &sig) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_schnorrsig_serialize(none, NULL, &sig) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_schnorrsig_serialize(none, sig64, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_schnorrsig_parse(none, &sig, sig64) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_schnorrsig_parse(none, NULL, sig64) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_schnorrsig_parse(none, &sig, NULL) == 0); + CHECK(ecount == 4); + + ecount = 0; + CHECK(secp256k1_zkp_schnorrsig_verify(none, &sig, msg, &pk[0]) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_schnorrsig_verify(sign, &sig, msg, &pk[0]) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_schnorrsig_verify(vrfy, &sig, msg, &pk[0]) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_schnorrsig_verify(vrfy, NULL, msg, &pk[0]) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_schnorrsig_verify(vrfy, &sig, NULL, &pk[0]) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_schnorrsig_verify(vrfy, &sig, msg, NULL) == 0); + CHECK(ecount == 5); + + ecount = 0; + CHECK(secp256k1_zkp_schnorrsig_verify_batch(none, scratch, &sigptr, &msgptr, &pkptr, 1) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_schnorrsig_verify_batch(sign, scratch, &sigptr, &msgptr, &pkptr, 1) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, 1) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_schnorrsig_verify_batch(vrfy, scratch, NULL, NULL, NULL, 0) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_schnorrsig_verify_batch(vrfy, scratch, NULL, &msgptr, &pkptr, 1) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_schnorrsig_verify_batch(vrfy, scratch, &sigptr, NULL, &pkptr, 1) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, NULL, 1) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_zkp_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, (size_t)1 << (sizeof(size_t)*8-1)) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_zkp_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, 1 << 31) == 0); + CHECK(ecount == 7); + + secp256k1_zkp_context_destroy(none); + secp256k1_zkp_context_destroy(sign); + secp256k1_zkp_context_destroy(vrfy); + secp256k1_zkp_context_destroy(both); +} + +/* Helper function for schnorrsig_bip_vectors + * Signs the message and checks that it's the same as expected_sig. */ +void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *msg, const unsigned char *expected_sig, const int expected_nonce_is_negated) { + secp256k1_zkp_schnorrsig sig; + unsigned char serialized_sig[64]; + secp256k1_zkp_pubkey pk; + int nonce_is_negated; + + CHECK(secp256k1_zkp_schnorrsig_sign(ctx, &sig, &nonce_is_negated, msg, sk, NULL, NULL)); + CHECK(nonce_is_negated == expected_nonce_is_negated); + CHECK(secp256k1_zkp_schnorrsig_serialize(ctx, serialized_sig, &sig)); + CHECK(memcmp(serialized_sig, expected_sig, 64) == 0); + + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, &pk, pk_serialized, 33)); + CHECK(secp256k1_zkp_schnorrsig_verify(ctx, &sig, msg, &pk)); +} + +/* Helper function for schnorrsig_bip_vectors + * Checks that both verify and verify_batch return the same value as expected. */ +void test_schnorrsig_bip_vectors_check_verify(secp256k1_zkp_scratch_space *scratch, const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig_serialized, int expected) { + const unsigned char *msg_arr[1]; + const secp256k1_zkp_schnorrsig *sig_arr[1]; + const secp256k1_zkp_pubkey *pk_arr[1]; + secp256k1_zkp_pubkey pk; + secp256k1_zkp_schnorrsig sig; + + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, &pk, pk_serialized, 33)); + CHECK(secp256k1_zkp_schnorrsig_parse(ctx, &sig, sig_serialized)); + + sig_arr[0] = &sig; + msg_arr[0] = msg32; + pk_arr[0] = &pk; + + CHECK(expected == secp256k1_zkp_schnorrsig_verify(ctx, &sig, msg32, &pk)); + CHECK(expected == secp256k1_zkp_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 1)); +} + +/* Test vectors according to BIP-schnorr + * (https://github.com/sipa/bips/blob/7f6a73e53c8bbcf2d008ea0546f76433e22094a8/bip-schnorr/test-vectors.csv). + */ +void test_schnorrsig_bip_vectors(secp256k1_zkp_scratch_space *scratch) { + { + /* Test vector 1 */ + const unsigned char sk1[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + const unsigned char pk1[33] = { + 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, + 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, + 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, + 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, + 0x98 + }; + const unsigned char msg1[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char sig1[64] = { + 0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28, + 0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2, + 0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB, + 0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6, + 0x70, 0x31, 0xA9, 0x88, 0x31, 0x85, 0x9D, 0xC3, + 0x4D, 0xFF, 0xEE, 0xDD, 0xA8, 0x68, 0x31, 0x84, + 0x2C, 0xCD, 0x00, 0x79, 0xE1, 0xF9, 0x2A, 0xF1, + 0x77, 0xF7, 0xF2, 0x2C, 0xC1, 0xDC, 0xED, 0x05 + }; + test_schnorrsig_bip_vectors_check_signing(sk1, pk1, msg1, sig1, 1); + test_schnorrsig_bip_vectors_check_verify(scratch, pk1, msg1, sig1, 1); + } + { + /* Test vector 2 */ + const unsigned char sk2[32] = { + 0xB7, 0xE1, 0x51, 0x62, 0x8A, 0xED, 0x2A, 0x6A, + 0xBF, 0x71, 0x58, 0x80, 0x9C, 0xF4, 0xF3, 0xC7, + 0x62, 0xE7, 0x16, 0x0F, 0x38, 0xB4, 0xDA, 0x56, + 0xA7, 0x84, 0xD9, 0x04, 0x51, 0x90, 0xCF, 0xEF + }; + const unsigned char pk2[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg2[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig2[64] = { + 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, + 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, + 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, + 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + }; + test_schnorrsig_bip_vectors_check_signing(sk2, pk2, msg2, sig2, 0); + test_schnorrsig_bip_vectors_check_verify(scratch, pk2, msg2, sig2, 1); + } + { + /* Test vector 3 */ + const unsigned char sk3[32] = { + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x14, 0xE5, 0xC7 + }; + const unsigned char pk3[33] = { + 0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, + 0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, + 0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, + 0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, + 0x4B + }; + const unsigned char msg3[32] = { + 0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, + 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, + 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, + 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C + }; + const unsigned char sig3[64] = { + 0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F, + 0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D, + 0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53, + 0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE, + 0x00, 0x88, 0x03, 0x71, 0xD0, 0x17, 0x66, 0x93, + 0x5B, 0x92, 0xD2, 0xAB, 0x4C, 0xD5, 0xC8, 0xA2, + 0xA5, 0x83, 0x7E, 0xC5, 0x7F, 0xED, 0x76, 0x60, + 0x77, 0x3A, 0x05, 0xF0, 0xDE, 0x14, 0x23, 0x80 + }; + test_schnorrsig_bip_vectors_check_signing(sk3, pk3, msg3, sig3, 0); + test_schnorrsig_bip_vectors_check_verify(scratch, pk3, msg3, sig3, 1); + } + { + /* Test vector 4 */ + const unsigned char pk4[33] = { + 0x03, 0xDE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, + 0x50, 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, + 0x21, 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, + 0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, + 0x34 + }; + const unsigned char msg4[32] = { + 0x4D, 0xF3, 0xC3, 0xF6, 0x8F, 0xCC, 0x83, 0xB2, + 0x7E, 0x9D, 0x42, 0xC9, 0x04, 0x31, 0xA7, 0x24, + 0x99, 0xF1, 0x78, 0x75, 0xC8, 0x1A, 0x59, 0x9B, + 0x56, 0x6C, 0x98, 0x89, 0xB9, 0x69, 0x67, 0x03 + }; + const unsigned char sig4[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3B, 0x78, 0xCE, 0x56, 0x3F, + 0x89, 0xA0, 0xED, 0x94, 0x14, 0xF5, 0xAA, 0x28, + 0xAD, 0x0D, 0x96, 0xD6, 0x79, 0x5F, 0x9C, 0x63, + 0x02, 0xA8, 0xDC, 0x32, 0xE6, 0x4E, 0x86, 0xA3, + 0x33, 0xF2, 0x0E, 0xF5, 0x6E, 0xAC, 0x9B, 0xA3, + 0x0B, 0x72, 0x46, 0xD6, 0xD2, 0x5E, 0x22, 0xAD, + 0xB8, 0xC6, 0xBE, 0x1A, 0xEB, 0x08, 0xD4, 0x9D + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk4, msg4, sig4, 1); + } + { + /* Test vector 5 */ + const unsigned char pk5[33] = { + 0x03, 0x1B, 0x84, 0xC5, 0x56, 0x7B, 0x12, 0x64, + 0x40, 0x99, 0x5D, 0x3E, 0xD5, 0xAA, 0xBA, 0x05, + 0x65, 0xD7, 0x1E, 0x18, 0x34, 0x60, 0x48, 0x19, + 0xFF, 0x9C, 0x17, 0xF5, 0xE9, 0xD5, 0xDD, 0x07, + 0x8F + }; + const unsigned char msg5[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char sig5[64] = { + 0x52, 0x81, 0x85, 0x79, 0xAC, 0xA5, 0x97, 0x67, + 0xE3, 0x29, 0x1D, 0x91, 0xB7, 0x6B, 0x63, 0x7B, + 0xEF, 0x06, 0x20, 0x83, 0x28, 0x49, 0x92, 0xF2, + 0xD9, 0x5F, 0x56, 0x4C, 0xA6, 0xCB, 0x4E, 0x35, + 0x30, 0xB1, 0xDA, 0x84, 0x9C, 0x8E, 0x83, 0x04, + 0xAD, 0xC0, 0xCF, 0xE8, 0x70, 0x66, 0x03, 0x34, + 0xB3, 0xCF, 0xC1, 0x8E, 0x82, 0x5E, 0xF1, 0xDB, + 0x34, 0xCF, 0xAE, 0x3D, 0xFC, 0x5D, 0x81, 0x87 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk5, msg5, sig5, 1); + } + { + /* Test vector 6 */ + const unsigned char pk6[33] = { + 0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, + 0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, + 0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, + 0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, + 0x4B + }; + const unsigned char msg6[32] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + const unsigned char sig6[64] = { + 0x57, 0x0D, 0xD4, 0xCA, 0x83, 0xD4, 0xE6, 0x31, + 0x7B, 0x8E, 0xE6, 0xBA, 0xE8, 0x34, 0x67, 0xA1, + 0xBF, 0x41, 0x9D, 0x07, 0x67, 0x12, 0x2D, 0xE4, + 0x09, 0x39, 0x44, 0x14, 0xB0, 0x50, 0x80, 0xDC, + 0xE9, 0xEE, 0x5F, 0x23, 0x7C, 0xBD, 0x10, 0x8E, + 0xAB, 0xAE, 0x1E, 0x37, 0x75, 0x9A, 0xE4, 0x7F, + 0x8E, 0x42, 0x03, 0xDA, 0x35, 0x32, 0xEB, 0x28, + 0xDB, 0x86, 0x0F, 0x33, 0xD6, 0x2D, 0x49, 0xBD + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk6, msg6, sig6, 1); + } + { + /* Test vector 7 */ + const unsigned char pk7[33] = { + 0x03, 0xEE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, + 0x50, 0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, + 0x21, 0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, + 0x87, 0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, + 0x34 + }; + secp256k1_zkp_pubkey pk7_parsed; + /* No need to check the signature of the test vector as parsing the pubkey already fails */ + CHECK(!secp256k1_zkp_ec_pubkey_parse(ctx, &pk7_parsed, pk7, 33)); + } + { + /* Test vector 8 */ + const unsigned char pk8[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg8[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig8[64] = { + 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0xFA, 0x16, 0xAE, 0xE0, 0x66, 0x09, 0x28, 0x0A, + 0x19, 0xB6, 0x7A, 0x24, 0xE1, 0x97, 0x7E, 0x46, + 0x97, 0x71, 0x2B, 0x5F, 0xD2, 0x94, 0x39, 0x14, + 0xEC, 0xD5, 0xF7, 0x30, 0x90, 0x1B, 0x4A, 0xB7 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk8, msg8, sig8, 0); + } + { + /* Test vector 9 */ + const unsigned char pk9[33] = { + 0x03, 0xFA, 0xC2, 0x11, 0x4C, 0x2F, 0xBB, 0x09, + 0x15, 0x27, 0xEB, 0x7C, 0x64, 0xEC, 0xB1, 0x1F, + 0x80, 0x21, 0xCB, 0x45, 0xE8, 0xE7, 0x80, 0x9D, + 0x3C, 0x09, 0x38, 0xE4, 0xB8, 0xC0, 0xE5, 0xF8, + 0x4B + }; + const unsigned char msg9[32] = { + 0x5E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A, + 0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D, + 0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33, + 0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C + }; + const unsigned char sig9[64] = { + 0x00, 0xDA, 0x9B, 0x08, 0x17, 0x2A, 0x9B, 0x6F, + 0x04, 0x66, 0xA2, 0xDE, 0xFD, 0x81, 0x7F, 0x2D, + 0x7A, 0xB4, 0x37, 0xE0, 0xD2, 0x53, 0xCB, 0x53, + 0x95, 0xA9, 0x63, 0x86, 0x6B, 0x35, 0x74, 0xBE, + 0xD0, 0x92, 0xF9, 0xD8, 0x60, 0xF1, 0x77, 0x6A, + 0x1F, 0x74, 0x12, 0xAD, 0x8A, 0x1E, 0xB5, 0x0D, + 0xAC, 0xCC, 0x22, 0x2B, 0xC8, 0xC0, 0xE2, 0x6B, + 0x20, 0x56, 0xDF, 0x2F, 0x27, 0x3E, 0xFD, 0xEC + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk9, msg9, sig9, 0); + } + { + /* Test vector 10 */ + const unsigned char pk10[33] = { + 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, + 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, + 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, + 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, + 0x98 + }; + const unsigned char msg10[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const unsigned char sig10[64] = { + 0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28, + 0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, 0x32, 0xB2, + 0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB, + 0xDD, 0x2B, 0xD1, 0xDF, 0xBF, 0x18, 0x7E, 0xF6, + 0x8F, 0xCE, 0x56, 0x77, 0xCE, 0x7A, 0x62, 0x3C, + 0xB2, 0x00, 0x11, 0x22, 0x57, 0x97, 0xCE, 0x7A, + 0x8D, 0xE1, 0xDC, 0x6C, 0xCD, 0x4F, 0x75, 0x4A, + 0x47, 0xDA, 0x6C, 0x60, 0x0E, 0x59, 0x54, 0x3C + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk10, msg10, sig10, 0); + } + { + /* Test vector 11 */ + const unsigned char pk11[33] = { + 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg11[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig11[64] = { + 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, + 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, + 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, + 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk11, msg11, sig11, 0); + } + { + /* Test vector 12 */ + const unsigned char pk12[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg12[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig12[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9E, 0x9D, 0x01, 0xAF, 0x98, 0x8B, 0x5C, 0xED, + 0xCE, 0x47, 0x22, 0x1B, 0xFA, 0x9B, 0x22, 0x27, + 0x21, 0xF3, 0xFA, 0x40, 0x89, 0x15, 0x44, 0x4A, + 0x4B, 0x48, 0x90, 0x21, 0xDB, 0x55, 0x77, 0x5F + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk12, msg12, sig12, 0); + } + { + /* Test vector 13 */ + const unsigned char pk13[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg13[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig13[64] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xD3, 0x7D, 0xDF, 0x02, 0x54, 0x35, 0x18, 0x36, + 0xD8, 0x4B, 0x1B, 0xD6, 0xA7, 0x95, 0xFD, 0x5D, + 0x52, 0x30, 0x48, 0xF2, 0x98, 0xC4, 0x21, 0x4D, + 0x18, 0x7F, 0xE4, 0x89, 0x29, 0x47, 0xF7, 0x28 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk13, msg13, sig13, 0); + } + { + /* Test vector 14 */ + const unsigned char pk14[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg14[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x14, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig14[64] = { + 0x4A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, + 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, + 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, + 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk14, msg14, sig14, 0); + } + { + /* Test vector 15 */ + const unsigned char pk15[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg15[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig15[64] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x2F, + 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, + 0xB8, 0xF2, 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, + 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, + 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk15, msg15, sig15, 0); + } + { + /* Test vector 16 */ + const unsigned char pk16[33] = { + 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, + 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, + 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, + 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, + 0x59 + }; + const unsigned char msg16[32] = { + 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, + 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, + 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, + 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89 + }; + const unsigned char sig16[64] = { + 0x2A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, + 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB, + 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, + 0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, + 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 + }; + test_schnorrsig_bip_vectors_check_verify(scratch, pk16, msg16, sig16, 0); + } +} + +/* Nonce function that returns constant 0 */ +static int nonce_function_failing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void) msg32; + (void) key32; + (void) algo16; + (void) data; + (void) counter; + (void) nonce32; + return 0; +} + +/* Nonce function that sets nonce to 0 */ +static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void) msg32; + (void) key32; + (void) algo16; + (void) data; + (void) counter; + + memset(nonce32, 0, 32); + return 1; +} + +void test_schnorrsig_sign(void) { + unsigned char sk[32]; + const unsigned char msg[32] = "this is a msg for a schnorrsig.."; + secp256k1_zkp_schnorrsig sig; + + memset(sk, 23, sizeof(sk)); + CHECK(secp256k1_zkp_schnorrsig_sign(ctx, &sig, NULL, msg, sk, NULL, NULL) == 1); + + /* Overflowing secret key */ + memset(sk, 0xFF, sizeof(sk)); + CHECK(secp256k1_zkp_schnorrsig_sign(ctx, &sig, NULL, msg, sk, NULL, NULL) == 0); + memset(sk, 23, sizeof(sk)); + + CHECK(secp256k1_zkp_schnorrsig_sign(ctx, &sig, NULL, msg, sk, nonce_function_failing, NULL) == 0); + CHECK(secp256k1_zkp_schnorrsig_sign(ctx, &sig, NULL, msg, sk, nonce_function_0, NULL) == 0); +} + +#define N_SIGS 200 +/* Creates N_SIGS valid signatures and verifies them with verify and verify_batch. Then flips some + * bits and checks that verification now fails. */ +void test_schnorrsig_sign_verify(secp256k1_zkp_scratch_space *scratch) { + const unsigned char sk[32] = "shhhhhhhh! this key is a secret."; + unsigned char msg[N_SIGS][32]; + secp256k1_zkp_schnorrsig sig[N_SIGS]; + size_t i; + const secp256k1_zkp_schnorrsig *sig_arr[N_SIGS]; + const unsigned char *msg_arr[N_SIGS]; + const secp256k1_zkp_pubkey *pk_arr[N_SIGS]; + secp256k1_zkp_pubkey pk; + + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pk, sk)); + + CHECK(secp256k1_zkp_schnorrsig_verify_batch(ctx, scratch, NULL, NULL, NULL, 0)); + + for (i = 0; i < N_SIGS; i++) { + secp256k1_zkp_rand256(msg[i]); + CHECK(secp256k1_zkp_schnorrsig_sign(ctx, &sig[i], NULL, msg[i], sk, NULL, NULL)); + CHECK(secp256k1_zkp_schnorrsig_verify(ctx, &sig[i], msg[i], &pk)); + sig_arr[i] = &sig[i]; + msg_arr[i] = msg[i]; + pk_arr[i] = &pk; + } + + CHECK(secp256k1_zkp_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 1)); + CHECK(secp256k1_zkp_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 2)); + CHECK(secp256k1_zkp_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + CHECK(secp256k1_zkp_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, N_SIGS)); + + { + /* Flip a few bits in the signature and in the message and check that + * verify and verify_batch fail */ + size_t sig_idx = secp256k1_zkp_rand_int(4); + size_t byte_idx = secp256k1_zkp_rand_int(32); + unsigned char xorbyte = secp256k1_zkp_rand_int(254)+1; + sig[sig_idx].data[byte_idx] ^= xorbyte; + CHECK(!secp256k1_zkp_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); + CHECK(!secp256k1_zkp_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + sig[sig_idx].data[byte_idx] ^= xorbyte; + + byte_idx = secp256k1_zkp_rand_int(32); + sig[sig_idx].data[32+byte_idx] ^= xorbyte; + CHECK(!secp256k1_zkp_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); + CHECK(!secp256k1_zkp_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + sig[sig_idx].data[32+byte_idx] ^= xorbyte; + + byte_idx = secp256k1_zkp_rand_int(32); + msg[sig_idx][byte_idx] ^= xorbyte; + CHECK(!secp256k1_zkp_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); + CHECK(!secp256k1_zkp_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + msg[sig_idx][byte_idx] ^= xorbyte; + + /* Check that above bitflips have been reversed correctly */ + CHECK(secp256k1_zkp_schnorrsig_verify(ctx, &sig[sig_idx], msg[sig_idx], &pk)); + CHECK(secp256k1_zkp_schnorrsig_verify_batch(ctx, scratch, sig_arr, msg_arr, pk_arr, 4)); + } +} +#undef N_SIGS + +void run_schnorrsig_tests(void) { + secp256k1_zkp_scratch_space *scratch = secp256k1_zkp_scratch_space_create(ctx, 1024 * 1024); + + test_schnorrsig_serialize(); + test_schnorrsig_api(scratch); + test_schnorrsig_bip_vectors(scratch); + test_schnorrsig_sign(); + test_schnorrsig_sign_verify(scratch); + + secp256k1_zkp_scratch_space_destroy(scratch); +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/Makefile.am.include b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/Makefile.am.include new file mode 100644 index 00000000..9cfd3df2 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/Makefile.am.include @@ -0,0 +1,6 @@ +include_HEADERS += include/secp256k1_zkp_surjectionproof.h +noinst_HEADERS += src/modules/surjection/main_impl.h +noinst_HEADERS += src/modules/surjection/surjection.h +noinst_HEADERS += src/modules/surjection/surjection_impl.h +noinst_HEADERS += src/modules/surjection/tests_impl.h + diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/main_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/main_impl.h new file mode 100644 index 00000000..b9b4e588 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/main_impl.h @@ -0,0 +1,338 @@ +/********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +#ifndef SECP256K1_MODULE_SURJECTION_MAIN +#define SECP256K1_MODULE_SURJECTION_MAIN + +#include +#include + +#include "modules/rangeproof/borromean.h" +#include "modules/surjection/surjection_impl.h" +#include "hash.h" +#include "include/secp256k1_rangeproof.h" +#include "include/secp256k1_surjectionproof.h" + +static size_t secp256k1_zkp_count_bits_set(const unsigned char* data, size_t count) { + size_t ret = 0; + size_t i; + for (i = 0; i < count; i++) { +#ifdef HAVE_BUILTIN_POPCOUNT + ret += __builtin_popcount(data[i]); +#else + ret += !!(data[i] & 0x1); + ret += !!(data[i] & 0x2); + ret += !!(data[i] & 0x4); + ret += !!(data[i] & 0x8); + ret += !!(data[i] & 0x10); + ret += !!(data[i] & 0x20); + ret += !!(data[i] & 0x40); + ret += !!(data[i] & 0x80); +#endif + } + return ret; +} + +int secp256k1_zkp_surjectionproof_parse(const secp256k1_zkp_context* ctx, secp256k1_zkp_surjectionproof *proof, const unsigned char *input, size_t inputlen) { + size_t n_inputs; + size_t signature_len; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(proof != NULL); + ARG_CHECK(input != NULL); + (void) ctx; + + if (inputlen < 2) { + return 0; + } + n_inputs = ((size_t) (input[1] << 8)) + input[0]; + if (n_inputs > SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) { + return 0; + } + if (inputlen < 2 + (n_inputs + 7) / 8) { + return 0; + } + + signature_len = 32 * (1 + secp256k1_zkp_count_bits_set(&input[2], (n_inputs + 7) / 8)); + if (inputlen != 2 + (n_inputs + 7) / 8 + signature_len) { + return 0; + } + proof->n_inputs = n_inputs; + memcpy(proof->used_inputs, &input[2], (n_inputs + 7) / 8); + memcpy(proof->data, &input[2 + (n_inputs + 7) / 8], signature_len); + + return 1; +} + +int secp256k1_zkp_surjectionproof_serialize(const secp256k1_zkp_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_zkp_surjectionproof *proof) { + size_t signature_len; + size_t serialized_len; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(proof != NULL); + (void) ctx; + + signature_len = 32 * (1 + secp256k1_zkp_count_bits_set(proof->used_inputs, (proof->n_inputs + 7) / 8)); + serialized_len = 2 + (proof->n_inputs + 7) / 8 + signature_len; + if (*outputlen < serialized_len) { + return 0; + } + + output[0] = proof->n_inputs % 0x100; + output[1] = proof->n_inputs / 0x100; + memcpy(&output[2], proof->used_inputs, (proof->n_inputs + 7) / 8); + memcpy(&output[2 + (proof->n_inputs + 7) / 8], proof->data, signature_len); + *outputlen = serialized_len; + + return 1; +} + +size_t secp256k1_zkp_surjectionproof_n_total_inputs(const secp256k1_zkp_context* ctx, const secp256k1_zkp_surjectionproof* proof) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(proof != NULL); + (void) ctx; + return proof->n_inputs; +} + +size_t secp256k1_zkp_surjectionproof_n_used_inputs(const secp256k1_zkp_context* ctx, const secp256k1_zkp_surjectionproof* proof) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(proof != NULL); + (void) ctx; + return secp256k1_zkp_count_bits_set(proof->used_inputs, (proof->n_inputs + 7) / 8); +} + +size_t secp256k1_zkp_surjectionproof_serialized_size(const secp256k1_zkp_context* ctx, const secp256k1_zkp_surjectionproof* proof) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(proof != NULL); + return 2 + (proof->n_inputs + 7) / 8 + 32 * (1 + secp256k1_zkp_surjectionproof_n_used_inputs(ctx, proof)); +} + +typedef struct { + unsigned char state[32]; + size_t state_i; +} secp256k1_zkp_surjectionproof_csprng; + +static void secp256k1_zkp_surjectionproof_csprng_init(secp256k1_zkp_surjectionproof_csprng *csprng, const unsigned char* state) { + memcpy(csprng->state, state, 32); + csprng->state_i = 0; +} + +static size_t secp256k1_zkp_surjectionproof_csprng_next(secp256k1_zkp_surjectionproof_csprng *csprng, size_t rand_max) { + /* The number of random bytes to read for each random sample */ + const size_t increment = rand_max > 256 ? 2 : 1; + /* The maximum value expressable by the number of random bytes we read */ + const size_t selection_range = rand_max > 256 ? 0xffff : 0xff; + /* The largest multiple of rand_max that fits within selection_range */ + const size_t limit = ((selection_range + 1) / rand_max) * rand_max; + + while (1) { + size_t val; + if (csprng->state_i + increment >= 32) { + secp256k1_zkp_sha256 sha; + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_sha256_write(&sha, csprng->state, 32); + secp256k1_zkp_sha256_finalize(&sha, csprng->state); + csprng->state_i = 0; + } + val = csprng->state[csprng->state_i]; + if (increment > 1) { + val = (val << 8) + csprng->state[csprng->state_i + 1]; + } + csprng->state_i += increment; + /* Accept only values below our limit. Values equal to or above the limit are + * biased because they comprise only a subset of the range (0, rand_max - 1) */ + if (val < limit) { + return val % rand_max; + } + } +} + +int secp256k1_zkp_surjectionproof_initialize(const secp256k1_zkp_context* ctx, secp256k1_zkp_surjectionproof* proof, size_t *input_index, const secp256k1_zkp_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, const secp256k1_zkp_fixed_asset_tag* fixed_output_tag, const size_t n_max_iterations, const unsigned char *random_seed32) { + secp256k1_zkp_surjectionproof_csprng csprng; + size_t n_iterations = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(proof != NULL); + ARG_CHECK(input_index != NULL); + ARG_CHECK(fixed_input_tags != NULL); + ARG_CHECK(fixed_output_tag != NULL); + ARG_CHECK(random_seed32 != NULL); + ARG_CHECK(n_input_tags <= SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS); + ARG_CHECK(n_input_tags_to_use <= n_input_tags); + (void) ctx; + + secp256k1_zkp_surjectionproof_csprng_init(&csprng, random_seed32); + memset(proof->data, 0, sizeof(proof->data)); + proof->n_inputs = n_input_tags; + + while (1) { + int has_output_tag = 0; + size_t i; + + /* obtain a random set of indices */ + memset(proof->used_inputs, 0, sizeof(proof->used_inputs)); + for (i = 0; i < n_input_tags_to_use; i++) { + while (1) { + size_t next_input_index; + next_input_index = secp256k1_zkp_surjectionproof_csprng_next(&csprng, n_input_tags); + if (memcmp(&fixed_input_tags[next_input_index], fixed_output_tag, sizeof(*fixed_output_tag)) == 0) { + *input_index = next_input_index; + has_output_tag = 1; + } + + if (!(proof->used_inputs[next_input_index / 8] & (1 << (next_input_index % 8)))) { + proof->used_inputs[next_input_index / 8] |= (1 << (next_input_index % 8)); + break; + } + } + } + + /* Check if we succeeded */ + n_iterations++; + if (has_output_tag) { +#ifdef VERIFY + proof->initialized = 1; +#endif + return n_iterations; + } + if (n_iterations >= n_max_iterations) { +#ifdef VERIFY + proof->initialized = 0; +#endif + return 0; + } + } +} + +int secp256k1_zkp_surjectionproof_generate(const secp256k1_zkp_context* ctx, secp256k1_zkp_surjectionproof* proof, const secp256k1_zkp_generator* ephemeral_input_tags, size_t n_ephemeral_input_tags, const secp256k1_zkp_generator* ephemeral_output_tag, size_t input_index, const unsigned char *input_blinding_key, const unsigned char *output_blinding_key) { + secp256k1_zkp_scalar blinding_key; + secp256k1_zkp_scalar tmps; + secp256k1_zkp_scalar nonce; + int overflow = 0; + size_t rsizes[1]; /* array needed for borromean sig API */ + size_t indices[1]; /* array needed for borromean sig API */ + size_t i; + size_t n_total_pubkeys; + size_t n_used_pubkeys; + size_t ring_input_index = 0; + secp256k1_zkp_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS]; + secp256k1_zkp_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS]; + secp256k1_zkp_ge inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS]; + secp256k1_zkp_ge output; + unsigned char msg32[32]; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(secp256k1_zkp_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(proof != NULL); + ARG_CHECK(ephemeral_input_tags != NULL); + ARG_CHECK(ephemeral_output_tag != NULL); + ARG_CHECK(input_blinding_key != NULL); + ARG_CHECK(output_blinding_key != NULL); +#ifdef VERIFY + CHECK(proof->initialized == 1); +#endif + + /* Compute secret key */ + secp256k1_zkp_scalar_set_b32(&tmps, input_blinding_key, &overflow); + if (overflow) { + return 0; + } + secp256k1_zkp_scalar_set_b32(&blinding_key, output_blinding_key, &overflow); + if (overflow) { + return 0; + } + /* The only time the input may equal the output is if neither one was blinded in the first place, + * i.e. both blinding keys are zero. Otherwise this is a privacy leak. */ + if (secp256k1_zkp_scalar_eq(&tmps, &blinding_key) && !secp256k1_zkp_scalar_is_zero(&blinding_key)) { + return 0; + } + secp256k1_zkp_scalar_negate(&tmps, &tmps); + secp256k1_zkp_scalar_add(&blinding_key, &blinding_key, &tmps); + + /* Compute public keys */ + n_total_pubkeys = secp256k1_zkp_surjectionproof_n_total_inputs(ctx, proof); + n_used_pubkeys = secp256k1_zkp_surjectionproof_n_used_inputs(ctx, proof); + if (n_used_pubkeys > n_total_pubkeys || n_total_pubkeys != n_ephemeral_input_tags) { + return 0; + } + + secp256k1_zkp_generator_load(&output, ephemeral_output_tag); + for (i = 0; i < n_total_pubkeys; i++) { + secp256k1_zkp_generator_load(&inputs[i], &ephemeral_input_tags[i]); + } + + secp256k1_zkp_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, inputs, n_total_pubkeys, proof->used_inputs, &output, input_index, &ring_input_index); + + /* Produce signature */ + rsizes[0] = (int) n_used_pubkeys; + indices[0] = (int) ring_input_index; + secp256k1_zkp_surjection_genmessage(msg32, inputs, n_total_pubkeys, &output); + if (secp256k1_zkp_surjection_genrand(borromean_s, n_used_pubkeys, &blinding_key) == 0) { + return 0; + } + /* Borromean sign will overwrite one of the s values we just generated, so use + * it as a nonce instead. This avoids extra random generation and also is an + * homage to the rangeproof code which does this very cleverly to encode messages. */ + nonce = borromean_s[ring_input_index]; + secp256k1_zkp_scalar_clear(&borromean_s[ring_input_index]); + if (secp256k1_zkp_borromean_sign(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, &proof->data[0], borromean_s, ring_pubkeys, &nonce, &blinding_key, rsizes, indices, 1, msg32, 32) == 0) { + return 0; + } + for (i = 0; i < n_used_pubkeys; i++) { + secp256k1_zkp_scalar_get_b32(&proof->data[32 + 32 * i], &borromean_s[i]); + } + return 1; +} + +int secp256k1_zkp_surjectionproof_verify(const secp256k1_zkp_context* ctx, const secp256k1_zkp_surjectionproof* proof, const secp256k1_zkp_generator* ephemeral_input_tags, size_t n_ephemeral_input_tags, const secp256k1_zkp_generator* ephemeral_output_tag) { + size_t rsizes[1]; /* array needed for borromean sig API */ + size_t i; + size_t n_total_pubkeys; + size_t n_used_pubkeys; + secp256k1_zkp_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS]; + secp256k1_zkp_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS]; + secp256k1_zkp_ge inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS]; + secp256k1_zkp_ge output; + unsigned char msg32[32]; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(proof != NULL); + ARG_CHECK(ephemeral_input_tags != NULL); + ARG_CHECK(ephemeral_output_tag != NULL); + + /* Compute public keys */ + n_total_pubkeys = secp256k1_zkp_surjectionproof_n_total_inputs(ctx, proof); + n_used_pubkeys = secp256k1_zkp_surjectionproof_n_used_inputs(ctx, proof); + if (n_used_pubkeys == 0 || n_used_pubkeys > n_total_pubkeys || n_total_pubkeys != n_ephemeral_input_tags) { + return 0; + } + + secp256k1_zkp_generator_load(&output, ephemeral_output_tag); + for (i = 0; i < n_total_pubkeys; i++) { + secp256k1_zkp_generator_load(&inputs[i], &ephemeral_input_tags[i]); + } + + if (secp256k1_zkp_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, inputs, n_total_pubkeys, proof->used_inputs, &output, 0, NULL) == 0) { + return 0; + } + + /* Verify signature */ + rsizes[0] = (int) n_used_pubkeys; + for (i = 0; i < n_used_pubkeys; i++) { + int overflow = 0; + secp256k1_zkp_scalar_set_b32(&borromean_s[i], &proof->data[32 + 32 * i], &overflow); + if (overflow == 1) { + return 0; + } + } + secp256k1_zkp_surjection_genmessage(msg32, inputs, n_total_pubkeys, &output); + return secp256k1_zkp_borromean_verify(&ctx->ecmult_ctx, NULL, &proof->data[0], borromean_s, ring_pubkeys, rsizes, 1, msg32, 32); +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/surjection.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/surjection.h new file mode 100644 index 00000000..21829969 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/surjection.h @@ -0,0 +1,19 @@ +/********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SURJECTION_H_ +#define _SECP256K1_SURJECTION_H_ + +#include "group.h" +#include "scalar.h" + +SECP256K1_INLINE static int secp256k1_zkp_surjection_genmessage(unsigned char *msg32, secp256k1_zkp_ge *ephemeral_input_tags, size_t n_input_tags, secp256k1_zkp_ge *ephemeral_output_tag); + +SECP256K1_INLINE static int secp256k1_zkp_surjection_genrand(secp256k1_zkp_scalar *s, size_t ns, const secp256k1_zkp_scalar *blinding_key); + +SECP256K1_INLINE static int secp256k1_zkp_surjection_compute_public_keys(secp256k1_zkp_gej *pubkeys, size_t n_pubkeys, const secp256k1_zkp_ge *input_tags, size_t n_input_tags, const unsigned char *used_tags, const secp256k1_zkp_ge *output_tag, size_t input_index, size_t *ring_input_index); + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/surjection.md b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/surjection.md new file mode 100644 index 00000000..e7bd4db1 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/surjection.md @@ -0,0 +1,108 @@ +Surjection Proof Module +=========================== + +This module implements a scheme by which a given point can be proven to be +equal to one of a set of points, plus a known difference. This is used in +Confidential Assets when reblinding "asset commitments", which are NUMS +points, to prove that the underlying NUMS point does not change during +reblinding. + +Assets are represented, in general, by a 32-byte seed (a hash of some +transaction data) which is hashed to form a NUMS generator, which appears +on the blockchain only in blinded form. We refer to the seed as an +"asset ID" and the blinded generator as an "(ephemeral) asset commitment". +These asset commitments are unique per-output, and their NUMS components +are in general known only to the holder of the output. + +The result is that within a transaction, all outputs are able to have +a new uniformly-random asset commitment which cannot be associated with +any individual input asset id, but verifiers are nonetheless assured that +all assets coming out of a transaction are ones that went in. + +### Terminology + +Assets are identified by a 32-byte "asset ID". In this library these IDs +are used as input to a point-valued hash function `H`. We usually refer +to the hash output as `A`, since this output is the only thing that appears +in the algebra. + +Then transaction outputs have "asset commitments", which are curvepoints +of the form `A + rG`, where `A` is the hash of the asset ID and `r` is +some random "blinding factor". + +### Design Rationale + +Confidential Assets essentially works by replacing the second NUMS generator +`H` in Confidental Transactions with a per-asset unique NUMS generator. This +allows the same verification equation (the sum of all blinded inputs must +equal the sum of all blinded outputs) to imply that quantity of *every* asset +type is preserved in each transaction. + +It turns out that even if outputs are reblinded by the addition of `rG` for +some known `r`, this verification equation has the same meaning, with one +caveat: verifiers must be assured that the reblinding preserves the original +generators (and does not, for example, negate them). + +This assurance is what surjection proofs provide. + +### Limitations + +The naive scheme works as follows: every output asset is shown to have come +from some input asset. However, the proofs scale with the number of input +assets, so for all outputs the total size of all surjection proofs is `O(mn)` +for `m`, `n` the number of inputs and outputs. + +We therefore restrict the number of inputs that each output may have come +from to 3 (well, some fixed number, which is passed into the API), which +provides a weaker form of blinding, but gives `O(n)` scaling. Over many +transactions, the privacy afforded by this increases exponentially. + +### Our Scheme + +Our scheme works as follows. Proofs are generated in two steps, "initialization" +which selects a subset of inputs and "generation" which does the mathematical +part of proof generation. + +Every input has an asset commitment for which we know the blinding key and +underlying asset ID. + +#### Initialization + +The initialization function takes a list of input asset IDs and one output +asset ID. It chooses an input subset of some fixed size repeatedly until it +the output ID appears at least once in its subset. + +It stores a bitmap representing this subset in the proof object and returns +the number of iterations it needed to choose the subset. The reciprocal of +this represents the probability that a uniformly random input-output +mapping would correspond to the actual input-output mapping, and therefore +gives a measure of privacy. (Lower iteration counts are better.) + +It also informs the caller the index of the input whose ID matches the output. + +As the API works on only a single output at a time, the total probability +should be computed by multiplying together the counts for each output. + +#### Generation + +The generation function takes a list of input asset commitments, an output +asset commitment, the input index returned by the initialization step, and +blinding keys for (a) the output commitment, (b) the input commitment. Here +"the input commitment" refers specifically to the input whose index was +chosen during initialization. + +Next, it computes a ring signature over the differences between the output +commitment and every input commitment chosen during initialization. Since +the discrete log of one of these is the difference between the output and +input blinding keys, it is possible to create a ring signature over every +differences will be the blinding factor of the output. We create such a +signature, which completes the proof. + +#### Verification + +Verification takes a surjection proof object, a list of input commitments, +and an output commitment. The proof object contains a ring signature and +a bitmap describing which input commitments to use, and verification +succeeds iff the signature verifies. + + diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/surjection_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/surjection_impl.h new file mode 100644 index 00000000..a6a1c465 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/surjection_impl.h @@ -0,0 +1,86 @@ +/********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SURJECTION_IMPL_H_ +#define _SECP256K1_SURJECTION_IMPL_H_ + +#include +#include + +#include "eckey.h" +#include "group.h" +#include "scalar.h" +#include "hash.h" + +SECP256K1_INLINE static void secp256k1_zkp_surjection_genmessage(unsigned char *msg32, secp256k1_zkp_ge *ephemeral_input_tags, size_t n_input_tags, secp256k1_zkp_ge *ephemeral_output_tag) { + /* compute message */ + size_t i; + unsigned char pk_ser[33]; + size_t pk_len = sizeof(pk_ser); + secp256k1_zkp_sha256 sha256_en; + + secp256k1_zkp_sha256_initialize(&sha256_en); + for (i = 0; i < n_input_tags; i++) { + secp256k1_zkp_eckey_pubkey_serialize(&ephemeral_input_tags[i], pk_ser, &pk_len, 1); + assert(pk_len == sizeof(pk_ser)); + secp256k1_zkp_sha256_write(&sha256_en, pk_ser, pk_len); + } + secp256k1_zkp_eckey_pubkey_serialize(ephemeral_output_tag, pk_ser, &pk_len, 1); + assert(pk_len == sizeof(pk_ser)); + secp256k1_zkp_sha256_write(&sha256_en, pk_ser, pk_len); + secp256k1_zkp_sha256_finalize(&sha256_en, msg32); +} + +SECP256K1_INLINE static int secp256k1_zkp_surjection_genrand(secp256k1_zkp_scalar *s, size_t ns, const secp256k1_zkp_scalar *blinding_key) { + size_t i; + unsigned char sec_input[36]; + secp256k1_zkp_sha256 sha256_en; + + /* compute s values */ + secp256k1_zkp_scalar_get_b32(&sec_input[4], blinding_key); + for (i = 0; i < ns; i++) { + int overflow = 0; + sec_input[0] = i; + sec_input[1] = i >> 8; + sec_input[2] = i >> 16; + sec_input[3] = i >> 24; + + secp256k1_zkp_sha256_initialize(&sha256_en); + secp256k1_zkp_sha256_write(&sha256_en, sec_input, 36); + secp256k1_zkp_sha256_finalize(&sha256_en, sec_input); + secp256k1_zkp_scalar_set_b32(&s[i], sec_input, &overflow); + if (overflow == 1) { + memset(sec_input, 0, 32); + return 0; + } + } + memset(sec_input, 0, 32); + return 1; +} + +SECP256K1_INLINE static int secp256k1_zkp_surjection_compute_public_keys(secp256k1_zkp_gej *pubkeys, size_t n_pubkeys, const secp256k1_zkp_ge *input_tags, size_t n_input_tags, const unsigned char *used_tags, const secp256k1_zkp_ge *output_tag, size_t input_index, size_t *ring_input_index) { + size_t i; + size_t j = 0; + for (i = 0; i < n_input_tags; i++) { + if (used_tags[i / 8] & (1 << (i % 8))) { + secp256k1_zkp_ge tmpge; + secp256k1_zkp_ge_neg(&tmpge, &input_tags[i]); + secp256k1_zkp_gej_set_ge(&pubkeys[j], &tmpge); + secp256k1_zkp_gej_add_ge_var(&pubkeys[j], &pubkeys[j], output_tag, NULL); + if (ring_input_index != NULL && input_index == i) { + *ring_input_index = j; + } + j++; + if (j > n_pubkeys) { + return 0; + } + } + } + return 1; +} + + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/tests_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/tests_impl.h new file mode 100644 index 00000000..46030d2a --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/surjection/tests_impl.h @@ -0,0 +1,494 @@ +/********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_SURJECTIONPROOF_TESTS +#define SECP256K1_MODULE_SURJECTIONPROOF_TESTS + +#include "testrand.h" +#include "group.h" +#include "include/secp256k1_generator.h" +#include "include/secp256k1_rangeproof.h" +#include "include/secp256k1_surjectionproof.h" + +static void test_surjectionproof_api(void) { + unsigned char seed[32]; + secp256k1_zkp_context *none = secp256k1_zkp_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_zkp_context *sign = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_zkp_context *vrfy = secp256k1_zkp_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_zkp_context *both = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_zkp_fixed_asset_tag fixed_input_tags[10]; + secp256k1_zkp_fixed_asset_tag fixed_output_tag; + secp256k1_zkp_generator ephemeral_input_tags[10]; + secp256k1_zkp_generator ephemeral_output_tag; + unsigned char input_blinding_key[10][32]; + unsigned char output_blinding_key[32]; + unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX]; + size_t serialized_len; + secp256k1_zkp_surjectionproof proof; + size_t n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]); + size_t input_index; + int32_t ecount = 0; + size_t i; + + secp256k1_zkp_rand256(seed); + secp256k1_zkp_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); + + for (i = 0; i < n_inputs; i++) { + secp256k1_zkp_rand256(input_blinding_key[i]); + secp256k1_zkp_rand256(fixed_input_tags[i].data); + CHECK(secp256k1_zkp_generator_generate_blinded(ctx, &ephemeral_input_tags[i], fixed_input_tags[i].data, input_blinding_key[i])); + } + secp256k1_zkp_rand256(output_blinding_key); + memcpy(&fixed_output_tag, &fixed_input_tags[0], sizeof(fixed_input_tags[0])); + CHECK(secp256k1_zkp_generator_generate_blinded(ctx, &ephemeral_output_tag, fixed_output_tag.data, output_blinding_key)); + + /* check initialize */ + CHECK(secp256k1_zkp_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, seed) == 0); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_surjectionproof_initialize(none, NULL, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_surjectionproof_initialize(none, &proof, NULL, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_surjectionproof_initialize(none, &proof, &input_index, NULL, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS + 1, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], 100, seed) != 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs + 1, &fixed_input_tags[0], 100, seed) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_zkp_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, NULL, 100, seed) == 0); + CHECK(ecount == 6); + CHECK((secp256k1_zkp_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 0, seed) & 1) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_zkp_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, NULL) == 0); + CHECK(ecount == 7); + + CHECK(secp256k1_zkp_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0); + /* check generate */ + CHECK(secp256k1_zkp_surjectionproof_generate(none, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 8); + CHECK(secp256k1_zkp_surjectionproof_generate(vrfy, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 9); + + CHECK(secp256k1_zkp_surjectionproof_generate(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 10); + CHECK(secp256k1_zkp_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0); + CHECK(ecount == 10); + + CHECK(secp256k1_zkp_surjectionproof_generate(both, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 11); + CHECK(secp256k1_zkp_surjectionproof_generate(both, &proof, NULL, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_zkp_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs + 1, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_zkp_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs - 1, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_zkp_surjectionproof_generate(both, &proof, ephemeral_input_tags, 0, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_zkp_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, NULL, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 13); + CHECK(secp256k1_zkp_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 1, input_blinding_key[0], output_blinding_key) != 0); + CHECK(ecount == 13); /* the above line "succeeds" but generates an invalid proof as the input_index is wrong. it is fairly expensive to detect this. should we? */ + CHECK(secp256k1_zkp_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, n_inputs + 1, input_blinding_key[0], output_blinding_key) != 0); + CHECK(ecount == 13); + CHECK(secp256k1_zkp_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, NULL, output_blinding_key) == 0); + CHECK(ecount == 14); + CHECK(secp256k1_zkp_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], NULL) == 0); + CHECK(ecount == 15); + + CHECK(secp256k1_zkp_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0); + /* check verify */ + CHECK(secp256k1_zkp_surjectionproof_verify(none, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0); + CHECK(ecount == 16); + CHECK(secp256k1_zkp_surjectionproof_verify(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0); + CHECK(ecount == 17); + CHECK(secp256k1_zkp_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) != 0); + CHECK(ecount == 17); + + CHECK(secp256k1_zkp_surjectionproof_verify(vrfy, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0); + CHECK(ecount == 18); + CHECK(secp256k1_zkp_surjectionproof_verify(vrfy, &proof, NULL, n_inputs, &ephemeral_output_tag) == 0); + CHECK(ecount == 19); + CHECK(secp256k1_zkp_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs - 1, &ephemeral_output_tag) == 0); + CHECK(ecount == 19); + CHECK(secp256k1_zkp_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs + 1, &ephemeral_output_tag) == 0); + CHECK(ecount == 19); + CHECK(secp256k1_zkp_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs, NULL) == 0); + CHECK(ecount == 20); + + /* Check serialize */ + serialized_len = sizeof(serialized_proof); + CHECK(secp256k1_zkp_surjectionproof_serialize(none, serialized_proof, &serialized_len, &proof) != 0); + CHECK(ecount == 20); + serialized_len = sizeof(serialized_proof); + CHECK(secp256k1_zkp_surjectionproof_serialize(none, NULL, &serialized_len, &proof) == 0); + CHECK(ecount == 21); + serialized_len = sizeof(serialized_proof); + CHECK(secp256k1_zkp_surjectionproof_serialize(none, serialized_proof, NULL, &proof) == 0); + CHECK(ecount == 22); + serialized_len = sizeof(serialized_proof); + CHECK(secp256k1_zkp_surjectionproof_serialize(none, serialized_proof, &serialized_len, NULL) == 0); + CHECK(ecount == 23); + + serialized_len = sizeof(serialized_proof); + CHECK(secp256k1_zkp_surjectionproof_serialize(none, serialized_proof, &serialized_len, &proof) != 0); + /* Check parse */ + CHECK(secp256k1_zkp_surjectionproof_parse(none, &proof, serialized_proof, serialized_len) != 0); + CHECK(ecount == 23); + CHECK(secp256k1_zkp_surjectionproof_parse(none, NULL, serialized_proof, serialized_len) == 0); + CHECK(ecount == 24); + CHECK(secp256k1_zkp_surjectionproof_parse(none, &proof, NULL, serialized_len) == 0); + CHECK(ecount == 25); + CHECK(secp256k1_zkp_surjectionproof_parse(none, &proof, serialized_proof, 0) == 0); + CHECK(ecount == 25); + + secp256k1_zkp_context_destroy(none); + secp256k1_zkp_context_destroy(sign); + secp256k1_zkp_context_destroy(vrfy); + secp256k1_zkp_context_destroy(both); +} + +static void test_input_selection(size_t n_inputs) { + unsigned char seed[32]; + size_t i; + size_t result; + size_t input_index; + size_t try_count = n_inputs * 100; + secp256k1_zkp_surjectionproof proof; + secp256k1_zkp_fixed_asset_tag fixed_input_tags[1000]; + const size_t max_n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]) - 1; + + CHECK(n_inputs < max_n_inputs); + secp256k1_zkp_rand256(seed); + + for (i = 0; i < n_inputs + 1; i++) { + secp256k1_zkp_rand256(fixed_input_tags[i].data); + } + + /* cannot match output when told to use zero keys */ + result = secp256k1_zkp_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], try_count, seed); + CHECK(result == 0); + CHECK(secp256k1_zkp_surjectionproof_n_used_inputs(ctx, &proof) == 0); + CHECK(secp256k1_zkp_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); + CHECK(secp256k1_zkp_surjectionproof_serialized_size(ctx, &proof) == 34 + (n_inputs + 7) / 8); + if (n_inputs > 0) { + /* succeed in 100*n_inputs tries (probability of failure e^-100) */ + result = secp256k1_zkp_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 1, &fixed_input_tags[0], try_count, seed); + CHECK(result > 0); + CHECK(result < n_inputs * 10); + CHECK(secp256k1_zkp_surjectionproof_n_used_inputs(ctx, &proof) == 1); + CHECK(secp256k1_zkp_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); + CHECK(secp256k1_zkp_surjectionproof_serialized_size(ctx, &proof) == 66 + (n_inputs + 7) / 8); + CHECK(input_index == 0); + } + + if (n_inputs >= 3) { + /* succeed in 10*n_inputs tries (probability of failure e^-10) */ + result = secp256k1_zkp_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[1], try_count, seed); + CHECK(result > 0); + CHECK(secp256k1_zkp_surjectionproof_n_used_inputs(ctx, &proof) == 3); + CHECK(secp256k1_zkp_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); + CHECK(secp256k1_zkp_surjectionproof_serialized_size(ctx, &proof) == 130 + (n_inputs + 7) / 8); + CHECK(input_index == 1); + + /* fail, key not found */ + result = secp256k1_zkp_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[n_inputs], try_count, seed); + CHECK(result == 0); + + /* succeed on first try when told to use all keys */ + result = secp256k1_zkp_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], try_count, seed); + CHECK(result == 1); + CHECK(secp256k1_zkp_surjectionproof_n_used_inputs(ctx, &proof) == n_inputs); + CHECK(secp256k1_zkp_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); + CHECK(secp256k1_zkp_surjectionproof_serialized_size(ctx, &proof) == 2 + 32 * (n_inputs + 1) + (n_inputs + 7) / 8); + CHECK(input_index == 0); + + /* succeed in less than 64 tries when told to use half keys. (probability of failure 2^-64) */ + result = secp256k1_zkp_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs / 2, &fixed_input_tags[0], 64, seed); + CHECK(result > 0); + CHECK(result < 64); + CHECK(secp256k1_zkp_surjectionproof_n_used_inputs(ctx, &proof) == n_inputs / 2); + CHECK(secp256k1_zkp_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); + CHECK(secp256k1_zkp_surjectionproof_serialized_size(ctx, &proof) == 2 + 32 * (n_inputs / 2 + 1) + (n_inputs + 7) / 8); + CHECK(input_index == 0); + } +} + +/** Runs surjectionproof_initilize multiple times and records the number of times each input was used. + */ +static void test_input_selection_distribution_helper(const secp256k1_zkp_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, size_t *used_inputs) { + secp256k1_zkp_surjectionproof proof; + size_t input_index; + size_t i; + size_t j; + unsigned char seed[32]; + size_t result; + for (i = 0; i < n_input_tags; i++) { + used_inputs[i] = 0; + } + for(j = 0; j < 10000; j++) { + secp256k1_zkp_rand256(seed); + result = secp256k1_zkp_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_input_tags, n_input_tags_to_use, &fixed_input_tags[0], 64, seed); + CHECK(result > 0); + + for (i = 0; i < n_input_tags; i++) { + if (proof.used_inputs[i / 8] & (1 << (i % 8))) { + used_inputs[i] += 1; + } + } + } +} + +/** Probabilistic test of the distribution of used_inputs after surjectionproof_initialize. + * Each confidence interval assertion fails incorrectly with a probability of 2^-128. + */ +static void test_input_selection_distribution(void) { + size_t i; + size_t n_input_tags_to_use; + const size_t n_inputs = 4; + secp256k1_zkp_fixed_asset_tag fixed_input_tags[4]; + size_t used_inputs[4]; + + for (i = 0; i < n_inputs; i++) { + secp256k1_zkp_rand256(fixed_input_tags[i].data); + } + + /* If there is one input tag to use, initialize must choose the one equal to fixed_output_tag. */ + n_input_tags_to_use = 1; + test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); + CHECK(used_inputs[0] == 10000); + CHECK(used_inputs[1] == 0); + CHECK(used_inputs[2] == 0); + CHECK(used_inputs[3] == 0); + + n_input_tags_to_use = 2; + /* The input equal to the fixed_output_tag must be included in all used_inputs sets. + * For each fixed_input_tag != fixed_output_tag the probability that it's included + * in the used_inputs set is P(used_input|not fixed_output_tag) = 1/3. + */ + test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); + CHECK(used_inputs[0] == 10000); + CHECK(used_inputs[1] > 2725 && used_inputs[1] < 3961); + CHECK(used_inputs[2] > 2725 && used_inputs[2] < 3961); + CHECK(used_inputs[3] > 2725 && used_inputs[3] < 3961); + + n_input_tags_to_use = 3; + /* P(used_input|not fixed_output_tag) = 2/3 */ + test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); + CHECK(used_inputs[0] == 10000); + CHECK(used_inputs[1] > 6039 && used_inputs[1] < 7275); + CHECK(used_inputs[2] > 6039 && used_inputs[2] < 7275); + CHECK(used_inputs[3] > 6039 && used_inputs[3] < 7275); + + + n_input_tags_to_use = 1; + /* Create second input tag that is equal to the output tag. Therefore, when using only + * one input we have P(used_input|fixed_output_tag) = 1/2 and P(used_input|not fixed_output_tag) = 0 + */ + memcpy(fixed_input_tags[0].data, fixed_input_tags[1].data, 32); + test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); + CHECK(used_inputs[0] > 4345 && used_inputs[0] < 5655); + CHECK(used_inputs[1] > 4345 && used_inputs[1] < 5655); + CHECK(used_inputs[2] == 0); + CHECK(used_inputs[3] == 0); + + n_input_tags_to_use = 2; + /* When choosing 2 inputs in initialization there are 5 possible combinations of + * input indexes {(0, 1), (1, 2), (0, 3), (1, 3), (0, 2)}. Therefore we have + * P(used_input|fixed_output_tag) = 3/5 and P(used_input|not fixed_output_tag) = 2/5. + */ + test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); + CHECK(used_inputs[0] > 5352 && used_inputs[0] < 6637); + CHECK(used_inputs[1] > 5352 && used_inputs[1] < 6637); + CHECK(used_inputs[2] > 3363 && used_inputs[2] < 4648); + CHECK(used_inputs[3] > 3363 && used_inputs[3] < 4648); + + n_input_tags_to_use = 3; + /* There are 4 combinations, each with all inputs except one. Therefore we have + * P(used_input|fixed_output_tag) = 3/4 and P(used_input|not fixed_output_tag) = 3/4. + */ + test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); + CHECK(used_inputs[0] > 6918 && used_inputs[0] < 8053); + CHECK(used_inputs[1] > 6918 && used_inputs[1] < 8053); + CHECK(used_inputs[2] > 6918 && used_inputs[2] < 8053); + CHECK(used_inputs[3] > 6918 && used_inputs[3] < 8053); +} + +static void test_gen_verify(size_t n_inputs, size_t n_used) { + unsigned char seed[32]; + secp256k1_zkp_surjectionproof proof; + unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX]; + unsigned char serialized_proof_trailing[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX + 1]; + size_t serialized_len = SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX; + secp256k1_zkp_fixed_asset_tag fixed_input_tags[1000]; + secp256k1_zkp_generator ephemeral_input_tags[1000]; + unsigned char *input_blinding_key[1000]; + const size_t max_n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]) - 1; + size_t try_count = n_inputs * 100; + size_t key_index; + size_t input_index; + size_t i; + int result; + + /* setup */ + CHECK(n_used <= n_inputs); + CHECK(n_inputs < max_n_inputs); + secp256k1_zkp_rand256(seed); + + key_index = (((size_t) seed[0] << 8) + seed[1]) % n_inputs; + + for (i = 0; i < n_inputs + 1; i++) { + input_blinding_key[i] = malloc(32); + secp256k1_zkp_rand256(input_blinding_key[i]); + /* choose random fixed tag, except that for the output one copy from the key_index */ + if (i < n_inputs) { + secp256k1_zkp_rand256(fixed_input_tags[i].data); + } else { + memcpy(&fixed_input_tags[i], &fixed_input_tags[key_index], sizeof(fixed_input_tags[i])); + } + CHECK(secp256k1_zkp_generator_generate_blinded(ctx, &ephemeral_input_tags[i], fixed_input_tags[i].data, input_blinding_key[i])); + } + + /* test */ + result = secp256k1_zkp_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_used, &fixed_input_tags[key_index], try_count, seed); + if (n_used == 0) { + CHECK(result == 0); + return; + } + CHECK(result > 0); + CHECK(input_index == key_index); + + result = secp256k1_zkp_surjectionproof_generate(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs], input_index, input_blinding_key[input_index], input_blinding_key[n_inputs]); + CHECK(result == 1); + + CHECK(secp256k1_zkp_surjectionproof_serialize(ctx, serialized_proof, &serialized_len, &proof)); + CHECK(serialized_len == secp256k1_zkp_surjectionproof_serialized_size(ctx, &proof)); + CHECK(serialized_len == SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(n_inputs, n_used)); + + /* trailing garbage */ + memcpy(&serialized_proof_trailing, &serialized_proof, serialized_len); + serialized_proof_trailing[serialized_len] = seed[0]; + CHECK(secp256k1_zkp_surjectionproof_parse(ctx, &proof, serialized_proof, serialized_len + 1) == 0); + + CHECK(secp256k1_zkp_surjectionproof_parse(ctx, &proof, serialized_proof, serialized_len)); + result = secp256k1_zkp_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs]); + CHECK(result == 1); + /* various fail cases */ + if (n_inputs > 1) { + result = secp256k1_zkp_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs - 1]); + CHECK(result == 0); + + /* number of entries in ephemeral_input_tags array is less than proof.n_inputs */ + n_inputs -= 1; + result = secp256k1_zkp_surjectionproof_generate(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs], input_index, input_blinding_key[input_index], input_blinding_key[n_inputs]); + CHECK(result == 0); + result = secp256k1_zkp_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs - 1]); + CHECK(result == 0); + n_inputs += 1; + } + + /* cleanup */ + for (i = 0; i < n_inputs + 1; i++) { + free(input_blinding_key[i]); + } +} + +/* check that a proof with empty n_used_inputs is invalid */ +static void test_no_used_inputs_verify(void) { + secp256k1_zkp_surjectionproof proof; + secp256k1_zkp_fixed_asset_tag fixed_input_tag; + secp256k1_zkp_fixed_asset_tag fixed_output_tag; + secp256k1_zkp_generator ephemeral_input_tags[1]; + size_t n_ephemeral_input_tags = 1; + secp256k1_zkp_generator ephemeral_output_tag; + unsigned char blinding_key[32]; + secp256k1_zkp_ge inputs[1]; + secp256k1_zkp_ge output; + secp256k1_zkp_sha256 sha256_e0; + int result; + + /* Create proof that doesn't use inputs. secp256k1_zkp_surjectionproof_initialize + * will not work here since it insists on selecting an input that matches the output. */ + proof.n_inputs = 1; + memset(proof.used_inputs, 0, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS / 8); + + /* create different fixed input and output tags */ + secp256k1_zkp_rand256(fixed_input_tag.data); + secp256k1_zkp_rand256(fixed_output_tag.data); + + /* blind fixed output tags with random blinding key */ + secp256k1_zkp_rand256(blinding_key); + CHECK(secp256k1_zkp_generator_generate_blinded(ctx, &ephemeral_input_tags[0], fixed_input_tag.data, blinding_key)); + CHECK(secp256k1_zkp_generator_generate_blinded(ctx, &ephemeral_output_tag, fixed_output_tag.data, blinding_key)); + + /* create "borromean signature" which is just a hash of metadata (pubkeys, etc) in this case */ + secp256k1_zkp_generator_load(&output, &ephemeral_output_tag); + secp256k1_zkp_generator_load(&inputs[0], &ephemeral_input_tags[0]); + secp256k1_zkp_surjection_genmessage(proof.data, inputs, 1, &output); + secp256k1_zkp_sha256_initialize(&sha256_e0); + secp256k1_zkp_sha256_write(&sha256_e0, proof.data, 32); + secp256k1_zkp_sha256_finalize(&sha256_e0, proof.data); + + result = secp256k1_zkp_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_ephemeral_input_tags, &ephemeral_output_tag); + CHECK(result == 0); +} + +void test_bad_serialize(void) { + secp256k1_zkp_surjectionproof proof; + unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX]; + size_t serialized_len; + + proof.n_inputs = 0; + serialized_len = 2 + 31; + /* e0 is one byte too short */ + CHECK(secp256k1_zkp_surjectionproof_serialize(ctx, serialized_proof, &serialized_len, &proof) == 0); +} + +void test_bad_parse(void) { + secp256k1_zkp_surjectionproof proof; + unsigned char serialized_proof0[] = { 0x00 }; + unsigned char serialized_proof1[] = { 0x01, 0x00 }; + unsigned char serialized_proof2[33] = { 0 }; + + /* Missing total input count */ + CHECK(secp256k1_zkp_surjectionproof_parse(ctx, &proof, serialized_proof0, sizeof(serialized_proof0)) == 0); + /* Missing bitmap */ + CHECK(secp256k1_zkp_surjectionproof_parse(ctx, &proof, serialized_proof1, sizeof(serialized_proof1)) == 0); + /* Missing e0 value */ + CHECK(secp256k1_zkp_surjectionproof_parse(ctx, &proof, serialized_proof2, sizeof(serialized_proof2)) == 0); +} + +void run_surjection_tests(void) { + int i; + for (i = 0; i < count; i++) { + test_surjectionproof_api(); + } + + test_input_selection(0); + test_input_selection(1); + test_input_selection(5); + test_input_selection(100); + test_input_selection(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS); + + test_input_selection_distribution(); + test_gen_verify(10, 3); + test_gen_verify(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS); + test_no_used_inputs_verify(); + test_bad_serialize(); + test_bad_parse(); +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/Makefile.am.include b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/Makefile.am.include new file mode 100644 index 00000000..7cf31524 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/Makefile.am.include @@ -0,0 +1,10 @@ +include_HEADERS += include/secp256k1_zkp_whitelist.h +noinst_HEADERS += src/modules/whitelist/whitelist_impl.h +noinst_HEADERS += src/modules/whitelist/main_impl.h +noinst_HEADERS += src/modules/whitelist/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_whitelist +bench_whitelist_SOURCES = src/bench_whitelist.c +bench_whitelist_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_generator_LDFLAGS = -static +endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/main_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/main_impl.h new file mode 100644 index 00000000..cbe31041 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/main_impl.h @@ -0,0 +1,174 @@ +/********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_WHITELIST_MAIN +#define SECP256K1_MODULE_WHITELIST_MAIN + +#include "include/secp256k1_whitelist.h" +#include "modules/whitelist/whitelist_impl.h" + +#define MAX_KEYS SECP256K1_WHITELIST_MAX_N_KEYS /* shorter alias */ + +int secp256k1_zkp_whitelist_sign(const secp256k1_zkp_context* ctx, secp256k1_zkp_whitelist_signature *sig, const secp256k1_zkp_pubkey *online_pubkeys, const secp256k1_zkp_pubkey *offline_pubkeys, const size_t n_keys, const secp256k1_zkp_pubkey *sub_pubkey, const unsigned char *online_seckey, const unsigned char *summed_seckey, const size_t index, secp256k1_zkp_nonce_function noncefp, const void *noncedata) { + secp256k1_zkp_gej pubs[MAX_KEYS]; + secp256k1_zkp_scalar s[MAX_KEYS]; + secp256k1_zkp_scalar sec, non; + unsigned char msg32[32]; + int ret; + + if (noncefp == NULL) { + noncefp = secp256k1_zkp_nonce_function_default; + } + + /* Sanity checks */ + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(secp256k1_zkp_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(sig != NULL); + ARG_CHECK(online_pubkeys != NULL); + ARG_CHECK(offline_pubkeys != NULL); + ARG_CHECK(n_keys <= MAX_KEYS); + ARG_CHECK(sub_pubkey != NULL); + ARG_CHECK(online_seckey != NULL); + ARG_CHECK(summed_seckey != NULL); + ARG_CHECK(index < n_keys); + + /* Compute pubkeys: online_pubkey + tweaked(offline_pubkey + address), and message */ + ret = secp256k1_zkp_whitelist_compute_keys_and_message(ctx, msg32, pubs, online_pubkeys, offline_pubkeys, n_keys, sub_pubkey); + + /* Compute signing key: online_seckey + tweaked(summed_seckey) */ + if (ret) { + ret = secp256k1_zkp_whitelist_compute_tweaked_privkey(ctx, &sec, online_seckey, summed_seckey); + } + /* Compute nonce and random s-values */ + if (ret) { + unsigned char seckey32[32]; + unsigned int count = 0; + int overflow = 0; + + secp256k1_zkp_scalar_get_b32(seckey32, &sec); + while (1) { + size_t i; + unsigned char nonce32[32]; + int done; + ret = noncefp(nonce32, msg32, seckey32, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_zkp_scalar_set_b32(&non, nonce32, &overflow); + memset(nonce32, 0, 32); + if (overflow || secp256k1_zkp_scalar_is_zero(&non)) { + count++; + continue; + } + done = 1; + for (i = 0; i < n_keys; i++) { + msg32[0] ^= i + 1; + msg32[1] ^= (i + 1) / 0x100; + ret = noncefp(&sig->data[32 * (i + 1)], msg32, seckey32, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_zkp_scalar_set_b32(&s[i], &sig->data[32 * (i + 1)], &overflow); + msg32[0] ^= i + 1; + msg32[1] ^= (i + 1) / 0x100; + if (overflow || secp256k1_zkp_scalar_is_zero(&s[i])) { + count++; + done = 0; + break; + } + } + if (done) { + break; + } + } + memset(seckey32, 0, 32); + } + /* Actually sign */ + if (ret) { + sig->n_keys = n_keys; + ret = secp256k1_zkp_borromean_sign(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, &sig->data[0], s, pubs, &non, &sec, &n_keys, &index, 1, msg32, 32); + /* Signing will change s[index], so update in the sig structure */ + secp256k1_zkp_scalar_get_b32(&sig->data[32 * (index + 1)], &s[index]); + } + + secp256k1_zkp_scalar_clear(&non); + secp256k1_zkp_scalar_clear(&sec); + return ret; +} + +int secp256k1_zkp_whitelist_verify(const secp256k1_zkp_context* ctx, const secp256k1_zkp_whitelist_signature *sig, const secp256k1_zkp_pubkey *online_pubkeys, const secp256k1_zkp_pubkey *offline_pubkeys, const size_t n_keys, const secp256k1_zkp_pubkey *sub_pubkey) { + secp256k1_zkp_scalar s[MAX_KEYS]; + secp256k1_zkp_gej pubs[MAX_KEYS]; + unsigned char msg32[32]; + size_t i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(sig != NULL); + ARG_CHECK(online_pubkeys != NULL); + ARG_CHECK(offline_pubkeys != NULL); + ARG_CHECK(sub_pubkey != NULL); + + if (sig->n_keys > MAX_KEYS || sig->n_keys != n_keys) { + return 0; + } + for (i = 0; i < sig->n_keys; i++) { + int overflow = 0; + secp256k1_zkp_scalar_set_b32(&s[i], &sig->data[32 * (i + 1)], &overflow); + if (overflow || secp256k1_zkp_scalar_is_zero(&s[i])) { + return 0; + } + } + + /* Compute pubkeys: online_pubkey + tweaked(offline_pubkey + address), and message */ + if (!secp256k1_zkp_whitelist_compute_keys_and_message(ctx, msg32, pubs, online_pubkeys, offline_pubkeys, sig->n_keys, sub_pubkey)) { + return 0; + } + /* Do verification */ + return secp256k1_zkp_borromean_verify(&ctx->ecmult_ctx, NULL, &sig->data[0], s, pubs, &sig->n_keys, 1, msg32, 32); +} + +size_t secp256k1_zkp_whitelist_signature_n_keys(const secp256k1_zkp_whitelist_signature *sig) { + return sig->n_keys; +} + +int secp256k1_zkp_whitelist_signature_parse(const secp256k1_zkp_context* ctx, secp256k1_zkp_whitelist_signature *sig, const unsigned char *input, size_t input_len) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input != NULL); + + if (input_len == 0) { + return 0; + } + + sig->n_keys = input[0]; + if (sig->n_keys >= MAX_KEYS || input_len != 1 + 32 * (sig->n_keys + 1)) { + return 0; + } + memcpy(&sig->data[0], &input[1], 32 * (sig->n_keys + 1)); + + return 1; +} + +int secp256k1_zkp_whitelist_signature_serialize(const secp256k1_zkp_context* ctx, unsigned char *output, size_t *output_len, const secp256k1_zkp_whitelist_signature *sig) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(output_len != NULL); + ARG_CHECK(sig != NULL); + + if (*output_len < 1 + 32 * (sig->n_keys + 1)) { + return 0; + } + + output[0] = sig->n_keys; + memcpy(&output[1], &sig->data[0], 32 * (sig->n_keys + 1)); + *output_len = 1 + 32 * (sig->n_keys + 1); + + return 1; +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/tests_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/tests_impl.h new file mode 100644 index 00000000..195b1cb8 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/tests_impl.h @@ -0,0 +1,151 @@ +/********************************************************************** + * Copyright (c) 2014-2016 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_WHITELIST_TESTS +#define SECP256K1_MODULE_WHITELIST_TESTS + +#include "include/secp256k1_whitelist.h" + +void test_whitelist_end_to_end(const size_t n_keys) { + unsigned char **online_seckey = (unsigned char **) malloc(n_keys * sizeof(*online_seckey)); + unsigned char **summed_seckey = (unsigned char **) malloc(n_keys * sizeof(*summed_seckey)); + secp256k1_zkp_pubkey *online_pubkeys = (secp256k1_zkp_pubkey *) malloc(n_keys * sizeof(*online_pubkeys)); + secp256k1_zkp_pubkey *offline_pubkeys = (secp256k1_zkp_pubkey *) malloc(n_keys * sizeof(*offline_pubkeys)); + + secp256k1_zkp_scalar ssub; + unsigned char csub[32]; + secp256k1_zkp_pubkey sub_pubkey; + + /* Generate random keys */ + size_t i; + /* Start with subkey */ + random_scalar_order_test(&ssub); + secp256k1_zkp_scalar_get_b32(csub, &ssub); + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, csub) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &sub_pubkey, csub) == 1); + /* Then offline and online whitelist keys */ + for (i = 0; i < n_keys; i++) { + secp256k1_zkp_scalar son, soff; + + online_seckey[i] = (unsigned char *) malloc(32); + summed_seckey[i] = (unsigned char *) malloc(32); + + /* Create two keys */ + random_scalar_order_test(&son); + secp256k1_zkp_scalar_get_b32(online_seckey[i], &son); + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, online_seckey[i]) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &online_pubkeys[i], online_seckey[i]) == 1); + + random_scalar_order_test(&soff); + secp256k1_zkp_scalar_get_b32(summed_seckey[i], &soff); + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, summed_seckey[i]) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &offline_pubkeys[i], summed_seckey[i]) == 1); + + /* Make summed_seckey correspond to the sum of offline_pubkey and sub_pubkey */ + secp256k1_zkp_scalar_add(&soff, &soff, &ssub); + secp256k1_zkp_scalar_get_b32(summed_seckey[i], &soff); + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, summed_seckey[i]) == 1); + } + + /* Sign/verify with each one */ + for (i = 0; i < n_keys; i++) { + unsigned char serialized[32 + 4 + 32 * SECP256K1_WHITELIST_MAX_N_KEYS] = {0}; + size_t slen = sizeof(serialized); + secp256k1_zkp_whitelist_signature sig; + secp256k1_zkp_whitelist_signature sig1; + + CHECK(secp256k1_zkp_whitelist_sign(ctx, &sig, online_pubkeys, offline_pubkeys, n_keys, &sub_pubkey, online_seckey[i], summed_seckey[i], i, NULL, NULL)); + CHECK(secp256k1_zkp_whitelist_verify(ctx, &sig, online_pubkeys, offline_pubkeys, n_keys, &sub_pubkey) == 1); + /* Check that exchanging keys causes a failure */ + CHECK(secp256k1_zkp_whitelist_verify(ctx, &sig, offline_pubkeys, online_pubkeys, n_keys, &sub_pubkey) != 1); + /* Serialization round trip */ + CHECK(secp256k1_zkp_whitelist_signature_serialize(ctx, serialized, &slen, &sig) == 1); + CHECK(slen == 33 + 32 * n_keys); + CHECK(secp256k1_zkp_whitelist_signature_parse(ctx, &sig1, serialized, slen) == 1); + /* (Check various bad-length conditions) */ + CHECK(secp256k1_zkp_whitelist_signature_parse(ctx, &sig1, serialized, slen + 32) == 0); + CHECK(secp256k1_zkp_whitelist_signature_parse(ctx, &sig1, serialized, slen + 1) == 0); + CHECK(secp256k1_zkp_whitelist_signature_parse(ctx, &sig1, serialized, slen - 1) == 0); + CHECK(secp256k1_zkp_whitelist_signature_parse(ctx, &sig1, serialized, 0) == 0); + CHECK(secp256k1_zkp_whitelist_verify(ctx, &sig1, online_pubkeys, offline_pubkeys, n_keys, &sub_pubkey) == 1); + CHECK(secp256k1_zkp_whitelist_verify(ctx, &sig1, offline_pubkeys, online_pubkeys, n_keys, &sub_pubkey) != 1); + + /* Test n_keys */ + CHECK(secp256k1_zkp_whitelist_signature_n_keys(&sig) == n_keys); + CHECK(secp256k1_zkp_whitelist_signature_n_keys(&sig1) == n_keys); + + /* Test bad number of keys in signature */ + sig.n_keys = n_keys + 1; + CHECK(secp256k1_zkp_whitelist_verify(ctx, &sig, offline_pubkeys, online_pubkeys, n_keys, &sub_pubkey) != 1); + sig.n_keys = n_keys; + } + + for (i = 0; i < n_keys; i++) { + free(online_seckey[i]); + free(summed_seckey[i]); + } + free(online_seckey); + free(summed_seckey); + free(online_pubkeys); + free(offline_pubkeys); +} + +void test_whitelist_bad_parse(void) { + secp256k1_zkp_whitelist_signature sig; + + const unsigned char serialized0[] = { 1+32*(0+1) }; + const unsigned char serialized1[] = { + 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 + }; + const unsigned char serialized2[] = { + 0x01, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + + /* Empty input */ + CHECK(secp256k1_zkp_whitelist_signature_parse(ctx, &sig, serialized0, 0) == 0); + /* Misses one byte of e0 */ + CHECK(secp256k1_zkp_whitelist_signature_parse(ctx, &sig, serialized1, sizeof(serialized1)) == 0); + /* Enough bytes for e0, but there is no s value */ + CHECK(secp256k1_zkp_whitelist_signature_parse(ctx, &sig, serialized2, sizeof(serialized2)) == 0); +} + +void test_whitelist_bad_serialize(void) { + unsigned char serialized[] = { + 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + size_t serialized_len; + secp256k1_zkp_whitelist_signature sig; + + CHECK(secp256k1_zkp_whitelist_signature_parse(ctx, &sig, serialized, sizeof(serialized)) == 1); + serialized_len = sizeof(serialized) - 1; + /* Output buffer is one byte too short */ + CHECK(secp256k1_zkp_whitelist_signature_serialize(ctx, serialized, &serialized_len, &sig) == 0); +} + +void run_whitelist_tests(void) { + int i; + test_whitelist_bad_parse(); + test_whitelist_bad_serialize(); + for (i = 0; i < count; i++) { + test_whitelist_end_to_end(1); + test_whitelist_end_to_end(10); + test_whitelist_end_to_end(50); + } +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/whitelist.md b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/whitelist.md new file mode 100644 index 00000000..89d19caf --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/whitelist.md @@ -0,0 +1,105 @@ +Address Whitelisting Module +=========================== + +This module implements a scheme by which members of some group, having fixed +signing keys, can prove control of an arbitrary other key without associating +their own identity (only that they belong to the group) to the new key. The +application is to patch ring-signature-like behaviour onto systems such as +Bitcoin or PGP which do not directly support this. + +We refer to such delegation as "whitelisting" because we expect it to be used +to build a dynamic whitelist of authorized keys. + +For example, imagine a private sidechain with a fixed membership set but +stronger privacy properties than Bitcoin. When moving coins from this system +to Bitcoin, it is desirable that the destination Bitcoin addresses be provably +in control of some user of the sidechain. This prevents malicious or erroneous +behaviour on the sidechain, which can likely be resolved by its participants, +from translating to theft on the wider Bitcoin network, which is irreversible. + +### Unused Schemes and Design Rationale + +#### Direct Signing + +An obvious scheme for such delegation is to simply have participants sign the +key they want to whitelist. To avoid revealing their specific identity, they +could use a ring signature. The problem with this is that it really only proves +that a participant *signed off* on a key, not that they control it. Thus any +security failure that allows text substitution could be used to subvert this +and redirect coins to an attacker-controlled address. + +#### Signing with Difference-of-Keys + +A less obvious scheme is to have a participant sign an arbitrary message with +the sum of her key `P` and the whitelisted key `W`. Such a signature with the key +`P + W` proves knowledge of either (a) discrete logarithms of both `P` and `W`; +or (b) neither. This makes directly attacking participants' signing schemes much +harder, but allows an attacker to whitelist arbitrary "garbage" keys by computing +`W` as the difference between an attacker-controlled key and `P`. For Bitcoin, +the effect of garbage keys is to "burn" stolen coins, destroying them. + +In an important sense, this "burning coins" attack is a good thing: it enables +*offline delegation*. That is, the key `P` does not need to be available at the +time of delegation. Instead, participants could choose `S = P + W`, sign with +this to delegate, and only later compute the discrete logarithm of `W = P - S`. +This allows `P` to be in cold storage or be otherwise inaccessible, improving +the overall system security. + +#### Signing with Tweaked-Difference-of-Keys + +A modification of this scheme, which prevents this "garbage key" attack, is to +instead have participants sign some message with the key `P + H(W)W`, for `H` +some random-oracle hash that maps group elements to scalars. This key, and its +discrete logarithm, cannot be known until after `W` is chosen, so `W` cannot +be selected as the difference between it and `P`. (Note that `P` could still +be some chosen difference; however `P` is a fixed key and must be verified +out-of-band to have come from a legitimate participant anyway.) + +This scheme is almost what we want, but it no longer supports offline +delegation. However, we can get this back by introducing a new key, `P'`, +and signing with the key `P + H(W + P')(W + P')`. This gives us the best +of both worlds: `P'` does not need to be online to delegate, allowing it +to be securely stored and preventing real-time attacks; `P` does need to +be online, but its compromise only allows an attacker to whitelist "garbage +keys", not attacker-controlled ones. + +### Our Scheme + +Our scheme works as follows: each participant `i` chooses two keys, `P_i` and `Q_i`. +We refer to `P_i` as the "online key" and `Q_i` as the "offline key". To whitelist +a key `W`, the participant computes the key `L_j = P_j + H(W + Q_j)(W + Q_j)` for +every participant `j`. Then she will know the discrete logarithm of `L_i` for her +own `i`. + +Next, she signs a message containing every `P_i` and `Q_i` as well as `W` with +a ring signature over all the keys `L_j`. This proves that she knows the discrete +logarithm of some `L_i` (though it is zero-knowledge which one), and therefore +knows: +1. The discrete logarithms of all of `W`, `P_i` and `Q_i`; or +2. The discrete logarithm of `P_i` but of *neither* `W` nor `Q_i`. +In other words, compromise of the online key `P_i` allows an attacker to whitelist +"garbage keys" for which nobody knows the discrete logarithm; to whitelist an +attacker-controlled key, he must compromise both `P_i` and `Q_i`. This is difficult +because by design, only the sum `S = W + Q_i` is used when signing; then by choosing +`S` freely, a participant can delegate without the secret key to `Q_i` ever being online. +(Later, when she wants to actually use `W`, she will need to compute its key as the +difference between `S` and `Q_i`; but this can be done offline and much later +and with more expensive security requirements.) + +The message to be signed contains all public keys to prevent a class of attacks +centered around choosing keys to match pre-computed signatures. In our proposed +use case, whitelisted keys already must be computed before they are signed, and +the remaining public keys are verified out-of-band when setting up the system, +so there is no direct benefit to this. We do it only to reduce fragility and +increase safety of unforeseen uses. + +Having to access the offline key `Q_i` to compute the secret to the sum `W + +Q_i` for every authorization is onerous. Instead, if the whitelisted keys are +created using +[BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) +unhardened derivation, the sum can be computed on an online machine. In order +to achieve that, the offline key `Q_j` is set to the negated last hardened +BIP32 derived parent key (typically, the public key corresponding to the xpub). +As a result `W + Q_i = I_L*G` where `I_L` is the public tweak used +to derive `W` and can be easily computed online using the extended public key +and the derivation path. diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/whitelist_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/whitelist_impl.h new file mode 100644 index 00000000..c9055e0a --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/modules/whitelist/whitelist_impl.h @@ -0,0 +1,129 @@ +/********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_WHITELIST_IMPL_H_ +#define _SECP256K1_WHITELIST_IMPL_H_ + +static int secp256k1_zkp_whitelist_hash_pubkey(secp256k1_zkp_scalar* output, secp256k1_zkp_gej* pubkey) { + unsigned char h[32]; + unsigned char c[33]; + secp256k1_zkp_sha256 sha; + int overflow = 0; + size_t size = 33; + secp256k1_zkp_ge ge; + + secp256k1_zkp_ge_set_gej(&ge, pubkey); + + secp256k1_zkp_sha256_initialize(&sha); + if (!secp256k1_zkp_eckey_pubkey_serialize(&ge, c, &size, SECP256K1_EC_COMPRESSED)) { + return 0; + } + secp256k1_zkp_sha256_write(&sha, c, size); + secp256k1_zkp_sha256_finalize(&sha, h); + + secp256k1_zkp_scalar_set_b32(output, h, &overflow); + if (overflow || secp256k1_zkp_scalar_is_zero(output)) { + /* This return path is mathematically impossible to hit */ + secp256k1_zkp_scalar_clear(output); + return 0; + } + return 1; +} + +static int secp256k1_zkp_whitelist_tweak_pubkey(const secp256k1_zkp_context* ctx, secp256k1_zkp_gej* pub_tweaked) { + secp256k1_zkp_scalar tweak; + secp256k1_zkp_scalar zero; + int ret; + + secp256k1_zkp_scalar_set_int(&zero, 0); + + ret = secp256k1_zkp_whitelist_hash_pubkey(&tweak, pub_tweaked); + if (ret) { + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, pub_tweaked, pub_tweaked, &tweak, &zero); + } + return ret; +} + +static int secp256k1_zkp_whitelist_compute_tweaked_privkey(const secp256k1_zkp_context* ctx, secp256k1_zkp_scalar* skey, const unsigned char *online_key, const unsigned char *summed_key) { + secp256k1_zkp_scalar tweak; + int ret = 1; + int overflow = 0; + + secp256k1_zkp_scalar_set_b32(skey, summed_key, &overflow); + if (overflow || secp256k1_zkp_scalar_is_zero(skey)) { + ret = 0; + } + if (ret) { + secp256k1_zkp_gej pkeyj; + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &pkeyj, skey); + ret = secp256k1_zkp_whitelist_hash_pubkey(&tweak, &pkeyj); + } + if (ret) { + secp256k1_zkp_scalar sonline; + secp256k1_zkp_scalar_mul(skey, skey, &tweak); + + secp256k1_zkp_scalar_set_b32(&sonline, online_key, &overflow); + if (overflow || secp256k1_zkp_scalar_is_zero(&sonline)) { + ret = 0; + } + secp256k1_zkp_scalar_add(skey, skey, &sonline); + secp256k1_zkp_scalar_clear(&sonline); + secp256k1_zkp_scalar_clear(&tweak); + } + + if (!ret) { + secp256k1_zkp_scalar_clear(skey); + } + return ret; +} + +/* Takes a list of pubkeys and combines them to form the public keys needed + * for the ring signature; also produce a commitment to every one that will + * be our "message". */ +static int secp256k1_zkp_whitelist_compute_keys_and_message(const secp256k1_zkp_context* ctx, unsigned char *msg32, secp256k1_zkp_gej *keys, const secp256k1_zkp_pubkey *online_pubkeys, const secp256k1_zkp_pubkey *offline_pubkeys, const int n_keys, const secp256k1_zkp_pubkey *sub_pubkey) { + unsigned char c[33]; + size_t size = 33; + secp256k1_zkp_sha256 sha; + int i; + secp256k1_zkp_ge subkey_ge; + + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_pubkey_load(ctx, &subkey_ge, sub_pubkey); + + /* commit to sub-key */ + if (!secp256k1_zkp_eckey_pubkey_serialize(&subkey_ge, c, &size, SECP256K1_EC_COMPRESSED)) { + return 0; + } + secp256k1_zkp_sha256_write(&sha, c, size); + for (i = 0; i < n_keys; i++) { + secp256k1_zkp_ge offline_ge; + secp256k1_zkp_ge online_ge; + secp256k1_zkp_gej tweaked_gej; + + /* commit to fixed keys */ + secp256k1_zkp_pubkey_load(ctx, &offline_ge, &offline_pubkeys[i]); + if (!secp256k1_zkp_eckey_pubkey_serialize(&offline_ge, c, &size, SECP256K1_EC_COMPRESSED)) { + return 0; + } + secp256k1_zkp_sha256_write(&sha, c, size); + secp256k1_zkp_pubkey_load(ctx, &online_ge, &online_pubkeys[i]); + if (!secp256k1_zkp_eckey_pubkey_serialize(&online_ge, c, &size, SECP256K1_EC_COMPRESSED)) { + return 0; + } + secp256k1_zkp_sha256_write(&sha, c, size); + + /* compute tweaked keys */ + secp256k1_zkp_gej_set_ge(&tweaked_gej, &offline_ge); + secp256k1_zkp_gej_add_ge_var(&tweaked_gej, &tweaked_gej, &subkey_ge, NULL); + secp256k1_zkp_whitelist_tweak_pubkey(ctx, &tweaked_gej); + secp256k1_zkp_gej_add_ge_var(&keys[i], &tweaked_gej, &online_ge, NULL); + } + secp256k1_zkp_sha256_finalize(&sha, msg32); + return 1; +} + + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/num.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/num.h new file mode 100644 index 00000000..c336712c --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/num.h @@ -0,0 +1,74 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_NUM_H +#define SECP256K1_NUM_H + +#ifndef USE_NUM_NONE + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#if defined(USE_NUM_GMP) +#include "num_gmp.h" +#else +#error "Please select num implementation" +#endif + +/** Copy a number. */ +static void secp256k1_zkp_num_copy(secp256k1_zkp_num *r, const secp256k1_zkp_num *a); + +/** Convert a number's absolute value to a binary big-endian string. + * There must be enough place. */ +static void secp256k1_zkp_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_zkp_num *a); + +/** Set a number to the value of a binary big-endian string. */ +static void secp256k1_zkp_num_set_bin(secp256k1_zkp_num *r, const unsigned char *a, unsigned int alen); + +/** Compute a modular inverse. The input must be less than the modulus. */ +static void secp256k1_zkp_num_mod_inverse(secp256k1_zkp_num *r, const secp256k1_zkp_num *a, const secp256k1_zkp_num *m); + +/** Compute the jacobi symbol (a|b). b must be positive and odd. */ +static int secp256k1_zkp_num_jacobi(const secp256k1_zkp_num *a, const secp256k1_zkp_num *b); + +/** Compare the absolute value of two numbers. */ +static int secp256k1_zkp_num_cmp(const secp256k1_zkp_num *a, const secp256k1_zkp_num *b); + +/** Test whether two number are equal (including sign). */ +static int secp256k1_zkp_num_eq(const secp256k1_zkp_num *a, const secp256k1_zkp_num *b); + +/** Add two (signed) numbers. */ +static void secp256k1_zkp_num_add(secp256k1_zkp_num *r, const secp256k1_zkp_num *a, const secp256k1_zkp_num *b); + +/** Subtract two (signed) numbers. */ +static void secp256k1_zkp_num_sub(secp256k1_zkp_num *r, const secp256k1_zkp_num *a, const secp256k1_zkp_num *b); + +/** Multiply two (signed) numbers. */ +static void secp256k1_zkp_num_mul(secp256k1_zkp_num *r, const secp256k1_zkp_num *a, const secp256k1_zkp_num *b); + +/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1, + even if r was negative. */ +static void secp256k1_zkp_num_mod(secp256k1_zkp_num *r, const secp256k1_zkp_num *m); + +/** Right-shift the passed number by bits bits. */ +static void secp256k1_zkp_num_shift(secp256k1_zkp_num *r, int bits); + +/** Check whether a number is zero. */ +static int secp256k1_zkp_num_is_zero(const secp256k1_zkp_num *a); + +/** Check whether a number is one. */ +static int secp256k1_zkp_num_is_one(const secp256k1_zkp_num *a); + +/** Check whether a number is strictly negative. */ +static int secp256k1_zkp_num_is_neg(const secp256k1_zkp_num *a); + +/** Change a number's sign. */ +static void secp256k1_zkp_num_negate(secp256k1_zkp_num *r); + +#endif + +#endif /* SECP256K1_NUM_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/num_gmp.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/num_gmp.h new file mode 100644 index 00000000..54cc7dc9 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/num_gmp.h @@ -0,0 +1,20 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_NUM_REPR_H +#define SECP256K1_NUM_REPR_H + +#include + +#define NUM_LIMBS ((256+GMP_NUMB_BITS-1)/GMP_NUMB_BITS) + +typedef struct { + mp_limb_t data[2*NUM_LIMBS]; + int neg; + int limbs; +} secp256k1_zkp_num; + +#endif /* SECP256K1_NUM_REPR_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/num_gmp_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/num_gmp_impl.h new file mode 100644 index 00000000..0a5a853f --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/num_gmp_impl.h @@ -0,0 +1,288 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_NUM_REPR_IMPL_H +#define SECP256K1_NUM_REPR_IMPL_H + +#include +#include +#include + +#include "util.h" +#include "num.h" + +#ifdef VERIFY +static void secp256k1_zkp_num_sanity(const secp256k1_zkp_num *a) { + VERIFY_CHECK(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0)); +} +#else +#define secp256k1_zkp_num_sanity(a) do { } while(0) +#endif + +static void secp256k1_zkp_num_copy(secp256k1_zkp_num *r, const secp256k1_zkp_num *a) { + *r = *a; +} + +static void secp256k1_zkp_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_zkp_num *a) { + unsigned char tmp[65]; + int len = 0; + int shift = 0; + if (a->limbs>1 || a->data[0] != 0) { + len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs); + } + while (shift < len && tmp[shift] == 0) shift++; + VERIFY_CHECK(len-shift <= (int)rlen); + memset(r, 0, rlen - len + shift); + if (len > shift) { + memcpy(r + rlen - len + shift, tmp + shift, len - shift); + } + memset(tmp, 0, sizeof(tmp)); +} + +static void secp256k1_zkp_num_set_bin(secp256k1_zkp_num *r, const unsigned char *a, unsigned int alen) { + int len; + VERIFY_CHECK(alen > 0); + VERIFY_CHECK(alen <= 64); + len = mpn_set_str(r->data, a, alen, 256); + if (len == 0) { + r->data[0] = 0; + len = 1; + } + VERIFY_CHECK(len <= NUM_LIMBS*2); + r->limbs = len; + r->neg = 0; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } +} + +static void secp256k1_zkp_num_add_abs(secp256k1_zkp_num *r, const secp256k1_zkp_num *a, const secp256k1_zkp_num *b) { + mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs); + r->limbs = a->limbs; + if (c != 0) { + VERIFY_CHECK(r->limbs < 2*NUM_LIMBS); + r->data[r->limbs++] = c; + } +} + +static void secp256k1_zkp_num_sub_abs(secp256k1_zkp_num *r, const secp256k1_zkp_num *a, const secp256k1_zkp_num *b) { + mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs); + (void)c; + VERIFY_CHECK(c == 0); + r->limbs = a->limbs; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } +} + +static void secp256k1_zkp_num_mod(secp256k1_zkp_num *r, const secp256k1_zkp_num *m) { + secp256k1_zkp_num_sanity(r); + secp256k1_zkp_num_sanity(m); + + if (r->limbs >= m->limbs) { + mp_limb_t t[2*NUM_LIMBS]; + mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs); + memset(t, 0, sizeof(t)); + r->limbs = m->limbs; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } + } + + if (r->neg && (r->limbs > 1 || r->data[0] != 0)) { + secp256k1_zkp_num_sub_abs(r, m, r); + r->neg = 0; + } +} + +static void secp256k1_zkp_num_mod_inverse(secp256k1_zkp_num *r, const secp256k1_zkp_num *a, const secp256k1_zkp_num *m) { + int i; + mp_limb_t g[NUM_LIMBS+1]; + mp_limb_t u[NUM_LIMBS+1]; + mp_limb_t v[NUM_LIMBS+1]; + mp_size_t sn; + mp_size_t gn; + secp256k1_zkp_num_sanity(a); + secp256k1_zkp_num_sanity(m); + + /** mpn_gcdext computes: (G,S) = gcdext(U,V), where + * * G = gcd(U,V) + * * G = U*S + V*T + * * U has equal or more limbs than V, and V has no padding + * If we set U to be (a padded version of) a, and V = m: + * G = a*S + m*T + * G = a*S mod m + * Assuming G=1: + * S = 1/a mod m + */ + VERIFY_CHECK(m->limbs <= NUM_LIMBS); + VERIFY_CHECK(m->data[m->limbs-1] != 0); + for (i = 0; i < m->limbs; i++) { + u[i] = (i < a->limbs) ? a->data[i] : 0; + v[i] = m->data[i]; + } + sn = NUM_LIMBS+1; + gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs); + (void)gn; + VERIFY_CHECK(gn == 1); + VERIFY_CHECK(g[0] == 1); + r->neg = a->neg ^ m->neg; + if (sn < 0) { + mpn_sub(r->data, m->data, m->limbs, r->data, -sn); + r->limbs = m->limbs; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } + } else { + r->limbs = sn; + } + memset(g, 0, sizeof(g)); + memset(u, 0, sizeof(u)); + memset(v, 0, sizeof(v)); +} + +static int secp256k1_zkp_num_jacobi(const secp256k1_zkp_num *a, const secp256k1_zkp_num *b) { + int ret; + mpz_t ga, gb; + secp256k1_zkp_num_sanity(a); + secp256k1_zkp_num_sanity(b); + VERIFY_CHECK(!b->neg && (b->limbs > 0) && (b->data[0] & 1)); + + mpz_inits(ga, gb, NULL); + + mpz_import(gb, b->limbs, -1, sizeof(mp_limb_t), 0, 0, b->data); + mpz_import(ga, a->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data); + if (a->neg) { + mpz_neg(ga, ga); + } + + ret = mpz_jacobi(ga, gb); + + mpz_clears(ga, gb, NULL); + + return ret; +} + +static int secp256k1_zkp_num_is_one(const secp256k1_zkp_num *a) { + return (a->limbs == 1 && a->data[0] == 1); +} + +static int secp256k1_zkp_num_is_zero(const secp256k1_zkp_num *a) { + return (a->limbs == 1 && a->data[0] == 0); +} + +static int secp256k1_zkp_num_is_neg(const secp256k1_zkp_num *a) { + return (a->limbs > 1 || a->data[0] != 0) && a->neg; +} + +static int secp256k1_zkp_num_cmp(const secp256k1_zkp_num *a, const secp256k1_zkp_num *b) { + if (a->limbs > b->limbs) { + return 1; + } + if (a->limbs < b->limbs) { + return -1; + } + return mpn_cmp(a->data, b->data, a->limbs); +} + +static int secp256k1_zkp_num_eq(const secp256k1_zkp_num *a, const secp256k1_zkp_num *b) { + if (a->limbs > b->limbs) { + return 0; + } + if (a->limbs < b->limbs) { + return 0; + } + if ((a->neg && !secp256k1_zkp_num_is_zero(a)) != (b->neg && !secp256k1_zkp_num_is_zero(b))) { + return 0; + } + return mpn_cmp(a->data, b->data, a->limbs) == 0; +} + +static void secp256k1_zkp_num_subadd(secp256k1_zkp_num *r, const secp256k1_zkp_num *a, const secp256k1_zkp_num *b, int bneg) { + if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */ + r->neg = a->neg; + if (a->limbs >= b->limbs) { + secp256k1_zkp_num_add_abs(r, a, b); + } else { + secp256k1_zkp_num_add_abs(r, b, a); + } + } else { + if (secp256k1_zkp_num_cmp(a, b) > 0) { + r->neg = a->neg; + secp256k1_zkp_num_sub_abs(r, a, b); + } else { + r->neg = b->neg ^ bneg; + secp256k1_zkp_num_sub_abs(r, b, a); + } + } +} + +static void secp256k1_zkp_num_add(secp256k1_zkp_num *r, const secp256k1_zkp_num *a, const secp256k1_zkp_num *b) { + secp256k1_zkp_num_sanity(a); + secp256k1_zkp_num_sanity(b); + secp256k1_zkp_num_subadd(r, a, b, 0); +} + +static void secp256k1_zkp_num_sub(secp256k1_zkp_num *r, const secp256k1_zkp_num *a, const secp256k1_zkp_num *b) { + secp256k1_zkp_num_sanity(a); + secp256k1_zkp_num_sanity(b); + secp256k1_zkp_num_subadd(r, a, b, 1); +} + +static void secp256k1_zkp_num_mul(secp256k1_zkp_num *r, const secp256k1_zkp_num *a, const secp256k1_zkp_num *b) { + mp_limb_t tmp[2*NUM_LIMBS+1]; + secp256k1_zkp_num_sanity(a); + secp256k1_zkp_num_sanity(b); + + VERIFY_CHECK(a->limbs + b->limbs <= 2*NUM_LIMBS+1); + if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) { + r->limbs = 1; + r->neg = 0; + r->data[0] = 0; + return; + } + if (a->limbs >= b->limbs) { + mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs); + } else { + mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs); + } + r->limbs = a->limbs + b->limbs; + if (r->limbs > 1 && tmp[r->limbs - 1]==0) { + r->limbs--; + } + VERIFY_CHECK(r->limbs <= 2*NUM_LIMBS); + mpn_copyi(r->data, tmp, r->limbs); + r->neg = a->neg ^ b->neg; + memset(tmp, 0, sizeof(tmp)); +} + +static void secp256k1_zkp_num_shift(secp256k1_zkp_num *r, int bits) { + if (bits % GMP_NUMB_BITS) { + /* Shift within limbs. */ + mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS); + } + if (bits >= GMP_NUMB_BITS) { + int i; + /* Shift full limbs. */ + for (i = 0; i < r->limbs; i++) { + int index = i + (bits / GMP_NUMB_BITS); + if (index < r->limbs && index < 2*NUM_LIMBS) { + r->data[i] = r->data[index]; + } else { + r->data[i] = 0; + } + } + } + while (r->limbs>1 && r->data[r->limbs-1]==0) { + r->limbs--; + } +} + +static void secp256k1_zkp_num_negate(secp256k1_zkp_num *r) { + r->neg ^= 1; +} + +#endif /* SECP256K1_NUM_REPR_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/num_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/num_impl.h new file mode 100644 index 00000000..c45193b0 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/num_impl.h @@ -0,0 +1,24 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_NUM_IMPL_H +#define SECP256K1_NUM_IMPL_H + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include "num.h" + +#if defined(USE_NUM_GMP) +#include "num_gmp_impl.h" +#elif defined(USE_NUM_NONE) +/* Nothing. */ +#else +#error "Please select num implementation" +#endif + +#endif /* SECP256K1_NUM_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar.h new file mode 100644 index 00000000..8df39534 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar.h @@ -0,0 +1,112 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_SCALAR_H +#define SECP256K1_SCALAR_H + +#include "num.h" + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#if defined(EXHAUSTIVE_TEST_ORDER) +#include "scalar_low.h" +#elif defined(USE_SCALAR_4X64) +#include "scalar_4x64.h" +#elif defined(USE_SCALAR_8X32) +#include "scalar_8x32.h" +#else +#error "Please select scalar implementation" +#endif + +/** Clear a scalar to prevent the leak of sensitive data. */ +static void secp256k1_zkp_scalar_clear(secp256k1_zkp_scalar *r); + +/** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */ +static unsigned int secp256k1_zkp_scalar_get_bits(const secp256k1_zkp_scalar *a, unsigned int offset, unsigned int count); + +/** Access bits from a scalar. Not constant time. */ +static unsigned int secp256k1_zkp_scalar_get_bits_var(const secp256k1_zkp_scalar *a, unsigned int offset, unsigned int count); + +/** Set a scalar from a big endian byte array. */ +static void secp256k1_zkp_scalar_set_b32(secp256k1_zkp_scalar *r, const unsigned char *bin, int *overflow); + +/** Set a scalar to an unsigned integer. */ +static void secp256k1_zkp_scalar_set_int(secp256k1_zkp_scalar *r, unsigned int v); + +/** Set a scalar to an unsigned 64-bit integer */ +static void secp256k1_zkp_scalar_set_u64(secp256k1_zkp_scalar *r, uint64_t v); + +/** Convert a scalar to a byte array. */ +static void secp256k1_zkp_scalar_get_b32(unsigned char *bin, const secp256k1_zkp_scalar* a); + +/** Add two scalars together (modulo the group order). Returns whether it overflowed. */ +static int secp256k1_zkp_scalar_add(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b); + +/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */ +static void secp256k1_zkp_scalar_cadd_bit(secp256k1_zkp_scalar *r, unsigned int bit, int flag); + +/** Multiply two scalars (modulo the group order). */ +static void secp256k1_zkp_scalar_mul(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b); + +/** Shift a scalar right by some amount strictly between 0 and 16, returning + * the low bits that were shifted off */ +static int secp256k1_zkp_scalar_shr_int(secp256k1_zkp_scalar *r, int n); + +/** Compute the square of a scalar (modulo the group order). */ +static void secp256k1_zkp_scalar_sqr(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a); + +/** Compute the inverse of a scalar (modulo the group order). */ +static void secp256k1_zkp_scalar_inverse(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a); + +/** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */ +static void secp256k1_zkp_scalar_inverse_var(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a); + +/** Compute the complement of a scalar (modulo the group order). */ +static void secp256k1_zkp_scalar_negate(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a); + +/** Check whether a scalar equals zero. */ +static int secp256k1_zkp_scalar_is_zero(const secp256k1_zkp_scalar *a); + +/** Check whether a scalar equals one. */ +static int secp256k1_zkp_scalar_is_one(const secp256k1_zkp_scalar *a); + +/** Check whether a scalar, considered as an nonnegative integer, is even. */ +static int secp256k1_zkp_scalar_is_even(const secp256k1_zkp_scalar *a); + +/** Check whether a scalar is higher than the group order divided by 2. */ +static int secp256k1_zkp_scalar_is_high(const secp256k1_zkp_scalar *a); + +/** Conditionally negate a number, in constant time. + * Returns -1 if the number was negated, 1 otherwise */ +static int secp256k1_zkp_scalar_cond_negate(secp256k1_zkp_scalar *a, int flag); + +#ifndef USE_NUM_NONE +/** Convert a scalar to a number. */ +static void secp256k1_zkp_scalar_get_num(secp256k1_zkp_num *r, const secp256k1_zkp_scalar *a); + +/** Get the order of the group as a number. */ +static void secp256k1_zkp_scalar_order_get_num(secp256k1_zkp_num *r); +#endif + +/** Compare two scalars. */ +static int secp256k1_zkp_scalar_eq(const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b); + +#ifdef USE_ENDOMORPHISM +/** Find r1 and r2 such that r1+r2*2^128 = a. */ +static void secp256k1_zkp_scalar_split_128(secp256k1_zkp_scalar *r1, secp256k1_zkp_scalar *r2, const secp256k1_zkp_scalar *a); +/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_zkp_gej_mul_lambda). */ +static void secp256k1_zkp_scalar_split_lambda(secp256k1_zkp_scalar *r1, secp256k1_zkp_scalar *r2, const secp256k1_zkp_scalar *a); +#endif + +/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ +static void secp256k1_zkp_scalar_mul_shift_var(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b, unsigned int shift); + +/** Generate two scalars from a 32-byte seed and an integer using the chacha20 stream cipher */ +static void secp256k1_zkp_scalar_chacha20(secp256k1_zkp_scalar *r1, secp256k1_zkp_scalar *r2, const unsigned char *seed, uint64_t idx); + +#endif /* SECP256K1_SCALAR_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_4x64.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_4x64.h new file mode 100644 index 00000000..de4612a1 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_4x64.h @@ -0,0 +1,19 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef struct { + uint64_t d[4]; +} secp256k1_zkp_scalar; + +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}} + +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_4x64_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_4x64_impl.h new file mode 100644 index 00000000..573900f6 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_4x64_impl.h @@ -0,0 +1,1049 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H + +#include "scalar.h" +#include + +/* Limbs of the secp256k1 order. */ +#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) +#define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL) +#define SECP256K1_N_2 ((uint64_t)0xFFFFFFFFFFFFFFFEULL) +#define SECP256K1_N_3 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) + +/* Limbs of 2^256 minus the secp256k1 order. */ +#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) +#define SECP256K1_N_C_1 (~SECP256K1_N_1) +#define SECP256K1_N_C_2 (1) + +/* Limbs of half the secp256k1 order. */ +#define SECP256K1_N_H_0 ((uint64_t)0xDFE92F46681B20A0ULL) +#define SECP256K1_N_H_1 ((uint64_t)0x5D576E7357A4501DULL) +#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) +#define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL) + +SECP256K1_INLINE static void secp256k1_zkp_scalar_clear(secp256k1_zkp_scalar *r) { + r->d[0] = 0; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; +} + +SECP256K1_INLINE static void secp256k1_zkp_scalar_set_int(secp256k1_zkp_scalar *r, unsigned int v) { + r->d[0] = v; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; +} + +SECP256K1_INLINE static void secp256k1_zkp_scalar_set_u64(secp256k1_zkp_scalar *r, uint64_t v) { + r->d[0] = v; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; +} + +SECP256K1_INLINE static unsigned int secp256k1_zkp_scalar_get_bits(const secp256k1_zkp_scalar *a, unsigned int offset, unsigned int count) { + VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); + return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1); +} + +SECP256K1_INLINE static unsigned int secp256k1_zkp_scalar_get_bits_var(const secp256k1_zkp_scalar *a, unsigned int offset, unsigned int count) { + VERIFY_CHECK(count < 32); + VERIFY_CHECK(offset + count <= 256); + if ((offset + count - 1) >> 6 == offset >> 6) { + return secp256k1_zkp_scalar_get_bits(a, offset, count); + } else { + VERIFY_CHECK((offset >> 6) + 1 < 4); + return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & ((((uint64_t)1) << count) - 1); + } +} + +SECP256K1_INLINE static int secp256k1_zkp_scalar_check_overflow(const secp256k1_zkp_scalar *a) { + int yes = 0; + int no = 0; + no |= (a->d[3] < SECP256K1_N_3); /* No need for a > check. */ + no |= (a->d[2] < SECP256K1_N_2); + yes |= (a->d[2] > SECP256K1_N_2) & ~no; + no |= (a->d[1] < SECP256K1_N_1); + yes |= (a->d[1] > SECP256K1_N_1) & ~no; + yes |= (a->d[0] >= SECP256K1_N_0) & ~no; + return yes; +} + +SECP256K1_INLINE static int secp256k1_zkp_scalar_reduce(secp256k1_zkp_scalar *r, unsigned int overflow) { + uint128_t t; + VERIFY_CHECK(overflow <= 1); + t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; + r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1; + r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[2] + overflow * SECP256K1_N_C_2; + r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint64_t)r->d[3]; + r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; + return overflow; +} + +static int secp256k1_zkp_scalar_add(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b) { + int overflow; + uint128_t t = (uint128_t)a->d[0] + b->d[0]; + r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)a->d[1] + b->d[1]; + r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)a->d[2] + b->d[2]; + r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)a->d[3] + b->d[3]; + r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + overflow = t + secp256k1_zkp_scalar_check_overflow(r); + VERIFY_CHECK(overflow == 0 || overflow == 1); + secp256k1_zkp_scalar_reduce(r, overflow); + return overflow; +} + +static void secp256k1_zkp_scalar_cadd_bit(secp256k1_zkp_scalar *r, unsigned int bit, int flag) { + uint128_t t; + VERIFY_CHECK(bit < 256); + bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ + t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); + r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); + r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[2] + (((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F)); + r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[3] + (((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F)); + r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; +#ifdef VERIFY + VERIFY_CHECK((t >> 64) == 0); + VERIFY_CHECK(secp256k1_zkp_scalar_check_overflow(r) == 0); +#endif +} + +static void secp256k1_zkp_scalar_set_b32(secp256k1_zkp_scalar *r, const unsigned char *b32, int *overflow) { + int over; + r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56; + r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56; + r->d[2] = (uint64_t)b32[15] | (uint64_t)b32[14] << 8 | (uint64_t)b32[13] << 16 | (uint64_t)b32[12] << 24 | (uint64_t)b32[11] << 32 | (uint64_t)b32[10] << 40 | (uint64_t)b32[9] << 48 | (uint64_t)b32[8] << 56; + r->d[3] = (uint64_t)b32[7] | (uint64_t)b32[6] << 8 | (uint64_t)b32[5] << 16 | (uint64_t)b32[4] << 24 | (uint64_t)b32[3] << 32 | (uint64_t)b32[2] << 40 | (uint64_t)b32[1] << 48 | (uint64_t)b32[0] << 56; + over = secp256k1_zkp_scalar_reduce(r, secp256k1_zkp_scalar_check_overflow(r)); + if (overflow) { + *overflow = over; + } +} + +static void secp256k1_zkp_scalar_get_b32(unsigned char *bin, const secp256k1_zkp_scalar* a) { + bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3]; + bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2]; + bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1]; + bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; +} + +SECP256K1_INLINE static int secp256k1_zkp_scalar_is_zero(const secp256k1_zkp_scalar *a) { + return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; +} + +static void secp256k1_zkp_scalar_negate(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a) { + uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_zkp_scalar_is_zero(a) == 0); + uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1; + r->d[0] = t & nonzero; t >>= 64; + t += (uint128_t)(~a->d[1]) + SECP256K1_N_1; + r->d[1] = t & nonzero; t >>= 64; + t += (uint128_t)(~a->d[2]) + SECP256K1_N_2; + r->d[2] = t & nonzero; t >>= 64; + t += (uint128_t)(~a->d[3]) + SECP256K1_N_3; + r->d[3] = t & nonzero; +} + +SECP256K1_INLINE static int secp256k1_zkp_scalar_is_one(const secp256k1_zkp_scalar *a) { + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; +} + +static int secp256k1_zkp_scalar_is_high(const secp256k1_zkp_scalar *a) { + int yes = 0; + int no = 0; + no |= (a->d[3] < SECP256K1_N_H_3); + yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; + no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; /* No need for a > check. */ + no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; + yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; + return yes; +} + +static int secp256k1_zkp_scalar_cond_negate(secp256k1_zkp_scalar *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_zkp_scalar_negate */ + uint64_t mask = !flag - 1; + uint64_t nonzero = (secp256k1_zkp_scalar_is_zero(r) != 0) - 1; + uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + r->d[0] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); + r->d[1] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); + r->d[2] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); + r->d[3] = t & nonzero; + return 2 * (mask == 0) - 1; +} + +/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ + +/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd(a,b) { \ + uint64_t tl, th; \ + { \ + uint128_t t = (uint128_t)a * b; \ + th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + c1 += th; /* overflow is handled on the next line */ \ + c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ +} + +/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ +#define muladd_fast(a,b) { \ + uint64_t tl, th; \ + { \ + uint128_t t = (uint128_t)a * b; \ + th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + c1 += th; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK(c1 >= th); \ +} + +/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd2(a,b) { \ + uint64_t tl, th, th2, tl2; \ + { \ + uint128_t t = (uint128_t)a * b; \ + th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = t; \ + } \ + th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \ + c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ + tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \ + th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + c0 += tl2; /* overflow is handled on the next line */ \ + th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ + c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ + c1 += th2; /* overflow is handled on the next line */ \ + c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ +} + +/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define sumadd(a) { \ + unsigned int over; \ + c0 += (a); /* overflow is handled on the next line */ \ + over = (c0 < (a)) ? 1 : 0; \ + c1 += over; /* overflow is handled on the next line */ \ + c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ +} + +/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ +#define sumadd_fast(a) { \ + c0 += (a); /* overflow is handled on the next line */ \ + c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ + VERIFY_CHECK(c2 == 0); \ +} + +/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. */ +#define extract(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = c2; \ + c2 = 0; \ +} + +/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. c2 is required to be zero. */ +#define extract_fast(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = 0; \ + VERIFY_CHECK(c2 == 0); \ +} + +static void secp256k1_zkp_scalar_reduce_512(secp256k1_zkp_scalar *r, const uint64_t *l) { +#ifdef USE_ASM_X86_64 + /* Reduce 512 bits into 385. */ + uint64_t m0, m1, m2, m3, m4, m5, m6; + uint64_t p0, p1, p2, p3, p4; + uint64_t c; + + __asm__ __volatile__( + /* Preload. */ + "movq 32(%%rsi), %%r11\n" + "movq 40(%%rsi), %%r12\n" + "movq 48(%%rsi), %%r13\n" + "movq 56(%%rsi), %%r14\n" + /* Initialize r8,r9,r10 */ + "movq 0(%%rsi), %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9) += n0 * c0 */ + "movq %8, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* extract m0 */ + "movq %%r8, %q0\n" + "xorq %%r8, %%r8\n" + /* (r9,r10) += l1 */ + "addq 8(%%rsi), %%r9\n" + "adcq $0, %%r10\n" + /* (r9,r10,r8) += n1 * c0 */ + "movq %8, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += n0 * c1 */ + "movq %9, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* extract m1 */ + "movq %%r9, %q1\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += l2 */ + "addq 16(%%rsi), %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n2 * c0 */ + "movq %8, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n1 * c1 */ + "movq %9, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n0 */ + "addq %%r11, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* extract m2 */ + "movq %%r10, %q2\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += l3 */ + "addq 24(%%rsi), %%r8\n" + "adcq $0, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n3 * c0 */ + "movq %8, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n2 * c1 */ + "movq %9, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n1 */ + "addq %%r12, %%r8\n" + "adcq $0, %%r9\n" + "adcq $0, %%r10\n" + /* extract m3 */ + "movq %%r8, %q3\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += n3 * c1 */ + "movq %9, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += n2 */ + "addq %%r13, %%r9\n" + "adcq $0, %%r10\n" + "adcq $0, %%r8\n" + /* extract m4 */ + "movq %%r9, %q4\n" + /* (r10,r8) += n3 */ + "addq %%r14, %%r10\n" + "adcq $0, %%r8\n" + /* extract m5 */ + "movq %%r10, %q5\n" + /* extract m6 */ + "movq %%r8, %q6\n" + : "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6) + : "S"(l), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc"); + + /* Reduce 385 bits into 258. */ + __asm__ __volatile__( + /* Preload */ + "movq %q9, %%r11\n" + "movq %q10, %%r12\n" + "movq %q11, %%r13\n" + /* Initialize (r8,r9,r10) */ + "movq %q5, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9) += m4 * c0 */ + "movq %12, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* extract p0 */ + "movq %%r8, %q0\n" + "xorq %%r8, %%r8\n" + /* (r9,r10) += m1 */ + "addq %q6, %%r9\n" + "adcq $0, %%r10\n" + /* (r9,r10,r8) += m5 * c0 */ + "movq %12, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += m4 * c1 */ + "movq %13, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* extract p1 */ + "movq %%r9, %q1\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += m2 */ + "addq %q7, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m6 * c0 */ + "movq %12, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m5 * c1 */ + "movq %13, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m4 */ + "addq %%r11, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* extract p2 */ + "movq %%r10, %q2\n" + /* (r8,r9) += m3 */ + "addq %q8, %%r8\n" + "adcq $0, %%r9\n" + /* (r8,r9) += m6 * c1 */ + "movq %13, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* (r8,r9) += m5 */ + "addq %%r12, %%r8\n" + "adcq $0, %%r9\n" + /* extract p3 */ + "movq %%r8, %q3\n" + /* (r9) += m6 */ + "addq %%r13, %%r9\n" + /* extract p4 */ + "movq %%r9, %q4\n" + : "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4) + : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc"); + + /* Reduce 258 bits into 256. */ + __asm__ __volatile__( + /* Preload */ + "movq %q5, %%r10\n" + /* (rax,rdx) = p4 * c0 */ + "movq %7, %%rax\n" + "mulq %%r10\n" + /* (rax,rdx) += p0 */ + "addq %q1, %%rax\n" + "adcq $0, %%rdx\n" + /* extract r0 */ + "movq %%rax, 0(%q6)\n" + /* Move to (r8,r9) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + /* (r8,r9) += p1 */ + "addq %q2, %%r8\n" + "adcq $0, %%r9\n" + /* (r8,r9) += p4 * c1 */ + "movq %8, %%rax\n" + "mulq %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* Extract r1 */ + "movq %%r8, 8(%q6)\n" + "xorq %%r8, %%r8\n" + /* (r9,r8) += p4 */ + "addq %%r10, %%r9\n" + "adcq $0, %%r8\n" + /* (r9,r8) += p2 */ + "addq %q3, %%r9\n" + "adcq $0, %%r8\n" + /* Extract r2 */ + "movq %%r9, 16(%q6)\n" + "xorq %%r9, %%r9\n" + /* (r8,r9) += p3 */ + "addq %q4, %%r8\n" + "adcq $0, %%r9\n" + /* Extract r3 */ + "movq %%r8, 24(%q6)\n" + /* Extract c */ + "movq %%r9, %q0\n" + : "=g"(c) + : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "cc", "memory"); +#else + uint128_t c; + uint64_t c0, c1, c2; + uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7]; + uint64_t m0, m1, m2, m3, m4, m5; + uint32_t m6; + uint64_t p0, p1, p2, p3; + uint32_t p4; + + /* Reduce 512 bits into 385. */ + /* m[0..6] = l[0..3] + n[0..3] * SECP256K1_N_C. */ + c0 = l[0]; c1 = 0; c2 = 0; + muladd_fast(n0, SECP256K1_N_C_0); + extract_fast(m0); + sumadd_fast(l[1]); + muladd(n1, SECP256K1_N_C_0); + muladd(n0, SECP256K1_N_C_1); + extract(m1); + sumadd(l[2]); + muladd(n2, SECP256K1_N_C_0); + muladd(n1, SECP256K1_N_C_1); + sumadd(n0); + extract(m2); + sumadd(l[3]); + muladd(n3, SECP256K1_N_C_0); + muladd(n2, SECP256K1_N_C_1); + sumadd(n1); + extract(m3); + muladd(n3, SECP256K1_N_C_1); + sumadd(n2); + extract(m4); + sumadd_fast(n3); + extract_fast(m5); + VERIFY_CHECK(c0 <= 1); + m6 = c0; + + /* Reduce 385 bits into 258. */ + /* p[0..4] = m[0..3] + m[4..6] * SECP256K1_N_C. */ + c0 = m0; c1 = 0; c2 = 0; + muladd_fast(m4, SECP256K1_N_C_0); + extract_fast(p0); + sumadd_fast(m1); + muladd(m5, SECP256K1_N_C_0); + muladd(m4, SECP256K1_N_C_1); + extract(p1); + sumadd(m2); + muladd(m6, SECP256K1_N_C_0); + muladd(m5, SECP256K1_N_C_1); + sumadd(m4); + extract(p2); + sumadd_fast(m3); + muladd_fast(m6, SECP256K1_N_C_1); + sumadd_fast(m5); + extract_fast(p3); + p4 = c0 + m6; + VERIFY_CHECK(p4 <= 2); + + /* Reduce 258 bits into 256. */ + /* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */ + c = p0 + (uint128_t)SECP256K1_N_C_0 * p4; + r->d[0] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + c += p1 + (uint128_t)SECP256K1_N_C_1 * p4; + r->d[1] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + c += p2 + (uint128_t)p4; + r->d[2] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + c += p3; + r->d[3] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; +#endif + + /* Final reduction of r. */ + secp256k1_zkp_scalar_reduce(r, c + secp256k1_zkp_scalar_check_overflow(r)); +} + +static void secp256k1_zkp_scalar_mul_512(uint64_t l[8], const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b) { +#ifdef USE_ASM_X86_64 + const uint64_t *pb = b->d; + __asm__ __volatile__( + /* Preload */ + "movq 0(%%rdi), %%r15\n" + "movq 8(%%rdi), %%rbx\n" + "movq 16(%%rdi), %%rcx\n" + "movq 0(%%rdx), %%r11\n" + "movq 8(%%rdx), %%r12\n" + "movq 16(%%rdx), %%r13\n" + "movq 24(%%rdx), %%r14\n" + /* (rax,rdx) = a0 * b0 */ + "movq %%r15, %%rax\n" + "mulq %%r11\n" + /* Extract l0 */ + "movq %%rax, 0(%%rsi)\n" + /* (r8,r9,r10) = (rdx) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += a0 * b1 */ + "movq %%r15, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a1 * b0 */ + "movq %%rbx, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l1 */ + "movq %%r8, 8(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += a0 * b2 */ + "movq %%r15, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a1 * b1 */ + "movq %%rbx, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a2 * b0 */ + "movq %%rcx, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l2 */ + "movq %%r9, 16(%%rsi)\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += a0 * b3 */ + "movq %%r15, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Preload a3 */ + "movq 24(%%rdi), %%r15\n" + /* (r10,r8,r9) += a1 * b2 */ + "movq %%rbx, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += a2 * b1 */ + "movq %%rcx, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += a3 * b0 */ + "movq %%r15, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Extract l3 */ + "movq %%r10, 24(%%rsi)\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += a1 * b3 */ + "movq %%rbx, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a2 * b2 */ + "movq %%rcx, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a3 * b1 */ + "movq %%r15, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l4 */ + "movq %%r8, 32(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += a2 * b3 */ + "movq %%rcx, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a3 * b2 */ + "movq %%r15, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l5 */ + "movq %%r9, 40(%%rsi)\n" + /* (r10,r8) += a3 * b3 */ + "movq %%r15, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + /* Extract l6 */ + "movq %%r10, 48(%%rsi)\n" + /* Extract l7 */ + "movq %%r8, 56(%%rsi)\n" + : "+d"(pb) + : "S"(l), "D"(a->d) + : "rax", "rbx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "cc", "memory"); +#else + /* 160 bit accumulator. */ + uint64_t c0 = 0, c1 = 0; + uint32_t c2 = 0; + + /* l[0..7] = a[0..3] * b[0..3]. */ + muladd_fast(a->d[0], b->d[0]); + extract_fast(l[0]); + muladd(a->d[0], b->d[1]); + muladd(a->d[1], b->d[0]); + extract(l[1]); + muladd(a->d[0], b->d[2]); + muladd(a->d[1], b->d[1]); + muladd(a->d[2], b->d[0]); + extract(l[2]); + muladd(a->d[0], b->d[3]); + muladd(a->d[1], b->d[2]); + muladd(a->d[2], b->d[1]); + muladd(a->d[3], b->d[0]); + extract(l[3]); + muladd(a->d[1], b->d[3]); + muladd(a->d[2], b->d[2]); + muladd(a->d[3], b->d[1]); + extract(l[4]); + muladd(a->d[2], b->d[3]); + muladd(a->d[3], b->d[2]); + extract(l[5]); + muladd_fast(a->d[3], b->d[3]); + extract_fast(l[6]); + VERIFY_CHECK(c1 == 0); + l[7] = c0; +#endif +} + +static void secp256k1_zkp_scalar_sqr_512(uint64_t l[8], const secp256k1_zkp_scalar *a) { +#ifdef USE_ASM_X86_64 + __asm__ __volatile__( + /* Preload */ + "movq 0(%%rdi), %%r11\n" + "movq 8(%%rdi), %%r12\n" + "movq 16(%%rdi), %%r13\n" + "movq 24(%%rdi), %%r14\n" + /* (rax,rdx) = a0 * a0 */ + "movq %%r11, %%rax\n" + "mulq %%r11\n" + /* Extract l0 */ + "movq %%rax, 0(%%rsi)\n" + /* (r8,r9,r10) = (rdx,0) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += 2 * a0 * a1 */ + "movq %%r11, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l1 */ + "movq %%r8, 8(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += 2 * a0 * a2 */ + "movq %%r11, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a1 * a1 */ + "movq %%r12, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l2 */ + "movq %%r9, 16(%%rsi)\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += 2 * a0 * a3 */ + "movq %%r11, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += 2 * a1 * a2 */ + "movq %%r12, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Extract l3 */ + "movq %%r10, 24(%%rsi)\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += 2 * a1 * a3 */ + "movq %%r12, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a2 * a2 */ + "movq %%r13, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l4 */ + "movq %%r8, 32(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += 2 * a2 * a3 */ + "movq %%r13, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l5 */ + "movq %%r9, 40(%%rsi)\n" + /* (r10,r8) += a3 * a3 */ + "movq %%r14, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + /* Extract l6 */ + "movq %%r10, 48(%%rsi)\n" + /* Extract l7 */ + "movq %%r8, 56(%%rsi)\n" + : + : "S"(l), "D"(a->d) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc", "memory"); +#else + /* 160 bit accumulator. */ + uint64_t c0 = 0, c1 = 0; + uint32_t c2 = 0; + + /* l[0..7] = a[0..3] * b[0..3]. */ + muladd_fast(a->d[0], a->d[0]); + extract_fast(l[0]); + muladd2(a->d[0], a->d[1]); + extract(l[1]); + muladd2(a->d[0], a->d[2]); + muladd(a->d[1], a->d[1]); + extract(l[2]); + muladd2(a->d[0], a->d[3]); + muladd2(a->d[1], a->d[2]); + extract(l[3]); + muladd2(a->d[1], a->d[3]); + muladd(a->d[2], a->d[2]); + extract(l[4]); + muladd2(a->d[2], a->d[3]); + extract(l[5]); + muladd_fast(a->d[3], a->d[3]); + extract_fast(l[6]); + VERIFY_CHECK(c1 == 0); + l[7] = c0; +#endif +} + +#undef sumadd +#undef sumadd_fast +#undef muladd +#undef muladd_fast +#undef muladd2 +#undef extract +#undef extract_fast + +static void secp256k1_zkp_scalar_mul(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b) { + uint64_t l[8]; + secp256k1_zkp_scalar_mul_512(l, a, b); + secp256k1_zkp_scalar_reduce_512(r, l); +} + +static int secp256k1_zkp_scalar_shr_int(secp256k1_zkp_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = r->d[0] & ((1 << n) - 1); + r->d[0] = (r->d[0] >> n) + (r->d[1] << (64 - n)); + r->d[1] = (r->d[1] >> n) + (r->d[2] << (64 - n)); + r->d[2] = (r->d[2] >> n) + (r->d[3] << (64 - n)); + r->d[3] = (r->d[3] >> n); + return ret; +} + +static void secp256k1_zkp_scalar_sqr(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a) { + uint64_t l[8]; + secp256k1_zkp_scalar_sqr_512(l, a); + secp256k1_zkp_scalar_reduce_512(r, l); +} + +#ifdef USE_ENDOMORPHISM +static void secp256k1_zkp_scalar_split_128(secp256k1_zkp_scalar *r1, secp256k1_zkp_scalar *r2, const secp256k1_zkp_scalar *a) { + r1->d[0] = a->d[0]; + r1->d[1] = a->d[1]; + r1->d[2] = 0; + r1->d[3] = 0; + r2->d[0] = a->d[2]; + r2->d[1] = a->d[3]; + r2->d[2] = 0; + r2->d[3] = 0; +} +#endif + +SECP256K1_INLINE static int secp256k1_zkp_scalar_eq(const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b) { + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; +} + +SECP256K1_INLINE static void secp256k1_zkp_scalar_mul_shift_var(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b, unsigned int shift) { + uint64_t l[8]; + unsigned int shiftlimbs; + unsigned int shiftlow; + unsigned int shifthigh; + VERIFY_CHECK(shift >= 256); + secp256k1_zkp_scalar_mul_512(l, a, b); + shiftlimbs = shift >> 6; + shiftlow = shift & 0x3F; + shifthigh = 64 - shiftlow; + r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; + secp256k1_zkp_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); +} + +#define ROTL32(x,n) ((x) << (n) | (x) >> (32-(n))) +#define QUARTERROUND(a,b,c,d) \ + a += b; d = ROTL32(d ^ a, 16); \ + c += d; b = ROTL32(b ^ c, 12); \ + a += b; d = ROTL32(d ^ a, 8); \ + c += d; b = ROTL32(b ^ c, 7); + +#ifdef WORDS_BIGENDIAN +#define LE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#define BE32(p) (p) +#else +#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#define LE32(p) (p) +#endif + +static void secp256k1_zkp_scalar_chacha20(secp256k1_zkp_scalar *r1, secp256k1_zkp_scalar *r2, const unsigned char *seed, uint64_t idx) { + size_t n; + size_t over_count = 0; + uint32_t seed32[8]; + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + int over1, over2; + + memcpy((void *) seed32, (const void *) seed, 32); + do { + x0 = 0x61707865; + x1 = 0x3320646e; + x2 = 0x79622d32; + x3 = 0x6b206574; + x4 = LE32(seed32[0]); + x5 = LE32(seed32[1]); + x6 = LE32(seed32[2]); + x7 = LE32(seed32[3]); + x8 = LE32(seed32[4]); + x9 = LE32(seed32[5]); + x10 = LE32(seed32[6]); + x11 = LE32(seed32[7]); + x12 = idx; + x13 = idx >> 32; + x14 = 0; + x15 = over_count; + + n = 10; + while (n--) { + QUARTERROUND(x0, x4, x8,x12) + QUARTERROUND(x1, x5, x9,x13) + QUARTERROUND(x2, x6,x10,x14) + QUARTERROUND(x3, x7,x11,x15) + QUARTERROUND(x0, x5,x10,x15) + QUARTERROUND(x1, x6,x11,x12) + QUARTERROUND(x2, x7, x8,x13) + QUARTERROUND(x3, x4, x9,x14) + } + + x0 += 0x61707865; + x1 += 0x3320646e; + x2 += 0x79622d32; + x3 += 0x6b206574; + x4 += LE32(seed32[0]); + x5 += LE32(seed32[1]); + x6 += LE32(seed32[2]); + x7 += LE32(seed32[3]); + x8 += LE32(seed32[4]); + x9 += LE32(seed32[5]); + x10 += LE32(seed32[6]); + x11 += LE32(seed32[7]); + x12 += idx; + x13 += idx >> 32; + x14 += 0; + x15 += over_count; + + r1->d[3] = LE32((uint64_t) x0) << 32 | LE32(x1); + r1->d[2] = LE32((uint64_t) x2) << 32 | LE32(x3); + r1->d[1] = LE32((uint64_t) x4) << 32 | LE32(x5); + r1->d[0] = LE32((uint64_t) x6) << 32 | LE32(x7); + r2->d[3] = LE32((uint64_t) x8) << 32 | LE32(x9); + r2->d[2] = LE32((uint64_t) x10) << 32 | LE32(x11); + r2->d[1] = LE32((uint64_t) x12) << 32 | LE32(x13); + r2->d[0] = LE32((uint64_t) x14) << 32 | LE32(x15); + + over1 = secp256k1_zkp_scalar_check_overflow(r1); + over2 = secp256k1_zkp_scalar_check_overflow(r2); + over_count++; + } while (over1 | over2); +} + +#undef ROTL32 +#undef QUARTERROUND +#undef BE32 +#undef LE32 + +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_8x32.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_8x32.h new file mode 100644 index 00000000..2aa61b9c --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_8x32.h @@ -0,0 +1,19 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef struct { + uint32_t d[8]; +} secp256k1_zkp_scalar; + +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} + +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_8x32_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_8x32_impl.h new file mode 100644 index 00000000..f679dd46 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_8x32_impl.h @@ -0,0 +1,832 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H + +#include + +/* Limbs of the secp256k1 order. */ +#define SECP256K1_N_0 ((uint32_t)0xD0364141UL) +#define SECP256K1_N_1 ((uint32_t)0xBFD25E8CUL) +#define SECP256K1_N_2 ((uint32_t)0xAF48A03BUL) +#define SECP256K1_N_3 ((uint32_t)0xBAAEDCE6UL) +#define SECP256K1_N_4 ((uint32_t)0xFFFFFFFEUL) +#define SECP256K1_N_5 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_6 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_7 ((uint32_t)0xFFFFFFFFUL) + +/* Limbs of 2^256 minus the secp256k1 order. */ +#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) +#define SECP256K1_N_C_1 (~SECP256K1_N_1) +#define SECP256K1_N_C_2 (~SECP256K1_N_2) +#define SECP256K1_N_C_3 (~SECP256K1_N_3) +#define SECP256K1_N_C_4 (1) + +/* Limbs of half the secp256k1 order. */ +#define SECP256K1_N_H_0 ((uint32_t)0x681B20A0UL) +#define SECP256K1_N_H_1 ((uint32_t)0xDFE92F46UL) +#define SECP256K1_N_H_2 ((uint32_t)0x57A4501DUL) +#define SECP256K1_N_H_3 ((uint32_t)0x5D576E73UL) +#define SECP256K1_N_H_4 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_5 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL) + +SECP256K1_INLINE static void secp256k1_zkp_scalar_clear(secp256k1_zkp_scalar *r) { + r->d[0] = 0; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; + r->d[4] = 0; + r->d[5] = 0; + r->d[6] = 0; + r->d[7] = 0; +} + +SECP256K1_INLINE static void secp256k1_zkp_scalar_set_int(secp256k1_zkp_scalar *r, unsigned int v) { + r->d[0] = v; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; + r->d[4] = 0; + r->d[5] = 0; + r->d[6] = 0; + r->d[7] = 0; +} + +SECP256K1_INLINE static void secp256k1_zkp_scalar_set_u64(secp256k1_zkp_scalar *r, uint64_t v) { + r->d[0] = v; + r->d[1] = v >> 32; + r->d[2] = 0; + r->d[3] = 0; + r->d[4] = 0; + r->d[5] = 0; + r->d[6] = 0; + r->d[7] = 0; +} + +SECP256K1_INLINE static unsigned int secp256k1_zkp_scalar_get_bits(const secp256k1_zkp_scalar *a, unsigned int offset, unsigned int count) { + VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); + return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1); +} + +SECP256K1_INLINE static unsigned int secp256k1_zkp_scalar_get_bits_var(const secp256k1_zkp_scalar *a, unsigned int offset, unsigned int count) { + VERIFY_CHECK(count < 32); + VERIFY_CHECK(offset + count <= 256); + if ((offset + count - 1) >> 5 == offset >> 5) { + return secp256k1_zkp_scalar_get_bits(a, offset, count); + } else { + VERIFY_CHECK((offset >> 5) + 1 < 8); + return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & ((((uint32_t)1) << count) - 1); + } +} + +SECP256K1_INLINE static int secp256k1_zkp_scalar_check_overflow(const secp256k1_zkp_scalar *a) { + int yes = 0; + int no = 0; + no |= (a->d[7] < SECP256K1_N_7); /* No need for a > check. */ + no |= (a->d[6] < SECP256K1_N_6); /* No need for a > check. */ + no |= (a->d[5] < SECP256K1_N_5); /* No need for a > check. */ + no |= (a->d[4] < SECP256K1_N_4); + yes |= (a->d[4] > SECP256K1_N_4) & ~no; + no |= (a->d[3] < SECP256K1_N_3) & ~yes; + yes |= (a->d[3] > SECP256K1_N_3) & ~no; + no |= (a->d[2] < SECP256K1_N_2) & ~yes; + yes |= (a->d[2] > SECP256K1_N_2) & ~no; + no |= (a->d[1] < SECP256K1_N_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_1) & ~no; + yes |= (a->d[0] >= SECP256K1_N_0) & ~no; + return yes; +} + +SECP256K1_INLINE static int secp256k1_zkp_scalar_reduce(secp256k1_zkp_scalar *r, uint32_t overflow) { + uint64_t t; + VERIFY_CHECK(overflow <= 1); + t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; + r->d[0] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1; + r->d[1] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[2] + overflow * SECP256K1_N_C_2; + r->d[2] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[3] + overflow * SECP256K1_N_C_3; + r->d[3] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[4] + overflow * SECP256K1_N_C_4; + r->d[4] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[5]; + r->d[5] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[6]; + r->d[6] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[7]; + r->d[7] = t & 0xFFFFFFFFUL; + return overflow; +} + +static int secp256k1_zkp_scalar_add(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b) { + int overflow; + uint64_t t = (uint64_t)a->d[0] + b->d[0]; + r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[1] + b->d[1]; + r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[2] + b->d[2]; + r->d[2] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[3] + b->d[3]; + r->d[3] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[4] + b->d[4]; + r->d[4] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[5] + b->d[5]; + r->d[5] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[6] + b->d[6]; + r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[7] + b->d[7]; + r->d[7] = t & 0xFFFFFFFFULL; t >>= 32; + overflow = t + secp256k1_zkp_scalar_check_overflow(r); + VERIFY_CHECK(overflow == 0 || overflow == 1); + secp256k1_zkp_scalar_reduce(r, overflow); + return overflow; +} + +static void secp256k1_zkp_scalar_cadd_bit(secp256k1_zkp_scalar *r, unsigned int bit, int flag) { + uint64_t t; + VERIFY_CHECK(bit < 256); + bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ + t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); + r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F)); + r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[2] + (((uint32_t)((bit >> 5) == 2)) << (bit & 0x1F)); + r->d[2] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[3] + (((uint32_t)((bit >> 5) == 3)) << (bit & 0x1F)); + r->d[3] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[4] + (((uint32_t)((bit >> 5) == 4)) << (bit & 0x1F)); + r->d[4] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[5] + (((uint32_t)((bit >> 5) == 5)) << (bit & 0x1F)); + r->d[5] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[6] + (((uint32_t)((bit >> 5) == 6)) << (bit & 0x1F)); + r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F)); + r->d[7] = t & 0xFFFFFFFFULL; +#ifdef VERIFY + VERIFY_CHECK((t >> 32) == 0); + VERIFY_CHECK(secp256k1_zkp_scalar_check_overflow(r) == 0); +#endif +} + +static void secp256k1_zkp_scalar_set_b32(secp256k1_zkp_scalar *r, const unsigned char *b32, int *overflow) { + int over; + r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24; + r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24; + r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24; + r->d[3] = (uint32_t)b32[19] | (uint32_t)b32[18] << 8 | (uint32_t)b32[17] << 16 | (uint32_t)b32[16] << 24; + r->d[4] = (uint32_t)b32[15] | (uint32_t)b32[14] << 8 | (uint32_t)b32[13] << 16 | (uint32_t)b32[12] << 24; + r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24; + r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24; + r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24; + over = secp256k1_zkp_scalar_reduce(r, secp256k1_zkp_scalar_check_overflow(r)); + if (overflow) { + *overflow = over; + } +} + +static void secp256k1_zkp_scalar_get_b32(unsigned char *bin, const secp256k1_zkp_scalar* a) { + bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7]; + bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6]; + bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5]; + bin[12] = a->d[4] >> 24; bin[13] = a->d[4] >> 16; bin[14] = a->d[4] >> 8; bin[15] = a->d[4]; + bin[16] = a->d[3] >> 24; bin[17] = a->d[3] >> 16; bin[18] = a->d[3] >> 8; bin[19] = a->d[3]; + bin[20] = a->d[2] >> 24; bin[21] = a->d[2] >> 16; bin[22] = a->d[2] >> 8; bin[23] = a->d[2]; + bin[24] = a->d[1] >> 24; bin[25] = a->d[1] >> 16; bin[26] = a->d[1] >> 8; bin[27] = a->d[1]; + bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; +} + +SECP256K1_INLINE static int secp256k1_zkp_scalar_is_zero(const secp256k1_zkp_scalar *a) { + return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; +} + +static void secp256k1_zkp_scalar_negate(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a) { + uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_zkp_scalar_is_zero(a) == 0); + uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1; + r->d[0] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[1]) + SECP256K1_N_1; + r->d[1] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[2]) + SECP256K1_N_2; + r->d[2] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[3]) + SECP256K1_N_3; + r->d[3] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[4]) + SECP256K1_N_4; + r->d[4] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[5]) + SECP256K1_N_5; + r->d[5] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[6]) + SECP256K1_N_6; + r->d[6] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[7]) + SECP256K1_N_7; + r->d[7] = t & nonzero; +} + +SECP256K1_INLINE static int secp256k1_zkp_scalar_is_one(const secp256k1_zkp_scalar *a) { + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; +} + +static int secp256k1_zkp_scalar_is_high(const secp256k1_zkp_scalar *a) { + int yes = 0; + int no = 0; + no |= (a->d[7] < SECP256K1_N_H_7); + yes |= (a->d[7] > SECP256K1_N_H_7) & ~no; + no |= (a->d[6] < SECP256K1_N_H_6) & ~yes; /* No need for a > check. */ + no |= (a->d[5] < SECP256K1_N_H_5) & ~yes; /* No need for a > check. */ + no |= (a->d[4] < SECP256K1_N_H_4) & ~yes; /* No need for a > check. */ + no |= (a->d[3] < SECP256K1_N_H_3) & ~yes; + yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; + no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; + yes |= (a->d[2] > SECP256K1_N_H_2) & ~no; + no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; + yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; + return yes; +} + +static int secp256k1_zkp_scalar_cond_negate(secp256k1_zkp_scalar *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_zkp_scalar_negate */ + uint32_t mask = !flag - 1; + uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_zkp_scalar_is_zero(r) == 0); + uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + r->d[0] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); + r->d[1] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); + r->d[2] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); + r->d[3] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[4] ^ mask) + (SECP256K1_N_4 & mask); + r->d[4] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[5] ^ mask) + (SECP256K1_N_5 & mask); + r->d[5] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[6] ^ mask) + (SECP256K1_N_6 & mask); + r->d[6] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask); + r->d[7] = t & nonzero; + return 2 * (mask == 0) - 1; +} + + +/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ + +/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd(a,b) { \ + uint32_t tl, th; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + c1 += th; /* overflow is handled on the next line */ \ + c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ +} + +/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ +#define muladd_fast(a,b) { \ + uint32_t tl, th; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + c1 += th; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK(c1 >= th); \ +} + +/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd2(a,b) { \ + uint32_t tl, th, th2, tl2; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \ + c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ + tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \ + th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + c0 += tl2; /* overflow is handled on the next line */ \ + th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ + c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ + c1 += th2; /* overflow is handled on the next line */ \ + c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ +} + +/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define sumadd(a) { \ + unsigned int over; \ + c0 += (a); /* overflow is handled on the next line */ \ + over = (c0 < (a)) ? 1 : 0; \ + c1 += over; /* overflow is handled on the next line */ \ + c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ +} + +/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ +#define sumadd_fast(a) { \ + c0 += (a); /* overflow is handled on the next line */ \ + c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ + VERIFY_CHECK(c2 == 0); \ +} + +/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. */ +#define extract(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = c2; \ + c2 = 0; \ +} + +/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. c2 is required to be zero. */ +#define extract_fast(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = 0; \ + VERIFY_CHECK(c2 == 0); \ +} + +static void secp256k1_zkp_scalar_reduce_512(secp256k1_zkp_scalar *r, const uint32_t *l) { + uint64_t c; + uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15]; + uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12; + uint32_t p0, p1, p2, p3, p4, p5, p6, p7, p8; + + /* 96 bit accumulator. */ + uint32_t c0, c1, c2; + + /* Reduce 512 bits into 385. */ + /* m[0..12] = l[0..7] + n[0..7] * SECP256K1_N_C. */ + c0 = l[0]; c1 = 0; c2 = 0; + muladd_fast(n0, SECP256K1_N_C_0); + extract_fast(m0); + sumadd_fast(l[1]); + muladd(n1, SECP256K1_N_C_0); + muladd(n0, SECP256K1_N_C_1); + extract(m1); + sumadd(l[2]); + muladd(n2, SECP256K1_N_C_0); + muladd(n1, SECP256K1_N_C_1); + muladd(n0, SECP256K1_N_C_2); + extract(m2); + sumadd(l[3]); + muladd(n3, SECP256K1_N_C_0); + muladd(n2, SECP256K1_N_C_1); + muladd(n1, SECP256K1_N_C_2); + muladd(n0, SECP256K1_N_C_3); + extract(m3); + sumadd(l[4]); + muladd(n4, SECP256K1_N_C_0); + muladd(n3, SECP256K1_N_C_1); + muladd(n2, SECP256K1_N_C_2); + muladd(n1, SECP256K1_N_C_3); + sumadd(n0); + extract(m4); + sumadd(l[5]); + muladd(n5, SECP256K1_N_C_0); + muladd(n4, SECP256K1_N_C_1); + muladd(n3, SECP256K1_N_C_2); + muladd(n2, SECP256K1_N_C_3); + sumadd(n1); + extract(m5); + sumadd(l[6]); + muladd(n6, SECP256K1_N_C_0); + muladd(n5, SECP256K1_N_C_1); + muladd(n4, SECP256K1_N_C_2); + muladd(n3, SECP256K1_N_C_3); + sumadd(n2); + extract(m6); + sumadd(l[7]); + muladd(n7, SECP256K1_N_C_0); + muladd(n6, SECP256K1_N_C_1); + muladd(n5, SECP256K1_N_C_2); + muladd(n4, SECP256K1_N_C_3); + sumadd(n3); + extract(m7); + muladd(n7, SECP256K1_N_C_1); + muladd(n6, SECP256K1_N_C_2); + muladd(n5, SECP256K1_N_C_3); + sumadd(n4); + extract(m8); + muladd(n7, SECP256K1_N_C_2); + muladd(n6, SECP256K1_N_C_3); + sumadd(n5); + extract(m9); + muladd(n7, SECP256K1_N_C_3); + sumadd(n6); + extract(m10); + sumadd_fast(n7); + extract_fast(m11); + VERIFY_CHECK(c0 <= 1); + m12 = c0; + + /* Reduce 385 bits into 258. */ + /* p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. */ + c0 = m0; c1 = 0; c2 = 0; + muladd_fast(m8, SECP256K1_N_C_0); + extract_fast(p0); + sumadd_fast(m1); + muladd(m9, SECP256K1_N_C_0); + muladd(m8, SECP256K1_N_C_1); + extract(p1); + sumadd(m2); + muladd(m10, SECP256K1_N_C_0); + muladd(m9, SECP256K1_N_C_1); + muladd(m8, SECP256K1_N_C_2); + extract(p2); + sumadd(m3); + muladd(m11, SECP256K1_N_C_0); + muladd(m10, SECP256K1_N_C_1); + muladd(m9, SECP256K1_N_C_2); + muladd(m8, SECP256K1_N_C_3); + extract(p3); + sumadd(m4); + muladd(m12, SECP256K1_N_C_0); + muladd(m11, SECP256K1_N_C_1); + muladd(m10, SECP256K1_N_C_2); + muladd(m9, SECP256K1_N_C_3); + sumadd(m8); + extract(p4); + sumadd(m5); + muladd(m12, SECP256K1_N_C_1); + muladd(m11, SECP256K1_N_C_2); + muladd(m10, SECP256K1_N_C_3); + sumadd(m9); + extract(p5); + sumadd(m6); + muladd(m12, SECP256K1_N_C_2); + muladd(m11, SECP256K1_N_C_3); + sumadd(m10); + extract(p6); + sumadd_fast(m7); + muladd_fast(m12, SECP256K1_N_C_3); + sumadd_fast(m11); + extract_fast(p7); + p8 = c0 + m12; + VERIFY_CHECK(p8 <= 2); + + /* Reduce 258 bits into 256. */ + /* r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. */ + c = p0 + (uint64_t)SECP256K1_N_C_0 * p8; + r->d[0] = c & 0xFFFFFFFFUL; c >>= 32; + c += p1 + (uint64_t)SECP256K1_N_C_1 * p8; + r->d[1] = c & 0xFFFFFFFFUL; c >>= 32; + c += p2 + (uint64_t)SECP256K1_N_C_2 * p8; + r->d[2] = c & 0xFFFFFFFFUL; c >>= 32; + c += p3 + (uint64_t)SECP256K1_N_C_3 * p8; + r->d[3] = c & 0xFFFFFFFFUL; c >>= 32; + c += p4 + (uint64_t)p8; + r->d[4] = c & 0xFFFFFFFFUL; c >>= 32; + c += p5; + r->d[5] = c & 0xFFFFFFFFUL; c >>= 32; + c += p6; + r->d[6] = c & 0xFFFFFFFFUL; c >>= 32; + c += p7; + r->d[7] = c & 0xFFFFFFFFUL; c >>= 32; + + /* Final reduction of r. */ + secp256k1_zkp_scalar_reduce(r, c + secp256k1_zkp_scalar_check_overflow(r)); +} + +static void secp256k1_zkp_scalar_mul_512(uint32_t *l, const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b) { + /* 96 bit accumulator. */ + uint32_t c0 = 0, c1 = 0, c2 = 0; + + /* l[0..15] = a[0..7] * b[0..7]. */ + muladd_fast(a->d[0], b->d[0]); + extract_fast(l[0]); + muladd(a->d[0], b->d[1]); + muladd(a->d[1], b->d[0]); + extract(l[1]); + muladd(a->d[0], b->d[2]); + muladd(a->d[1], b->d[1]); + muladd(a->d[2], b->d[0]); + extract(l[2]); + muladd(a->d[0], b->d[3]); + muladd(a->d[1], b->d[2]); + muladd(a->d[2], b->d[1]); + muladd(a->d[3], b->d[0]); + extract(l[3]); + muladd(a->d[0], b->d[4]); + muladd(a->d[1], b->d[3]); + muladd(a->d[2], b->d[2]); + muladd(a->d[3], b->d[1]); + muladd(a->d[4], b->d[0]); + extract(l[4]); + muladd(a->d[0], b->d[5]); + muladd(a->d[1], b->d[4]); + muladd(a->d[2], b->d[3]); + muladd(a->d[3], b->d[2]); + muladd(a->d[4], b->d[1]); + muladd(a->d[5], b->d[0]); + extract(l[5]); + muladd(a->d[0], b->d[6]); + muladd(a->d[1], b->d[5]); + muladd(a->d[2], b->d[4]); + muladd(a->d[3], b->d[3]); + muladd(a->d[4], b->d[2]); + muladd(a->d[5], b->d[1]); + muladd(a->d[6], b->d[0]); + extract(l[6]); + muladd(a->d[0], b->d[7]); + muladd(a->d[1], b->d[6]); + muladd(a->d[2], b->d[5]); + muladd(a->d[3], b->d[4]); + muladd(a->d[4], b->d[3]); + muladd(a->d[5], b->d[2]); + muladd(a->d[6], b->d[1]); + muladd(a->d[7], b->d[0]); + extract(l[7]); + muladd(a->d[1], b->d[7]); + muladd(a->d[2], b->d[6]); + muladd(a->d[3], b->d[5]); + muladd(a->d[4], b->d[4]); + muladd(a->d[5], b->d[3]); + muladd(a->d[6], b->d[2]); + muladd(a->d[7], b->d[1]); + extract(l[8]); + muladd(a->d[2], b->d[7]); + muladd(a->d[3], b->d[6]); + muladd(a->d[4], b->d[5]); + muladd(a->d[5], b->d[4]); + muladd(a->d[6], b->d[3]); + muladd(a->d[7], b->d[2]); + extract(l[9]); + muladd(a->d[3], b->d[7]); + muladd(a->d[4], b->d[6]); + muladd(a->d[5], b->d[5]); + muladd(a->d[6], b->d[4]); + muladd(a->d[7], b->d[3]); + extract(l[10]); + muladd(a->d[4], b->d[7]); + muladd(a->d[5], b->d[6]); + muladd(a->d[6], b->d[5]); + muladd(a->d[7], b->d[4]); + extract(l[11]); + muladd(a->d[5], b->d[7]); + muladd(a->d[6], b->d[6]); + muladd(a->d[7], b->d[5]); + extract(l[12]); + muladd(a->d[6], b->d[7]); + muladd(a->d[7], b->d[6]); + extract(l[13]); + muladd_fast(a->d[7], b->d[7]); + extract_fast(l[14]); + VERIFY_CHECK(c1 == 0); + l[15] = c0; +} + +static void secp256k1_zkp_scalar_sqr_512(uint32_t *l, const secp256k1_zkp_scalar *a) { + /* 96 bit accumulator. */ + uint32_t c0 = 0, c1 = 0, c2 = 0; + + /* l[0..15] = a[0..7]^2. */ + muladd_fast(a->d[0], a->d[0]); + extract_fast(l[0]); + muladd2(a->d[0], a->d[1]); + extract(l[1]); + muladd2(a->d[0], a->d[2]); + muladd(a->d[1], a->d[1]); + extract(l[2]); + muladd2(a->d[0], a->d[3]); + muladd2(a->d[1], a->d[2]); + extract(l[3]); + muladd2(a->d[0], a->d[4]); + muladd2(a->d[1], a->d[3]); + muladd(a->d[2], a->d[2]); + extract(l[4]); + muladd2(a->d[0], a->d[5]); + muladd2(a->d[1], a->d[4]); + muladd2(a->d[2], a->d[3]); + extract(l[5]); + muladd2(a->d[0], a->d[6]); + muladd2(a->d[1], a->d[5]); + muladd2(a->d[2], a->d[4]); + muladd(a->d[3], a->d[3]); + extract(l[6]); + muladd2(a->d[0], a->d[7]); + muladd2(a->d[1], a->d[6]); + muladd2(a->d[2], a->d[5]); + muladd2(a->d[3], a->d[4]); + extract(l[7]); + muladd2(a->d[1], a->d[7]); + muladd2(a->d[2], a->d[6]); + muladd2(a->d[3], a->d[5]); + muladd(a->d[4], a->d[4]); + extract(l[8]); + muladd2(a->d[2], a->d[7]); + muladd2(a->d[3], a->d[6]); + muladd2(a->d[4], a->d[5]); + extract(l[9]); + muladd2(a->d[3], a->d[7]); + muladd2(a->d[4], a->d[6]); + muladd(a->d[5], a->d[5]); + extract(l[10]); + muladd2(a->d[4], a->d[7]); + muladd2(a->d[5], a->d[6]); + extract(l[11]); + muladd2(a->d[5], a->d[7]); + muladd(a->d[6], a->d[6]); + extract(l[12]); + muladd2(a->d[6], a->d[7]); + extract(l[13]); + muladd_fast(a->d[7], a->d[7]); + extract_fast(l[14]); + VERIFY_CHECK(c1 == 0); + l[15] = c0; +} + +#undef sumadd +#undef sumadd_fast +#undef muladd +#undef muladd_fast +#undef muladd2 +#undef extract +#undef extract_fast + +static void secp256k1_zkp_scalar_mul(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b) { + uint32_t l[16]; + secp256k1_zkp_scalar_mul_512(l, a, b); + secp256k1_zkp_scalar_reduce_512(r, l); +} + +static int secp256k1_zkp_scalar_shr_int(secp256k1_zkp_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = r->d[0] & ((1 << n) - 1); + r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n)); + r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n)); + r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n)); + r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n)); + r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - n)); + r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n)); + r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n)); + r->d[7] = (r->d[7] >> n); + return ret; +} + +static void secp256k1_zkp_scalar_sqr(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a) { + uint32_t l[16]; + secp256k1_zkp_scalar_sqr_512(l, a); + secp256k1_zkp_scalar_reduce_512(r, l); +} + +#ifdef USE_ENDOMORPHISM +static void secp256k1_zkp_scalar_split_128(secp256k1_zkp_scalar *r1, secp256k1_zkp_scalar *r2, const secp256k1_zkp_scalar *a) { + r1->d[0] = a->d[0]; + r1->d[1] = a->d[1]; + r1->d[2] = a->d[2]; + r1->d[3] = a->d[3]; + r1->d[4] = 0; + r1->d[5] = 0; + r1->d[6] = 0; + r1->d[7] = 0; + r2->d[0] = a->d[4]; + r2->d[1] = a->d[5]; + r2->d[2] = a->d[6]; + r2->d[3] = a->d[7]; + r2->d[4] = 0; + r2->d[5] = 0; + r2->d[6] = 0; + r2->d[7] = 0; +} +#endif + +SECP256K1_INLINE static int secp256k1_zkp_scalar_eq(const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b) { + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0; +} + +SECP256K1_INLINE static void secp256k1_zkp_scalar_mul_shift_var(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b, unsigned int shift) { + uint32_t l[16]; + unsigned int shiftlimbs; + unsigned int shiftlow; + unsigned int shifthigh; + VERIFY_CHECK(shift >= 256); + secp256k1_zkp_scalar_mul_512(l, a, b); + shiftlimbs = shift >> 5; + shiftlow = shift & 0x1F; + shifthigh = 32 - shiftlow; + r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 480 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[1] = shift < 480 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[2] = shift < 448 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 416 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[3] = shift < 416 ? (l[3 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[4 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[4] = shift < 384 ? (l[4 + shiftlimbs] >> shiftlow | (shift < 352 && shiftlow ? (l[5 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0; + secp256k1_zkp_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); +} + +#define ROTL32(x,n) ((x) << (n) | (x) >> (32-(n))) +#define QUARTERROUND(a,b,c,d) \ + a += b; d = ROTL32(d ^ a, 16); \ + c += d; b = ROTL32(b ^ c, 12); \ + a += b; d = ROTL32(d ^ a, 8); \ + c += d; b = ROTL32(b ^ c, 7); + +#ifdef WORDS_BIGENDIAN +#define LE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#define BE32(p) (p) +#else +#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#define LE32(p) (p) +#endif + +static void secp256k1_zkp_scalar_chacha20(secp256k1_zkp_scalar *r1, secp256k1_zkp_scalar *r2, const unsigned char *seed, uint64_t idx) { + size_t n; + size_t over_count = 0; + uint32_t seed32[8]; + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + int over1, over2; + + memcpy((void *) seed32, (const void *) seed, 32); + do { + x0 = 0x61707865; + x1 = 0x3320646e; + x2 = 0x79622d32; + x3 = 0x6b206574; + x4 = LE32(seed32[0]); + x5 = LE32(seed32[1]); + x6 = LE32(seed32[2]); + x7 = LE32(seed32[3]); + x8 = LE32(seed32[4]); + x9 = LE32(seed32[5]); + x10 = LE32(seed32[6]); + x11 = LE32(seed32[7]); + x12 = idx; + x13 = idx >> 32; + x14 = 0; + x15 = over_count; + + n = 10; + while (n--) { + QUARTERROUND(x0, x4, x8,x12) + QUARTERROUND(x1, x5, x9,x13) + QUARTERROUND(x2, x6,x10,x14) + QUARTERROUND(x3, x7,x11,x15) + QUARTERROUND(x0, x5,x10,x15) + QUARTERROUND(x1, x6,x11,x12) + QUARTERROUND(x2, x7, x8,x13) + QUARTERROUND(x3, x4, x9,x14) + } + + x0 += 0x61707865; + x1 += 0x3320646e; + x2 += 0x79622d32; + x3 += 0x6b206574; + x4 += LE32(seed32[0]); + x5 += LE32(seed32[1]); + x6 += LE32(seed32[2]); + x7 += LE32(seed32[3]); + x8 += LE32(seed32[4]); + x9 += LE32(seed32[5]); + x10 += LE32(seed32[6]); + x11 += LE32(seed32[7]); + x12 += idx; + x13 += idx >> 32; + x14 += 0; + x15 += over_count; + + r1->d[7] = LE32(x0); + r1->d[6] = LE32(x1); + r1->d[5] = LE32(x2); + r1->d[4] = LE32(x3); + r1->d[3] = LE32(x4); + r1->d[2] = LE32(x5); + r1->d[1] = LE32(x6); + r1->d[0] = LE32(x7); + r2->d[7] = LE32(x8); + r2->d[6] = LE32(x9); + r2->d[5] = LE32(x10); + r2->d[4] = LE32(x11); + r2->d[3] = LE32(x12); + r2->d[2] = LE32(x13); + r2->d[1] = LE32(x14); + r2->d[0] = LE32(x15); + + over1 = secp256k1_zkp_scalar_check_overflow(r1); + over2 = secp256k1_zkp_scalar_check_overflow(r2); + over_count++; + } while (over1 | over2); +} + +#undef ROTL32 +#undef QUARTERROUND +#undef BE32 +#undef LE32 + +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_impl.h new file mode 100644 index 00000000..0961ec0d --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_impl.h @@ -0,0 +1,333 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_SCALAR_IMPL_H +#define SECP256K1_SCALAR_IMPL_H + +#include "group.h" +#include "scalar.h" + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#if defined(EXHAUSTIVE_TEST_ORDER) +#include "scalar_low_impl.h" +#elif defined(USE_SCALAR_4X64) +#include "scalar_4x64_impl.h" +#elif defined(USE_SCALAR_8X32) +#include "scalar_8x32_impl.h" +#else +#error "Please select scalar implementation" +#endif + +#ifndef USE_NUM_NONE +static void secp256k1_zkp_scalar_get_num(secp256k1_zkp_num *r, const secp256k1_zkp_scalar *a) { + unsigned char c[32]; + secp256k1_zkp_scalar_get_b32(c, a); + secp256k1_zkp_num_set_bin(r, c, 32); +} + +/** secp256k1 curve order, see secp256k1_zkp_ecdsa_const_order_as_fe in ecdsa_impl.h */ +static void secp256k1_zkp_scalar_order_get_num(secp256k1_zkp_num *r) { +#if defined(EXHAUSTIVE_TEST_ORDER) + static const unsigned char order[32] = { + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,EXHAUSTIVE_TEST_ORDER + }; +#else + static const unsigned char order[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 + }; +#endif + secp256k1_zkp_num_set_bin(r, order, 32); +} +#endif + +static void secp256k1_zkp_scalar_inverse(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *x) { +#if defined(EXHAUSTIVE_TEST_ORDER) + int i; + *r = 0; + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) + if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) + *r = i; + /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus + * have a composite group order; fix it in exhaustive_tests.c). */ + VERIFY_CHECK(*r != 0); +} +#else + secp256k1_zkp_scalar *t; + int i; + /* First compute xN as x ^ (2^N - 1) for some values of N, + * and uM as x ^ M for some values of M. */ + secp256k1_zkp_scalar x2, x3, x6, x8, x14, x28, x56, x112, x126; + secp256k1_zkp_scalar u2, u5, u9, u11, u13; + + secp256k1_zkp_scalar_sqr(&u2, x); + secp256k1_zkp_scalar_mul(&x2, &u2, x); + secp256k1_zkp_scalar_mul(&u5, &u2, &x2); + secp256k1_zkp_scalar_mul(&x3, &u5, &u2); + secp256k1_zkp_scalar_mul(&u9, &x3, &u2); + secp256k1_zkp_scalar_mul(&u11, &u9, &u2); + secp256k1_zkp_scalar_mul(&u13, &u11, &u2); + + secp256k1_zkp_scalar_sqr(&x6, &u13); + secp256k1_zkp_scalar_sqr(&x6, &x6); + secp256k1_zkp_scalar_mul(&x6, &x6, &u11); + + secp256k1_zkp_scalar_sqr(&x8, &x6); + secp256k1_zkp_scalar_sqr(&x8, &x8); + secp256k1_zkp_scalar_mul(&x8, &x8, &x2); + + secp256k1_zkp_scalar_sqr(&x14, &x8); + for (i = 0; i < 5; i++) { + secp256k1_zkp_scalar_sqr(&x14, &x14); + } + secp256k1_zkp_scalar_mul(&x14, &x14, &x6); + + secp256k1_zkp_scalar_sqr(&x28, &x14); + for (i = 0; i < 13; i++) { + secp256k1_zkp_scalar_sqr(&x28, &x28); + } + secp256k1_zkp_scalar_mul(&x28, &x28, &x14); + + secp256k1_zkp_scalar_sqr(&x56, &x28); + for (i = 0; i < 27; i++) { + secp256k1_zkp_scalar_sqr(&x56, &x56); + } + secp256k1_zkp_scalar_mul(&x56, &x56, &x28); + + secp256k1_zkp_scalar_sqr(&x112, &x56); + for (i = 0; i < 55; i++) { + secp256k1_zkp_scalar_sqr(&x112, &x112); + } + secp256k1_zkp_scalar_mul(&x112, &x112, &x56); + + secp256k1_zkp_scalar_sqr(&x126, &x112); + for (i = 0; i < 13; i++) { + secp256k1_zkp_scalar_sqr(&x126, &x126); + } + secp256k1_zkp_scalar_mul(&x126, &x126, &x14); + + /* Then accumulate the final result (t starts at x126). */ + t = &x126; + for (i = 0; i < 3; i++) { + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u5); /* 101 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u5); /* 101 */ + for (i = 0; i < 5; i++) { /* 0 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u11); /* 1011 */ + for (i = 0; i < 4; i++) { + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u11); /* 1011 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 5; i++) { /* 00 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 6; i++) { /* 00 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u5); /* 101 */ + for (i = 0; i < 3; i++) { + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 5; i++) { /* 0 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u9); /* 1001 */ + for (i = 0; i < 6; i++) { /* 000 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u5); /* 101 */ + for (i = 0; i < 10; i++) { /* 0000000 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 9; i++) { /* 0 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &x8); /* 11111111 */ + for (i = 0; i < 5; i++) { /* 0 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u9); /* 1001 */ + for (i = 0; i < 6; i++) { /* 00 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u11); /* 1011 */ + for (i = 0; i < 4; i++) { + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 5; i++) { + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &x2); /* 11 */ + for (i = 0; i < 6; i++) { /* 00 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 10; i++) { /* 000000 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 4; i++) { + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, &u9); /* 1001 */ + for (i = 0; i < 6; i++) { /* 00000 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 8; i++) { /* 00 */ + secp256k1_zkp_scalar_sqr(t, t); + } + secp256k1_zkp_scalar_mul(r, t, &x6); /* 111111 */ +} + +SECP256K1_INLINE static int secp256k1_zkp_scalar_is_even(const secp256k1_zkp_scalar *a) { + return !(a->d[0] & 1); +} +#endif + +static void secp256k1_zkp_scalar_inverse_var(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *x) { +#if defined(USE_SCALAR_INV_BUILTIN) + secp256k1_zkp_scalar_inverse(r, x); +#elif defined(USE_SCALAR_INV_NUM) + unsigned char b[32]; + secp256k1_zkp_num n, m; + secp256k1_zkp_scalar t = *x; + secp256k1_zkp_scalar_get_b32(b, &t); + secp256k1_zkp_num_set_bin(&n, b, 32); + secp256k1_zkp_scalar_order_get_num(&m); + secp256k1_zkp_num_mod_inverse(&n, &n, &m); + secp256k1_zkp_num_get_bin(b, 32, &n); + secp256k1_zkp_scalar_set_b32(r, b, NULL); + /* Verify that the inverse was computed correctly, without GMP code. */ + secp256k1_zkp_scalar_mul(&t, &t, r); + CHECK(secp256k1_zkp_scalar_is_one(&t)); +#else +#error "Please select scalar inverse implementation" +#endif +} + +#ifdef USE_ENDOMORPHISM +#if defined(EXHAUSTIVE_TEST_ORDER) +/** + * Find k1 and k2 given k, such that k1 + k2 * lambda == k mod n; unlike in the + * full case we don't bother making k1 and k2 be small, we just want them to be + * nontrivial to get full test coverage for the exhaustive tests. We therefore + * (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda. + */ +static void secp256k1_zkp_scalar_split_lambda(secp256k1_zkp_scalar *r1, secp256k1_zkp_scalar *r2, const secp256k1_zkp_scalar *a) { + *r2 = (*a + 5) % EXHAUSTIVE_TEST_ORDER; + *r1 = (*a + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; +} +#else +/** + * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where + * lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, + * 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72} + * + * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm + * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 + * and k2 have a small size. + * It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are: + * + * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} + * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3} + * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8} + * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} + * + * The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives + * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and + * compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2. + * + * g1, g2 are precomputed constants used to replace division with a rounded multiplication + * when decomposing the scalar for an endomorphism-based point multiplication. + * + * The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve + * Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5. + * + * The derivation is described in the paper "Efficient Software Implementation of Public-Key + * Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez), + * Section 4.3 (here we use a somewhat higher-precision estimate): + * d = a1*b2 - b1*a2 + * g1 = round((2^272)*b2/d) + * g2 = round((2^272)*b1/d) + * + * (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found + * as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda'). + * + * The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order). + */ + +static void secp256k1_zkp_scalar_split_lambda(secp256k1_zkp_scalar *r1, secp256k1_zkp_scalar *r2, const secp256k1_zkp_scalar *a) { + secp256k1_zkp_scalar c1, c2; + static const secp256k1_zkp_scalar minus_lambda = SECP256K1_SCALAR_CONST( + 0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL, + 0xA880B9FCUL, 0x8EC739C2UL, 0xE0CFC810UL, 0xB51283CFUL + ); + static const secp256k1_zkp_scalar minus_b1 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, + 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL + ); + static const secp256k1_zkp_scalar minus_b2 = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL + ); + static const secp256k1_zkp_scalar g1 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL, + 0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL + ); + static const secp256k1_zkp_scalar g2 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL, + 0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL + ); + VERIFY_CHECK(r1 != a); + VERIFY_CHECK(r2 != a); + /* these _var calls are constant time since the shift amount is constant */ + secp256k1_zkp_scalar_mul_shift_var(&c1, a, &g1, 272); + secp256k1_zkp_scalar_mul_shift_var(&c2, a, &g2, 272); + secp256k1_zkp_scalar_mul(&c1, &c1, &minus_b1); + secp256k1_zkp_scalar_mul(&c2, &c2, &minus_b2); + secp256k1_zkp_scalar_add(r2, &c1, &c2); + secp256k1_zkp_scalar_mul(r1, r2, &minus_lambda); + secp256k1_zkp_scalar_add(r1, r1, a); +} +#endif +#endif + +#endif /* SECP256K1_SCALAR_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_low.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_low.h new file mode 100644 index 00000000..7e729d4b --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_low.h @@ -0,0 +1,15 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef uint32_t secp256k1_zkp_scalar; + +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_low_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_low_impl.h new file mode 100644 index 00000000..f85ebac7 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scalar_low_impl.h @@ -0,0 +1,120 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H + +#include "scalar.h" + +#include + +SECP256K1_INLINE static int secp256k1_zkp_scalar_is_even(const secp256k1_zkp_scalar *a) { + return !(*a & 1); +} + +SECP256K1_INLINE static void secp256k1_zkp_scalar_clear(secp256k1_zkp_scalar *r) { *r = 0; } +SECP256K1_INLINE static void secp256k1_zkp_scalar_set_int(secp256k1_zkp_scalar *r, unsigned int v) { *r = v; } +SECP256K1_INLINE static void secp256k1_zkp_scalar_set_u64(secp256k1_zkp_scalar *r, uint64_t v) { *r = v % EXHAUSTIVE_TEST_ORDER; } + +SECP256K1_INLINE static unsigned int secp256k1_zkp_scalar_get_bits(const secp256k1_zkp_scalar *a, unsigned int offset, unsigned int count) { + if (offset < 32) + return ((*a >> offset) & ((((uint32_t)1) << count) - 1)); + else + return 0; +} + +SECP256K1_INLINE static unsigned int secp256k1_zkp_scalar_get_bits_var(const secp256k1_zkp_scalar *a, unsigned int offset, unsigned int count) { + return secp256k1_zkp_scalar_get_bits(a, offset, count); +} + +SECP256K1_INLINE static int secp256k1_zkp_scalar_check_overflow(const secp256k1_zkp_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; } + +static int secp256k1_zkp_scalar_add(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b) { + *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER; + return *r < *b; +} + +static void secp256k1_zkp_scalar_cadd_bit(secp256k1_zkp_scalar *r, unsigned int bit, int flag) { + if (flag && bit < 32) + *r += (1 << bit); +#ifdef VERIFY + VERIFY_CHECK(secp256k1_zkp_scalar_check_overflow(r) == 0); +#endif +} + +static void secp256k1_zkp_scalar_set_b32(secp256k1_zkp_scalar *r, const unsigned char *b32, int *overflow) { + const int base = 0x100 % EXHAUSTIVE_TEST_ORDER; + int i; + *r = 0; + for (i = 0; i < 32; i++) { + *r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER; + } + /* just deny overflow, it basically always happens */ + if (overflow) *overflow = 0; +} + +static void secp256k1_zkp_scalar_get_b32(unsigned char *bin, const secp256k1_zkp_scalar* a) { + memset(bin, 0, 32); + bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a; +} + +SECP256K1_INLINE static int secp256k1_zkp_scalar_is_zero(const secp256k1_zkp_scalar *a) { + return *a == 0; +} + +static void secp256k1_zkp_scalar_negate(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a) { + if (*a == 0) { + *r = 0; + } else { + *r = EXHAUSTIVE_TEST_ORDER - *a; + } +} + +SECP256K1_INLINE static int secp256k1_zkp_scalar_is_one(const secp256k1_zkp_scalar *a) { + return *a == 1; +} + +static int secp256k1_zkp_scalar_is_high(const secp256k1_zkp_scalar *a) { + return *a > EXHAUSTIVE_TEST_ORDER / 2; +} + +static int secp256k1_zkp_scalar_cond_negate(secp256k1_zkp_scalar *r, int flag) { + if (flag) secp256k1_zkp_scalar_negate(r, r); + return flag ? -1 : 1; +} + +static void secp256k1_zkp_scalar_mul(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b) { + *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; +} + +static int secp256k1_zkp_scalar_shr_int(secp256k1_zkp_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = *r & ((1 << n) - 1); + *r >>= n; + return ret; +} + +static void secp256k1_zkp_scalar_sqr(secp256k1_zkp_scalar *r, const secp256k1_zkp_scalar *a) { + *r = (*a * *a) % EXHAUSTIVE_TEST_ORDER; +} + +static void secp256k1_zkp_scalar_split_128(secp256k1_zkp_scalar *r1, secp256k1_zkp_scalar *r2, const secp256k1_zkp_scalar *a) { + *r1 = *a; + *r2 = 0; +} + +SECP256K1_INLINE static int secp256k1_zkp_scalar_eq(const secp256k1_zkp_scalar *a, const secp256k1_zkp_scalar *b) { + return *a == *b; +} + +SECP256K1_INLINE static void secp256k1_zkp_scalar_chacha20(secp256k1_zkp_scalar *r1, secp256k1_zkp_scalar *r2, const unsigned char *seed, uint64_t n) { + *r1 = (seed[0] + n) % EXHAUSTIVE_TEST_ORDER; + *r2 = (seed[1] + n) % EXHAUSTIVE_TEST_ORDER; +} + +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scratch.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scratch.h new file mode 100644 index 00000000..1b5d1742 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scratch.h @@ -0,0 +1,39 @@ +/********************************************************************** + * Copyright (c) 2017 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCRATCH_ +#define _SECP256K1_SCRATCH_ + +#define SECP256K1_SCRATCH_MAX_FRAMES 5 + +/* The typedef is used internally; the struct name is used in the public API + * (where it is exposed as a different typedef) */ +typedef struct secp256k1_zkp_scratch_space_struct { + void *data[SECP256K1_SCRATCH_MAX_FRAMES]; + size_t offset[SECP256K1_SCRATCH_MAX_FRAMES]; + size_t frame_size[SECP256K1_SCRATCH_MAX_FRAMES]; + size_t frame; + size_t max_size; + const secp256k1_zkp_callback* error_callback; +} secp256k1_zkp_scratch; + +static secp256k1_zkp_scratch* secp256k1_zkp_scratch_create(const secp256k1_zkp_callback* error_callback, size_t max_size); + +static void secp256k1_zkp_scratch_destroy(secp256k1_zkp_scratch* scratch); + +/** Attempts to allocate a new stack frame with `n` available bytes. Returns 1 on success, 0 on failure */ +static int secp256k1_zkp_scratch_allocate_frame(secp256k1_zkp_scratch* scratch, size_t n, size_t objects); + +/** Deallocates a stack frame */ +static void secp256k1_zkp_scratch_deallocate_frame(secp256k1_zkp_scratch* scratch); + +/** Returns the maximum allocation the scratch space will allow */ +static size_t secp256k1_zkp_scratch_max_allocation(const secp256k1_zkp_scratch* scratch, size_t n_objects); + +/** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */ +static void *secp256k1_zkp_scratch_alloc(secp256k1_zkp_scratch* scratch, size_t n); + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scratch_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scratch_impl.h new file mode 100644 index 00000000..f467567c --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/scratch_impl.h @@ -0,0 +1,81 @@ +/********************************************************************** + * Copyright (c) 2017 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCRATCH_IMPL_H_ +#define _SECP256K1_SCRATCH_IMPL_H_ + +#include "util.h" +#include "scratch.h" + +static secp256k1_zkp_scratch* secp256k1_zkp_scratch_create(const secp256k1_zkp_callback* error_callback, size_t max_size) { + secp256k1_zkp_scratch* ret = (secp256k1_zkp_scratch*)checked_malloc(error_callback, sizeof(*ret)); + if (ret != NULL) { + memset(ret, 0, sizeof(*ret)); + ret->max_size = max_size; + ret->error_callback = error_callback; + } + return ret; +} + +static void secp256k1_zkp_scratch_destroy(secp256k1_zkp_scratch* scratch) { + if (scratch != NULL) { + VERIFY_CHECK(scratch->frame == 0); + free(scratch); + } +} + +static size_t secp256k1_zkp_scratch_max_allocation(const secp256k1_zkp_scratch* scratch, size_t objects) { + size_t i = 0; + size_t allocated = 0; + for (i = 0; i < scratch->frame; i++) { + allocated += scratch->frame_size[i]; + } + if (scratch->max_size - allocated <= objects * ALIGNMENT) { + return 0; + } + return scratch->max_size - allocated - objects * ALIGNMENT; +} + +static int secp256k1_zkp_scratch_allocate_frame(secp256k1_zkp_scratch* scratch, size_t n, size_t objects) { + VERIFY_CHECK(scratch->frame < SECP256K1_SCRATCH_MAX_FRAMES); + + if (n <= secp256k1_zkp_scratch_max_allocation(scratch, objects)) { + n += objects * ALIGNMENT; + scratch->data[scratch->frame] = checked_malloc(scratch->error_callback, n); + if (scratch->data[scratch->frame] == NULL) { + return 0; + } + scratch->frame_size[scratch->frame] = n; + scratch->offset[scratch->frame] = 0; + scratch->frame++; + return 1; + } else { + return 0; + } +} + +static void secp256k1_zkp_scratch_deallocate_frame(secp256k1_zkp_scratch* scratch) { + VERIFY_CHECK(scratch->frame > 0); + scratch->frame -= 1; + free(scratch->data[scratch->frame]); +} + +static void *secp256k1_zkp_scratch_alloc(secp256k1_zkp_scratch* scratch, size_t size) { + void *ret; + size_t frame = scratch->frame - 1; + size = ROUND_TO_ALIGN(size); + + if (scratch->frame == 0 || size + scratch->offset[frame] > scratch->frame_size[frame]) { + return NULL; + } + ret = (void *) ((unsigned char *) scratch->data[frame] + scratch->offset[frame]); + memset(ret, 0, size); + scratch->offset[frame] += size; + + return ret; +} + +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/secp256k1.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/secp256k1.c new file mode 100644 index 00000000..38abc191 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/secp256k1.c @@ -0,0 +1,743 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include "include/secp256k1.h" +#include "include/secp256k1_preallocated.h" + +#include "util.h" +#include "num_impl.h" +#include "field_impl.h" +#include "scalar_impl.h" +#include "group_impl.h" +#include "ecmult_impl.h" +#include "ecmult_const_impl.h" +#include "ecmult_gen_impl.h" +#include "ecdsa_impl.h" +#include "eckey_impl.h" +#include "hash_impl.h" +#include "scratch_impl.h" + +#ifdef ENABLE_MODULE_GENERATOR +# include "include/secp256k1_zkp_generator.h" +#endif + +#ifdef ENABLE_MODULE_RANGEPROOF +# include "include/secp256k1_zkp_rangeproof.h" +# include "modules/rangeproof/pedersen.h" +# include "modules/rangeproof/rangeproof.h" +#endif + +#define ARG_CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + secp256k1_zkp_callback_call(&ctx->illegal_callback, #cond); \ + return 0; \ + } \ +} while(0) + +#define ARG_CHECK_NO_RETURN(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + secp256k1_zkp_callback_call(&ctx->illegal_callback, #cond); \ + } \ +} while(0) + +#ifndef USE_EXTERNAL_DEFAULT_CALLBACKS +#include +#include +static void secp256k1_zkp_default_illegal_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); + abort(); +} +static void secp256k1_zkp_default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} +#else +void secp256k1_zkp_default_illegal_callback_fn(const char* str, void* data); +void secp256k1_zkp_default_error_callback_fn(const char* str, void* data); +#endif + +static const secp256k1_zkp_callback default_illegal_callback = { + secp256k1_zkp_default_illegal_callback_fn, + NULL +}; + +static const secp256k1_zkp_callback default_error_callback = { + secp256k1_zkp_default_error_callback_fn, + NULL +}; + +struct secp256k1_zkp_context_struct { + secp256k1_zkp_ecmult_context ecmult_ctx; + secp256k1_zkp_ecmult_gen_context ecmult_gen_ctx; + secp256k1_zkp_callback illegal_callback; + secp256k1_zkp_callback error_callback; +}; + +static const secp256k1_zkp_context secp256k1_zkp_context_no_precomp_ = { + { 0 }, + { 0 }, + { secp256k1_zkp_default_illegal_callback_fn, 0 }, + { secp256k1_zkp_default_error_callback_fn, 0 } +}; +const secp256k1_zkp_context *secp256k1_zkp_context_no_precomp = &secp256k1_zkp_context_no_precomp_; + +size_t secp256k1_zkp_context_preallocated_size(unsigned int flags) { + size_t ret = ROUND_TO_ALIGN(sizeof(secp256k1_zkp_context)); + + if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { + secp256k1_zkp_callback_call(&default_illegal_callback, + "Invalid flags"); + return 0; + } + + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) { + ret += SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE; + } + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) { + ret += SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE; + } + return ret; +} + +size_t secp256k1_zkp_context_preallocated_clone_size(const secp256k1_zkp_context* ctx) { + size_t ret = ROUND_TO_ALIGN(sizeof(secp256k1_zkp_context)); + VERIFY_CHECK(ctx != NULL); + if (secp256k1_zkp_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) { + ret += SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE; + } + if (secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)) { + ret += SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE; + } + return ret; +} + +secp256k1_zkp_context* secp256k1_zkp_context_preallocated_create(void* prealloc, unsigned int flags) { + void* const base = prealloc; + size_t prealloc_size; + secp256k1_zkp_context* ret; + + VERIFY_CHECK(prealloc != NULL); + prealloc_size = secp256k1_zkp_context_preallocated_size(flags); + ret = (secp256k1_zkp_context*)manual_alloc(&prealloc, sizeof(secp256k1_zkp_context), base, prealloc_size); + ret->illegal_callback = default_illegal_callback; + ret->error_callback = default_error_callback; + + if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { + secp256k1_zkp_callback_call(&ret->illegal_callback, + "Invalid flags"); + return NULL; + } + + secp256k1_zkp_ecmult_context_init(&ret->ecmult_ctx); + secp256k1_zkp_ecmult_gen_context_init(&ret->ecmult_gen_ctx); + + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) { + secp256k1_zkp_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &prealloc); + } + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) { + secp256k1_zkp_ecmult_context_build(&ret->ecmult_ctx, &prealloc); + } + + return (secp256k1_zkp_context*) ret; +} + +secp256k1_zkp_context* secp256k1_zkp_context_create(unsigned int flags) { + size_t const prealloc_size = secp256k1_zkp_context_preallocated_size(flags); + secp256k1_zkp_context* ctx = (secp256k1_zkp_context*)checked_malloc(&default_error_callback, prealloc_size); + if (EXPECT(secp256k1_zkp_context_preallocated_create(ctx, flags) == NULL, 0)) { + free(ctx); + return NULL; + } + + return ctx; +} + +secp256k1_zkp_context* secp256k1_zkp_context_preallocated_clone(const secp256k1_zkp_context* ctx, void* prealloc) { + size_t prealloc_size; + secp256k1_zkp_context* ret; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(prealloc != NULL); + + prealloc_size = secp256k1_zkp_context_preallocated_clone_size(ctx); + ret = (secp256k1_zkp_context*)prealloc; + memcpy(ret, ctx, prealloc_size); + secp256k1_zkp_ecmult_gen_context_finalize_memcpy(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx); + secp256k1_zkp_ecmult_context_finalize_memcpy(&ret->ecmult_ctx, &ctx->ecmult_ctx); + return ret; +} + +secp256k1_zkp_context* secp256k1_zkp_context_clone(const secp256k1_zkp_context* ctx) { + secp256k1_zkp_context* ret; + size_t prealloc_size; + + VERIFY_CHECK(ctx != NULL); + prealloc_size = secp256k1_zkp_context_preallocated_clone_size(ctx); + ret = (secp256k1_zkp_context*)checked_malloc(&ctx->error_callback, prealloc_size); + ret = secp256k1_zkp_context_preallocated_clone(ctx, ret); + return ret; +} + +void secp256k1_zkp_context_preallocated_destroy(secp256k1_zkp_context* ctx) { + ARG_CHECK_NO_RETURN(ctx != secp256k1_zkp_context_no_precomp); + if (ctx != NULL) { + secp256k1_zkp_ecmult_context_clear(&ctx->ecmult_ctx); + secp256k1_zkp_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); + } +} + +void secp256k1_zkp_context_destroy(secp256k1_zkp_context* ctx) { + if (ctx != NULL) { + secp256k1_zkp_context_preallocated_destroy(ctx); + free(ctx); + } +} + +void secp256k1_zkp_context_set_illegal_callback(secp256k1_zkp_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + ARG_CHECK_NO_RETURN(ctx != secp256k1_zkp_context_no_precomp); + if (fun == NULL) { + fun = secp256k1_zkp_default_illegal_callback_fn; + } + ctx->illegal_callback.fn = fun; + ctx->illegal_callback.data = data; +} + +void secp256k1_zkp_context_set_error_callback(secp256k1_zkp_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + ARG_CHECK_NO_RETURN(ctx != secp256k1_zkp_context_no_precomp); + if (fun == NULL) { + fun = secp256k1_zkp_default_error_callback_fn; + } + ctx->error_callback.fn = fun; + ctx->error_callback.data = data; +} + +secp256k1_zkp_scratch_space* secp256k1_zkp_scratch_space_create(const secp256k1_zkp_context* ctx, size_t max_size) { + VERIFY_CHECK(ctx != NULL); + return secp256k1_zkp_scratch_create(&ctx->error_callback, max_size); +} + +void secp256k1_zkp_scratch_space_destroy(secp256k1_zkp_scratch_space* scratch) { + secp256k1_zkp_scratch_destroy(scratch); +} + +static int secp256k1_zkp_pubkey_load(const secp256k1_zkp_context* ctx, secp256k1_zkp_ge* ge, const secp256k1_zkp_pubkey* pubkey) { + if (sizeof(secp256k1_zkp_ge_storage) == 64) { + /* When the secp256k1_zkp_ge_storage type is exactly 64 byte, use its + * representation inside secp256k1_zkp_pubkey, as conversion is very fast. + * Note that secp256k1_zkp_pubkey_save must use the same representation. */ + secp256k1_zkp_ge_storage s; + memcpy(&s, &pubkey->data[0], sizeof(s)); + secp256k1_zkp_ge_from_storage(ge, &s); + } else { + /* Otherwise, fall back to 32-byte big endian for X and Y. */ + secp256k1_zkp_fe x, y; + secp256k1_zkp_fe_set_b32(&x, pubkey->data); + secp256k1_zkp_fe_set_b32(&y, pubkey->data + 32); + secp256k1_zkp_ge_set_xy(ge, &x, &y); + } + ARG_CHECK(!secp256k1_zkp_fe_is_zero(&ge->x)); + return 1; +} + +static void secp256k1_zkp_pubkey_save(secp256k1_zkp_pubkey* pubkey, secp256k1_zkp_ge* ge) { + if (sizeof(secp256k1_zkp_ge_storage) == 64) { + secp256k1_zkp_ge_storage s; + secp256k1_zkp_ge_to_storage(&s, ge); + memcpy(&pubkey->data[0], &s, sizeof(s)); + } else { + VERIFY_CHECK(!secp256k1_zkp_ge_is_infinity(ge)); + secp256k1_zkp_fe_normalize_var(&ge->x); + secp256k1_zkp_fe_normalize_var(&ge->y); + secp256k1_zkp_fe_get_b32(pubkey->data, &ge->x); + secp256k1_zkp_fe_get_b32(pubkey->data + 32, &ge->y); + } +} + +int secp256k1_zkp_ec_pubkey_parse(const secp256k1_zkp_context* ctx, secp256k1_zkp_pubkey* pubkey, const unsigned char *input, size_t inputlen) { + secp256k1_zkp_ge Q; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(input != NULL); + if (!secp256k1_zkp_eckey_pubkey_parse(&Q, input, inputlen)) { + return 0; + } + secp256k1_zkp_pubkey_save(pubkey, &Q); + secp256k1_zkp_ge_clear(&Q); + return 1; +} + +int secp256k1_zkp_ec_pubkey_serialize(const secp256k1_zkp_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_zkp_pubkey* pubkey, unsigned int flags) { + secp256k1_zkp_ge Q; + size_t len; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65)); + len = *outputlen; + *outputlen = 0; + ARG_CHECK(output != NULL); + memset(output, 0, len); + ARG_CHECK(pubkey != NULL); + ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); + if (secp256k1_zkp_pubkey_load(ctx, &Q, pubkey)) { + ret = secp256k1_zkp_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); + if (ret) { + *outputlen = len; + } + } + return ret; +} + +static void secp256k1_zkp_ecdsa_signature_load(const secp256k1_zkp_context* ctx, secp256k1_zkp_scalar* r, secp256k1_zkp_scalar* s, const secp256k1_zkp_ecdsa_signature* sig) { + (void)ctx; + if (sizeof(secp256k1_zkp_scalar) == 32) { + /* When the secp256k1_zkp_scalar type is exactly 32 byte, use its + * representation inside secp256k1_zkp_ecdsa_signature, as conversion is very fast. + * Note that secp256k1_zkp_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + secp256k1_zkp_scalar_set_b32(r, &sig->data[0], NULL); + secp256k1_zkp_scalar_set_b32(s, &sig->data[32], NULL); + } +} + +static void secp256k1_zkp_ecdsa_signature_save(secp256k1_zkp_ecdsa_signature* sig, const secp256k1_zkp_scalar* r, const secp256k1_zkp_scalar* s) { + if (sizeof(secp256k1_zkp_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + secp256k1_zkp_scalar_get_b32(&sig->data[0], r); + secp256k1_zkp_scalar_get_b32(&sig->data[32], s); + } +} + +int secp256k1_zkp_ecdsa_signature_parse_der(const secp256k1_zkp_context* ctx, secp256k1_zkp_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + secp256k1_zkp_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input != NULL); + + if (secp256k1_zkp_ecdsa_sig_parse(&r, &s, input, inputlen)) { + secp256k1_zkp_ecdsa_signature_save(sig, &r, &s); + return 1; + } else { + memset(sig, 0, sizeof(*sig)); + return 0; + } +} + +int secp256k1_zkp_ecdsa_signature_parse_compact(const secp256k1_zkp_context* ctx, secp256k1_zkp_ecdsa_signature* sig, const unsigned char *input64) { + secp256k1_zkp_scalar r, s; + int ret = 1; + int overflow = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + + secp256k1_zkp_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_zkp_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + secp256k1_zkp_ecdsa_signature_save(sig, &r, &s); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int secp256k1_zkp_ecdsa_signature_serialize_der(const secp256k1_zkp_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_zkp_ecdsa_signature* sig) { + secp256k1_zkp_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_zkp_ecdsa_signature_load(ctx, &r, &s, sig); + return secp256k1_zkp_ecdsa_sig_serialize(output, outputlen, &r, &s); +} + +int secp256k1_zkp_ecdsa_signature_serialize_compact(const secp256k1_zkp_context* ctx, unsigned char *output64, const secp256k1_zkp_ecdsa_signature* sig) { + secp256k1_zkp_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_zkp_ecdsa_signature_load(ctx, &r, &s, sig); + secp256k1_zkp_scalar_get_b32(&output64[0], &r); + secp256k1_zkp_scalar_get_b32(&output64[32], &s); + return 1; +} + +int secp256k1_zkp_ecdsa_signature_normalize(const secp256k1_zkp_context* ctx, secp256k1_zkp_ecdsa_signature *sigout, const secp256k1_zkp_ecdsa_signature *sigin) { + secp256k1_zkp_scalar r, s; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_zkp_ecdsa_signature_load(ctx, &r, &s, sigin); + ret = secp256k1_zkp_scalar_is_high(&s); + if (sigout != NULL) { + if (ret) { + secp256k1_zkp_scalar_negate(&s, &s); + } + secp256k1_zkp_ecdsa_signature_save(sigout, &r, &s); + } + + return ret; +} + +int secp256k1_zkp_ecdsa_verify(const secp256k1_zkp_context* ctx, const secp256k1_zkp_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_zkp_pubkey *pubkey) { + secp256k1_zkp_ge q; + secp256k1_zkp_scalar r, s; + secp256k1_zkp_scalar m; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_zkp_scalar_set_b32(&m, msg32, NULL); + secp256k1_zkp_ecdsa_signature_load(ctx, &r, &s, sig); + return (!secp256k1_zkp_scalar_is_high(&s) && + secp256k1_zkp_pubkey_load(ctx, &q, pubkey) && + secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m)); +} + +static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *offset, const void *data, unsigned int len) { + memcpy(buf + *offset, data, len); + *offset += len; +} + +/* This nonce function is described in BIP-schnorr + * (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki) */ +static int secp256k1_zkp_nonce_function_bipschnorr(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + secp256k1_zkp_sha256 sha; + (void) data; + (void) counter; + VERIFY_CHECK(counter == 0); + + /* Hash x||msg as per the spec */ + secp256k1_zkp_sha256_initialize(&sha); + secp256k1_zkp_sha256_write(&sha, key32, 32); + secp256k1_zkp_sha256_write(&sha, msg32, 32); + /* Hash in algorithm, which is not in the spec, but may be critical to + * users depending on it to avoid nonce reuse across algorithms. */ + if (algo16 != NULL) { + secp256k1_zkp_sha256_write(&sha, algo16, 16); + } + secp256k1_zkp_sha256_finalize(&sha, nonce32); + return 1; +} + +static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + unsigned char keydata[112]; + unsigned int offset = 0; + secp256k1_zkp_rfc6979_hmac_sha256 rng; + unsigned int i; + /* We feed a byte array to the PRNG as input, consisting of: + * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d. + * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. + * - optionally 16 extra bytes with the algorithm name. + * Because the arguments have distinct fixed lengths it is not possible for + * different argument mixtures to emulate each other and result in the same + * nonces. + */ + buffer_append(keydata, &offset, key32, 32); + buffer_append(keydata, &offset, msg32, 32); + if (data != NULL) { + buffer_append(keydata, &offset, data, 32); + } + if (algo16 != NULL) { + buffer_append(keydata, &offset, algo16, 16); + } + secp256k1_zkp_rfc6979_hmac_sha256_initialize(&rng, keydata, offset); + memset(keydata, 0, sizeof(keydata)); + for (i = 0; i <= counter; i++) { + secp256k1_zkp_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + } + secp256k1_zkp_rfc6979_hmac_sha256_finalize(&rng); + return 1; +} + +const secp256k1_zkp_nonce_function secp256k1_zkp_nonce_function_rfc6979 = nonce_function_rfc6979; +const secp256k1_zkp_nonce_function secp256k1_zkp_nonce_function_default = nonce_function_rfc6979; + +int secp256k1_zkp_ecdsa_sign(const secp256k1_zkp_context* ctx, secp256k1_zkp_ecdsa_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_zkp_nonce_function noncefp, const void* noncedata) { + secp256k1_zkp_scalar r, s; + secp256k1_zkp_scalar sec, non, msg; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_zkp_nonce_function_default; + } + + secp256k1_zkp_scalar_set_b32(&sec, seckey, &overflow); + /* Fail if the secret key is invalid. */ + if (!overflow && !secp256k1_zkp_scalar_is_zero(&sec)) { + unsigned char nonce32[32]; + unsigned int count = 0; + secp256k1_zkp_scalar_set_b32(&msg, msg32, NULL); + while (1) { + ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_zkp_scalar_set_b32(&non, nonce32, &overflow); + if (!overflow && !secp256k1_zkp_scalar_is_zero(&non)) { + if (secp256k1_zkp_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) { + break; + } + } + count++; + } + memset(nonce32, 0, 32); + secp256k1_zkp_scalar_clear(&msg); + secp256k1_zkp_scalar_clear(&non); + secp256k1_zkp_scalar_clear(&sec); + } + if (ret) { + secp256k1_zkp_ecdsa_signature_save(signature, &r, &s); + } else { + memset(signature, 0, sizeof(*signature)); + } + return ret; +} + +int secp256k1_zkp_ec_seckey_verify(const secp256k1_zkp_context* ctx, const unsigned char *seckey) { + secp256k1_zkp_scalar sec; + int ret; + int overflow; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + + secp256k1_zkp_scalar_set_b32(&sec, seckey, &overflow); + ret = !overflow && !secp256k1_zkp_scalar_is_zero(&sec); + secp256k1_zkp_scalar_clear(&sec); + return ret; +} + +int secp256k1_zkp_ec_pubkey_create(const secp256k1_zkp_context* ctx, secp256k1_zkp_pubkey *pubkey, const unsigned char *seckey) { + secp256k1_zkp_gej pj; + secp256k1_zkp_ge p; + secp256k1_zkp_scalar sec; + int overflow; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(secp256k1_zkp_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey != NULL); + + secp256k1_zkp_scalar_set_b32(&sec, seckey, &overflow); + ret = (!overflow) & (!secp256k1_zkp_scalar_is_zero(&sec)); + if (ret) { + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); + secp256k1_zkp_ge_set_gej(&p, &pj); + secp256k1_zkp_pubkey_save(pubkey, &p); + } + secp256k1_zkp_scalar_clear(&sec); + return ret; +} + +int secp256k1_zkp_ec_privkey_negate(const secp256k1_zkp_context* ctx, unsigned char *seckey) { + secp256k1_zkp_scalar sec; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + + secp256k1_zkp_scalar_set_b32(&sec, seckey, NULL); + secp256k1_zkp_scalar_negate(&sec, &sec); + secp256k1_zkp_scalar_get_b32(seckey, &sec); + + return 1; +} + +int secp256k1_zkp_ec_pubkey_negate(const secp256k1_zkp_context* ctx, secp256k1_zkp_pubkey *pubkey) { + int ret = 0; + secp256k1_zkp_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + + ret = secp256k1_zkp_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + secp256k1_zkp_ge_neg(&p, &p); + secp256k1_zkp_pubkey_save(pubkey, &p); + } + return ret; +} + +int secp256k1_zkp_ec_privkey_tweak_add(const secp256k1_zkp_context* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_zkp_scalar term; + secp256k1_zkp_scalar sec; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); + + secp256k1_zkp_scalar_set_b32(&term, tweak, &overflow); + secp256k1_zkp_scalar_set_b32(&sec, seckey, NULL); + + ret = !overflow && secp256k1_zkp_eckey_privkey_tweak_add(&sec, &term); + memset(seckey, 0, 32); + if (ret) { + secp256k1_zkp_scalar_get_b32(seckey, &sec); + } + + secp256k1_zkp_scalar_clear(&sec); + secp256k1_zkp_scalar_clear(&term); + return ret; +} + +int secp256k1_zkp_ec_pubkey_tweak_add(const secp256k1_zkp_context* ctx, secp256k1_zkp_pubkey *pubkey, const unsigned char *tweak) { + secp256k1_zkp_ge p; + secp256k1_zkp_scalar term; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak != NULL); + + secp256k1_zkp_scalar_set_b32(&term, tweak, &overflow); + ret = !overflow && secp256k1_zkp_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + if (secp256k1_zkp_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) { + secp256k1_zkp_pubkey_save(pubkey, &p); + } else { + ret = 0; + } + } + + return ret; +} + +int secp256k1_zkp_ec_privkey_tweak_mul(const secp256k1_zkp_context* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_zkp_scalar factor; + secp256k1_zkp_scalar sec; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); + + secp256k1_zkp_scalar_set_b32(&factor, tweak, &overflow); + secp256k1_zkp_scalar_set_b32(&sec, seckey, NULL); + ret = !overflow && secp256k1_zkp_eckey_privkey_tweak_mul(&sec, &factor); + memset(seckey, 0, 32); + if (ret) { + secp256k1_zkp_scalar_get_b32(seckey, &sec); + } + + secp256k1_zkp_scalar_clear(&sec); + secp256k1_zkp_scalar_clear(&factor); + return ret; +} + +int secp256k1_zkp_ec_pubkey_tweak_mul(const secp256k1_zkp_context* ctx, secp256k1_zkp_pubkey *pubkey, const unsigned char *tweak) { + secp256k1_zkp_ge p; + secp256k1_zkp_scalar factor; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_zkp_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak != NULL); + + secp256k1_zkp_scalar_set_b32(&factor, tweak, &overflow); + ret = !overflow && secp256k1_zkp_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + if (secp256k1_zkp_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor)) { + secp256k1_zkp_pubkey_save(pubkey, &p); + } else { + ret = 0; + } + } + + return ret; +} + +int secp256k1_zkp_context_randomize(secp256k1_zkp_context* ctx, const unsigned char *seed32) { + VERIFY_CHECK(ctx != NULL); + if (secp256k1_zkp_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) { + secp256k1_zkp_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + } + return 1; +} + +int secp256k1_zkp_ec_pubkey_combine(const secp256k1_zkp_context* ctx, secp256k1_zkp_pubkey *pubnonce, const secp256k1_zkp_pubkey * const *pubnonces, size_t n) { + size_t i; + secp256k1_zkp_gej Qj; + secp256k1_zkp_ge Q; + + ARG_CHECK(pubnonce != NULL); + memset(pubnonce, 0, sizeof(*pubnonce)); + ARG_CHECK(n >= 1); + ARG_CHECK(pubnonces != NULL); + + secp256k1_zkp_gej_set_infinity(&Qj); + + for (i = 0; i < n; i++) { + secp256k1_zkp_pubkey_load(ctx, &Q, pubnonces[i]); + secp256k1_zkp_gej_add_ge(&Qj, &Qj, &Q); + } + if (secp256k1_zkp_gej_is_infinity(&Qj)) { + return 0; + } + secp256k1_zkp_ge_set_gej(&Q, &Qj); + secp256k1_zkp_pubkey_save(pubnonce, &Q); + return 1; +} + +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_MUSIG +# include "modules/musig/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_GENERATOR +# include "modules/generator/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_RANGEPROOF +# include "modules/rangeproof/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_WHITELIST +# include "modules/whitelist/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_SURJECTIONPROOF +# include "modules/surjection/main_impl.h" +#endif diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/testrand.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/testrand.h new file mode 100644 index 00000000..6d63e8d0 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/testrand.h @@ -0,0 +1,41 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_TESTRAND_H +#define SECP256K1_TESTRAND_H + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +/* A non-cryptographic RNG used only for test infrastructure. */ + +/** Seed the pseudorandom number generator for testing. */ +SECP256K1_INLINE static void secp256k1_zkp_rand_seed(const unsigned char *seed16); + +/** Generate a pseudorandom number in the range [0..2**32-1]. */ +static uint32_t secp256k1_zkp_rand32(void); + +/** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or + * more. */ +static uint32_t secp256k1_zkp_rand_bits(int bits); + +/** Generate a pseudorandom number in the range [0..range-1]. */ +static uint32_t secp256k1_zkp_rand_int(uint32_t range); + +/** Generate a pseudorandom 32-byte array. */ +static void secp256k1_zkp_rand256(unsigned char *b32); + +/** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ +static void secp256k1_zkp_rand256_test(unsigned char *b32); + +/** Generate pseudorandom bytes with long sequences of zero and one bits. */ +static void secp256k1_zkp_rand_bytes_test(unsigned char *bytes, size_t len); + +/** Generate a pseudorandom 64-bit integer in the range min..max, inclusive. */ +static int64_t secp256k1_zkp_rands64(uint64_t min, uint64_t max); + +#endif /* SECP256K1_TESTRAND_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/testrand_impl.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/testrand_impl.h new file mode 100644 index 00000000..9e0e19b8 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/testrand_impl.h @@ -0,0 +1,127 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille, Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_TESTRAND_IMPL_H +#define SECP256K1_TESTRAND_IMPL_H + +#include +#include + +#include "testrand.h" +#include "hash.h" + +static secp256k1_zkp_rfc6979_hmac_sha256 secp256k1_zkp_test_rng; +static uint32_t secp256k1_zkp_test_rng_precomputed[8]; +static int secp256k1_zkp_test_rng_precomputed_used = 8; +static uint64_t secp256k1_zkp_test_rng_integer; +static int secp256k1_zkp_test_rng_integer_bits_left = 0; + +SECP256K1_INLINE static void secp256k1_zkp_rand_seed(const unsigned char *seed16) { + secp256k1_zkp_rfc6979_hmac_sha256_initialize(&secp256k1_zkp_test_rng, seed16, 16); +} + +SECP256K1_INLINE static uint32_t secp256k1_zkp_rand32(void) { + if (secp256k1_zkp_test_rng_precomputed_used == 8) { + secp256k1_zkp_rfc6979_hmac_sha256_generate(&secp256k1_zkp_test_rng, (unsigned char*)(&secp256k1_zkp_test_rng_precomputed[0]), sizeof(secp256k1_zkp_test_rng_precomputed)); + secp256k1_zkp_test_rng_precomputed_used = 0; + } + return secp256k1_zkp_test_rng_precomputed[secp256k1_zkp_test_rng_precomputed_used++]; +} + +static uint32_t secp256k1_zkp_rand_bits(int bits) { + uint32_t ret; + if (secp256k1_zkp_test_rng_integer_bits_left < bits) { + secp256k1_zkp_test_rng_integer |= (((uint64_t)secp256k1_zkp_rand32()) << secp256k1_zkp_test_rng_integer_bits_left); + secp256k1_zkp_test_rng_integer_bits_left += 32; + } + ret = secp256k1_zkp_test_rng_integer; + secp256k1_zkp_test_rng_integer >>= bits; + secp256k1_zkp_test_rng_integer_bits_left -= bits; + ret &= ((~((uint32_t)0)) >> (32 - bits)); + return ret; +} + +static uint32_t secp256k1_zkp_rand_int(uint32_t range) { + /* We want a uniform integer between 0 and range-1, inclusive. + * B is the smallest number such that range <= 2**B. + * two mechanisms implemented here: + * - generate B bits numbers until one below range is found, and return it + * - find the largest multiple M of range that is <= 2**(B+A), generate B+A + * bits numbers until one below M is found, and return it modulo range + * The second mechanism consumes A more bits of entropy in every iteration, + * but may need fewer iterations due to M being closer to 2**(B+A) then + * range is to 2**B. The array below (indexed by B) contains a 0 when the + * first mechanism is to be used, and the number A otherwise. + */ + static const int addbits[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0}; + uint32_t trange, mult; + int bits = 0; + if (range <= 1) { + return 0; + } + trange = range - 1; + while (trange > 0) { + trange >>= 1; + bits++; + } + if (addbits[bits]) { + bits = bits + addbits[bits]; + mult = ((~((uint32_t)0)) >> (32 - bits)) / range; + trange = range * mult; + } else { + trange = range; + mult = 1; + } + while(1) { + uint32_t x = secp256k1_zkp_rand_bits(bits); + if (x < trange) { + return (mult == 1) ? x : (x % range); + } + } +} + +static void secp256k1_zkp_rand256(unsigned char *b32) { + secp256k1_zkp_rfc6979_hmac_sha256_generate(&secp256k1_zkp_test_rng, b32, 32); +} + +static void secp256k1_zkp_rand_bytes_test(unsigned char *bytes, size_t len) { + size_t bits = 0; + memset(bytes, 0, len); + while (bits < len * 8) { + int now; + uint32_t val; + now = 1 + (secp256k1_zkp_rand_bits(6) * secp256k1_zkp_rand_bits(5) + 16) / 31; + val = secp256k1_zkp_rand_bits(1); + while (now > 0 && bits < len * 8) { + bytes[bits / 8] |= val << (bits % 8); + now--; + bits++; + } + } +} + +static void secp256k1_zkp_rand256_test(unsigned char *b32) { + secp256k1_zkp_rand_bytes_test(b32, 32); +} + +SECP256K1_INLINE static int64_t secp256k1_zkp_rands64(uint64_t min, uint64_t max) { + uint64_t range; + uint64_t r; + uint64_t clz; + VERIFY_CHECK(max >= min); + if (max == min) { + return min; + } + range = max - min; + clz = secp256k1_zkp_clz64_var(range); + do { + r = ((uint64_t)secp256k1_zkp_rand32() << 32) | secp256k1_zkp_rand32(); + r >>= clz; + } while (r > range); + return min + (int64_t)r; +} + +#endif /* SECP256K1_TESTRAND_IMPL_H */ diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/tests.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/tests.c new file mode 100644 index 00000000..c97be2fa --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/tests.c @@ -0,0 +1,5389 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille, Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include +#include +#include + +#include + +#include "secp256k1.c" +#include "include/secp256k1.h" +#include "include/secp256k1_preallocated.h" +#include "testrand_impl.h" + +#ifdef ENABLE_OPENSSL_TESTS +#include "openssl/bn.h" +#include "openssl/ec.h" +#include "openssl/ecdsa.h" +#include "openssl/obj_mac.h" +# if OPENSSL_VERSION_NUMBER < 0x10100000L +void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) {*pr = sig->r; *ps = sig->s;} +# endif +#endif + +#include "contrib/lax_der_parsing.c" +#include "contrib/lax_der_privatekey_parsing.c" + +#if !defined(VG_CHECK) +# if defined(VALGRIND) +# include +# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) +# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) +# else +# define VG_UNDEF(x,y) +# define VG_CHECK(x,y) +# endif +#endif + +static int count = 64; +static secp256k1_zkp_context *ctx = NULL; + +static void counting_illegal_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts. */ + int32_t *p; + (void)str; + p = data; + (*p)++; +} + +static void uncounting_illegal_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts (backwards). */ + int32_t *p; + (void)str; + p = data; + (*p)--; +} + +void random_field_element_test(secp256k1_zkp_fe *fe) { + do { + unsigned char b32[32]; + secp256k1_zkp_rand256_test(b32); + if (secp256k1_zkp_fe_set_b32(fe, b32)) { + break; + } + } while(1); +} + +void random_field_element_magnitude(secp256k1_zkp_fe *fe) { + secp256k1_zkp_fe zero; + int n = secp256k1_zkp_rand_int(9); + secp256k1_zkp_fe_normalize(fe); + if (n == 0) { + return; + } + secp256k1_zkp_fe_clear(&zero); + secp256k1_zkp_fe_negate(&zero, &zero, 0); + secp256k1_zkp_fe_mul_int(&zero, n - 1); + secp256k1_zkp_fe_add(fe, &zero); + VERIFY_CHECK(fe->magnitude == n); +} + +void random_group_element_test(secp256k1_zkp_ge *ge) { + secp256k1_zkp_fe fe; + do { + random_field_element_test(&fe); + if (secp256k1_zkp_ge_set_xo_var(ge, &fe, secp256k1_zkp_rand_bits(1))) { + secp256k1_zkp_fe_normalize(&ge->y); + break; + } + } while(1); +} + +void random_group_element_jacobian_test(secp256k1_zkp_gej *gej, const secp256k1_zkp_ge *ge) { + secp256k1_zkp_fe z2, z3; + do { + random_field_element_test(&gej->z); + if (!secp256k1_zkp_fe_is_zero(&gej->z)) { + break; + } + } while(1); + secp256k1_zkp_fe_sqr(&z2, &gej->z); + secp256k1_zkp_fe_mul(&z3, &z2, &gej->z); + secp256k1_zkp_fe_mul(&gej->x, &ge->x, &z2); + secp256k1_zkp_fe_mul(&gej->y, &ge->y, &z3); + gej->infinity = ge->infinity; +} + +void random_scalar_order_test(secp256k1_zkp_scalar *num) { + do { + unsigned char b32[32]; + int overflow = 0; + secp256k1_zkp_rand256_test(b32); + secp256k1_zkp_scalar_set_b32(num, b32, &overflow); + if (overflow || secp256k1_zkp_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +void random_scalar_order(secp256k1_zkp_scalar *num) { + do { + unsigned char b32[32]; + int overflow = 0; + secp256k1_zkp_rand256(b32); + secp256k1_zkp_scalar_set_b32(num, b32, &overflow); + if (overflow || secp256k1_zkp_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +void run_util_tests(void) { + int i; + uint64_t r; + uint64_t r2; + uint64_t r3; + int64_t s; + CHECK(secp256k1_zkp_clz64_var(0) == 64); + CHECK(secp256k1_zkp_clz64_var(1) == 63); + CHECK(secp256k1_zkp_clz64_var(2) == 62); + CHECK(secp256k1_zkp_clz64_var(3) == 62); + CHECK(secp256k1_zkp_clz64_var(~0ULL) == 0); + CHECK(secp256k1_zkp_clz64_var((~0ULL) - 1) == 0); + CHECK(secp256k1_zkp_clz64_var((~0ULL) >> 1) == 1); + CHECK(secp256k1_zkp_clz64_var((~0ULL) >> 2) == 2); + CHECK(secp256k1_zkp_sign_and_abs64(&r, INT64_MAX) == 0); + CHECK(r == INT64_MAX); + CHECK(secp256k1_zkp_sign_and_abs64(&r, INT64_MAX - 1) == 0); + CHECK(r == INT64_MAX - 1); + CHECK(secp256k1_zkp_sign_and_abs64(&r, INT64_MIN) == 1); + CHECK(r == (uint64_t)INT64_MAX + 1); + CHECK(secp256k1_zkp_sign_and_abs64(&r, INT64_MIN + 1) == 1); + CHECK(r == (uint64_t)INT64_MAX); + CHECK(secp256k1_zkp_sign_and_abs64(&r, 0) == 0); + CHECK(r == 0); + CHECK(secp256k1_zkp_sign_and_abs64(&r, 1) == 0); + CHECK(r == 1); + CHECK(secp256k1_zkp_sign_and_abs64(&r, -1) == 1); + CHECK(r == 1); + CHECK(secp256k1_zkp_sign_and_abs64(&r, 2) == 0); + CHECK(r == 2); + CHECK(secp256k1_zkp_sign_and_abs64(&r, -2) == 1); + CHECK(r == 2); + for (i = 0; i < 10; i++) { + CHECK(secp256k1_zkp_clz64_var((~0ULL) - secp256k1_zkp_rand32()) == 0); + r = ((uint64_t)secp256k1_zkp_rand32() << 32) | secp256k1_zkp_rand32(); + r2 = secp256k1_zkp_rands64(0, r); + CHECK(r2 <= r); + r3 = secp256k1_zkp_rands64(r2, r); + CHECK((r3 >= r2) && (r3 <= r)); + r = secp256k1_zkp_rands64(0, INT64_MAX); + s = (int64_t)r * (secp256k1_zkp_rand32()&1?-1:1); + CHECK(secp256k1_zkp_sign_and_abs64(&r2, s) == (s < 0)); + CHECK(r2 == r); + } +} + +void run_context_tests(int use_prealloc) { + secp256k1_zkp_pubkey pubkey; + secp256k1_zkp_pubkey zero_pubkey; + secp256k1_zkp_ecdsa_signature sig; + unsigned char ctmp[32]; + int32_t ecount; + int32_t ecount2; + secp256k1_zkp_context *none; + secp256k1_zkp_context *sign; + secp256k1_zkp_context *vrfy; + secp256k1_zkp_context *both; + void *none_prealloc = NULL; + void *sign_prealloc = NULL; + void *vrfy_prealloc = NULL; + void *both_prealloc = NULL; + + secp256k1_zkp_gej pubj; + secp256k1_zkp_ge pub; + secp256k1_zkp_scalar msg, key, nonce; + secp256k1_zkp_scalar sigr, sigs; + + if (use_prealloc) { + none_prealloc = malloc(secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + sign_prealloc = malloc(secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); + vrfy_prealloc = malloc(secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); + both_prealloc = malloc(secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); + CHECK(none_prealloc != NULL); + CHECK(sign_prealloc != NULL); + CHECK(vrfy_prealloc != NULL); + CHECK(both_prealloc != NULL); + none = secp256k1_zkp_context_preallocated_create(none_prealloc, SECP256K1_CONTEXT_NONE); + sign = secp256k1_zkp_context_preallocated_create(sign_prealloc, SECP256K1_CONTEXT_SIGN); + vrfy = secp256k1_zkp_context_preallocated_create(vrfy_prealloc, SECP256K1_CONTEXT_VERIFY); + both = secp256k1_zkp_context_preallocated_create(both_prealloc, SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + } else { + none = secp256k1_zkp_context_create(SECP256K1_CONTEXT_NONE); + sign = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN); + vrfy = secp256k1_zkp_context_create(SECP256K1_CONTEXT_VERIFY); + both = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + } + + memset(&zero_pubkey, 0, sizeof(zero_pubkey)); + + ecount = 0; + ecount2 = 10; + secp256k1_zkp_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_zkp_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2); + secp256k1_zkp_context_set_error_callback(sign, counting_illegal_callback_fn, NULL); + CHECK(vrfy->error_callback.fn != sign->error_callback.fn); + + /* check if sizes for cloning are consistent */ + CHECK(secp256k1_zkp_context_preallocated_clone_size(none) == secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_NONE)); + CHECK(secp256k1_zkp_context_preallocated_clone_size(sign) == secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); + CHECK(secp256k1_zkp_context_preallocated_clone_size(vrfy) == secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); + CHECK(secp256k1_zkp_context_preallocated_clone_size(both) == secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); + + /*** clone and destroy all of them to make sure cloning was complete ***/ + { + secp256k1_zkp_context *ctx_tmp; + + if (use_prealloc) { + /* clone into a non-preallocated context and then again into a new preallocated one. */ + ctx_tmp = none; none = secp256k1_zkp_context_clone(none); secp256k1_zkp_context_preallocated_destroy(ctx_tmp); + free(none_prealloc); none_prealloc = malloc(secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(none_prealloc != NULL); + ctx_tmp = none; none = secp256k1_zkp_context_preallocated_clone(none, none_prealloc); secp256k1_zkp_context_destroy(ctx_tmp); + + ctx_tmp = sign; sign = secp256k1_zkp_context_clone(sign); secp256k1_zkp_context_preallocated_destroy(ctx_tmp); + free(sign_prealloc); sign_prealloc = malloc(secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(sign_prealloc != NULL); + ctx_tmp = sign; sign = secp256k1_zkp_context_preallocated_clone(sign, sign_prealloc); secp256k1_zkp_context_destroy(ctx_tmp); + + ctx_tmp = vrfy; vrfy = secp256k1_zkp_context_clone(vrfy); secp256k1_zkp_context_preallocated_destroy(ctx_tmp); + free(vrfy_prealloc); vrfy_prealloc = malloc(secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(vrfy_prealloc != NULL); + ctx_tmp = vrfy; vrfy = secp256k1_zkp_context_preallocated_clone(vrfy, vrfy_prealloc); secp256k1_zkp_context_destroy(ctx_tmp); + + ctx_tmp = both; both = secp256k1_zkp_context_clone(both); secp256k1_zkp_context_preallocated_destroy(ctx_tmp); + free(both_prealloc); both_prealloc = malloc(secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(both_prealloc != NULL); + ctx_tmp = both; both = secp256k1_zkp_context_preallocated_clone(both, both_prealloc); secp256k1_zkp_context_destroy(ctx_tmp); + } else { + /* clone into a preallocated context and then again into a new non-preallocated one. */ + void *prealloc_tmp; + + prealloc_tmp = malloc(secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_NONE)); CHECK(prealloc_tmp != NULL); + ctx_tmp = none; none = secp256k1_zkp_context_preallocated_clone(none, prealloc_tmp); secp256k1_zkp_context_destroy(ctx_tmp); + ctx_tmp = none; none = secp256k1_zkp_context_clone(none); secp256k1_zkp_context_preallocated_destroy(ctx_tmp); + free(prealloc_tmp); + + prealloc_tmp = malloc(secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_SIGN)); CHECK(prealloc_tmp != NULL); + ctx_tmp = sign; sign = secp256k1_zkp_context_preallocated_clone(sign, prealloc_tmp); secp256k1_zkp_context_destroy(ctx_tmp); + ctx_tmp = sign; sign = secp256k1_zkp_context_clone(sign); secp256k1_zkp_context_preallocated_destroy(ctx_tmp); + free(prealloc_tmp); + + prealloc_tmp = malloc(secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL); + ctx_tmp = vrfy; vrfy = secp256k1_zkp_context_preallocated_clone(vrfy, prealloc_tmp); secp256k1_zkp_context_destroy(ctx_tmp); + ctx_tmp = vrfy; vrfy = secp256k1_zkp_context_clone(vrfy); secp256k1_zkp_context_preallocated_destroy(ctx_tmp); + free(prealloc_tmp); + + prealloc_tmp = malloc(secp256k1_zkp_context_preallocated_size(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)); CHECK(prealloc_tmp != NULL); + ctx_tmp = both; both = secp256k1_zkp_context_preallocated_clone(both, prealloc_tmp); secp256k1_zkp_context_destroy(ctx_tmp); + ctx_tmp = both; both = secp256k1_zkp_context_clone(both); secp256k1_zkp_context_preallocated_destroy(ctx_tmp); + free(prealloc_tmp); + } + } + + /* Verify that the error callback makes it across the clone. */ + CHECK(vrfy->error_callback.fn != sign->error_callback.fn); + /* And that it resets back to default. */ + secp256k1_zkp_context_set_error_callback(sign, NULL, NULL); + CHECK(vrfy->error_callback.fn == sign->error_callback.fn); + + /*** attempt to use them ***/ + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_zkp_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key); + secp256k1_zkp_ge_set_gej(&pub, &pubj); + + /* Verify context-type checking illegal-argument errors. */ + memset(ctmp, 1, 32); + CHECK(secp256k1_zkp_ec_pubkey_create(vrfy, &pubkey, ctmp) == 0); + CHECK(ecount == 1); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_create(sign, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ecdsa_sign(vrfy, &sig, ctmp, ctmp, NULL, NULL) == 0); + CHECK(ecount == 2); + VG_UNDEF(&sig, sizeof(sig)); + CHECK(secp256k1_zkp_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1); + VG_CHECK(&sig, sizeof(sig)); + CHECK(ecount2 == 10); + CHECK(secp256k1_zkp_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 0); + CHECK(ecount2 == 11); + CHECK(secp256k1_zkp_ecdsa_verify(vrfy, &sig, ctmp, &pubkey) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 0); + CHECK(ecount2 == 12); + CHECK(secp256k1_zkp_ec_pubkey_tweak_add(vrfy, &pubkey, ctmp) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0); + CHECK(ecount2 == 13); + CHECK(secp256k1_zkp_ec_pubkey_negate(vrfy, &pubkey) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ec_pubkey_negate(sign, &pubkey) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ec_pubkey_negate(sign, NULL) == 0); + CHECK(ecount2 == 14); + CHECK(secp256k1_zkp_ec_pubkey_negate(vrfy, &zero_pubkey) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_context_randomize(vrfy, ctmp) == 1); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_context_randomize(vrfy, NULL) == 1); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_context_randomize(sign, ctmp) == 1); + CHECK(ecount2 == 14); + CHECK(secp256k1_zkp_context_randomize(sign, NULL) == 1); + CHECK(ecount2 == 14); + secp256k1_zkp_context_set_illegal_callback(vrfy, NULL, NULL); + secp256k1_zkp_context_set_illegal_callback(sign, NULL, NULL); + + /* obtain a working nonce */ + do { + random_scalar_order_test(&nonce); + } while(!secp256k1_zkp_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + + /* try signing */ + CHECK(secp256k1_zkp_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_zkp_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + + /* try verifying */ + CHECK(secp256k1_zkp_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + + /* cleanup */ + if (use_prealloc) { + secp256k1_zkp_context_preallocated_destroy(none); + secp256k1_zkp_context_preallocated_destroy(sign); + secp256k1_zkp_context_preallocated_destroy(vrfy); + secp256k1_zkp_context_preallocated_destroy(both); + free(none_prealloc); + free(sign_prealloc); + free(vrfy_prealloc); + free(both_prealloc); + } else { + secp256k1_zkp_context_destroy(none); + secp256k1_zkp_context_destroy(sign); + secp256k1_zkp_context_destroy(vrfy); + secp256k1_zkp_context_destroy(both); + } + /* Defined as no-op. */ + secp256k1_zkp_context_destroy(NULL); + secp256k1_zkp_context_preallocated_destroy(NULL); + +} + +void run_scratch_tests(void) { + int32_t ecount = 0; + secp256k1_zkp_context *none = secp256k1_zkp_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_zkp_scratch_space *scratch; + + /* Test public API */ + secp256k1_zkp_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + + scratch = secp256k1_zkp_scratch_space_create(none, 1000); + CHECK(scratch != NULL); + CHECK(ecount == 0); + + /* Test internal API */ + CHECK(secp256k1_zkp_scratch_max_allocation(scratch, 0) == 1000); + CHECK(secp256k1_zkp_scratch_max_allocation(scratch, 1) < 1000); + + /* Allocating 500 bytes with no frame fails */ + CHECK(secp256k1_zkp_scratch_alloc(scratch, 500) == NULL); + CHECK(secp256k1_zkp_scratch_max_allocation(scratch, 0) == 1000); + + /* ...but pushing a new stack frame does affect the max allocation */ + CHECK(secp256k1_zkp_scratch_allocate_frame(scratch, 500, 1 == 1)); + CHECK(secp256k1_zkp_scratch_max_allocation(scratch, 1) < 500); /* 500 - ALIGNMENT */ + CHECK(secp256k1_zkp_scratch_alloc(scratch, 500) != NULL); + CHECK(secp256k1_zkp_scratch_alloc(scratch, 500) == NULL); + + CHECK(secp256k1_zkp_scratch_allocate_frame(scratch, 500, 1) == 0); + + /* ...and this effect is undone by popping the frame */ + secp256k1_zkp_scratch_deallocate_frame(scratch); + CHECK(secp256k1_zkp_scratch_max_allocation(scratch, 0) == 1000); + CHECK(secp256k1_zkp_scratch_alloc(scratch, 500) == NULL); + + /* cleanup */ + secp256k1_zkp_scratch_space_destroy(scratch); + secp256k1_zkp_context_destroy(none); +} + +/***** HASH TESTS *****/ + +void run_sha256_tests(void) { + static const char *inputs[8] = { + "", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "For this sample, this 63-byte string will be used as input data", + "This is exactly 64 bytes long, not counting the terminating byte" + }; + static const unsigned char outputs[8][32] = { + {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, + {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}, + {0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50}, + {0xf3, 0x0c, 0xeb, 0x2b, 0xb2, 0x82, 0x9e, 0x79, 0xe4, 0xca, 0x97, 0x53, 0xd3, 0x5a, 0x8e, 0xcc, 0x00, 0x26, 0x2d, 0x16, 0x4c, 0xc0, 0x77, 0x08, 0x02, 0x95, 0x38, 0x1c, 0xbd, 0x64, 0x3f, 0x0d}, + {0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30}, + {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}, + {0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42}, + {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8} + }; + int i; + for (i = 0; i < 8; i++) { + unsigned char out[32]; + secp256k1_zkp_sha256 hasher; + secp256k1_zkp_sha256_initialize(&hasher); + secp256k1_zkp_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + secp256k1_zkp_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + if (strlen(inputs[i]) > 0) { + int split = secp256k1_zkp_rand_int(strlen(inputs[i])); + secp256k1_zkp_sha256_initialize(&hasher); + secp256k1_zkp_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_zkp_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + secp256k1_zkp_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + } + } +} + +void run_hmac_sha256_tests(void) { + static const char *keys[6] = { + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + "\x4a\x65\x66\x65", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + }; + static const char *inputs[6] = { + "\x48\x69\x20\x54\x68\x65\x72\x65", + "\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f", + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", + "\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61\x72\x67\x65\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f\x63\x6b\x2d\x53\x69\x7a\x65\x20\x4b\x65\x79\x20\x2d\x20\x48\x61\x73\x68\x20\x4b\x65\x79\x20\x46\x69\x72\x73\x74", + "\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e" + }; + static const unsigned char outputs[6][32] = { + {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7}, + {0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43}, + {0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe}, + {0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b}, + {0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54}, + {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2} + }; + int i; + for (i = 0; i < 6; i++) { + secp256k1_zkp_hmac_sha256 hasher; + unsigned char out[32]; + secp256k1_zkp_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_zkp_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + secp256k1_zkp_hmac_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + if (strlen(inputs[i]) > 0) { + int split = secp256k1_zkp_rand_int(strlen(inputs[i])); + secp256k1_zkp_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_zkp_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_zkp_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + secp256k1_zkp_hmac_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + } + } +} + +void run_rfc6979_hmac_sha256_tests(void) { + static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0}; + static const unsigned char out1[3][32] = { + {0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb}, + {0x2b, 0xf0, 0xff, 0xf1, 0xd3, 0xc3, 0x78, 0xa2, 0x2d, 0xc5, 0xde, 0x1d, 0x85, 0x65, 0x22, 0x32, 0x5c, 0x65, 0xb5, 0x04, 0x49, 0x1a, 0x0c, 0xbd, 0x01, 0xcb, 0x8f, 0x3a, 0xa6, 0x7f, 0xfd, 0x4a}, + {0xf5, 0x28, 0xb4, 0x10, 0xcb, 0x54, 0x1f, 0x77, 0x00, 0x0d, 0x7a, 0xfb, 0x6c, 0x5b, 0x53, 0xc5, 0xc4, 0x71, 0xea, 0xb4, 0x3e, 0x46, 0x6d, 0x9a, 0xc5, 0x19, 0x0c, 0x39, 0xc8, 0x2f, 0xd8, 0x2e} + }; + + static const unsigned char key2[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; + static const unsigned char out2[3][32] = { + {0x9c, 0x23, 0x6c, 0x16, 0x5b, 0x82, 0xae, 0x0c, 0xd5, 0x90, 0x65, 0x9e, 0x10, 0x0b, 0x6b, 0xab, 0x30, 0x36, 0xe7, 0xba, 0x8b, 0x06, 0x74, 0x9b, 0xaf, 0x69, 0x81, 0xe1, 0x6f, 0x1a, 0x2b, 0x95}, + {0xdf, 0x47, 0x10, 0x61, 0x62, 0x5b, 0xc0, 0xea, 0x14, 0xb6, 0x82, 0xfe, 0xee, 0x2c, 0x9c, 0x02, 0xf2, 0x35, 0xda, 0x04, 0x20, 0x4c, 0x1d, 0x62, 0xa1, 0x53, 0x6c, 0x6e, 0x17, 0xae, 0xd7, 0xa9}, + {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} + }; + + secp256k1_zkp_rfc6979_hmac_sha256 rng; + unsigned char out[32]; + int i; + + secp256k1_zkp_rfc6979_hmac_sha256_initialize(&rng, key1, 64); + for (i = 0; i < 3; i++) { + secp256k1_zkp_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(memcmp(out, out1[i], 32) == 0); + } + secp256k1_zkp_rfc6979_hmac_sha256_finalize(&rng); + + secp256k1_zkp_rfc6979_hmac_sha256_initialize(&rng, key1, 65); + for (i = 0; i < 3; i++) { + secp256k1_zkp_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(memcmp(out, out1[i], 32) != 0); + } + secp256k1_zkp_rfc6979_hmac_sha256_finalize(&rng); + + secp256k1_zkp_rfc6979_hmac_sha256_initialize(&rng, key2, 64); + for (i = 0; i < 3; i++) { + secp256k1_zkp_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(memcmp(out, out2[i], 32) == 0); + } + secp256k1_zkp_rfc6979_hmac_sha256_finalize(&rng); +} + +/***** RANDOM TESTS *****/ + +void test_rand_bits(int rand32, int bits) { + /* (1-1/2^B)^rounds[B] < 1/10^9, so rounds is the number of iterations to + * get a false negative chance below once in a billion */ + static const unsigned int rounds[7] = {1, 30, 73, 156, 322, 653, 1316}; + /* We try multiplying the results with various odd numbers, which shouldn't + * influence the uniform distribution modulo a power of 2. */ + static const uint32_t mults[6] = {1, 3, 21, 289, 0x9999, 0x80402011}; + /* We only select up to 6 bits from the output to analyse */ + unsigned int usebits = bits > 6 ? 6 : bits; + unsigned int maxshift = bits - usebits; + /* For each of the maxshift+1 usebits-bit sequences inside a bits-bit + number, track all observed outcomes, one per bit in a uint64_t. */ + uint64_t x[6][27] = {{0}}; + unsigned int i, shift, m; + /* Multiply the output of all rand calls with the odd number m, which + should not change the uniformity of its distribution. */ + for (i = 0; i < rounds[usebits]; i++) { + uint32_t r = (rand32 ? secp256k1_zkp_rand32() : secp256k1_zkp_rand_bits(bits)); + CHECK((((uint64_t)r) >> bits) == 0); + for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { + uint32_t rm = r * mults[m]; + for (shift = 0; shift <= maxshift; shift++) { + x[m][shift] |= (((uint64_t)1) << ((rm >> shift) & ((1 << usebits) - 1))); + } + } + } + for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { + for (shift = 0; shift <= maxshift; shift++) { + /* Test that the lower usebits bits of x[shift] are 1 */ + CHECK(((~x[m][shift]) << (64 - (1 << usebits))) == 0); + } + } +} + +/* Subrange must be a whole divisor of range, and at most 64 */ +void test_rand_int(uint32_t range, uint32_t subrange) { + /* (1-1/subrange)^rounds < 1/10^9 */ + int rounds = (subrange * 2073) / 100; + int i; + uint64_t x = 0; + CHECK((range % subrange) == 0); + for (i = 0; i < rounds; i++) { + uint32_t r = secp256k1_zkp_rand_int(range); + CHECK(r < range); + r = r % subrange; + x |= (((uint64_t)1) << r); + } + /* Test that the lower subrange bits of x are 1. */ + CHECK(((~x) << (64 - subrange)) == 0); +} + +void run_rand_bits(void) { + size_t b; + test_rand_bits(1, 32); + for (b = 1; b <= 32; b++) { + test_rand_bits(0, b); + } +} + +void run_rand_int(void) { + static const uint32_t ms[] = {1, 3, 17, 1000, 13771, 999999, 33554432}; + static const uint32_t ss[] = {1, 3, 6, 9, 13, 31, 64}; + unsigned int m, s; + for (m = 0; m < sizeof(ms) / sizeof(ms[0]); m++) { + for (s = 0; s < sizeof(ss) / sizeof(ss[0]); s++) { + test_rand_int(ms[m] * ss[s], ss[s]); + } + } +} + +/***** NUM TESTS *****/ + +#ifndef USE_NUM_NONE +void random_num_negate(secp256k1_zkp_num *num) { + if (secp256k1_zkp_rand_bits(1)) { + secp256k1_zkp_num_negate(num); + } +} + +void random_num_order_test(secp256k1_zkp_num *num) { + secp256k1_zkp_scalar sc; + random_scalar_order_test(&sc); + secp256k1_zkp_scalar_get_num(num, &sc); +} + +void random_num_order(secp256k1_zkp_num *num) { + secp256k1_zkp_scalar sc; + random_scalar_order(&sc); + secp256k1_zkp_scalar_get_num(num, &sc); +} + +void test_num_negate(void) { + secp256k1_zkp_num n1; + secp256k1_zkp_num n2; + random_num_order_test(&n1); /* n1 = R */ + random_num_negate(&n1); + secp256k1_zkp_num_copy(&n2, &n1); /* n2 = R */ + secp256k1_zkp_num_sub(&n1, &n2, &n1); /* n1 = n2-n1 = 0 */ + CHECK(secp256k1_zkp_num_is_zero(&n1)); + secp256k1_zkp_num_copy(&n1, &n2); /* n1 = R */ + secp256k1_zkp_num_negate(&n1); /* n1 = -R */ + CHECK(!secp256k1_zkp_num_is_zero(&n1)); + secp256k1_zkp_num_add(&n1, &n2, &n1); /* n1 = n2+n1 = 0 */ + CHECK(secp256k1_zkp_num_is_zero(&n1)); + secp256k1_zkp_num_copy(&n1, &n2); /* n1 = R */ + secp256k1_zkp_num_negate(&n1); /* n1 = -R */ + CHECK(secp256k1_zkp_num_is_neg(&n1) != secp256k1_zkp_num_is_neg(&n2)); + secp256k1_zkp_num_negate(&n1); /* n1 = R */ + CHECK(secp256k1_zkp_num_eq(&n1, &n2)); +} + +void test_num_add_sub(void) { + int i; + secp256k1_zkp_scalar s; + secp256k1_zkp_num n1; + secp256k1_zkp_num n2; + secp256k1_zkp_num n1p2, n2p1, n1m2, n2m1; + random_num_order_test(&n1); /* n1 = R1 */ + if (secp256k1_zkp_rand_bits(1)) { + random_num_negate(&n1); + } + random_num_order_test(&n2); /* n2 = R2 */ + if (secp256k1_zkp_rand_bits(1)) { + random_num_negate(&n2); + } + secp256k1_zkp_num_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */ + secp256k1_zkp_num_add(&n2p1, &n2, &n1); /* n2p1 = R2 + R1 */ + secp256k1_zkp_num_sub(&n1m2, &n1, &n2); /* n1m2 = R1 - R2 */ + secp256k1_zkp_num_sub(&n2m1, &n2, &n1); /* n2m1 = R2 - R1 */ + CHECK(secp256k1_zkp_num_eq(&n1p2, &n2p1)); + CHECK(!secp256k1_zkp_num_eq(&n1p2, &n1m2)); + secp256k1_zkp_num_negate(&n2m1); /* n2m1 = -R2 + R1 */ + CHECK(secp256k1_zkp_num_eq(&n2m1, &n1m2)); + CHECK(!secp256k1_zkp_num_eq(&n2m1, &n1)); + secp256k1_zkp_num_add(&n2m1, &n2m1, &n2); /* n2m1 = -R2 + R1 + R2 = R1 */ + CHECK(secp256k1_zkp_num_eq(&n2m1, &n1)); + CHECK(!secp256k1_zkp_num_eq(&n2p1, &n1)); + secp256k1_zkp_num_sub(&n2p1, &n2p1, &n2); /* n2p1 = R2 + R1 - R2 = R1 */ + CHECK(secp256k1_zkp_num_eq(&n2p1, &n1)); + + /* check is_one */ + secp256k1_zkp_scalar_set_int(&s, 1); + secp256k1_zkp_scalar_get_num(&n1, &s); + CHECK(secp256k1_zkp_num_is_one(&n1)); + /* check that 2^n + 1 is never 1 */ + secp256k1_zkp_scalar_get_num(&n2, &s); + for (i = 0; i < 250; ++i) { + secp256k1_zkp_num_add(&n1, &n1, &n1); /* n1 *= 2 */ + secp256k1_zkp_num_add(&n1p2, &n1, &n2); /* n1p2 = n1 + 1 */ + CHECK(!secp256k1_zkp_num_is_one(&n1p2)); + } +} + +void test_num_mod(void) { + int i; + secp256k1_zkp_scalar s; + secp256k1_zkp_num order, n; + + /* check that 0 mod anything is 0 */ + random_scalar_order_test(&s); + secp256k1_zkp_scalar_get_num(&order, &s); + secp256k1_zkp_scalar_set_int(&s, 0); + secp256k1_zkp_scalar_get_num(&n, &s); + secp256k1_zkp_num_mod(&n, &order); + CHECK(secp256k1_zkp_num_is_zero(&n)); + + /* check that anything mod 1 is 0 */ + secp256k1_zkp_scalar_set_int(&s, 1); + secp256k1_zkp_scalar_get_num(&order, &s); + secp256k1_zkp_scalar_get_num(&n, &s); + secp256k1_zkp_num_mod(&n, &order); + CHECK(secp256k1_zkp_num_is_zero(&n)); + + /* check that increasing the number past 2^256 does not break this */ + random_scalar_order_test(&s); + secp256k1_zkp_scalar_get_num(&n, &s); + /* multiply by 2^8, which'll test this case with high probability */ + for (i = 0; i < 8; ++i) { + secp256k1_zkp_num_add(&n, &n, &n); + } + secp256k1_zkp_num_mod(&n, &order); + CHECK(secp256k1_zkp_num_is_zero(&n)); +} + +void test_num_jacobi(void) { + secp256k1_zkp_scalar sqr; + secp256k1_zkp_scalar small; + secp256k1_zkp_scalar five; /* five is not a quadratic residue */ + secp256k1_zkp_num order, n; + int i; + /* squares mod 5 are 1, 4 */ + const int jacobi5[10] = { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1 }; + + /* check some small values with 5 as the order */ + secp256k1_zkp_scalar_set_int(&five, 5); + secp256k1_zkp_scalar_get_num(&order, &five); + for (i = 0; i < 10; ++i) { + secp256k1_zkp_scalar_set_int(&small, i); + secp256k1_zkp_scalar_get_num(&n, &small); + CHECK(secp256k1_zkp_num_jacobi(&n, &order) == jacobi5[i]); + } + + /** test large values with 5 as group order */ + secp256k1_zkp_scalar_get_num(&order, &five); + /* we first need a scalar which is not a multiple of 5 */ + do { + secp256k1_zkp_num fiven; + random_scalar_order_test(&sqr); + secp256k1_zkp_scalar_get_num(&fiven, &five); + secp256k1_zkp_scalar_get_num(&n, &sqr); + secp256k1_zkp_num_mod(&n, &fiven); + } while (secp256k1_zkp_num_is_zero(&n)); + /* next force it to be a residue. 2 is a nonresidue mod 5 so we can + * just multiply by two, i.e. add the number to itself */ + if (secp256k1_zkp_num_jacobi(&n, &order) == -1) { + secp256k1_zkp_num_add(&n, &n, &n); + } + + /* test residue */ + CHECK(secp256k1_zkp_num_jacobi(&n, &order) == 1); + /* test nonresidue */ + secp256k1_zkp_num_add(&n, &n, &n); + CHECK(secp256k1_zkp_num_jacobi(&n, &order) == -1); + + /** test with secp group order as order */ + secp256k1_zkp_scalar_order_get_num(&order); + random_scalar_order_test(&sqr); + secp256k1_zkp_scalar_sqr(&sqr, &sqr); + /* test residue */ + secp256k1_zkp_scalar_get_num(&n, &sqr); + CHECK(secp256k1_zkp_num_jacobi(&n, &order) == 1); + /* test nonresidue */ + secp256k1_zkp_scalar_mul(&sqr, &sqr, &five); + secp256k1_zkp_scalar_get_num(&n, &sqr); + CHECK(secp256k1_zkp_num_jacobi(&n, &order) == -1); + /* test multiple of the order*/ + CHECK(secp256k1_zkp_num_jacobi(&order, &order) == 0); + + /* check one less than the order */ + secp256k1_zkp_scalar_set_int(&small, 1); + secp256k1_zkp_scalar_get_num(&n, &small); + secp256k1_zkp_num_sub(&n, &order, &n); + CHECK(secp256k1_zkp_num_jacobi(&n, &order) == 1); /* sage confirms this is 1 */ +} + +void run_num_smalltests(void) { + int i; + for (i = 0; i < 100*count; i++) { + test_num_negate(); + test_num_add_sub(); + test_num_mod(); + test_num_jacobi(); + } +} +#endif + +/***** SCALAR TESTS *****/ + +void scalar_test(void) { + secp256k1_zkp_scalar s; + secp256k1_zkp_scalar s1; + secp256k1_zkp_scalar s2; +#ifndef USE_NUM_NONE + secp256k1_zkp_num snum, s1num, s2num; + secp256k1_zkp_num order, half_order; +#endif + unsigned char c[32]; + + /* Set 's' to a random scalar, with value 'snum'. */ + random_scalar_order_test(&s); + + /* Set 's1' to a random scalar, with value 's1num'. */ + random_scalar_order_test(&s1); + + /* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */ + random_scalar_order_test(&s2); + secp256k1_zkp_scalar_get_b32(c, &s2); + +#ifndef USE_NUM_NONE + secp256k1_zkp_scalar_get_num(&snum, &s); + secp256k1_zkp_scalar_get_num(&s1num, &s1); + secp256k1_zkp_scalar_get_num(&s2num, &s2); + + secp256k1_zkp_scalar_order_get_num(&order); + half_order = order; + secp256k1_zkp_num_shift(&half_order, 1); +#endif + + { + int i; + /* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */ + secp256k1_zkp_scalar n; + secp256k1_zkp_scalar_set_int(&n, 0); + for (i = 0; i < 256; i += 4) { + secp256k1_zkp_scalar t; + int j; + secp256k1_zkp_scalar_set_int(&t, secp256k1_zkp_scalar_get_bits(&s, 256 - 4 - i, 4)); + for (j = 0; j < 4; j++) { + secp256k1_zkp_scalar_add(&n, &n, &n); + } + secp256k1_zkp_scalar_add(&n, &n, &t); + } + CHECK(secp256k1_zkp_scalar_eq(&n, &s)); + } + + { + /* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */ + secp256k1_zkp_scalar n; + int i = 0; + secp256k1_zkp_scalar_set_int(&n, 0); + while (i < 256) { + secp256k1_zkp_scalar t; + int j; + int now = secp256k1_zkp_rand_int(15) + 1; + if (now + i > 256) { + now = 256 - i; + } + secp256k1_zkp_scalar_set_int(&t, secp256k1_zkp_scalar_get_bits_var(&s, 256 - now - i, now)); + for (j = 0; j < now; j++) { + secp256k1_zkp_scalar_add(&n, &n, &n); + } + secp256k1_zkp_scalar_add(&n, &n, &t); + i += now; + } + CHECK(secp256k1_zkp_scalar_eq(&n, &s)); + } + +#ifndef USE_NUM_NONE + { + /* Test that adding the scalars together is equal to adding their numbers together modulo the order. */ + secp256k1_zkp_num rnum; + secp256k1_zkp_num r2num; + secp256k1_zkp_scalar r; + secp256k1_zkp_num_add(&rnum, &snum, &s2num); + secp256k1_zkp_num_mod(&rnum, &order); + secp256k1_zkp_scalar_add(&r, &s, &s2); + secp256k1_zkp_scalar_get_num(&r2num, &r); + CHECK(secp256k1_zkp_num_eq(&rnum, &r2num)); + } + + { + /* Test that multiplying the scalars is equal to multiplying their numbers modulo the order. */ + secp256k1_zkp_scalar r; + secp256k1_zkp_num r2num; + secp256k1_zkp_num rnum; + secp256k1_zkp_num_mul(&rnum, &snum, &s2num); + secp256k1_zkp_num_mod(&rnum, &order); + secp256k1_zkp_scalar_mul(&r, &s, &s2); + secp256k1_zkp_scalar_get_num(&r2num, &r); + CHECK(secp256k1_zkp_num_eq(&rnum, &r2num)); + /* The result can only be zero if at least one of the factors was zero. */ + CHECK(secp256k1_zkp_scalar_is_zero(&r) == (secp256k1_zkp_scalar_is_zero(&s) || secp256k1_zkp_scalar_is_zero(&s2))); + /* The results can only be equal to one of the factors if that factor was zero, or the other factor was one. */ + CHECK(secp256k1_zkp_num_eq(&rnum, &snum) == (secp256k1_zkp_scalar_is_zero(&s) || secp256k1_zkp_scalar_is_one(&s2))); + CHECK(secp256k1_zkp_num_eq(&rnum, &s2num) == (secp256k1_zkp_scalar_is_zero(&s2) || secp256k1_zkp_scalar_is_one(&s))); + } + + { + secp256k1_zkp_scalar neg; + secp256k1_zkp_num negnum; + secp256k1_zkp_num negnum2; + /* Check that comparison with zero matches comparison with zero on the number. */ + CHECK(secp256k1_zkp_num_is_zero(&snum) == secp256k1_zkp_scalar_is_zero(&s)); + /* Check that comparison with the half order is equal to testing for high scalar. */ + CHECK(secp256k1_zkp_scalar_is_high(&s) == (secp256k1_zkp_num_cmp(&snum, &half_order) > 0)); + secp256k1_zkp_scalar_negate(&neg, &s); + secp256k1_zkp_num_sub(&negnum, &order, &snum); + secp256k1_zkp_num_mod(&negnum, &order); + /* Check that comparison with the half order is equal to testing for high scalar after negation. */ + CHECK(secp256k1_zkp_scalar_is_high(&neg) == (secp256k1_zkp_num_cmp(&negnum, &half_order) > 0)); + /* Negating should change the high property, unless the value was already zero. */ + CHECK((secp256k1_zkp_scalar_is_high(&s) == secp256k1_zkp_scalar_is_high(&neg)) == secp256k1_zkp_scalar_is_zero(&s)); + secp256k1_zkp_scalar_get_num(&negnum2, &neg); + /* Negating a scalar should be equal to (order - n) mod order on the number. */ + CHECK(secp256k1_zkp_num_eq(&negnum, &negnum2)); + secp256k1_zkp_scalar_add(&neg, &neg, &s); + /* Adding a number to its negation should result in zero. */ + CHECK(secp256k1_zkp_scalar_is_zero(&neg)); + secp256k1_zkp_scalar_negate(&neg, &neg); + /* Negating zero should still result in zero. */ + CHECK(secp256k1_zkp_scalar_is_zero(&neg)); + } + + { + /* Test secp256k1_zkp_scalar_mul_shift_var. */ + secp256k1_zkp_scalar r; + secp256k1_zkp_num one; + secp256k1_zkp_num rnum; + secp256k1_zkp_num rnum2; + unsigned char cone[1] = {0x01}; + unsigned int shift = 256 + secp256k1_zkp_rand_int(257); + secp256k1_zkp_scalar_mul_shift_var(&r, &s1, &s2, shift); + secp256k1_zkp_num_mul(&rnum, &s1num, &s2num); + secp256k1_zkp_num_shift(&rnum, shift - 1); + secp256k1_zkp_num_set_bin(&one, cone, 1); + secp256k1_zkp_num_add(&rnum, &rnum, &one); + secp256k1_zkp_num_shift(&rnum, 1); + secp256k1_zkp_scalar_get_num(&rnum2, &r); + CHECK(secp256k1_zkp_num_eq(&rnum, &rnum2)); + } + + { + /* test secp256k1_zkp_scalar_shr_int */ + secp256k1_zkp_scalar r; + int i; + random_scalar_order_test(&r); + for (i = 0; i < 100; ++i) { + int low; + int shift = 1 + secp256k1_zkp_rand_int(15); + int expected = r.d[0] % (1 << shift); + low = secp256k1_zkp_scalar_shr_int(&r, shift); + CHECK(expected == low); + } + } +#endif + + { + /* Test that scalar inverses are equal to the inverse of their number modulo the order. */ + if (!secp256k1_zkp_scalar_is_zero(&s)) { + secp256k1_zkp_scalar inv; +#ifndef USE_NUM_NONE + secp256k1_zkp_num invnum; + secp256k1_zkp_num invnum2; +#endif + secp256k1_zkp_scalar_inverse(&inv, &s); +#ifndef USE_NUM_NONE + secp256k1_zkp_num_mod_inverse(&invnum, &snum, &order); + secp256k1_zkp_scalar_get_num(&invnum2, &inv); + CHECK(secp256k1_zkp_num_eq(&invnum, &invnum2)); +#endif + secp256k1_zkp_scalar_mul(&inv, &inv, &s); + /* Multiplying a scalar with its inverse must result in one. */ + CHECK(secp256k1_zkp_scalar_is_one(&inv)); + secp256k1_zkp_scalar_inverse(&inv, &inv); + /* Inverting one must result in one. */ + CHECK(secp256k1_zkp_scalar_is_one(&inv)); +#ifndef USE_NUM_NONE + secp256k1_zkp_scalar_get_num(&invnum, &inv); + CHECK(secp256k1_zkp_num_is_one(&invnum)); +#endif + } + } + + { + /* Test commutativity of add. */ + secp256k1_zkp_scalar r1, r2; + secp256k1_zkp_scalar_add(&r1, &s1, &s2); + secp256k1_zkp_scalar_add(&r2, &s2, &s1); + CHECK(secp256k1_zkp_scalar_eq(&r1, &r2)); + } + + { + secp256k1_zkp_scalar r1, r2; + secp256k1_zkp_scalar b; + int i; + /* Test add_bit. */ + int bit = secp256k1_zkp_rand_bits(8); + secp256k1_zkp_scalar_set_int(&b, 1); + CHECK(secp256k1_zkp_scalar_is_one(&b)); + for (i = 0; i < bit; i++) { + secp256k1_zkp_scalar_add(&b, &b, &b); + } + r1 = s1; + r2 = s1; + if (!secp256k1_zkp_scalar_add(&r1, &r1, &b)) { + /* No overflow happened. */ + secp256k1_zkp_scalar_cadd_bit(&r2, bit, 1); + CHECK(secp256k1_zkp_scalar_eq(&r1, &r2)); + /* cadd is a noop when flag is zero */ + secp256k1_zkp_scalar_cadd_bit(&r2, bit, 0); + CHECK(secp256k1_zkp_scalar_eq(&r1, &r2)); + } + } + + { + /* Test commutativity of mul. */ + secp256k1_zkp_scalar r1, r2; + secp256k1_zkp_scalar_mul(&r1, &s1, &s2); + secp256k1_zkp_scalar_mul(&r2, &s2, &s1); + CHECK(secp256k1_zkp_scalar_eq(&r1, &r2)); + } + + { + /* Test associativity of add. */ + secp256k1_zkp_scalar r1, r2; + secp256k1_zkp_scalar_add(&r1, &s1, &s2); + secp256k1_zkp_scalar_add(&r1, &r1, &s); + secp256k1_zkp_scalar_add(&r2, &s2, &s); + secp256k1_zkp_scalar_add(&r2, &s1, &r2); + CHECK(secp256k1_zkp_scalar_eq(&r1, &r2)); + } + + { + /* Test associativity of mul. */ + secp256k1_zkp_scalar r1, r2; + secp256k1_zkp_scalar_mul(&r1, &s1, &s2); + secp256k1_zkp_scalar_mul(&r1, &r1, &s); + secp256k1_zkp_scalar_mul(&r2, &s2, &s); + secp256k1_zkp_scalar_mul(&r2, &s1, &r2); + CHECK(secp256k1_zkp_scalar_eq(&r1, &r2)); + } + + { + /* Test distributitivity of mul over add. */ + secp256k1_zkp_scalar r1, r2, t; + secp256k1_zkp_scalar_add(&r1, &s1, &s2); + secp256k1_zkp_scalar_mul(&r1, &r1, &s); + secp256k1_zkp_scalar_mul(&r2, &s1, &s); + secp256k1_zkp_scalar_mul(&t, &s2, &s); + secp256k1_zkp_scalar_add(&r2, &r2, &t); + CHECK(secp256k1_zkp_scalar_eq(&r1, &r2)); + } + + { + /* Test square. */ + secp256k1_zkp_scalar r1, r2; + secp256k1_zkp_scalar_sqr(&r1, &s1); + secp256k1_zkp_scalar_mul(&r2, &s1, &s1); + CHECK(secp256k1_zkp_scalar_eq(&r1, &r2)); + } + + { + /* Test multiplicative identity. */ + secp256k1_zkp_scalar r1, v1; + secp256k1_zkp_scalar_set_int(&v1,1); + secp256k1_zkp_scalar_mul(&r1, &s1, &v1); + CHECK(secp256k1_zkp_scalar_eq(&r1, &s1)); + } + + { + /* Test additive identity. */ + secp256k1_zkp_scalar r1, v0; + secp256k1_zkp_scalar_set_int(&v0,0); + secp256k1_zkp_scalar_add(&r1, &s1, &v0); + CHECK(secp256k1_zkp_scalar_eq(&r1, &s1)); + } + + { + /* Test zero product property. */ + secp256k1_zkp_scalar r1, v0; + secp256k1_zkp_scalar_set_int(&v0,0); + secp256k1_zkp_scalar_mul(&r1, &s1, &v0); + CHECK(secp256k1_zkp_scalar_eq(&r1, &v0)); + } + +} + +void scalar_chacha_tests(void) { + /* Test vectors 1 to 4 from https://tools.ietf.org/html/rfc8439#appendix-A + * Note that scalar_set_b32 and scalar_get_b32 represent integers + * underlying the scalar in big-endian format. */ + unsigned char expected1[64] = { + 0xad, 0xe0, 0xb8, 0x76, 0x90, 0x3d, 0xf1, 0xa0, + 0xe5, 0x6a, 0x5d, 0x40, 0x28, 0xbd, 0x86, 0x53, + 0xb8, 0x19, 0xd2, 0xbd, 0x1a, 0xed, 0x8d, 0xa0, + 0xcc, 0xef, 0x36, 0xa8, 0xc7, 0x0d, 0x77, 0x8b, + 0x7c, 0x59, 0x41, 0xda, 0x8d, 0x48, 0x57, 0x51, + 0x3f, 0xe0, 0x24, 0x77, 0x37, 0x4a, 0xd8, 0xb8, + 0xf4, 0xb8, 0x43, 0x6a, 0x1c, 0xa1, 0x18, 0x15, + 0x69, 0xb6, 0x87, 0xc3, 0x86, 0x65, 0xee, 0xb2 + }; + unsigned char expected2[64] = { + 0xbe, 0xe7, 0x07, 0x9f, 0x7a, 0x38, 0x51, 0x55, + 0x7c, 0x97, 0xba, 0x98, 0x0d, 0x08, 0x2d, 0x73, + 0xa0, 0x29, 0x0f, 0xcb, 0x69, 0x65, 0xe3, 0x48, + 0x3e, 0x53, 0xc6, 0x12, 0xed, 0x7a, 0xee, 0x32, + 0x76, 0x21, 0xb7, 0x29, 0x43, 0x4e, 0xe6, 0x9c, + 0xb0, 0x33, 0x71, 0xd5, 0xd5, 0x39, 0xd8, 0x74, + 0x28, 0x1f, 0xed, 0x31, 0x45, 0xfb, 0x0a, 0x51, + 0x1f, 0x0a, 0xe1, 0xac, 0x6f, 0x4d, 0x79, 0x4b + }; + unsigned char seed3[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; + unsigned char expected3[64] = { + 0x24, 0x52, 0xeb, 0x3a, 0x92, 0x49, 0xf8, 0xec, + 0x8d, 0x82, 0x9d, 0x9b, 0xdd, 0xd4, 0xce, 0xb1, + 0xe8, 0x25, 0x20, 0x83, 0x60, 0x81, 0x8b, 0x01, + 0xf3, 0x84, 0x22, 0xb8, 0x5a, 0xaa, 0x49, 0xc9, + 0xbb, 0x00, 0xca, 0x8e, 0xda, 0x3b, 0xa7, 0xb4, + 0xc4, 0xb5, 0x92, 0xd1, 0xfd, 0xf2, 0x73, 0x2f, + 0x44, 0x36, 0x27, 0x4e, 0x25, 0x61, 0xb3, 0xc8, + 0xeb, 0xdd, 0x4a, 0xa6, 0xa0, 0x13, 0x6c, 0x00 + }; + unsigned char seed4[32] = { + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + unsigned char expected4[64] = { + 0xfb, 0x4d, 0xd5, 0x72, 0x4b, 0xc4, 0x2e, 0xf1, + 0xdf, 0x92, 0x26, 0x36, 0x32, 0x7f, 0x13, 0x94, + 0xa7, 0x8d, 0xea, 0x8f, 0x5e, 0x26, 0x90, 0x39, + 0xa1, 0xbe, 0xbb, 0xc1, 0xca, 0xf0, 0x9a, 0xae, + 0xa2, 0x5a, 0xb2, 0x13, 0x48, 0xa6, 0xb4, 0x6c, + 0x1b, 0x9d, 0x9b, 0xcb, 0x09, 0x2c, 0x5b, 0xe6, + 0x54, 0x6c, 0xa6, 0x24, 0x1b, 0xec, 0x45, 0xd5, + 0x87, 0xf4, 0x74, 0x73, 0x96, 0xf0, 0x99, 0x2e + }; + unsigned char seed5[32] = { + 0x32, 0x56, 0x56, 0xf4, 0x29, 0x02, 0xc2, 0xf8, + 0xa3, 0x4b, 0x96, 0xf5, 0xa7, 0xf7, 0xe3, 0x6c, + 0x92, 0xad, 0xa5, 0x18, 0x1c, 0xe3, 0x41, 0xae, + 0xc3, 0xf3, 0x18, 0xd0, 0xfa, 0x5b, 0x72, 0x53 + }; + unsigned char expected5[64] = { + 0xe7, 0x56, 0xd3, 0x28, 0xe9, 0xc6, 0x19, 0x5c, + 0x6f, 0x17, 0x8e, 0x21, 0x8c, 0x1e, 0x72, 0x11, + 0xe7, 0xbd, 0x17, 0x0d, 0xac, 0x14, 0xad, 0xe9, + 0x3d, 0x9f, 0xb6, 0x92, 0xd6, 0x09, 0x20, 0xfb, + 0x43, 0x8e, 0x3b, 0x6d, 0xe3, 0x33, 0xdc, 0xc7, + 0x6c, 0x07, 0x6f, 0xbb, 0x1f, 0xb4, 0xc8, 0xb5, + 0xe3, 0x6c, 0xe5, 0x12, 0xd9, 0xd7, 0x64, 0x0c, + 0xf5, 0xa7, 0x0d, 0xab, 0x79, 0x03, 0xf1, 0x81 + }; + + secp256k1_zkp_scalar exp_r1, exp_r2; + secp256k1_zkp_scalar r1, r2; + unsigned char seed0[32] = { 0 }; + + secp256k1_zkp_scalar_chacha20(&r1, &r2, seed0, 0); + secp256k1_zkp_scalar_set_b32(&exp_r1, &expected1[0], NULL); + secp256k1_zkp_scalar_set_b32(&exp_r2, &expected1[32], NULL); + CHECK(secp256k1_zkp_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_zkp_scalar_eq(&exp_r2, &r2)); + + secp256k1_zkp_scalar_chacha20(&r1, &r2, seed0, 1); + secp256k1_zkp_scalar_set_b32(&exp_r1, &expected2[0], NULL); + secp256k1_zkp_scalar_set_b32(&exp_r2, &expected2[32], NULL); + CHECK(secp256k1_zkp_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_zkp_scalar_eq(&exp_r2, &r2)); + + secp256k1_zkp_scalar_chacha20(&r1, &r2, seed3, 1); + secp256k1_zkp_scalar_set_b32(&exp_r1, &expected3[0], NULL); + secp256k1_zkp_scalar_set_b32(&exp_r2, &expected3[32], NULL); + CHECK(secp256k1_zkp_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_zkp_scalar_eq(&exp_r2, &r2)); + + secp256k1_zkp_scalar_chacha20(&r1, &r2, seed4, 2); + secp256k1_zkp_scalar_set_b32(&exp_r1, &expected4[0], NULL); + secp256k1_zkp_scalar_set_b32(&exp_r2, &expected4[32], NULL); + CHECK(secp256k1_zkp_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_zkp_scalar_eq(&exp_r2, &r2)); + + secp256k1_zkp_scalar_chacha20(&r1, &r2, seed5, 0x6ff8602a7a78e2f2ULL); + secp256k1_zkp_scalar_set_b32(&exp_r1, &expected5[0], NULL); + secp256k1_zkp_scalar_set_b32(&exp_r2, &expected5[32], NULL); + CHECK(secp256k1_zkp_scalar_eq(&exp_r1, &r1)); + CHECK(secp256k1_zkp_scalar_eq(&exp_r2, &r2)); +} + +void run_scalar_tests(void) { + int i; + for (i = 0; i < 128 * count; i++) { + scalar_test(); + } + + scalar_chacha_tests(); + + { + /* (-1)+1 should be zero. */ + secp256k1_zkp_scalar s, o; + secp256k1_zkp_scalar_set_int(&s, 1); + CHECK(secp256k1_zkp_scalar_is_one(&s)); + secp256k1_zkp_scalar_negate(&o, &s); + secp256k1_zkp_scalar_add(&o, &o, &s); + CHECK(secp256k1_zkp_scalar_is_zero(&o)); + secp256k1_zkp_scalar_negate(&o, &o); + CHECK(secp256k1_zkp_scalar_is_zero(&o)); + } + +#ifndef USE_NUM_NONE + { + /* A scalar with value of the curve order should be 0. */ + secp256k1_zkp_num order; + secp256k1_zkp_scalar zero; + unsigned char bin[32]; + int overflow = 0; + secp256k1_zkp_scalar_order_get_num(&order); + secp256k1_zkp_num_get_bin(bin, 32, &order); + secp256k1_zkp_scalar_set_b32(&zero, bin, &overflow); + CHECK(overflow == 1); + CHECK(secp256k1_zkp_scalar_is_zero(&zero)); + } +#endif + + { + /* Does check_overflow check catch all ones? */ + static const secp256k1_zkp_scalar overflowed = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + CHECK(secp256k1_zkp_scalar_check_overflow(&overflowed)); + } + + { + /* Static test vectors. + * These were reduced from ~10^12 random vectors based on comparison-decision + * and edge-case coverage on 32-bit and 64-bit implementations. + * The responses were generated with Sage 5.9. + */ + secp256k1_zkp_scalar x; + secp256k1_zkp_scalar y; + secp256k1_zkp_scalar z; + secp256k1_zkp_scalar zz; + secp256k1_zkp_scalar one; + secp256k1_zkp_scalar r1; + secp256k1_zkp_scalar r2; +#if defined(USE_SCALAR_INV_NUM) + secp256k1_zkp_scalar zzv; +#endif + int overflow; + unsigned char chal[33][2][32] = { + {{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff}}, + {{0xef, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1e, 0xf8, 0xff, 0xff, 0xff, 0xfd, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xe0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, + 0xf3, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xfc, 0x9f, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x0f, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0xf8, 0xff, 0x0f, 0xc0, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x00, 0xf8, 0xff, 0x03, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0xc0, 0xff, 0x0f, 0xfc, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x8f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0x7f}, + {0xff, 0xcf, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, + 0xbf, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x01, 0xfc, 0xff, 0x01, 0x00, 0xfe, 0xff}, + {0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0xff, + 0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x3f, + 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x0f, 0x7e, 0x00, 0x00}}, + {{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x1f, 0x00, 0x00, 0xfe, 0x07, 0x00}, + {0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60}}, + {{0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, + 0x80, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0xff, 0xff, 0xcf, 0xff, 0x1f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00}, + {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x80, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x1f, 0x00, 0xfe}}, + {{0xff, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0x03, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xc0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff}}, + {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7e, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0xc0, 0xf1, 0x7f, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, + 0x00, 0x00, 0xfc, 0xff, 0xff, 0x01, 0xff, 0xff}}, + {{0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x03, 0xe0, 0x01, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xf0, 0x07, 0x00, 0x3c, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x07, 0xe0, 0xff, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x80, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0xff, 0x1f, + 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0xfe, 0xff}}, + {{0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, + 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, + 0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}}, + {{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}, + {0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}} + }; + unsigned char res[33][2][32] = { + {{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9, + 0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1, + 0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6, + 0x20, 0x1e, 0x86, 0xd0, 0x95, 0xf6, 0x92, 0x35}, + {0xdc, 0x90, 0x7a, 0x07, 0x2e, 0x1e, 0x44, 0x6d, + 0xf8, 0x15, 0x24, 0x5b, 0x5a, 0x96, 0x37, 0x9c, + 0x37, 0x7b, 0x0d, 0xac, 0x1b, 0x65, 0x58, 0x49, + 0x43, 0xb7, 0x31, 0xbb, 0xa7, 0xf4, 0x97, 0x15}}, + {{0xf1, 0xf7, 0x3a, 0x50, 0xe6, 0x10, 0xba, 0x22, + 0x43, 0x4d, 0x1f, 0x1f, 0x7c, 0x27, 0xca, 0x9c, + 0xb8, 0xb6, 0xa0, 0xfc, 0xd8, 0xc0, 0x05, 0x2f, + 0xf7, 0x08, 0xe1, 0x76, 0xdd, 0xd0, 0x80, 0xc8}, + {0xe3, 0x80, 0x80, 0xb8, 0xdb, 0xe3, 0xa9, 0x77, + 0x00, 0xb0, 0xf5, 0x2e, 0x27, 0xe2, 0x68, 0xc4, + 0x88, 0xe8, 0x04, 0xc1, 0x12, 0xbf, 0x78, 0x59, + 0xe6, 0xa9, 0x7c, 0xe1, 0x81, 0xdd, 0xb9, 0xd5}}, + {{0x96, 0xe2, 0xee, 0x01, 0xa6, 0x80, 0x31, 0xef, + 0x5c, 0xd0, 0x19, 0xb4, 0x7d, 0x5f, 0x79, 0xab, + 0xa1, 0x97, 0xd3, 0x7e, 0x33, 0xbb, 0x86, 0x55, + 0x60, 0x20, 0x10, 0x0d, 0x94, 0x2d, 0x11, 0x7c}, + {0xcc, 0xab, 0xe0, 0xe8, 0x98, 0x65, 0x12, 0x96, + 0x38, 0x5a, 0x1a, 0xf2, 0x85, 0x23, 0x59, 0x5f, + 0xf9, 0xf3, 0xc2, 0x81, 0x70, 0x92, 0x65, 0x12, + 0x9c, 0x65, 0x1e, 0x96, 0x00, 0xef, 0xe7, 0x63}}, + {{0xac, 0x1e, 0x62, 0xc2, 0x59, 0xfc, 0x4e, 0x5c, + 0x83, 0xb0, 0xd0, 0x6f, 0xce, 0x19, 0xf6, 0xbf, + 0xa4, 0xb0, 0xe0, 0x53, 0x66, 0x1f, 0xbf, 0xc9, + 0x33, 0x47, 0x37, 0xa9, 0x3d, 0x5d, 0xb0, 0x48}, + {0x86, 0xb9, 0x2a, 0x7f, 0x8e, 0xa8, 0x60, 0x42, + 0x26, 0x6d, 0x6e, 0x1c, 0xa2, 0xec, 0xe0, 0xe5, + 0x3e, 0x0a, 0x33, 0xbb, 0x61, 0x4c, 0x9f, 0x3c, + 0xd1, 0xdf, 0x49, 0x33, 0xcd, 0x72, 0x78, 0x18}}, + {{0xf7, 0xd3, 0xcd, 0x49, 0x5c, 0x13, 0x22, 0xfb, + 0x2e, 0xb2, 0x2f, 0x27, 0xf5, 0x8a, 0x5d, 0x74, + 0xc1, 0x58, 0xc5, 0xc2, 0x2d, 0x9f, 0x52, 0xc6, + 0x63, 0x9f, 0xba, 0x05, 0x76, 0x45, 0x7a, 0x63}, + {0x8a, 0xfa, 0x55, 0x4d, 0xdd, 0xa3, 0xb2, 0xc3, + 0x44, 0xfd, 0xec, 0x72, 0xde, 0xef, 0xc0, 0x99, + 0xf5, 0x9f, 0xe2, 0x52, 0xb4, 0x05, 0x32, 0x58, + 0x57, 0xc1, 0x8f, 0xea, 0xc3, 0x24, 0x5b, 0x94}}, + {{0x05, 0x83, 0xee, 0xdd, 0x64, 0xf0, 0x14, 0x3b, + 0xa0, 0x14, 0x4a, 0x3a, 0x41, 0x82, 0x7c, 0xa7, + 0x2c, 0xaa, 0xb1, 0x76, 0xbb, 0x59, 0x64, 0x5f, + 0x52, 0xad, 0x25, 0x29, 0x9d, 0x8f, 0x0b, 0xb0}, + {0x7e, 0xe3, 0x7c, 0xca, 0xcd, 0x4f, 0xb0, 0x6d, + 0x7a, 0xb2, 0x3e, 0xa0, 0x08, 0xb9, 0xa8, 0x2d, + 0xc2, 0xf4, 0x99, 0x66, 0xcc, 0xac, 0xd8, 0xb9, + 0x72, 0x2a, 0x4a, 0x3e, 0x0f, 0x7b, 0xbf, 0xf4}}, + {{0x8c, 0x9c, 0x78, 0x2b, 0x39, 0x61, 0x7e, 0xf7, + 0x65, 0x37, 0x66, 0x09, 0x38, 0xb9, 0x6f, 0x70, + 0x78, 0x87, 0xff, 0xcf, 0x93, 0xca, 0x85, 0x06, + 0x44, 0x84, 0xa7, 0xfe, 0xd3, 0xa4, 0xe3, 0x7e}, + {0xa2, 0x56, 0x49, 0x23, 0x54, 0xa5, 0x50, 0xe9, + 0x5f, 0xf0, 0x4d, 0xe7, 0xdc, 0x38, 0x32, 0x79, + 0x4f, 0x1c, 0xb7, 0xe4, 0xbb, 0xf8, 0xbb, 0x2e, + 0x40, 0x41, 0x4b, 0xcc, 0xe3, 0x1e, 0x16, 0x36}}, + {{0x0c, 0x1e, 0xd7, 0x09, 0x25, 0x40, 0x97, 0xcb, + 0x5c, 0x46, 0xa8, 0xda, 0xef, 0x25, 0xd5, 0xe5, + 0x92, 0x4d, 0xcf, 0xa3, 0xc4, 0x5d, 0x35, 0x4a, + 0xe4, 0x61, 0x92, 0xf3, 0xbf, 0x0e, 0xcd, 0xbe}, + {0xe4, 0xaf, 0x0a, 0xb3, 0x30, 0x8b, 0x9b, 0x48, + 0x49, 0x43, 0xc7, 0x64, 0x60, 0x4a, 0x2b, 0x9e, + 0x95, 0x5f, 0x56, 0xe8, 0x35, 0xdc, 0xeb, 0xdc, + 0xc7, 0xc4, 0xfe, 0x30, 0x40, 0xc7, 0xbf, 0xa4}}, + {{0xd4, 0xa0, 0xf5, 0x81, 0x49, 0x6b, 0xb6, 0x8b, + 0x0a, 0x69, 0xf9, 0xfe, 0xa8, 0x32, 0xe5, 0xe0, + 0xa5, 0xcd, 0x02, 0x53, 0xf9, 0x2c, 0xe3, 0x53, + 0x83, 0x36, 0xc6, 0x02, 0xb5, 0xeb, 0x64, 0xb8}, + {0x1d, 0x42, 0xb9, 0xf9, 0xe9, 0xe3, 0x93, 0x2c, + 0x4c, 0xee, 0x6c, 0x5a, 0x47, 0x9e, 0x62, 0x01, + 0x6b, 0x04, 0xfe, 0xa4, 0x30, 0x2b, 0x0d, 0x4f, + 0x71, 0x10, 0xd3, 0x55, 0xca, 0xf3, 0x5e, 0x80}}, + {{0x77, 0x05, 0xf6, 0x0c, 0x15, 0x9b, 0x45, 0xe7, + 0xb9, 0x11, 0xb8, 0xf5, 0xd6, 0xda, 0x73, 0x0c, + 0xda, 0x92, 0xea, 0xd0, 0x9d, 0xd0, 0x18, 0x92, + 0xce, 0x9a, 0xaa, 0xee, 0x0f, 0xef, 0xde, 0x30}, + {0xf1, 0xf1, 0xd6, 0x9b, 0x51, 0xd7, 0x77, 0x62, + 0x52, 0x10, 0xb8, 0x7a, 0x84, 0x9d, 0x15, 0x4e, + 0x07, 0xdc, 0x1e, 0x75, 0x0d, 0x0c, 0x3b, 0xdb, + 0x74, 0x58, 0x62, 0x02, 0x90, 0x54, 0x8b, 0x43}}, + {{0xa6, 0xfe, 0x0b, 0x87, 0x80, 0x43, 0x67, 0x25, + 0x57, 0x5d, 0xec, 0x40, 0x50, 0x08, 0xd5, 0x5d, + 0x43, 0xd7, 0xe0, 0xaa, 0xe0, 0x13, 0xb6, 0xb0, + 0xc0, 0xd4, 0xe5, 0x0d, 0x45, 0x83, 0xd6, 0x13}, + {0x40, 0x45, 0x0a, 0x92, 0x31, 0xea, 0x8c, 0x60, + 0x8c, 0x1f, 0xd8, 0x76, 0x45, 0xb9, 0x29, 0x00, + 0x26, 0x32, 0xd8, 0xa6, 0x96, 0x88, 0xe2, 0xc4, + 0x8b, 0xdb, 0x7f, 0x17, 0x87, 0xcc, 0xc8, 0xf2}}, + {{0xc2, 0x56, 0xe2, 0xb6, 0x1a, 0x81, 0xe7, 0x31, + 0x63, 0x2e, 0xbb, 0x0d, 0x2f, 0x81, 0x67, 0xd4, + 0x22, 0xe2, 0x38, 0x02, 0x25, 0x97, 0xc7, 0x88, + 0x6e, 0xdf, 0xbe, 0x2a, 0xa5, 0x73, 0x63, 0xaa}, + {0x50, 0x45, 0xe2, 0xc3, 0xbd, 0x89, 0xfc, 0x57, + 0xbd, 0x3c, 0xa3, 0x98, 0x7e, 0x7f, 0x36, 0x38, + 0x92, 0x39, 0x1f, 0x0f, 0x81, 0x1a, 0x06, 0x51, + 0x1f, 0x8d, 0x6a, 0xff, 0x47, 0x16, 0x06, 0x9c}}, + {{0x33, 0x95, 0xa2, 0x6f, 0x27, 0x5f, 0x9c, 0x9c, + 0x64, 0x45, 0xcb, 0xd1, 0x3c, 0xee, 0x5e, 0x5f, + 0x48, 0xa6, 0xaf, 0xe3, 0x79, 0xcf, 0xb1, 0xe2, + 0xbf, 0x55, 0x0e, 0xa2, 0x3b, 0x62, 0xf0, 0xe4}, + {0x14, 0xe8, 0x06, 0xe3, 0xbe, 0x7e, 0x67, 0x01, + 0xc5, 0x21, 0x67, 0xd8, 0x54, 0xb5, 0x7f, 0xa4, + 0xf9, 0x75, 0x70, 0x1c, 0xfd, 0x79, 0xdb, 0x86, + 0xad, 0x37, 0x85, 0x83, 0x56, 0x4e, 0xf0, 0xbf}}, + {{0xbc, 0xa6, 0xe0, 0x56, 0x4e, 0xef, 0xfa, 0xf5, + 0x1d, 0x5d, 0x3f, 0x2a, 0x5b, 0x19, 0xab, 0x51, + 0xc5, 0x8b, 0xdd, 0x98, 0x28, 0x35, 0x2f, 0xc3, + 0x81, 0x4f, 0x5c, 0xe5, 0x70, 0xb9, 0xeb, 0x62}, + {0xc4, 0x6d, 0x26, 0xb0, 0x17, 0x6b, 0xfe, 0x6c, + 0x12, 0xf8, 0xe7, 0xc1, 0xf5, 0x2f, 0xfa, 0x91, + 0x13, 0x27, 0xbd, 0x73, 0xcc, 0x33, 0x31, 0x1c, + 0x39, 0xe3, 0x27, 0x6a, 0x95, 0xcf, 0xc5, 0xfb}}, + {{0x30, 0xb2, 0x99, 0x84, 0xf0, 0x18, 0x2a, 0x6e, + 0x1e, 0x27, 0xed, 0xa2, 0x29, 0x99, 0x41, 0x56, + 0xe8, 0xd4, 0x0d, 0xef, 0x99, 0x9c, 0xf3, 0x58, + 0x29, 0x55, 0x1a, 0xc0, 0x68, 0xd6, 0x74, 0xa4}, + {0x07, 0x9c, 0xe7, 0xec, 0xf5, 0x36, 0x73, 0x41, + 0xa3, 0x1c, 0xe5, 0x93, 0x97, 0x6a, 0xfd, 0xf7, + 0x53, 0x18, 0xab, 0xaf, 0xeb, 0x85, 0xbd, 0x92, + 0x90, 0xab, 0x3c, 0xbf, 0x30, 0x82, 0xad, 0xf6}}, + {{0xc6, 0x87, 0x8a, 0x2a, 0xea, 0xc0, 0xa9, 0xec, + 0x6d, 0xd3, 0xdc, 0x32, 0x23, 0xce, 0x62, 0x19, + 0xa4, 0x7e, 0xa8, 0xdd, 0x1c, 0x33, 0xae, 0xd3, + 0x4f, 0x62, 0x9f, 0x52, 0xe7, 0x65, 0x46, 0xf4}, + {0x97, 0x51, 0x27, 0x67, 0x2d, 0xa2, 0x82, 0x87, + 0x98, 0xd3, 0xb6, 0x14, 0x7f, 0x51, 0xd3, 0x9a, + 0x0b, 0xd0, 0x76, 0x81, 0xb2, 0x4f, 0x58, 0x92, + 0xa4, 0x86, 0xa1, 0xa7, 0x09, 0x1d, 0xef, 0x9b}}, + {{0xb3, 0x0f, 0x2b, 0x69, 0x0d, 0x06, 0x90, 0x64, + 0xbd, 0x43, 0x4c, 0x10, 0xe8, 0x98, 0x1c, 0xa3, + 0xe1, 0x68, 0xe9, 0x79, 0x6c, 0x29, 0x51, 0x3f, + 0x41, 0xdc, 0xdf, 0x1f, 0xf3, 0x60, 0xbe, 0x33}, + {0xa1, 0x5f, 0xf7, 0x1d, 0xb4, 0x3e, 0x9b, 0x3c, + 0xe7, 0xbd, 0xb6, 0x06, 0xd5, 0x60, 0x06, 0x6d, + 0x50, 0xd2, 0xf4, 0x1a, 0x31, 0x08, 0xf2, 0xea, + 0x8e, 0xef, 0x5f, 0x7d, 0xb6, 0xd0, 0xc0, 0x27}}, + {{0x62, 0x9a, 0xd9, 0xbb, 0x38, 0x36, 0xce, 0xf7, + 0x5d, 0x2f, 0x13, 0xec, 0xc8, 0x2d, 0x02, 0x8a, + 0x2e, 0x72, 0xf0, 0xe5, 0x15, 0x9d, 0x72, 0xae, + 0xfc, 0xb3, 0x4f, 0x02, 0xea, 0xe1, 0x09, 0xfe}, + {0x00, 0x00, 0x00, 0x00, 0xfa, 0x0a, 0x3d, 0xbc, + 0xad, 0x16, 0x0c, 0xb6, 0xe7, 0x7c, 0x8b, 0x39, + 0x9a, 0x43, 0xbb, 0xe3, 0xc2, 0x55, 0x15, 0x14, + 0x75, 0xac, 0x90, 0x9b, 0x7f, 0x9a, 0x92, 0x00}}, + {{0x8b, 0xac, 0x70, 0x86, 0x29, 0x8f, 0x00, 0x23, + 0x7b, 0x45, 0x30, 0xaa, 0xb8, 0x4c, 0xc7, 0x8d, + 0x4e, 0x47, 0x85, 0xc6, 0x19, 0xe3, 0x96, 0xc2, + 0x9a, 0xa0, 0x12, 0xed, 0x6f, 0xd7, 0x76, 0x16}, + {0x45, 0xaf, 0x7e, 0x33, 0xc7, 0x7f, 0x10, 0x6c, + 0x7c, 0x9f, 0x29, 0xc1, 0xa8, 0x7e, 0x15, 0x84, + 0xe7, 0x7d, 0xc0, 0x6d, 0xab, 0x71, 0x5d, 0xd0, + 0x6b, 0x9f, 0x97, 0xab, 0xcb, 0x51, 0x0c, 0x9f}}, + {{0x9e, 0xc3, 0x92, 0xb4, 0x04, 0x9f, 0xc8, 0xbb, + 0xdd, 0x9e, 0xc6, 0x05, 0xfd, 0x65, 0xec, 0x94, + 0x7f, 0x2c, 0x16, 0xc4, 0x40, 0xac, 0x63, 0x7b, + 0x7d, 0xb8, 0x0c, 0xe4, 0x5b, 0xe3, 0xa7, 0x0e}, + {0x43, 0xf4, 0x44, 0xe8, 0xcc, 0xc8, 0xd4, 0x54, + 0x33, 0x37, 0x50, 0xf2, 0x87, 0x42, 0x2e, 0x00, + 0x49, 0x60, 0x62, 0x02, 0xfd, 0x1a, 0x7c, 0xdb, + 0x29, 0x6c, 0x6d, 0x54, 0x53, 0x08, 0xd1, 0xc8}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0x28, 0x56, 0xac, 0x0e, 0x4f, 0x98, 0x09, 0xf0, + 0x49, 0xfa, 0x7f, 0x84, 0xac, 0x7e, 0x50, 0x5b, + 0x17, 0x43, 0x14, 0x89, 0x9c, 0x53, 0xa8, 0x94, + 0x30, 0xf2, 0x11, 0x4d, 0x92, 0x14, 0x27, 0xe8}, + {0x39, 0x7a, 0x84, 0x56, 0x79, 0x9d, 0xec, 0x26, + 0x2c, 0x53, 0xc1, 0x94, 0xc9, 0x8d, 0x9e, 0x9d, + 0x32, 0x1f, 0xdd, 0x84, 0x04, 0xe8, 0xe2, 0x0a, + 0x6b, 0xbe, 0xbb, 0x42, 0x40, 0x67, 0x30, 0x6c}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x73, 0x2f, 0xc9, 0xbe, 0xbd}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, + {{0x1c, 0xc4, 0xf7, 0xda, 0x0f, 0x65, 0xca, 0x39, + 0x70, 0x52, 0x92, 0x8e, 0xc3, 0xc8, 0x15, 0xea, + 0x7f, 0x10, 0x9e, 0x77, 0x4b, 0x6e, 0x2d, 0xdf, + 0xe8, 0x30, 0x9d, 0xda, 0xe8, 0x9a, 0x65, 0xae}, + {0x02, 0xb0, 0x16, 0xb1, 0x1d, 0xc8, 0x57, 0x7b, + 0xa2, 0x3a, 0xa2, 0xa3, 0x38, 0x5c, 0x8f, 0xeb, + 0x66, 0x37, 0x91, 0xa8, 0x5f, 0xef, 0x04, 0xf6, + 0x59, 0x75, 0xe1, 0xee, 0x92, 0xf6, 0x0e, 0x30}}, + {{0x8d, 0x76, 0x14, 0xa4, 0x14, 0x06, 0x9f, 0x9a, + 0xdf, 0x4a, 0x85, 0xa7, 0x6b, 0xbf, 0x29, 0x6f, + 0xbc, 0x34, 0x87, 0x5d, 0xeb, 0xbb, 0x2e, 0xa9, + 0xc9, 0x1f, 0x58, 0xd6, 0x9a, 0x82, 0xa0, 0x56}, + {0xd4, 0xb9, 0xdb, 0x88, 0x1d, 0x04, 0xe9, 0x93, + 0x8d, 0x3f, 0x20, 0xd5, 0x86, 0xa8, 0x83, 0x07, + 0xdb, 0x09, 0xd8, 0x22, 0x1f, 0x7f, 0xf1, 0x71, + 0xc8, 0xe7, 0x5d, 0x47, 0xaf, 0x8b, 0x72, 0xe9}}, + {{0x83, 0xb9, 0x39, 0xb2, 0xa4, 0xdf, 0x46, 0x87, + 0xc2, 0xb8, 0xf1, 0xe6, 0x4c, 0xd1, 0xe2, 0xa9, + 0xe4, 0x70, 0x30, 0x34, 0xbc, 0x52, 0x7c, 0x55, + 0xa6, 0xec, 0x80, 0xa4, 0xe5, 0xd2, 0xdc, 0x73}, + {0x08, 0xf1, 0x03, 0xcf, 0x16, 0x73, 0xe8, 0x7d, + 0xb6, 0x7e, 0x9b, 0xc0, 0xb4, 0xc2, 0xa5, 0x86, + 0x02, 0x77, 0xd5, 0x27, 0x86, 0xa5, 0x15, 0xfb, + 0xae, 0x9b, 0x8c, 0xa9, 0xf9, 0xf8, 0xa8, 0x4a}}, + {{0x8b, 0x00, 0x49, 0xdb, 0xfa, 0xf0, 0x1b, 0xa2, + 0xed, 0x8a, 0x9a, 0x7a, 0x36, 0x78, 0x4a, 0xc7, + 0xf7, 0xad, 0x39, 0xd0, 0x6c, 0x65, 0x7a, 0x41, + 0xce, 0xd6, 0xd6, 0x4c, 0x20, 0x21, 0x6b, 0xc7}, + {0xc6, 0xca, 0x78, 0x1d, 0x32, 0x6c, 0x6c, 0x06, + 0x91, 0xf2, 0x1a, 0xe8, 0x43, 0x16, 0xea, 0x04, + 0x3c, 0x1f, 0x07, 0x85, 0xf7, 0x09, 0x22, 0x08, + 0xba, 0x13, 0xfd, 0x78, 0x1e, 0x3f, 0x6f, 0x62}}, + {{0x25, 0x9b, 0x7c, 0xb0, 0xac, 0x72, 0x6f, 0xb2, + 0xe3, 0x53, 0x84, 0x7a, 0x1a, 0x9a, 0x98, 0x9b, + 0x44, 0xd3, 0x59, 0xd0, 0x8e, 0x57, 0x41, 0x40, + 0x78, 0xa7, 0x30, 0x2f, 0x4c, 0x9c, 0xb9, 0x68}, + {0xb7, 0x75, 0x03, 0x63, 0x61, 0xc2, 0x48, 0x6e, + 0x12, 0x3d, 0xbf, 0x4b, 0x27, 0xdf, 0xb1, 0x7a, + 0xff, 0x4e, 0x31, 0x07, 0x83, 0xf4, 0x62, 0x5b, + 0x19, 0xa5, 0xac, 0xa0, 0x32, 0x58, 0x0d, 0xa7}}, + {{0x43, 0x4f, 0x10, 0xa4, 0xca, 0xdb, 0x38, 0x67, + 0xfa, 0xae, 0x96, 0xb5, 0x6d, 0x97, 0xff, 0x1f, + 0xb6, 0x83, 0x43, 0xd3, 0xa0, 0x2d, 0x70, 0x7a, + 0x64, 0x05, 0x4c, 0xa7, 0xc1, 0xa5, 0x21, 0x51}, + {0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2, + 0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38, + 0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34, + 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}}, + {{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}, + {0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}} + }; + secp256k1_zkp_scalar_set_int(&one, 1); + for (i = 0; i < 33; i++) { + secp256k1_zkp_scalar_set_b32(&x, chal[i][0], &overflow); + CHECK(!overflow); + secp256k1_zkp_scalar_set_b32(&y, chal[i][1], &overflow); + CHECK(!overflow); + secp256k1_zkp_scalar_set_b32(&r1, res[i][0], &overflow); + CHECK(!overflow); + secp256k1_zkp_scalar_set_b32(&r2, res[i][1], &overflow); + CHECK(!overflow); + secp256k1_zkp_scalar_mul(&z, &x, &y); + CHECK(!secp256k1_zkp_scalar_check_overflow(&z)); + CHECK(secp256k1_zkp_scalar_eq(&r1, &z)); + if (!secp256k1_zkp_scalar_is_zero(&y)) { + secp256k1_zkp_scalar_inverse(&zz, &y); + CHECK(!secp256k1_zkp_scalar_check_overflow(&zz)); +#if defined(USE_SCALAR_INV_NUM) + secp256k1_zkp_scalar_inverse_var(&zzv, &y); + CHECK(secp256k1_zkp_scalar_eq(&zzv, &zz)); +#endif + secp256k1_zkp_scalar_mul(&z, &z, &zz); + CHECK(!secp256k1_zkp_scalar_check_overflow(&z)); + CHECK(secp256k1_zkp_scalar_eq(&x, &z)); + secp256k1_zkp_scalar_mul(&zz, &zz, &y); + CHECK(!secp256k1_zkp_scalar_check_overflow(&zz)); + CHECK(secp256k1_zkp_scalar_eq(&one, &zz)); + } + secp256k1_zkp_scalar_mul(&z, &x, &x); + CHECK(!secp256k1_zkp_scalar_check_overflow(&z)); + secp256k1_zkp_scalar_sqr(&zz, &x); + CHECK(!secp256k1_zkp_scalar_check_overflow(&zz)); + CHECK(secp256k1_zkp_scalar_eq(&zz, &z)); + CHECK(secp256k1_zkp_scalar_eq(&r2, &zz)); + } + } +} + +/***** FIELD TESTS *****/ + +void random_fe(secp256k1_zkp_fe *x) { + unsigned char bin[32]; + do { + secp256k1_zkp_rand256(bin); + if (secp256k1_zkp_fe_set_b32(x, bin)) { + return; + } + } while(1); +} + +void random_fe_test(secp256k1_zkp_fe *x) { + unsigned char bin[32]; + do { + secp256k1_zkp_rand256_test(bin); + if (secp256k1_zkp_fe_set_b32(x, bin)) { + return; + } + } while(1); +} + +void random_fe_non_zero(secp256k1_zkp_fe *nz) { + int tries = 10; + while (--tries >= 0) { + random_fe(nz); + secp256k1_zkp_fe_normalize(nz); + if (!secp256k1_zkp_fe_is_zero(nz)) { + break; + } + } + /* Infinitesimal probability of spurious failure here */ + CHECK(tries >= 0); +} + +void random_fe_non_square(secp256k1_zkp_fe *ns) { + secp256k1_zkp_fe r; + random_fe_non_zero(ns); + if (secp256k1_zkp_fe_sqrt(&r, ns)) { + secp256k1_zkp_fe_negate(ns, ns, 1); + } +} + +int check_fe_equal(const secp256k1_zkp_fe *a, const secp256k1_zkp_fe *b) { + secp256k1_zkp_fe an = *a; + secp256k1_zkp_fe bn = *b; + secp256k1_zkp_fe_normalize_weak(&an); + secp256k1_zkp_fe_normalize_var(&bn); + return secp256k1_zkp_fe_equal_var(&an, &bn); +} + +int check_fe_inverse(const secp256k1_zkp_fe *a, const secp256k1_zkp_fe *ai) { + secp256k1_zkp_fe x; + secp256k1_zkp_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_zkp_fe_mul(&x, a, ai); + return check_fe_equal(&x, &one); +} + +void run_field_convert(void) { + static const unsigned char b32[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40 + }; + static const secp256k1_zkp_fe_storage fes = SECP256K1_FE_STORAGE_CONST( + 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, + 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL + ); + static const secp256k1_zkp_fe fe = SECP256K1_FE_CONST( + 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, + 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL + ); + secp256k1_zkp_fe fe2; + unsigned char b322[32]; + secp256k1_zkp_fe_storage fes2; + /* Check conversions to fe. */ + CHECK(secp256k1_zkp_fe_set_b32(&fe2, b32)); + CHECK(secp256k1_zkp_fe_equal_var(&fe, &fe2)); + secp256k1_zkp_fe_from_storage(&fe2, &fes); + CHECK(secp256k1_zkp_fe_equal_var(&fe, &fe2)); + /* Check conversion from fe. */ + secp256k1_zkp_fe_get_b32(b322, &fe); + CHECK(memcmp(b322, b32, 32) == 0); + secp256k1_zkp_fe_to_storage(&fes2, &fe); + CHECK(memcmp(&fes2, &fes, sizeof(fes)) == 0); +} + +int fe_memcmp(const secp256k1_zkp_fe *a, const secp256k1_zkp_fe *b) { + secp256k1_zkp_fe t = *b; +#ifdef VERIFY + t.magnitude = a->magnitude; + t.normalized = a->normalized; +#endif + return memcmp(a, &t, sizeof(secp256k1_zkp_fe)); +} + +void run_field_misc(void) { + secp256k1_zkp_fe x; + secp256k1_zkp_fe y; + secp256k1_zkp_fe z; + secp256k1_zkp_fe q; + secp256k1_zkp_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); + int i, j; + for (i = 0; i < 5*count; i++) { + secp256k1_zkp_fe_storage xs, ys, zs; + random_fe(&x); + random_fe_non_zero(&y); + /* Test the fe equality and comparison operations. */ + CHECK(secp256k1_zkp_fe_cmp_var(&x, &x) == 0); + CHECK(secp256k1_zkp_fe_equal_var(&x, &x)); + z = x; + secp256k1_zkp_fe_add(&z,&y); + /* Test fe conditional move; z is not normalized here. */ + q = x; + secp256k1_zkp_fe_cmov(&x, &z, 0); + VERIFY_CHECK(!x.normalized && x.magnitude == z.magnitude); + secp256k1_zkp_fe_cmov(&x, &x, 1); + CHECK(fe_memcmp(&x, &z) != 0); + CHECK(fe_memcmp(&x, &q) == 0); + secp256k1_zkp_fe_cmov(&q, &z, 1); + VERIFY_CHECK(!q.normalized && q.magnitude == z.magnitude); + CHECK(fe_memcmp(&q, &z) == 0); + secp256k1_zkp_fe_normalize_var(&x); + secp256k1_zkp_fe_normalize_var(&z); + CHECK(!secp256k1_zkp_fe_equal_var(&x, &z)); + secp256k1_zkp_fe_normalize_var(&q); + secp256k1_zkp_fe_cmov(&q, &z, (i&1)); + VERIFY_CHECK(q.normalized && q.magnitude == 1); + for (j = 0; j < 6; j++) { + secp256k1_zkp_fe_negate(&z, &z, j+1); + secp256k1_zkp_fe_normalize_var(&q); + secp256k1_zkp_fe_cmov(&q, &z, (j&1)); + VERIFY_CHECK(!q.normalized && q.magnitude == (j+2)); + } + secp256k1_zkp_fe_normalize_var(&z); + /* Test storage conversion and conditional moves. */ + secp256k1_zkp_fe_to_storage(&xs, &x); + secp256k1_zkp_fe_to_storage(&ys, &y); + secp256k1_zkp_fe_to_storage(&zs, &z); + secp256k1_zkp_fe_storage_cmov(&zs, &xs, 0); + secp256k1_zkp_fe_storage_cmov(&zs, &zs, 1); + CHECK(memcmp(&xs, &zs, sizeof(xs)) != 0); + secp256k1_zkp_fe_storage_cmov(&ys, &xs, 1); + CHECK(memcmp(&xs, &ys, sizeof(xs)) == 0); + secp256k1_zkp_fe_from_storage(&x, &xs); + secp256k1_zkp_fe_from_storage(&y, &ys); + secp256k1_zkp_fe_from_storage(&z, &zs); + /* Test that mul_int, mul, and add agree. */ + secp256k1_zkp_fe_add(&y, &x); + secp256k1_zkp_fe_add(&y, &x); + z = x; + secp256k1_zkp_fe_mul_int(&z, 3); + CHECK(check_fe_equal(&y, &z)); + secp256k1_zkp_fe_add(&y, &x); + secp256k1_zkp_fe_add(&z, &x); + CHECK(check_fe_equal(&z, &y)); + z = x; + secp256k1_zkp_fe_mul_int(&z, 5); + secp256k1_zkp_fe_mul(&q, &x, &fe5); + CHECK(check_fe_equal(&z, &q)); + secp256k1_zkp_fe_negate(&x, &x, 1); + secp256k1_zkp_fe_add(&z, &x); + secp256k1_zkp_fe_add(&q, &x); + CHECK(check_fe_equal(&y, &z)); + CHECK(check_fe_equal(&q, &y)); + } +} + +void run_field_inv(void) { + secp256k1_zkp_fe x, xi, xii; + int i; + for (i = 0; i < 10*count; i++) { + random_fe_non_zero(&x); + secp256k1_zkp_fe_inv(&xi, &x); + CHECK(check_fe_inverse(&x, &xi)); + secp256k1_zkp_fe_inv(&xii, &xi); + CHECK(check_fe_equal(&x, &xii)); + } +} + +void run_field_inv_var(void) { + secp256k1_zkp_fe x, xi, xii; + int i; + for (i = 0; i < 10*count; i++) { + random_fe_non_zero(&x); + secp256k1_zkp_fe_inv_var(&xi, &x); + CHECK(check_fe_inverse(&x, &xi)); + secp256k1_zkp_fe_inv_var(&xii, &xi); + CHECK(check_fe_equal(&x, &xii)); + } +} + +void run_field_inv_all_var(void) { + secp256k1_zkp_fe x[16], xi[16], xii[16]; + int i; + /* Check it's safe to call for 0 elements */ + secp256k1_zkp_fe_inv_all_var(xi, x, 0); + for (i = 0; i < count; i++) { + size_t j; + size_t len = secp256k1_zkp_rand_int(15) + 1; + for (j = 0; j < len; j++) { + random_fe_non_zero(&x[j]); + } + secp256k1_zkp_fe_inv_all_var(xi, x, len); + for (j = 0; j < len; j++) { + CHECK(check_fe_inverse(&x[j], &xi[j])); + } + secp256k1_zkp_fe_inv_all_var(xii, xi, len); + for (j = 0; j < len; j++) { + CHECK(check_fe_equal(&x[j], &xii[j])); + } + } +} + +void run_sqr(void) { + secp256k1_zkp_fe x, s; + + { + int i; + secp256k1_zkp_fe_set_int(&x, 1); + secp256k1_zkp_fe_negate(&x, &x, 1); + + for (i = 1; i <= 512; ++i) { + secp256k1_zkp_fe_mul_int(&x, 2); + secp256k1_zkp_fe_normalize(&x); + secp256k1_zkp_fe_sqr(&s, &x); + } + } +} + +void test_sqrt(const secp256k1_zkp_fe *a, const secp256k1_zkp_fe *k) { + secp256k1_zkp_fe r1, r2; + int v = secp256k1_zkp_fe_sqrt(&r1, a); + CHECK((v == 0) == (k == NULL)); + + if (k != NULL) { + /* Check that the returned root is +/- the given known answer */ + secp256k1_zkp_fe_negate(&r2, &r1, 1); + secp256k1_zkp_fe_add(&r1, k); secp256k1_zkp_fe_add(&r2, k); + secp256k1_zkp_fe_normalize(&r1); secp256k1_zkp_fe_normalize(&r2); + CHECK(secp256k1_zkp_fe_is_zero(&r1) || secp256k1_zkp_fe_is_zero(&r2)); + } +} + +void run_sqrt(void) { + secp256k1_zkp_fe ns, x, s, t; + int i; + + /* Check sqrt(0) is 0 */ + secp256k1_zkp_fe_set_int(&x, 0); + secp256k1_zkp_fe_sqr(&s, &x); + test_sqrt(&s, &x); + + /* Check sqrt of small squares (and their negatives) */ + for (i = 1; i <= 100; i++) { + secp256k1_zkp_fe_set_int(&x, i); + secp256k1_zkp_fe_sqr(&s, &x); + test_sqrt(&s, &x); + secp256k1_zkp_fe_negate(&t, &s, 1); + test_sqrt(&t, NULL); + } + + /* Consistency checks for large random values */ + for (i = 0; i < 10; i++) { + int j; + random_fe_non_square(&ns); + for (j = 0; j < count; j++) { + random_fe(&x); + secp256k1_zkp_fe_sqr(&s, &x); + test_sqrt(&s, &x); + secp256k1_zkp_fe_negate(&t, &s, 1); + test_sqrt(&t, NULL); + secp256k1_zkp_fe_mul(&t, &s, &ns); + test_sqrt(&t, NULL); + } + } +} + +/***** GROUP TESTS *****/ + +void ge_equals_ge(const secp256k1_zkp_ge *a, const secp256k1_zkp_ge *b) { + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + CHECK(secp256k1_zkp_fe_equal_var(&a->x, &b->x)); + CHECK(secp256k1_zkp_fe_equal_var(&a->y, &b->y)); +} + +/* This compares jacobian points including their Z, not just their geometric meaning. */ +int gej_xyz_equals_gej(const secp256k1_zkp_gej *a, const secp256k1_zkp_gej *b) { + secp256k1_zkp_gej a2; + secp256k1_zkp_gej b2; + int ret = 1; + ret &= a->infinity == b->infinity; + if (ret && !a->infinity) { + a2 = *a; + b2 = *b; + secp256k1_zkp_fe_normalize(&a2.x); + secp256k1_zkp_fe_normalize(&a2.y); + secp256k1_zkp_fe_normalize(&a2.z); + secp256k1_zkp_fe_normalize(&b2.x); + secp256k1_zkp_fe_normalize(&b2.y); + secp256k1_zkp_fe_normalize(&b2.z); + ret &= secp256k1_zkp_fe_cmp_var(&a2.x, &b2.x) == 0; + ret &= secp256k1_zkp_fe_cmp_var(&a2.y, &b2.y) == 0; + ret &= secp256k1_zkp_fe_cmp_var(&a2.z, &b2.z) == 0; + } + return ret; +} + +void ge_equals_gej(const secp256k1_zkp_ge *a, const secp256k1_zkp_gej *b) { + secp256k1_zkp_fe z2s; + secp256k1_zkp_fe u1, u2, s1, s2; + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ + secp256k1_zkp_fe_sqr(&z2s, &b->z); + secp256k1_zkp_fe_mul(&u1, &a->x, &z2s); + u2 = b->x; secp256k1_zkp_fe_normalize_weak(&u2); + secp256k1_zkp_fe_mul(&s1, &a->y, &z2s); secp256k1_zkp_fe_mul(&s1, &s1, &b->z); + s2 = b->y; secp256k1_zkp_fe_normalize_weak(&s2); + CHECK(secp256k1_zkp_fe_equal_var(&u1, &u2)); + CHECK(secp256k1_zkp_fe_equal_var(&s1, &s2)); +} + +void test_ge(void) { + int i, i1; +#ifdef USE_ENDOMORPHISM + int runs = 6; +#else + int runs = 4; +#endif + /* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4). + * The second in each pair of identical points uses a random Z coordinate in the Jacobian form. + * All magnitudes are randomized. + * All 17*17 combinations of points are added to each other, using all applicable methods. + * + * When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well. + */ + secp256k1_zkp_ge *ge = (secp256k1_zkp_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_zkp_ge) * (1 + 4 * runs)); + secp256k1_zkp_gej *gej = (secp256k1_zkp_gej *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_zkp_gej) * (1 + 4 * runs)); + secp256k1_zkp_fe *zinv = (secp256k1_zkp_fe *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_zkp_fe) * (1 + 4 * runs)); + secp256k1_zkp_fe zf; + secp256k1_zkp_fe zfi2, zfi3; + + secp256k1_zkp_gej_set_infinity(&gej[0]); + secp256k1_zkp_ge_clear(&ge[0]); + secp256k1_zkp_ge_set_gej_var(&ge[0], &gej[0]); + for (i = 0; i < runs; i++) { + int j; + secp256k1_zkp_ge g; + random_group_element_test(&g); +#ifdef USE_ENDOMORPHISM + if (i >= runs - 2) { + secp256k1_zkp_ge_mul_lambda(&g, &ge[1]); + } + if (i >= runs - 1) { + secp256k1_zkp_ge_mul_lambda(&g, &g); + } +#endif + ge[1 + 4 * i] = g; + ge[2 + 4 * i] = g; + secp256k1_zkp_ge_neg(&ge[3 + 4 * i], &g); + secp256k1_zkp_ge_neg(&ge[4 + 4 * i], &g); + secp256k1_zkp_gej_set_ge(&gej[1 + 4 * i], &ge[1 + 4 * i]); + random_group_element_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); + secp256k1_zkp_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]); + random_group_element_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); + for (j = 0; j < 4; j++) { + random_field_element_magnitude(&ge[1 + j + 4 * i].x); + random_field_element_magnitude(&ge[1 + j + 4 * i].y); + random_field_element_magnitude(&gej[1 + j + 4 * i].x); + random_field_element_magnitude(&gej[1 + j + 4 * i].y); + random_field_element_magnitude(&gej[1 + j + 4 * i].z); + } + } + + /* Compute z inverses. */ + { + secp256k1_zkp_fe *zs = checked_malloc(&ctx->error_callback, sizeof(secp256k1_zkp_fe) * (1 + 4 * runs)); + for (i = 0; i < 4 * runs + 1; i++) { + if (i == 0) { + /* The point at infinity does not have a meaningful z inverse. Any should do. */ + do { + random_field_element_test(&zs[i]); + } while(secp256k1_zkp_fe_is_zero(&zs[i])); + } else { + zs[i] = gej[i].z; + } + } + secp256k1_zkp_fe_inv_all_var(zinv, zs, 4 * runs + 1); + free(zs); + } + + /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */ + do { + random_field_element_test(&zf); + } while(secp256k1_zkp_fe_is_zero(&zf)); + random_field_element_magnitude(&zf); + secp256k1_zkp_fe_inv_var(&zfi3, &zf); + secp256k1_zkp_fe_sqr(&zfi2, &zfi3); + secp256k1_zkp_fe_mul(&zfi3, &zfi3, &zfi2); + + for (i1 = 0; i1 < 1 + 4 * runs; i1++) { + int i2; + for (i2 = 0; i2 < 1 + 4 * runs; i2++) { + /* Compute reference result using gej + gej (var). */ + secp256k1_zkp_gej refj, resj; + secp256k1_zkp_ge ref; + secp256k1_zkp_fe zr; + secp256k1_zkp_gej_add_var(&refj, &gej[i1], &gej[i2], secp256k1_zkp_gej_is_infinity(&gej[i1]) ? NULL : &zr); + /* Check Z ratio. */ + if (!secp256k1_zkp_gej_is_infinity(&gej[i1]) && !secp256k1_zkp_gej_is_infinity(&refj)) { + secp256k1_zkp_fe zrz; secp256k1_zkp_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(secp256k1_zkp_fe_equal_var(&zrz, &refj.z)); + } + secp256k1_zkp_ge_set_gej_var(&ref, &refj); + + /* Test gej + ge with Z ratio result (var). */ + secp256k1_zkp_gej_add_ge_var(&resj, &gej[i1], &ge[i2], secp256k1_zkp_gej_is_infinity(&gej[i1]) ? NULL : &zr); + ge_equals_gej(&ref, &resj); + if (!secp256k1_zkp_gej_is_infinity(&gej[i1]) && !secp256k1_zkp_gej_is_infinity(&resj)) { + secp256k1_zkp_fe zrz; secp256k1_zkp_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(secp256k1_zkp_fe_equal_var(&zrz, &resj.z)); + } + + /* Test gej + ge (var, with additional Z factor). */ + { + secp256k1_zkp_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */ + secp256k1_zkp_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2); + secp256k1_zkp_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3); + random_field_element_magnitude(&ge2_zfi.x); + random_field_element_magnitude(&ge2_zfi.y); + secp256k1_zkp_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf); + ge_equals_gej(&ref, &resj); + } + + /* Test gej + ge (const). */ + if (i2 != 0) { + /* secp256k1_zkp_gej_add_ge does not support its second argument being infinity. */ + secp256k1_zkp_gej_add_ge(&resj, &gej[i1], &ge[i2]); + ge_equals_gej(&ref, &resj); + } + + /* Test doubling (var). */ + if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) { + secp256k1_zkp_fe zr2; + /* Normal doubling with Z ratio result. */ + secp256k1_zkp_gej_double_var(&resj, &gej[i1], &zr2); + ge_equals_gej(&ref, &resj); + /* Check Z ratio. */ + secp256k1_zkp_fe_mul(&zr2, &zr2, &gej[i1].z); + CHECK(secp256k1_zkp_fe_equal_var(&zr2, &resj.z)); + /* Normal doubling. */ + secp256k1_zkp_gej_double_var(&resj, &gej[i2], NULL); + ge_equals_gej(&ref, &resj); + } + + /* Test adding opposites. */ + if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 != ((i2 + 3)%4)/2)) { + CHECK(secp256k1_zkp_ge_is_infinity(&ref)); + } + + /* Test adding infinity. */ + if (i1 == 0) { + CHECK(secp256k1_zkp_ge_is_infinity(&ge[i1])); + CHECK(secp256k1_zkp_gej_is_infinity(&gej[i1])); + ge_equals_gej(&ref, &gej[i2]); + } + if (i2 == 0) { + CHECK(secp256k1_zkp_ge_is_infinity(&ge[i2])); + CHECK(secp256k1_zkp_gej_is_infinity(&gej[i2])); + ge_equals_gej(&ref, &gej[i1]); + } + } + } + + /* Test adding all points together in random order equals infinity. */ + { + secp256k1_zkp_gej sum = SECP256K1_GEJ_CONST_INFINITY; + secp256k1_zkp_gej *gej_shuffled = (secp256k1_zkp_gej *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_zkp_gej)); + for (i = 0; i < 4 * runs + 1; i++) { + gej_shuffled[i] = gej[i]; + } + for (i = 0; i < 4 * runs + 1; i++) { + int swap = i + secp256k1_zkp_rand_int(4 * runs + 1 - i); + if (swap != i) { + secp256k1_zkp_gej t = gej_shuffled[i]; + gej_shuffled[i] = gej_shuffled[swap]; + gej_shuffled[swap] = t; + } + } + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_zkp_gej_add_var(&sum, &sum, &gej_shuffled[i], NULL); + } + CHECK(secp256k1_zkp_gej_is_infinity(&sum)); + free(gej_shuffled); + } + + /* Test batch gej -> ge conversion with and without known z ratios. */ + { + secp256k1_zkp_fe *zr = (secp256k1_zkp_fe *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_zkp_fe)); + secp256k1_zkp_ge *ge_set_all = (secp256k1_zkp_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_zkp_ge)); + for (i = 0; i < 4 * runs + 1; i++) { + /* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */ + if (i < 4 * runs) { + secp256k1_zkp_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z); + } + } + secp256k1_zkp_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1); + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_zkp_fe s; + random_fe_non_zero(&s); + secp256k1_zkp_gej_rescale(&gej[i], &s); + ge_equals_gej(&ge_set_all[i], &gej[i]); + } + free(ge_set_all); + free(zr); + } + + /* Test batch gej -> ge conversion with many infinities. */ + for (i = 0; i < 4 * runs + 1; i++) { + random_group_element_test(&ge[i]); + /* randomly set half the points to infinitiy */ + if(secp256k1_zkp_fe_is_odd(&ge[i].x)) { + secp256k1_zkp_ge_set_infinity(&ge[i]); + } + secp256k1_zkp_gej_set_ge(&gej[i], &ge[i]); + } + /* batch invert */ + secp256k1_zkp_ge_set_all_gej_var(ge, gej, 4 * runs + 1); + /* check result */ + for (i = 0; i < 4 * runs + 1; i++) { + ge_equals_gej(&ge[i], &gej[i]); + } + + free(ge); + free(gej); + free(zinv); +} + +void test_add_neg_y_diff_x(void) { + /* The point of this test is to check that we can add two points + * whose y-coordinates are negatives of each other but whose x + * coordinates differ. If the x-coordinates were the same, these + * points would be negatives of each other and their sum is + * infinity. This is cool because it "covers up" any degeneracy + * in the addition algorithm that would cause the xy coordinates + * of the sum to be wrong (since infinity has no xy coordinates). + * HOWEVER, if the x-coordinates are different, infinity is the + * wrong answer, and such degeneracies are exposed. This is the + * root of https://github.com/bitcoin-core/secp256k1/issues/257 + * which this test is a regression test for. + * + * These points were generated in sage as + * # secp256k1 params + * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) + * C = EllipticCurve ([F (0), F (7)]) + * G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) + * N = FiniteField(G.order()) + * + * # endomorphism values (lambda is 1^{1/3} in N, beta is 1^{1/3} in F) + * x = polygen(N) + * lam = (1 - x^3).roots()[1][0] + * + * # random "bad pair" + * P = C.random_element() + * Q = -int(lam) * P + * print " P: %x %x" % P.xy() + * print " Q: %x %x" % Q.xy() + * print "P + Q: %x %x" % (P + Q).xy() + */ + secp256k1_zkp_gej aj = SECP256K1_GEJ_CONST( + 0x8d24cd95, 0x0a355af1, 0x3c543505, 0x44238d30, + 0x0643d79f, 0x05a59614, 0x2f8ec030, 0xd58977cb, + 0x001e337a, 0x38093dcd, 0x6c0f386d, 0x0b1293a8, + 0x4d72c879, 0xd7681924, 0x44e6d2f3, 0x9190117d + ); + secp256k1_zkp_gej bj = SECP256K1_GEJ_CONST( + 0xc7b74206, 0x1f788cd9, 0xabd0937d, 0x164a0d86, + 0x95f6ff75, 0xf19a4ce9, 0xd013bd7b, 0xbf92d2a7, + 0xffe1cc85, 0xc7f6c232, 0x93f0c792, 0xf4ed6c57, + 0xb28d3786, 0x2897e6db, 0xbb192d0b, 0x6e6feab2 + ); + secp256k1_zkp_gej sumj = SECP256K1_GEJ_CONST( + 0x671a63c0, 0x3efdad4c, 0x389a7798, 0x24356027, + 0xb3d69010, 0x278625c3, 0x5c86d390, 0x184a8f7a, + 0x5f6409c2, 0x2ce01f2b, 0x511fd375, 0x25071d08, + 0xda651801, 0x70e95caf, 0x8f0d893c, 0xbed8fbbe + ); + secp256k1_zkp_ge b; + secp256k1_zkp_gej resj; + secp256k1_zkp_ge res; + secp256k1_zkp_ge_set_gej(&b, &bj); + + secp256k1_zkp_gej_add_var(&resj, &aj, &bj, NULL); + secp256k1_zkp_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); + + secp256k1_zkp_gej_add_ge(&resj, &aj, &b); + secp256k1_zkp_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); + + secp256k1_zkp_gej_add_ge_var(&resj, &aj, &b, NULL); + secp256k1_zkp_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); +} + +void run_ge(void) { + int i; + for (i = 0; i < count * 32; i++) { + test_ge(); + } + test_add_neg_y_diff_x(); +} + +void test_ec_combine(void) { + secp256k1_zkp_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_zkp_pubkey data[6]; + const secp256k1_zkp_pubkey* d[6]; + secp256k1_zkp_pubkey sd; + secp256k1_zkp_pubkey sd2; + secp256k1_zkp_gej Qj; + secp256k1_zkp_ge Q; + int i; + for (i = 1; i <= 6; i++) { + secp256k1_zkp_scalar s; + random_scalar_order_test(&s); + secp256k1_zkp_scalar_add(&sum, &sum, &s); + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &s); + secp256k1_zkp_ge_set_gej(&Q, &Qj); + secp256k1_zkp_pubkey_save(&data[i - 1], &Q); + d[i - 1] = &data[i - 1]; + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sum); + secp256k1_zkp_ge_set_gej(&Q, &Qj); + secp256k1_zkp_pubkey_save(&sd, &Q); + CHECK(secp256k1_zkp_ec_pubkey_combine(ctx, &sd2, d, i) == 1); + CHECK(memcmp(&sd, &sd2, sizeof(sd)) == 0); + } +} + +void run_ec_combine(void) { + int i; + for (i = 0; i < count * 8; i++) { + test_ec_combine(); + } +} + +void test_group_decompress(const secp256k1_zkp_fe* x) { + /* The input itself, normalized. */ + secp256k1_zkp_fe fex = *x; + secp256k1_zkp_fe fez; + /* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */ + secp256k1_zkp_ge ge_quad, ge_even, ge_odd; + secp256k1_zkp_gej gej_quad; + /* Return values of the above calls. */ + int res_quad, res_even, res_odd; + + secp256k1_zkp_fe_normalize_var(&fex); + + res_quad = secp256k1_zkp_ge_set_xquad(&ge_quad, &fex); + res_even = secp256k1_zkp_ge_set_xo_var(&ge_even, &fex, 0); + res_odd = secp256k1_zkp_ge_set_xo_var(&ge_odd, &fex, 1); + + CHECK(res_quad == res_even); + CHECK(res_quad == res_odd); + + if (res_quad) { + secp256k1_zkp_fe_normalize_var(&ge_quad.x); + secp256k1_zkp_fe_normalize_var(&ge_odd.x); + secp256k1_zkp_fe_normalize_var(&ge_even.x); + secp256k1_zkp_fe_normalize_var(&ge_quad.y); + secp256k1_zkp_fe_normalize_var(&ge_odd.y); + secp256k1_zkp_fe_normalize_var(&ge_even.y); + + /* No infinity allowed. */ + CHECK(!ge_quad.infinity); + CHECK(!ge_even.infinity); + CHECK(!ge_odd.infinity); + + /* Check that the x coordinates check out. */ + CHECK(secp256k1_zkp_fe_equal_var(&ge_quad.x, x)); + CHECK(secp256k1_zkp_fe_equal_var(&ge_even.x, x)); + CHECK(secp256k1_zkp_fe_equal_var(&ge_odd.x, x)); + + /* Check that the Y coordinate result in ge_quad is a square. */ + CHECK(secp256k1_zkp_fe_is_quad_var(&ge_quad.y)); + + /* Check odd/even Y in ge_odd, ge_even. */ + CHECK(secp256k1_zkp_fe_is_odd(&ge_odd.y)); + CHECK(!secp256k1_zkp_fe_is_odd(&ge_even.y)); + + /* Check secp256k1_zkp_gej_has_quad_y_var. */ + secp256k1_zkp_gej_set_ge(&gej_quad, &ge_quad); + CHECK(secp256k1_zkp_gej_has_quad_y_var(&gej_quad)); + do { + random_fe_test(&fez); + } while (secp256k1_zkp_fe_is_zero(&fez)); + secp256k1_zkp_gej_rescale(&gej_quad, &fez); + CHECK(secp256k1_zkp_gej_has_quad_y_var(&gej_quad)); + secp256k1_zkp_gej_neg(&gej_quad, &gej_quad); + CHECK(!secp256k1_zkp_gej_has_quad_y_var(&gej_quad)); + do { + random_fe_test(&fez); + } while (secp256k1_zkp_fe_is_zero(&fez)); + secp256k1_zkp_gej_rescale(&gej_quad, &fez); + CHECK(!secp256k1_zkp_gej_has_quad_y_var(&gej_quad)); + secp256k1_zkp_gej_neg(&gej_quad, &gej_quad); + CHECK(secp256k1_zkp_gej_has_quad_y_var(&gej_quad)); + } +} + +void run_group_decompress(void) { + int i; + for (i = 0; i < count * 4; i++) { + secp256k1_zkp_fe fe; + random_fe_test(&fe); + test_group_decompress(&fe); + } +} + +/***** ECMULT TESTS *****/ + +void run_ecmult_chain(void) { + /* random starting point A (on the curve) */ + secp256k1_zkp_gej a = SECP256K1_GEJ_CONST( + 0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3, + 0x727fd8bc, 0x04d3362c, 0x6c7bf458, 0xe2846004, + 0xa357ae91, 0x5c4a6528, 0x1309edf2, 0x0504740f, + 0x0eb33439, 0x90216b4f, 0x81063cb6, 0x5f2f7e0f + ); + /* two random initial factors xn and gn */ + secp256k1_zkp_scalar xn = SECP256K1_SCALAR_CONST( + 0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c, + 0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407 + ); + secp256k1_zkp_scalar gn = SECP256K1_SCALAR_CONST( + 0xa1e58d22, 0x553dcd42, 0xb2398062, 0x5d4c57a9, + 0x6e9323d4, 0x2b3152e5, 0xca2c3990, 0xedc7c9de + ); + /* two small multipliers to be applied to xn and gn in every iteration: */ + static const secp256k1_zkp_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); + static const secp256k1_zkp_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); + /* accumulators with the resulting coefficients to A and G */ + secp256k1_zkp_scalar ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_zkp_scalar ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + /* actual points */ + secp256k1_zkp_gej x; + secp256k1_zkp_gej x2; + int i; + + /* the point being computed */ + x = a; + for (i = 0; i < 200*count; i++) { + /* in each iteration, compute X = xn*X + gn*G; */ + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &x, &x, &xn, &gn); + /* also compute ae and ge: the actual accumulated factors for A and G */ + /* if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) */ + secp256k1_zkp_scalar_mul(&ae, &ae, &xn); + secp256k1_zkp_scalar_mul(&ge, &ge, &xn); + secp256k1_zkp_scalar_add(&ge, &ge, &gn); + /* modify xn and gn */ + secp256k1_zkp_scalar_mul(&xn, &xn, &xf); + secp256k1_zkp_scalar_mul(&gn, &gn, &gf); + + /* verify */ + if (i == 19999) { + /* expected result after 19999 iterations */ + secp256k1_zkp_gej rp = SECP256K1_GEJ_CONST( + 0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE, + 0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830, + 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D, + 0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88 + ); + + secp256k1_zkp_gej_neg(&rp, &rp); + secp256k1_zkp_gej_add_var(&rp, &rp, &x, NULL); + CHECK(secp256k1_zkp_gej_is_infinity(&rp)); + } + } + /* redo the computation, but directly with the resulting ae and ge coefficients: */ + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &x2, &a, &ae, &ge); + secp256k1_zkp_gej_neg(&x2, &x2); + secp256k1_zkp_gej_add_var(&x2, &x2, &x, NULL); + CHECK(secp256k1_zkp_gej_is_infinity(&x2)); +} + +void test_point_times_order(const secp256k1_zkp_gej *point) { + /* X * (point + G) + (order-X) * (pointer + G) = 0 */ + secp256k1_zkp_scalar x; + secp256k1_zkp_scalar nx; + secp256k1_zkp_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_zkp_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_zkp_gej res1, res2; + secp256k1_zkp_ge res3; + unsigned char pub[65]; + size_t psize = 65; + random_scalar_order_test(&x); + secp256k1_zkp_scalar_negate(&nx, &x); + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &res1, point, &x, &x); /* calc res1 = x * point + x * G; */ + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ + secp256k1_zkp_gej_add_var(&res1, &res1, &res2, NULL); + CHECK(secp256k1_zkp_gej_is_infinity(&res1)); + CHECK(secp256k1_zkp_gej_is_valid_var(&res1) == 0); + secp256k1_zkp_ge_set_gej(&res3, &res1); + CHECK(secp256k1_zkp_ge_is_infinity(&res3)); + CHECK(secp256k1_zkp_ge_is_valid_var(&res3) == 0); + CHECK(secp256k1_zkp_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0); + psize = 65; + CHECK(secp256k1_zkp_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); + /* check zero/one edge cases */ + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &zero); + secp256k1_zkp_ge_set_gej(&res3, &res1); + CHECK(secp256k1_zkp_ge_is_infinity(&res3)); + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &res1, point, &one, &zero); + secp256k1_zkp_ge_set_gej(&res3, &res1); + ge_equals_gej(&res3, point); + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &one); + secp256k1_zkp_ge_set_gej(&res3, &res1); + ge_equals_ge(&res3, &secp256k1_zkp_ge_const_g); +} + +void run_point_times_order(void) { + int i; + secp256k1_zkp_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); + static const secp256k1_zkp_fe xr = SECP256K1_FE_CONST( + 0x7603CB59, 0xB0EF6C63, 0xFE608479, 0x2A0C378C, + 0xDB3233A8, 0x0F8A9A09, 0xA877DEAD, 0x31B38C45 + ); + for (i = 0; i < 500; i++) { + secp256k1_zkp_ge p; + if (secp256k1_zkp_ge_set_xo_var(&p, &x, 1)) { + secp256k1_zkp_gej j; + CHECK(secp256k1_zkp_ge_is_valid_var(&p)); + secp256k1_zkp_gej_set_ge(&j, &p); + CHECK(secp256k1_zkp_gej_is_valid_var(&j)); + test_point_times_order(&j); + } + secp256k1_zkp_fe_sqr(&x, &x); + } + secp256k1_zkp_fe_normalize_var(&x); + CHECK(secp256k1_zkp_fe_equal_var(&x, &xr)); +} + +void ecmult_const_random_mult(void) { + /* random starting point A (on the curve) */ + secp256k1_zkp_ge a = SECP256K1_GE_CONST( + 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b, + 0xa97f9263, 0xb1e88044, 0x93351325, 0x91bc450a, + 0x535c59f7, 0x325e5d2b, 0xc391fbe8, 0x3c12787c, + 0x337e4a98, 0xe82a9011, 0x0123ba37, 0xdd769c7d + ); + /* random initial factor xn */ + secp256k1_zkp_scalar xn = SECP256K1_SCALAR_CONST( + 0x649d4f77, 0xc4242df7, 0x7f2079c9, 0x14530327, + 0xa31b876a, 0xd2d8ce2a, 0x2236d5c6, 0xd7b2029b + ); + /* expected xn * A (from sage) */ + secp256k1_zkp_ge expected_b = SECP256K1_GE_CONST( + 0x23773684, 0x4d209dc7, 0x098a786f, 0x20d06fcd, + 0x070a38bf, 0xc11ac651, 0x03004319, 0x1e2a8786, + 0xed8c3b8e, 0xc06dd57b, 0xd06ea66e, 0x45492b0f, + 0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956 + ); + secp256k1_zkp_gej b; + secp256k1_zkp_ecmult_const(&b, &a, &xn, 256); + + CHECK(secp256k1_zkp_ge_is_valid_var(&a)); + ge_equals_gej(&expected_b, &b); +} + +void ecmult_const_commutativity(void) { + secp256k1_zkp_scalar a; + secp256k1_zkp_scalar b; + secp256k1_zkp_gej res1; + secp256k1_zkp_gej res2; + secp256k1_zkp_ge mid1; + secp256k1_zkp_ge mid2; + random_scalar_order_test(&a); + random_scalar_order_test(&b); + + secp256k1_zkp_ecmult_const(&res1, &secp256k1_zkp_ge_const_g, &a, 256); + secp256k1_zkp_ecmult_const(&res2, &secp256k1_zkp_ge_const_g, &b, 256); + secp256k1_zkp_ge_set_gej(&mid1, &res1); + secp256k1_zkp_ge_set_gej(&mid2, &res2); + secp256k1_zkp_ecmult_const(&res1, &mid1, &b, 256); + secp256k1_zkp_ecmult_const(&res2, &mid2, &a, 256); + secp256k1_zkp_ge_set_gej(&mid1, &res1); + secp256k1_zkp_ge_set_gej(&mid2, &res2); + ge_equals_ge(&mid1, &mid2); +} + +void ecmult_const_mult_zero_one(void) { + secp256k1_zkp_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_zkp_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_zkp_scalar negone; + secp256k1_zkp_gej res1; + secp256k1_zkp_ge res2; + secp256k1_zkp_ge point; + secp256k1_zkp_scalar_negate(&negone, &one); + + random_group_element_test(&point); + secp256k1_zkp_ecmult_const(&res1, &point, &zero, 3); + secp256k1_zkp_ge_set_gej(&res2, &res1); + CHECK(secp256k1_zkp_ge_is_infinity(&res2)); + secp256k1_zkp_ecmult_const(&res1, &point, &one, 2); + secp256k1_zkp_ge_set_gej(&res2, &res1); + ge_equals_ge(&res2, &point); + secp256k1_zkp_ecmult_const(&res1, &point, &negone, 256); + secp256k1_zkp_gej_neg(&res1, &res1); + secp256k1_zkp_ge_set_gej(&res2, &res1); + ge_equals_ge(&res2, &point); +} + +void ecmult_const_chain_multiply(void) { + /* Check known result (randomly generated test problem from sage) */ + const secp256k1_zkp_scalar scalar = SECP256K1_SCALAR_CONST( + 0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d, + 0xcd83d307, 0x827bed62, 0x05fad0ce, 0x18fae63b + ); + const secp256k1_zkp_gej expected_point = SECP256K1_GEJ_CONST( + 0x5494c15d, 0x32099706, 0xc2395f94, 0x348745fd, + 0x757ce30e, 0x4e8c90fb, 0xa2bad184, 0xf883c69f, + 0x5d195d20, 0xe191bf7f, 0x1be3e55f, 0x56a80196, + 0x6071ad01, 0xf1462f66, 0xc997fa94, 0xdb858435 + ); + secp256k1_zkp_gej point; + secp256k1_zkp_ge res; + int i; + + secp256k1_zkp_gej_set_ge(&point, &secp256k1_zkp_ge_const_g); + for (i = 0; i < 100; ++i) { + secp256k1_zkp_ge tmp; + secp256k1_zkp_ge_set_gej(&tmp, &point); + secp256k1_zkp_ecmult_const(&point, &tmp, &scalar, 256); + } + secp256k1_zkp_ge_set_gej(&res, &point); + ge_equals_gej(&res, &expected_point); +} + +void run_ecmult_const_tests(void) { + ecmult_const_mult_zero_one(); + ecmult_const_random_mult(); + ecmult_const_commutativity(); + ecmult_const_chain_multiply(); +} + +typedef struct { + secp256k1_zkp_scalar *sc; + secp256k1_zkp_ge *pt; +} ecmult_multi_data; + +static int ecmult_multi_callback(secp256k1_zkp_scalar *sc, secp256k1_zkp_ge *pt, size_t idx, void *cbdata) { + ecmult_multi_data *data = (ecmult_multi_data*) cbdata; + *sc = data->sc[idx]; + *pt = data->pt[idx]; + return 1; +} + +static int ecmult_multi_false_callback(secp256k1_zkp_scalar *sc, secp256k1_zkp_ge *pt, size_t idx, void *cbdata) { + (void)sc; + (void)pt; + (void)idx; + (void)cbdata; + return 0; +} + +void test_ecmult_multi(secp256k1_zkp_scratch *scratch, secp256k1_zkp_ecmult_multi_func ecmult_multi) { + int ncount; + secp256k1_zkp_scalar szero; + secp256k1_zkp_scalar sc[32]; + secp256k1_zkp_ge pt[32]; + secp256k1_zkp_gej r; + secp256k1_zkp_gej r2; + ecmult_multi_data data; + secp256k1_zkp_scratch *scratch_empty; + + data.sc = sc; + data.pt = pt; + secp256k1_zkp_scalar_set_int(&szero, 0); + + /* No points to multiply */ + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, NULL, ecmult_multi_callback, &data, 0)); + + /* Check 1- and 2-point multiplies against ecmult */ + for (ncount = 0; ncount < count; ncount++) { + secp256k1_zkp_ge ptg; + secp256k1_zkp_gej ptgj; + random_scalar_order(&sc[0]); + random_scalar_order(&sc[1]); + + random_group_element_test(&ptg); + secp256k1_zkp_gej_set_ge(&ptgj, &ptg); + pt[0] = ptg; + pt[1] = secp256k1_zkp_ge_const_g; + + /* only G scalar */ + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &szero, &sc[0]); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0)); + secp256k1_zkp_gej_neg(&r2, &r2); + secp256k1_zkp_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + + /* 1-point */ + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &szero); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 1)); + secp256k1_zkp_gej_neg(&r2, &r2); + secp256k1_zkp_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + + /* Try to multiply 1 point, but scratch space is empty */ + scratch_empty = secp256k1_zkp_scratch_create(&ctx->error_callback, 0); + CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1)); + secp256k1_zkp_scratch_destroy(scratch_empty); + + /* Try to multiply 1 point, but callback returns false */ + CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1)); + + /* 2-point */ + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 2)); + secp256k1_zkp_gej_neg(&r2, &r2); + secp256k1_zkp_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + + /* 2-point with G scalar */ + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1)); + secp256k1_zkp_gej_neg(&r2, &r2); + secp256k1_zkp_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + } + + /* Check infinite outputs of various forms */ + for (ncount = 0; ncount < count; ncount++) { + secp256k1_zkp_ge ptg; + size_t i, j; + size_t sizes[] = { 2, 10, 32 }; + + for (j = 0; j < 3; j++) { + for (i = 0; i < 32; i++) { + random_scalar_order(&sc[i]); + secp256k1_zkp_ge_set_infinity(&pt[i]); + } + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + } + + for (j = 0; j < 3; j++) { + for (i = 0; i < 32; i++) { + random_group_element_test(&ptg); + pt[i] = ptg; + secp256k1_zkp_scalar_set_int(&sc[i], 0); + } + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + } + + for (j = 0; j < 3; j++) { + random_group_element_test(&ptg); + for (i = 0; i < 16; i++) { + random_scalar_order(&sc[2*i]); + secp256k1_zkp_scalar_negate(&sc[2*i + 1], &sc[2*i]); + pt[2 * i] = ptg; + pt[2 * i + 1] = ptg; + } + + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + + random_scalar_order(&sc[0]); + for (i = 0; i < 16; i++) { + random_group_element_test(&ptg); + + sc[2*i] = sc[0]; + sc[2*i+1] = sc[0]; + pt[2 * i] = ptg; + secp256k1_zkp_ge_neg(&pt[2*i+1], &pt[2*i]); + } + + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j])); + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + } + + random_group_element_test(&ptg); + secp256k1_zkp_scalar_set_int(&sc[0], 0); + pt[0] = ptg; + for (i = 1; i < 32; i++) { + pt[i] = ptg; + + random_scalar_order(&sc[i]); + secp256k1_zkp_scalar_add(&sc[0], &sc[0], &sc[i]); + secp256k1_zkp_scalar_negate(&sc[i], &sc[i]); + } + + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 32)); + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + } + + /* Check random points, constant scalar */ + for (ncount = 0; ncount < count; ncount++) { + size_t i; + secp256k1_zkp_gej_set_infinity(&r); + + random_scalar_order(&sc[0]); + for (i = 0; i < 20; i++) { + secp256k1_zkp_ge ptg; + sc[i] = sc[0]; + random_group_element_test(&ptg); + pt[i] = ptg; + secp256k1_zkp_gej_add_ge_var(&r, &r, &pt[i], NULL); + } + + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &r2, &r, &sc[0], &szero); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); + secp256k1_zkp_gej_neg(&r2, &r2); + secp256k1_zkp_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + } + + /* Check random scalars, constant point */ + for (ncount = 0; ncount < count; ncount++) { + size_t i; + secp256k1_zkp_ge ptg; + secp256k1_zkp_gej p0j; + secp256k1_zkp_scalar rs; + secp256k1_zkp_scalar_set_int(&rs, 0); + + random_group_element_test(&ptg); + for (i = 0; i < 20; i++) { + random_scalar_order(&sc[i]); + pt[i] = ptg; + secp256k1_zkp_scalar_add(&rs, &rs, &sc[i]); + } + + secp256k1_zkp_gej_set_ge(&p0j, &pt[0]); + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &r2, &p0j, &rs, &szero); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); + secp256k1_zkp_gej_neg(&r2, &r2); + secp256k1_zkp_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + } + + /* Sanity check that zero scalars don't cause problems */ + for (ncount = 0; ncount < 20; ncount++) { + random_scalar_order(&sc[ncount]); + random_group_element_test(&pt[ncount]); + } + + secp256k1_zkp_scalar_clear(&sc[0]); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20)); + secp256k1_zkp_scalar_clear(&sc[1]); + secp256k1_zkp_scalar_clear(&sc[2]); + secp256k1_zkp_scalar_clear(&sc[3]); + secp256k1_zkp_scalar_clear(&sc[4]); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 6)); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 5)); + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + + /* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */ + { + const size_t TOP = 8; + size_t s0i, s1i; + size_t t0i, t1i; + secp256k1_zkp_ge ptg; + secp256k1_zkp_gej ptgj; + + random_group_element_test(&ptg); + secp256k1_zkp_gej_set_ge(&ptgj, &ptg); + + for(t0i = 0; t0i < TOP; t0i++) { + for(t1i = 0; t1i < TOP; t1i++) { + secp256k1_zkp_gej t0p, t1p; + secp256k1_zkp_scalar t0, t1; + + secp256k1_zkp_scalar_set_int(&t0, (t0i + 1) / 2); + secp256k1_zkp_scalar_cond_negate(&t0, t0i & 1); + secp256k1_zkp_scalar_set_int(&t1, (t1i + 1) / 2); + secp256k1_zkp_scalar_cond_negate(&t1, t1i & 1); + + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &t0p, &ptgj, &t0, &szero); + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &t1p, &ptgj, &t1, &szero); + + for(s0i = 0; s0i < TOP; s0i++) { + for(s1i = 0; s1i < TOP; s1i++) { + secp256k1_zkp_scalar tmp1, tmp2; + secp256k1_zkp_gej expected, actual; + + secp256k1_zkp_ge_set_gej(&pt[0], &t0p); + secp256k1_zkp_ge_set_gej(&pt[1], &t1p); + + secp256k1_zkp_scalar_set_int(&sc[0], (s0i + 1) / 2); + secp256k1_zkp_scalar_cond_negate(&sc[0], s0i & 1); + secp256k1_zkp_scalar_set_int(&sc[1], (s1i + 1) / 2); + secp256k1_zkp_scalar_cond_negate(&sc[1], s1i & 1); + + secp256k1_zkp_scalar_mul(&tmp1, &t0, &sc[0]); + secp256k1_zkp_scalar_mul(&tmp2, &t1, &sc[1]); + secp256k1_zkp_scalar_add(&tmp1, &tmp1, &tmp2); + + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &expected, &ptgj, &tmp1, &szero); + CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &actual, &szero, ecmult_multi_callback, &data, 2)); + secp256k1_zkp_gej_neg(&expected, &expected); + secp256k1_zkp_gej_add_var(&actual, &actual, &expected, NULL); + CHECK(secp256k1_zkp_gej_is_infinity(&actual)); + } + } + } + } + } +} + +void test_secp256k1_zkp_pippenger_bucket_window_inv(void) { + int i; + + CHECK(secp256k1_zkp_pippenger_bucket_window_inv(0) == 0); + for(i = 1; i <= PIPPENGER_MAX_BUCKET_WINDOW; i++) { +#ifdef USE_ENDOMORPHISM + /* Bucket_window of 8 is not used with endo */ + if (i == 8) { + continue; + } +#endif + CHECK(secp256k1_zkp_pippenger_bucket_window(secp256k1_zkp_pippenger_bucket_window_inv(i)) == i); + if (i != PIPPENGER_MAX_BUCKET_WINDOW) { + CHECK(secp256k1_zkp_pippenger_bucket_window(secp256k1_zkp_pippenger_bucket_window_inv(i)+1) > i); + } + } +} + +/** + * Probabilistically test the function returning the maximum number of possible points + * for a given scratch space. + */ +void test_ecmult_multi_pippenger_max_points(void) { + size_t scratch_size = secp256k1_zkp_rand_int(256); + size_t max_size = secp256k1_zkp_pippenger_scratch_size(secp256k1_zkp_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12); + secp256k1_zkp_scratch *scratch; + size_t n_points_supported; + int bucket_window = 0; + + for(; scratch_size < max_size; scratch_size+=256) { + scratch = secp256k1_zkp_scratch_create(&ctx->error_callback, scratch_size); + CHECK(scratch != NULL); + n_points_supported = secp256k1_zkp_pippenger_max_points(scratch); + if (n_points_supported == 0) { + secp256k1_zkp_scratch_destroy(scratch); + continue; + } + bucket_window = secp256k1_zkp_pippenger_bucket_window(n_points_supported); + CHECK(secp256k1_zkp_scratch_allocate_frame(scratch, secp256k1_zkp_pippenger_scratch_size(n_points_supported, bucket_window), PIPPENGER_SCRATCH_OBJECTS)); + secp256k1_zkp_scratch_deallocate_frame(scratch); + secp256k1_zkp_scratch_destroy(scratch); + } + CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW); +} + +/** + * Run secp256k1_zkp_ecmult_multi_var with num points and a scratch space restricted to + * 1 <= i <= num points. + */ +void test_ecmult_multi_batching(void) { + static const int n_points = 2*ECMULT_PIPPENGER_THRESHOLD; + secp256k1_zkp_scalar scG; + secp256k1_zkp_scalar szero; + secp256k1_zkp_scalar *sc = (secp256k1_zkp_scalar *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_zkp_scalar) * n_points); + secp256k1_zkp_ge *pt = (secp256k1_zkp_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_zkp_ge) * n_points); + secp256k1_zkp_gej r; + secp256k1_zkp_gej r2; + ecmult_multi_data data; + int i; + secp256k1_zkp_scratch *scratch; + + secp256k1_zkp_gej_set_infinity(&r2); + secp256k1_zkp_scalar_set_int(&szero, 0); + + /* Get random scalars and group elements and compute result */ + random_scalar_order(&scG); + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &r2, &r2, &szero, &scG); + for(i = 0; i < n_points; i++) { + secp256k1_zkp_ge ptg; + secp256k1_zkp_gej ptgj; + random_group_element_test(&ptg); + secp256k1_zkp_gej_set_ge(&ptgj, &ptg); + pt[i] = ptg; + random_scalar_order(&sc[i]); + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &ptgj, &ptgj, &sc[i], NULL); + secp256k1_zkp_gej_add_var(&r2, &r2, &ptgj, NULL); + } + data.sc = sc; + data.pt = pt; + + /* Test with empty scratch space */ + scratch = secp256k1_zkp_scratch_create(&ctx->error_callback, 0); + CHECK(!secp256k1_zkp_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1)); + secp256k1_zkp_scratch_destroy(scratch); + + /* Test with space for 1 point in pippenger. That's not enough because + * ecmult_multi selects strauss which requires more memory. */ + scratch = secp256k1_zkp_scratch_create(&ctx->error_callback, secp256k1_zkp_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); + CHECK(!secp256k1_zkp_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1)); + secp256k1_zkp_scratch_destroy(scratch); + + secp256k1_zkp_gej_neg(&r2, &r2); + for(i = 1; i <= n_points; i++) { + if (i > ECMULT_PIPPENGER_THRESHOLD) { + int bucket_window = secp256k1_zkp_pippenger_bucket_window(i); + size_t scratch_size = secp256k1_zkp_pippenger_scratch_size(i, bucket_window); + scratch = secp256k1_zkp_scratch_create(&ctx->error_callback, scratch_size + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT); + } else { + size_t scratch_size = secp256k1_zkp_strauss_scratch_size(i); + scratch = secp256k1_zkp_scratch_create(&ctx->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); + } + CHECK(secp256k1_zkp_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points)); + secp256k1_zkp_gej_add_var(&r, &r, &r2, NULL); + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + secp256k1_zkp_scratch_destroy(scratch); + } + free(sc); + free(pt); +} + +void run_ecmult_multi_tests(void) { + secp256k1_zkp_scratch *scratch; + + test_secp256k1_zkp_pippenger_bucket_window_inv(); + test_ecmult_multi_pippenger_max_points(); + scratch = secp256k1_zkp_scratch_create(&ctx->error_callback, 819200); + test_ecmult_multi(scratch, secp256k1_zkp_ecmult_multi_var); + test_ecmult_multi(NULL, secp256k1_zkp_ecmult_multi_var); + test_ecmult_multi(scratch, secp256k1_zkp_ecmult_pippenger_batch_single); + test_ecmult_multi(scratch, secp256k1_zkp_ecmult_strauss_batch_single); + secp256k1_zkp_scratch_destroy(scratch); + + /* Run test_ecmult_multi with space for exactly one point */ + scratch = secp256k1_zkp_scratch_create(&ctx->error_callback, secp256k1_zkp_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT); + test_ecmult_multi(scratch, secp256k1_zkp_ecmult_multi_var); + secp256k1_zkp_scratch_destroy(scratch); + + test_ecmult_multi_batching(); +} + +void test_wnaf(const secp256k1_zkp_scalar *number, int w) { + secp256k1_zkp_scalar x, two, t; + int wnaf[256]; + int zeroes = -1; + int i; + int bits; + secp256k1_zkp_scalar_set_int(&x, 0); + secp256k1_zkp_scalar_set_int(&two, 2); + bits = secp256k1_zkp_ecmult_wnaf(wnaf, 256, number, w); + CHECK(bits <= 256); + for (i = bits-1; i >= 0; i--) { + int v = wnaf[i]; + secp256k1_zkp_scalar_mul(&x, &x, &two); + if (v) { + CHECK(zeroes == -1 || zeroes >= w-1); /* check that distance between non-zero elements is at least w-1 */ + zeroes=0; + CHECK((v & 1) == 1); /* check non-zero elements are odd */ + CHECK(v <= (1 << (w-1)) - 1); /* check range below */ + CHECK(v >= -(1 << (w-1)) - 1); /* check range above */ + } else { + CHECK(zeroes != -1); /* check that no unnecessary zero padding exists */ + zeroes++; + } + if (v >= 0) { + secp256k1_zkp_scalar_set_int(&t, v); + } else { + secp256k1_zkp_scalar_set_int(&t, -v); + secp256k1_zkp_scalar_negate(&t, &t); + } + secp256k1_zkp_scalar_add(&x, &x, &t); + } + CHECK(secp256k1_zkp_scalar_eq(&x, number)); /* check that wnaf represents number */ +} + +void test_constant_wnaf_negate(const secp256k1_zkp_scalar *number) { + secp256k1_zkp_scalar neg1 = *number; + secp256k1_zkp_scalar neg2 = *number; + int sign1 = 1; + int sign2 = 1; + + if (!secp256k1_zkp_scalar_get_bits(&neg1, 0, 1)) { + secp256k1_zkp_scalar_negate(&neg1, &neg1); + sign1 = -1; + } + sign2 = secp256k1_zkp_scalar_cond_negate(&neg2, secp256k1_zkp_scalar_is_even(&neg2)); + CHECK(sign1 == sign2); + CHECK(secp256k1_zkp_scalar_eq(&neg1, &neg2)); +} + +void test_constant_wnaf(const secp256k1_zkp_scalar *number, int w) { + secp256k1_zkp_scalar x, shift; + int wnaf[256] = {0}; + int i; + int skew; + int bits = 256; + secp256k1_zkp_scalar num = *number; + + secp256k1_zkp_scalar_set_int(&x, 0); + secp256k1_zkp_scalar_set_int(&shift, 1 << w); + /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */ +#ifdef USE_ENDOMORPHISM + for (i = 0; i < 16; ++i) { + secp256k1_zkp_scalar_shr_int(&num, 8); + } + bits = 128; +#endif + skew = secp256k1_zkp_wnaf_const(wnaf, num, w, bits); + + for (i = WNAF_SIZE_BITS(bits, w); i >= 0; --i) { + secp256k1_zkp_scalar t; + int v = wnaf[i]; + CHECK(v != 0); /* check nonzero */ + CHECK(v & 1); /* check parity */ + CHECK(v > -(1 << w)); /* check range above */ + CHECK(v < (1 << w)); /* check range below */ + + secp256k1_zkp_scalar_mul(&x, &x, &shift); + if (v >= 0) { + secp256k1_zkp_scalar_set_int(&t, v); + } else { + secp256k1_zkp_scalar_set_int(&t, -v); + secp256k1_zkp_scalar_negate(&t, &t); + } + secp256k1_zkp_scalar_add(&x, &x, &t); + } + /* Skew num because when encoding numbers as odd we use an offset */ + secp256k1_zkp_scalar_cadd_bit(&num, skew == 2, 1); + CHECK(secp256k1_zkp_scalar_eq(&x, &num)); +} + +void test_fixed_wnaf(const secp256k1_zkp_scalar *number, int w) { + secp256k1_zkp_scalar x, shift; + int wnaf[256] = {0}; + int i; + int skew; + secp256k1_zkp_scalar num = *number; + + secp256k1_zkp_scalar_set_int(&x, 0); + secp256k1_zkp_scalar_set_int(&shift, 1 << w); + /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */ +#ifdef USE_ENDOMORPHISM + for (i = 0; i < 16; ++i) { + secp256k1_zkp_scalar_shr_int(&num, 8); + } +#endif + skew = secp256k1_zkp_wnaf_fixed(wnaf, &num, w); + + for (i = WNAF_SIZE(w)-1; i >= 0; --i) { + secp256k1_zkp_scalar t; + int v = wnaf[i]; + CHECK(v == 0 || v & 1); /* check parity */ + CHECK(v > -(1 << w)); /* check range above */ + CHECK(v < (1 << w)); /* check range below */ + + secp256k1_zkp_scalar_mul(&x, &x, &shift); + if (v >= 0) { + secp256k1_zkp_scalar_set_int(&t, v); + } else { + secp256k1_zkp_scalar_set_int(&t, -v); + secp256k1_zkp_scalar_negate(&t, &t); + } + secp256k1_zkp_scalar_add(&x, &x, &t); + } + /* If skew is 1 then add 1 to num */ + secp256k1_zkp_scalar_cadd_bit(&num, 0, skew == 1); + CHECK(secp256k1_zkp_scalar_eq(&x, &num)); +} + +/* Checks that the first 8 elements of wnaf are equal to wnaf_expected and the + * rest is 0.*/ +void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) { + int i; + for (i = WNAF_SIZE(w)-1; i >= 8; --i) { + CHECK(wnaf[i] == 0); + } + for (i = 7; i >= 0; --i) { + CHECK(wnaf[i] == wnaf_expected[i]); + } +} + +void test_fixed_wnaf_small(void) { + int w = 4; + int wnaf[256] = {0}; + int i; + int skew; + secp256k1_zkp_scalar num; + + secp256k1_zkp_scalar_set_int(&num, 0); + skew = secp256k1_zkp_wnaf_fixed(wnaf, &num, w); + for (i = WNAF_SIZE(w)-1; i >= 0; --i) { + int v = wnaf[i]; + CHECK(v == 0); + } + CHECK(skew == 0); + + secp256k1_zkp_scalar_set_int(&num, 1); + skew = secp256k1_zkp_wnaf_fixed(wnaf, &num, w); + for (i = WNAF_SIZE(w)-1; i >= 1; --i) { + int v = wnaf[i]; + CHECK(v == 0); + } + CHECK(wnaf[0] == 1); + CHECK(skew == 0); + + { + int wnaf_expected[8] = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }; + secp256k1_zkp_scalar_set_int(&num, 0xffffffff); + skew = secp256k1_zkp_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 0); + } + { + int wnaf_expected[8] = { -1, -1, -1, -1, -1, -1, -1, 0xf }; + secp256k1_zkp_scalar_set_int(&num, 0xeeeeeeee); + skew = secp256k1_zkp_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 1); + } + { + int wnaf_expected[8] = { 1, 0, 1, 0, 1, 0, 1, 0 }; + secp256k1_zkp_scalar_set_int(&num, 0x01010101); + skew = secp256k1_zkp_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 0); + } + { + int wnaf_expected[8] = { -0xf, 0, 0xf, -0xf, 0, 0xf, 1, 0 }; + secp256k1_zkp_scalar_set_int(&num, 0x01ef1ef1); + skew = secp256k1_zkp_wnaf_fixed(wnaf, &num, w); + test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w); + CHECK(skew == 0); + } +} + +void run_wnaf(void) { + int i; + secp256k1_zkp_scalar n = {{0}}; + + /* Sanity check: 1 and 2 are the smallest odd and even numbers and should + * have easier-to-diagnose failure modes */ + n.d[0] = 1; + test_constant_wnaf(&n, 4); + n.d[0] = 2; + test_constant_wnaf(&n, 4); + /* Test 0 */ + test_fixed_wnaf_small(); + /* Random tests */ + for (i = 0; i < count; i++) { + random_scalar_order(&n); + test_wnaf(&n, 4+(i%10)); + test_constant_wnaf_negate(&n); + test_constant_wnaf(&n, 4 + (i % 10)); + test_fixed_wnaf(&n, 4 + (i % 10)); + } + secp256k1_zkp_scalar_set_int(&n, 0); + CHECK(secp256k1_zkp_scalar_cond_negate(&n, 1) == -1); + CHECK(secp256k1_zkp_scalar_is_zero(&n)); + CHECK(secp256k1_zkp_scalar_cond_negate(&n, 0) == 1); + CHECK(secp256k1_zkp_scalar_is_zero(&n)); +} + +void test_ecmult_constants(void) { + /* Test ecmult_gen() for [0..36) and [order-36..0). */ + secp256k1_zkp_scalar x; + secp256k1_zkp_gej r; + secp256k1_zkp_ge ng; + int i; + int j; + secp256k1_zkp_ge_neg(&ng, &secp256k1_zkp_ge_const_g); + for (i = 0; i < 36; i++ ) { + secp256k1_zkp_scalar_set_int(&x, i); + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x); + for (j = 0; j < i; j++) { + if (j == i - 1) { + ge_equals_gej(&secp256k1_zkp_ge_const_g, &r); + } + secp256k1_zkp_gej_add_ge(&r, &r, &ng); + } + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + } + for (i = 1; i <= 36; i++ ) { + secp256k1_zkp_scalar_set_int(&x, i); + secp256k1_zkp_scalar_negate(&x, &x); + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x); + for (j = 0; j < i; j++) { + if (j == i - 1) { + ge_equals_gej(&ng, &r); + } + secp256k1_zkp_gej_add_ge(&r, &r, &secp256k1_zkp_ge_const_g); + } + CHECK(secp256k1_zkp_gej_is_infinity(&r)); + } +} + +void run_ecmult_constants(void) { + test_ecmult_constants(); +} + +void test_ecmult_gen_blind(void) { + /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ + secp256k1_zkp_scalar key; + secp256k1_zkp_scalar b; + unsigned char seed32[32]; + secp256k1_zkp_gej pgej; + secp256k1_zkp_gej pgej2; + secp256k1_zkp_gej i; + secp256k1_zkp_ge pge; + random_scalar_order_test(&key); + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key); + secp256k1_zkp_rand256(seed32); + b = ctx->ecmult_gen_ctx.blind; + i = ctx->ecmult_gen_ctx.initial; + secp256k1_zkp_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + CHECK(!secp256k1_zkp_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej2, &key); + CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); + CHECK(!gej_xyz_equals_gej(&i, &ctx->ecmult_gen_ctx.initial)); + secp256k1_zkp_ge_set_gej(&pge, &pgej); + ge_equals_gej(&pge, &pgej2); +} + +void test_ecmult_gen_blind_reset(void) { + /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ + secp256k1_zkp_scalar b; + secp256k1_zkp_gej initial; + secp256k1_zkp_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); + b = ctx->ecmult_gen_ctx.blind; + initial = ctx->ecmult_gen_ctx.initial; + secp256k1_zkp_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); + CHECK(secp256k1_zkp_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); + CHECK(gej_xyz_equals_gej(&initial, &ctx->ecmult_gen_ctx.initial)); +} + +void run_ecmult_gen_blind(void) { + int i; + test_ecmult_gen_blind_reset(); + for (i = 0; i < 10; i++) { + test_ecmult_gen_blind(); + } +} + +#ifdef USE_ENDOMORPHISM +/***** ENDOMORPHISH TESTS *****/ +void test_scalar_split(void) { + secp256k1_zkp_scalar full; + secp256k1_zkp_scalar s1, slam; + const unsigned char zero[32] = {0}; + unsigned char tmp[32]; + + random_scalar_order_test(&full); + secp256k1_zkp_scalar_split_lambda(&s1, &slam, &full); + + /* check that both are <= 128 bits in size */ + if (secp256k1_zkp_scalar_is_high(&s1)) { + secp256k1_zkp_scalar_negate(&s1, &s1); + } + if (secp256k1_zkp_scalar_is_high(&slam)) { + secp256k1_zkp_scalar_negate(&slam, &slam); + } + + secp256k1_zkp_scalar_get_b32(tmp, &s1); + CHECK(memcmp(zero, tmp, 16) == 0); + secp256k1_zkp_scalar_get_b32(tmp, &slam); + CHECK(memcmp(zero, tmp, 16) == 0); +} + +void run_endomorphism_tests(void) { + test_scalar_split(); +} +#endif + +void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { + unsigned char pubkeyc[65]; + secp256k1_zkp_pubkey pubkey; + secp256k1_zkp_ge ge; + size_t pubkeyclen; + int32_t ecount; + ecount = 0; + secp256k1_zkp_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) { + /* Smaller sizes are tested exhaustively elsewhere. */ + int32_t i; + memcpy(&pubkeyc[1], input, 64); + VG_UNDEF(&pubkeyc[pubkeyclen], 65 - pubkeyclen); + for (i = 0; i < 256; i++) { + /* Try all type bytes. */ + int xpass; + int ypass; + int ysign; + pubkeyc[0] = i; + /* What sign does this point have? */ + ysign = (input[63] & 1) + 2; + /* For the current type (i) do we expect parsing to work? Handled all of compressed/uncompressed/hybrid. */ + xpass = xvalid && (pubkeyclen == 33) && ((i & 254) == 2); + /* Do we expect a parse and re-serialize as uncompressed to give a matching y? */ + ypass = xvalid && yvalid && ((i & 4) == ((pubkeyclen == 65) << 2)) && + ((i == 4) || ((i & 251) == ysign)) && ((pubkeyclen == 33) || (pubkeyclen == 65)); + if (xpass || ypass) { + /* These cases must parse. */ + unsigned char pubkeyo[65]; + size_t outl; + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + ecount = 0; + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + VG_UNDEF(pubkeyo, 65); + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + VG_CHECK(pubkeyo, outl); + CHECK(outl == 33); + CHECK(memcmp(&pubkeyo[1], &pubkeyc[1], 32) == 0); + CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0])); + if (ypass) { + /* This test isn't always done because we decode with alternative signs, so the y won't match. */ + CHECK(pubkeyo[0] == ysign); + CHECK(secp256k1_zkp_pubkey_load(ctx, &ge, &pubkey) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + secp256k1_zkp_pubkey_save(&pubkey, &ge); + VG_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + VG_UNDEF(pubkeyo, 65); + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + VG_CHECK(pubkeyo, outl); + CHECK(outl == 65); + CHECK(pubkeyo[0] == 4); + CHECK(memcmp(&pubkeyo[1], input, 64) == 0); + } + CHECK(ecount == 0); + } else { + /* These cases must fail to parse. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + } + } + secp256k1_zkp_context_set_illegal_callback(ctx, NULL, NULL); +} + +void run_ec_pubkey_parse_test(void) { +#define SECP256K1_EC_PARSE_TEST_NVALID (12) + const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = { + { + /* Point with leading and trailing zeros in x and y serialization. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x64, 0xef, 0xa1, 0x7b, 0x77, 0x61, 0xe1, 0xe4, 0x27, 0x06, 0x98, 0x9f, 0xb4, 0x83, + 0xb8, 0xd2, 0xd4, 0x9b, 0xf7, 0x8f, 0xae, 0x98, 0x03, 0xf0, 0x99, 0xb8, 0x34, 0xed, 0xeb, 0x00 + }, + { + /* Point with x equal to a 3rd root of unity.*/ + 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10, 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9, + 0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95, 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with largest x. (1/2) */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0x0e, 0x99, 0x4b, 0x14, 0xea, 0x72, 0xf8, 0xc3, 0xeb, 0x95, 0xc7, 0x1e, 0xf6, 0x92, 0x57, 0x5e, + 0x77, 0x50, 0x58, 0x33, 0x2d, 0x7e, 0x52, 0xd0, 0x99, 0x5c, 0xf8, 0x03, 0x88, 0x71, 0xb6, 0x7d, + }, + { + /* Point with largest x. (2/2) */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0xf1, 0x66, 0xb4, 0xeb, 0x15, 0x8d, 0x07, 0x3c, 0x14, 0x6a, 0x38, 0xe1, 0x09, 0x6d, 0xa8, 0xa1, + 0x88, 0xaf, 0xa7, 0xcc, 0xd2, 0x81, 0xad, 0x2f, 0x66, 0xa3, 0x07, 0xfb, 0x77, 0x8e, 0x45, 0xb2, + }, + { + /* Point with smallest x. (1/2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with smallest x. (2/2) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* Point with largest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with smallest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Point with smallest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Point with smallest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + } + }; +#define SECP256K1_EC_PARSE_TEST_NXVALID (4) + const unsigned char onlyxvalid[SECP256K1_EC_PARSE_TEST_NXVALID][64] = { + { + /* Valid if y overflow ignored (y = 1 mod p). (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (3/3)*/ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* x on curve, y is from y^2 = x^3 + 8. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 + } + }; +#define SECP256K1_EC_PARSE_TEST_NINVALID (7) + const unsigned char invalid[SECP256K1_EC_PARSE_TEST_NINVALID][64] = { + { + /* x is third root of -8, y is -1 * (x^3+7); also on the curve for y^2 = x^3 + 9. */ + 0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, + 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0xf4, 0x84, 0x14, 0x5c, 0xb0, 0x14, 0x9b, 0x82, 0x5d, 0xff, 0x41, 0x2f, 0xa0, 0x52, 0xa8, 0x3f, + 0xcb, 0x72, 0xdb, 0x61, 0xd5, 0x6f, 0x37, 0x70, 0xce, 0x06, 0x6b, 0x73, 0x49, 0xa2, 0xaa, 0x28, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0x0b, 0x7b, 0xeb, 0xa3, 0x4f, 0xeb, 0x64, 0x7d, 0xa2, 0x00, 0xbe, 0xd0, 0x5f, 0xad, 0x57, 0xc0, + 0x34, 0x8d, 0x24, 0x9e, 0x2a, 0x90, 0xc8, 0x8f, 0x31, 0xf9, 0x94, 0x8b, 0xb6, 0x5d, 0x52, 0x07, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8f, 0x53, 0x7e, 0xef, 0xdf, 0xc1, 0x60, 0x6a, 0x07, 0x27, 0xcd, 0x69, 0xb4, 0xa7, 0x33, 0x3d, + 0x38, 0xed, 0x44, 0xe3, 0x93, 0x2a, 0x71, 0x79, 0xee, 0xcb, 0x4b, 0x6f, 0xba, 0x93, 0x60, 0xdc, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0xac, 0x81, 0x10, 0x20, 0x3e, 0x9f, 0x95, 0xf8, 0xd8, 0x32, 0x96, 0x4b, 0x58, 0xcc, 0xc2, + 0xc7, 0x12, 0xbb, 0x1c, 0x6c, 0xd5, 0x8e, 0x86, 0x11, 0x34, 0xb4, 0x8f, 0x45, 0x6c, 0x9b, 0x53 + } + }; + const unsigned char pubkeyc[66] = { + /* Serialization of G. */ + 0x04, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, + 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, + 0x98, 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, + 0xA8, 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, + 0xB8, 0x00 + }; + unsigned char sout[65]; + unsigned char shortkey[2]; + secp256k1_zkp_ge ge; + secp256k1_zkp_pubkey pubkey; + size_t len; + int32_t i; + int32_t ecount; + int32_t ecount2; + ecount = 0; + /* Nothing should be reading this far into pubkeyc. */ + VG_UNDEF(&pubkeyc[65], 1); + secp256k1_zkp_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + /* Zero length claimed, fail, zeroize, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(shortkey, 2); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, shortkey, 0) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* Length one claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 256 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + shortkey[0] = i; + VG_UNDEF(&shortkey[1], 1); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, shortkey, 1) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + /* Length two claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 65536 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + shortkey[0] = i & 255; + shortkey[1] = i >> 8; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, shortkey, 2) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */ + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 33) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */ + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, NULL, pubkeyc, 65) == 0); + CHECK(ecount == 2); + /* NULL input string. Illegal arg and zeroize output. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, NULL, 65) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 2); + /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 64) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 66) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* Valid parse. */ + memset(&pubkey, 0, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1); + CHECK(secp256k1_zkp_ec_pubkey_parse(secp256k1_zkp_context_no_precomp, &pubkey, pubkeyc, 65) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + VG_UNDEF(&ge, sizeof(ge)); + CHECK(secp256k1_zkp_pubkey_load(ctx, &ge, &pubkey) == 1); + VG_CHECK(&ge.x, sizeof(ge.x)); + VG_CHECK(&ge.y, sizeof(ge.y)); + VG_CHECK(&ge.infinity, sizeof(ge.infinity)); + ge_equals_ge(&secp256k1_zkp_ge_const_g, &ge); + CHECK(ecount == 0); + /* secp256k1_zkp_ec_pubkey_serialize illegal args. */ + ecount = 0; + len = 65; + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); + CHECK(ecount == 1); + CHECK(len == 0); + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); + CHECK(ecount == 2); + len = 65; + VG_UNDEF(sout, 65); + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0); + VG_CHECK(sout, 65); + CHECK(ecount == 3); + CHECK(len == 0); + len = 65; + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, sout, &len, &pubkey, ~0) == 0); + CHECK(ecount == 4); + CHECK(len == 0); + len = 65; + VG_UNDEF(sout, 65); + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + VG_CHECK(sout, 65); + CHECK(ecount == 4); + CHECK(len == 65); + /* Multiple illegal args. Should still set arg error only once. */ + ecount = 0; + ecount2 = 11; + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); + CHECK(ecount == 1); + /* Does the illegal arg callback actually change the behavior? */ + secp256k1_zkp_context_set_illegal_callback(ctx, uncounting_illegal_callback_fn, &ecount2); + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); + CHECK(ecount == 1); + CHECK(ecount2 == 10); + secp256k1_zkp_context_set_illegal_callback(ctx, NULL, NULL); + /* Try a bunch of prefabbed points with all possible encodings. */ + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) { + ec_pubkey_parse_pointtest(valid[i], 1, 1); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NXVALID; i++) { + ec_pubkey_parse_pointtest(onlyxvalid[i], 1, 0); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NINVALID; i++) { + ec_pubkey_parse_pointtest(invalid[i], 0, 0); + } +} + +void run_eckey_edge_case_test(void) { + const unsigned char orderc[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + const unsigned char zeros[sizeof(secp256k1_zkp_pubkey)] = {0x00}; + unsigned char ctmp[33]; + unsigned char ctmp2[33]; + secp256k1_zkp_pubkey pubkey; + secp256k1_zkp_pubkey pubkey2; + secp256k1_zkp_pubkey pubkey_one; + secp256k1_zkp_pubkey pubkey_negone; + const secp256k1_zkp_pubkey *pubkeys[3]; + size_t len; + int32_t ecount; + /* Group order is too large, reject. */ + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, orderc) == 0); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, orderc) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) == 0); + /* Maximum value is too large, reject. */ + memset(ctmp, 255, 32); + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) == 0); + /* Zero is too small, reject. */ + memset(ctmp, 0, 32); + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) == 0); + /* One must be accepted. */ + ctmp[31] = 0x01; + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) > 0); + pubkey_one = pubkey; + /* Group order + 1 is too large, reject. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x42; + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) == 0); + /* -1 must be accepted. */ + ctmp[31] = 0x40; + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) > 0); + pubkey_negone = pubkey; + /* Tweak of zero leaves the value unchanged. */ + memset(ctmp2, 0, 32); + CHECK(secp256k1_zkp_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1); + CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); + memcpy(&pubkey2, &pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Multiply tweak of zero zeroizes the output. */ + CHECK(secp256k1_zkp_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + CHECK(secp256k1_zkp_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Overflowing key tweak zeroizes. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_zkp_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_zkp_ec_privkey_tweak_mul(ctx, ctmp, orderc) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_zkp_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Private key tweaks results in a key of zero. */ + ctmp2[31] = 1; + CHECK(secp256k1_zkp_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0); + CHECK(memcmp(zeros, ctmp2, 32) == 0); + ctmp2[31] = 1; + CHECK(secp256k1_zkp_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Tweak computation wraps and results in a key of 1. */ + ctmp2[31] = 2; + CHECK(secp256k1_zkp_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 1); + CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); + ctmp2[31] = 2; + CHECK(secp256k1_zkp_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + ctmp2[31] = 1; + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Tweak mul * 2 = 1+1. */ + CHECK(secp256k1_zkp_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + ctmp2[31] = 2; + CHECK(secp256k1_zkp_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Test argument errors. */ + ecount = 0; + secp256k1_zkp_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + CHECK(ecount == 0); + /* Zeroize pubkey on parse error. */ + memset(&pubkey, 0, 32); + CHECK(secp256k1_zkp_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + memset(&pubkey2, 0, 32); + CHECK(secp256k1_zkp_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0); + CHECK(ecount == 2); + CHECK(memcmp(&pubkey2, zeros, sizeof(pubkey2)) == 0); + /* Plain argument errors. */ + ecount = 0; + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, ctmp) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, NULL) == 0); + CHECK(ecount == 1); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK(secp256k1_zkp_ec_pubkey_tweak_add(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_ec_pubkey_tweak_add(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK(secp256k1_zkp_ec_pubkey_tweak_mul(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_ec_pubkey_tweak_mul(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + CHECK(secp256k1_zkp_ec_privkey_tweak_add(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_ec_privkey_tweak_add(ctx, ctmp, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 1; + CHECK(secp256k1_zkp_ec_privkey_tweak_mul(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_ec_privkey_tweak_mul(ctx, ctmp, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, NULL, ctmp) == 0); + CHECK(ecount == 1); + memset(&pubkey, 1, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) == 0); + /* secp256k1_zkp_ec_pubkey_combine tests. */ + ecount = 0; + pubkeys[0] = &pubkey_one; + VG_UNDEF(&pubkeys[0], sizeof(secp256k1_zkp_pubkey *)); + VG_UNDEF(&pubkeys[1], sizeof(secp256k1_zkp_pubkey *)); + VG_UNDEF(&pubkeys[2], sizeof(secp256k1_zkp_pubkey *)); + memset(&pubkey, 255, sizeof(secp256k1_zkp_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_zkp_pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_combine(ctx, &pubkey, pubkeys, 0) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_zkp_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_ec_pubkey_combine(ctx, NULL, pubkeys, 1) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) == 0); + CHECK(ecount == 2); + memset(&pubkey, 255, sizeof(secp256k1_zkp_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_zkp_pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_combine(ctx, &pubkey, NULL, 1) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_zkp_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) == 0); + CHECK(ecount == 3); + pubkeys[0] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_zkp_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_zkp_pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_combine(ctx, &pubkey, pubkeys, 1) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_zkp_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) > 0); + CHECK(ecount == 3); + len = 33; + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); + CHECK(memcmp(ctmp, ctmp2, 33) == 0); + /* Result is infinity. */ + pubkeys[0] = &pubkey_one; + pubkeys[1] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_zkp_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_zkp_pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_zkp_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) == 0); + CHECK(ecount == 3); + /* Passes through infinity but comes out one. */ + pubkeys[2] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_zkp_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_zkp_pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_combine(ctx, &pubkey, pubkeys, 3) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_zkp_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) > 0); + CHECK(ecount == 3); + len = 33; + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); + CHECK(memcmp(ctmp, ctmp2, 33) == 0); + /* Adds to two. */ + pubkeys[1] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_zkp_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_zkp_pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_zkp_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_zkp_pubkey)) > 0); + CHECK(ecount == 3); + secp256k1_zkp_context_set_illegal_callback(ctx, NULL, NULL); +} + +void random_sign(secp256k1_zkp_scalar *sigr, secp256k1_zkp_scalar *sigs, const secp256k1_zkp_scalar *key, const secp256k1_zkp_scalar *msg, int *recid) { + secp256k1_zkp_scalar nonce; + do { + random_scalar_order_test(&nonce); + } while(!secp256k1_zkp_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); +} + +void test_ecdsa_sign_verify(void) { + secp256k1_zkp_gej pubj; + secp256k1_zkp_ge pub; + secp256k1_zkp_scalar one; + secp256k1_zkp_scalar msg, key; + secp256k1_zkp_scalar sigr, sigs; + int recid; + int getrec; + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); + secp256k1_zkp_ge_set_gej(&pub, &pubj); + getrec = secp256k1_zkp_rand_bits(1); + random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL); + if (getrec) { + CHECK(recid >= 0 && recid < 4); + } + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + secp256k1_zkp_scalar_set_int(&one, 1); + secp256k1_zkp_scalar_add(&msg, &msg, &one); + CHECK(!secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); +} + +void run_ecdsa_sign_verify(void) { + int i; + for (i = 0; i < 10*count; i++) { + test_ecdsa_sign_verify(); + } +} + +/** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */ +static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void)msg32; + (void)key32; + (void)algo16; + memcpy(nonce32, data, 32); + return (counter == 0); +} + +static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + /* Dummy nonce generator that has a fatal error on the first counter value. */ + if (counter == 0) { + return 0; + } + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 1); +} + +static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */ + if (counter < 3) { + memset(nonce32, counter==0 ? 0 : 255, 32); + if (counter == 2) { + nonce32[31]--; + } + return 1; + } + if (counter < 5) { + static const unsigned char order[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 + }; + memcpy(nonce32, order, 32); + if (counter == 4) { + nonce32[31]++; + } + return 1; + } + /* Retry rate of 6979 is negligible esp. as we only call this in deterministic tests. */ + /* If someone does fine a case where it retries for secp256k1, we'd like to know. */ + if (counter > 5) { + return 0; + } + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5); +} + +int is_empty_signature(const secp256k1_zkp_ecdsa_signature *sig) { + static const unsigned char res[sizeof(secp256k1_zkp_ecdsa_signature)] = {0}; + return memcmp(sig, res, sizeof(secp256k1_zkp_ecdsa_signature)) == 0; +} + +void test_ecdsa_end_to_end(void) { + unsigned char extra[32] = {0x00}; + unsigned char privkey[32]; + unsigned char message[32]; + unsigned char privkey2[32]; + secp256k1_zkp_ecdsa_signature signature[6]; + secp256k1_zkp_scalar r, s; + unsigned char sig[74]; + size_t siglen = 74; + unsigned char pubkeyc[65]; + size_t pubkeyclen = 65; + secp256k1_zkp_pubkey pubkey; + secp256k1_zkp_pubkey pubkey_tmp; + unsigned char seckey[300]; + size_t seckeylen = 300; + + /* Generate a random key and message. */ + { + secp256k1_zkp_scalar msg, key; + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_zkp_scalar_get_b32(privkey, &key); + secp256k1_zkp_scalar_get_b32(message, &msg); + } + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_zkp_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Verify exporting and importing public key. */ + CHECK(secp256k1_zkp_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_zkp_rand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); + memset(&pubkey, 0, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); + + /* Verify negation changes the key and changes it back */ + memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey)); + CHECK(secp256k1_zkp_ec_pubkey_negate(ctx, &pubkey_tmp) == 1); + CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0); + CHECK(secp256k1_zkp_ec_pubkey_negate(ctx, &pubkey_tmp) == 1); + CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0); + + /* Verify private key import and export. */ + CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_zkp_rand_bits(1) == 1)); + CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1); + CHECK(memcmp(privkey, privkey2, 32) == 0); + + /* Optionally tweak the keys using addition. */ + if (secp256k1_zkp_rand_int(3) == 0) { + int ret1; + int ret2; + unsigned char rnd[32]; + secp256k1_zkp_pubkey pubkey2; + secp256k1_zkp_rand256_test(rnd); + ret1 = secp256k1_zkp_ec_privkey_tweak_add(ctx, privkey, rnd); + ret2 = secp256k1_zkp_ec_pubkey_tweak_add(ctx, &pubkey, rnd); + CHECK(ret1 == ret2); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + } + + /* Optionally tweak the keys using multiplication. */ + if (secp256k1_zkp_rand_int(3) == 0) { + int ret1; + int ret2; + unsigned char rnd[32]; + secp256k1_zkp_pubkey pubkey2; + secp256k1_zkp_rand256_test(rnd); + ret1 = secp256k1_zkp_ec_privkey_tweak_mul(ctx, privkey, rnd); + ret2 = secp256k1_zkp_ec_pubkey_tweak_mul(ctx, &pubkey, rnd); + CHECK(ret1 == ret2); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + } + + /* Sign. */ + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &signature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &signature[1], message, privkey, NULL, extra) == 1); + extra[31] = 1; + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &signature[2], message, privkey, NULL, extra) == 1); + extra[31] = 0; + extra[0] = 1; + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &signature[3], message, privkey, NULL, extra) == 1); + CHECK(memcmp(&signature[0], &signature[4], sizeof(signature[0])) == 0); + CHECK(memcmp(&signature[0], &signature[1], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[0], &signature[2], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[0], &signature[3], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[1], &signature[2], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[1], &signature[3], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[2], &signature[3], sizeof(signature[0])) != 0); + /* Verify. */ + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1); + /* Test lower-S form, malleate, verify and fail, test again, malleate again */ + CHECK(!secp256k1_zkp_ecdsa_signature_normalize(ctx, NULL, &signature[0])); + secp256k1_zkp_ecdsa_signature_load(ctx, &r, &s, &signature[0]); + secp256k1_zkp_scalar_negate(&s, &s); + secp256k1_zkp_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0); + CHECK(secp256k1_zkp_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_zkp_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); + CHECK(!secp256k1_zkp_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(!secp256k1_zkp_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + secp256k1_zkp_scalar_negate(&s, &s); + secp256k1_zkp_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(!secp256k1_zkp_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + CHECK(memcmp(&signature[5], &signature[0], 64) == 0); + + /* Serialize/parse DER and verify again */ + CHECK(secp256k1_zkp_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + memset(&signature[0], 0, sizeof(signature[0])); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); + /* Serialize/destroy/parse DER and verify again. */ + siglen = 74; + CHECK(secp256k1_zkp_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + sig[secp256k1_zkp_rand_int(siglen)] += 1 + secp256k1_zkp_rand_int(255); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 || + secp256k1_zkp_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0); +} + +void test_random_pubkeys(void) { + secp256k1_zkp_ge elem; + secp256k1_zkp_ge elem2; + unsigned char in[65]; + /* Generate some randomly sized pubkeys. */ + size_t len = secp256k1_zkp_rand_bits(2) == 0 ? 65 : 33; + if (secp256k1_zkp_rand_bits(2) == 0) { + len = secp256k1_zkp_rand_bits(6); + } + if (len == 65) { + in[0] = secp256k1_zkp_rand_bits(1) ? 4 : (secp256k1_zkp_rand_bits(1) ? 6 : 7); + } else { + in[0] = secp256k1_zkp_rand_bits(1) ? 2 : 3; + } + if (secp256k1_zkp_rand_bits(3) == 0) { + in[0] = secp256k1_zkp_rand_bits(8); + } + if (len > 1) { + secp256k1_zkp_rand256(&in[1]); + } + if (len > 33) { + secp256k1_zkp_rand256(&in[33]); + } + if (secp256k1_zkp_eckey_pubkey_parse(&elem, in, len)) { + unsigned char out[65]; + unsigned char firstb; + int res; + size_t size = len; + firstb = in[0]; + /* If the pubkey can be parsed, it should round-trip... */ + CHECK(secp256k1_zkp_eckey_pubkey_serialize(&elem, out, &size, len == 33)); + CHECK(size == len); + CHECK(memcmp(&in[1], &out[1], len-1) == 0); + /* ... except for the type of hybrid inputs. */ + if ((in[0] != 6) && (in[0] != 7)) { + CHECK(in[0] == out[0]); + } + size = 65; + CHECK(secp256k1_zkp_eckey_pubkey_serialize(&elem, in, &size, 0)); + CHECK(size == 65); + CHECK(secp256k1_zkp_eckey_pubkey_parse(&elem2, in, size)); + ge_equals_ge(&elem,&elem2); + /* Check that the X9.62 hybrid type is checked. */ + in[0] = secp256k1_zkp_rand_bits(1) ? 6 : 7; + res = secp256k1_zkp_eckey_pubkey_parse(&elem2, in, size); + if (firstb == 2 || firstb == 3) { + if (in[0] == firstb + 4) { + CHECK(res); + } else { + CHECK(!res); + } + } + if (res) { + ge_equals_ge(&elem,&elem2); + CHECK(secp256k1_zkp_eckey_pubkey_serialize(&elem, out, &size, 0)); + CHECK(memcmp(&in[1], &out[1], 64) == 0); + } + } +} + +void run_random_pubkeys(void) { + int i; + for (i = 0; i < 10*count; i++) { + test_random_pubkeys(); + } +} + +void run_ecdsa_end_to_end(void) { + int i; + for (i = 0; i < 64*count; i++) { + test_ecdsa_end_to_end(); + } +} + +int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { + static const unsigned char zeroes[32] = {0}; +#ifdef ENABLE_OPENSSL_TESTS + static const unsigned char max_scalar[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40 + }; +#endif + + int ret = 0; + + secp256k1_zkp_ecdsa_signature sig_der; + unsigned char roundtrip_der[2048]; + unsigned char compact_der[64]; + size_t len_der = 2048; + int parsed_der = 0, valid_der = 0, roundtrips_der = 0; + + secp256k1_zkp_ecdsa_signature sig_der_lax; + unsigned char roundtrip_der_lax[2048]; + unsigned char compact_der_lax[64]; + size_t len_der_lax = 2048; + int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0; + +#ifdef ENABLE_OPENSSL_TESTS + ECDSA_SIG *sig_openssl; + const BIGNUM *r = NULL, *s = NULL; + const unsigned char *sigptr; + unsigned char roundtrip_openssl[2048]; + int len_openssl = 2048; + int parsed_openssl, valid_openssl = 0, roundtrips_openssl = 0; +#endif + + parsed_der = secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig_der, sig, siglen); + if (parsed_der) { + ret |= (!secp256k1_zkp_ecdsa_signature_serialize_compact(ctx, compact_der, &sig_der)) << 0; + valid_der = (memcmp(compact_der, zeroes, 32) != 0) && (memcmp(compact_der + 32, zeroes, 32) != 0); + } + if (valid_der) { + ret |= (!secp256k1_zkp_ecdsa_signature_serialize_der(ctx, roundtrip_der, &len_der, &sig_der)) << 1; + roundtrips_der = (len_der == siglen) && memcmp(roundtrip_der, sig, siglen) == 0; + } + + parsed_der_lax = ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen); + if (parsed_der_lax) { + ret |= (!secp256k1_zkp_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10; + valid_der_lax = (memcmp(compact_der_lax, zeroes, 32) != 0) && (memcmp(compact_der_lax + 32, zeroes, 32) != 0); + } + if (valid_der_lax) { + ret |= (!secp256k1_zkp_ecdsa_signature_serialize_der(ctx, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; + roundtrips_der_lax = (len_der_lax == siglen) && memcmp(roundtrip_der_lax, sig, siglen) == 0; + } + + if (certainly_der) { + ret |= (!parsed_der) << 2; + } + if (certainly_not_der) { + ret |= (parsed_der) << 17; + } + if (valid_der) { + ret |= (!roundtrips_der) << 3; + } + + if (valid_der) { + ret |= (!roundtrips_der_lax) << 12; + ret |= (len_der != len_der_lax) << 13; + ret |= (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0) << 14; + } + ret |= (roundtrips_der != roundtrips_der_lax) << 15; + if (parsed_der) { + ret |= (!parsed_der_lax) << 16; + } + +#ifdef ENABLE_OPENSSL_TESTS + sig_openssl = ECDSA_SIG_new(); + sigptr = sig; + parsed_openssl = (d2i_ECDSA_SIG(&sig_openssl, &sigptr, siglen) != NULL); + if (parsed_openssl) { + ECDSA_SIG_get0(sig_openssl, &r, &s); + valid_openssl = !BN_is_negative(r) && !BN_is_negative(s) && BN_num_bits(r) > 0 && BN_num_bits(r) <= 256 && BN_num_bits(s) > 0 && BN_num_bits(s) <= 256; + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(r, tmp + 32 - BN_num_bytes(r)); + valid_openssl = memcmp(tmp, max_scalar, 32) < 0; + } + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(s, tmp + 32 - BN_num_bytes(s)); + valid_openssl = memcmp(tmp, max_scalar, 32) < 0; + } + } + len_openssl = i2d_ECDSA_SIG(sig_openssl, NULL); + if (len_openssl <= 2048) { + unsigned char *ptr = roundtrip_openssl; + CHECK(i2d_ECDSA_SIG(sig_openssl, &ptr) == len_openssl); + roundtrips_openssl = valid_openssl && ((size_t)len_openssl == siglen) && (memcmp(roundtrip_openssl, sig, siglen) == 0); + } else { + len_openssl = 0; + } + ECDSA_SIG_free(sig_openssl); + + ret |= (parsed_der && !parsed_openssl) << 4; + ret |= (valid_der && !valid_openssl) << 5; + ret |= (roundtrips_openssl && !parsed_der) << 6; + ret |= (roundtrips_der != roundtrips_openssl) << 7; + if (roundtrips_openssl) { + ret |= (len_der != (size_t)len_openssl) << 8; + ret |= (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0) << 9; + } +#endif + return ret; +} + +static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) { + size_t i; + for (i = 0; i < ptrlen; i++) { + int shift = ptrlen - 1 - i; + if (shift >= 4) { + ptr[i] = 0; + } else { + ptr[i] = (val >> shift) & 0xFF; + } + } +} + +static void damage_array(unsigned char *sig, size_t *len) { + int pos; + int action = secp256k1_zkp_rand_bits(3); + if (action < 1 && *len > 3) { + /* Delete a byte. */ + pos = secp256k1_zkp_rand_int(*len); + memmove(sig + pos, sig + pos + 1, *len - pos - 1); + (*len)--; + return; + } else if (action < 2 && *len < 2048) { + /* Insert a byte. */ + pos = secp256k1_zkp_rand_int(1 + *len); + memmove(sig + pos + 1, sig + pos, *len - pos); + sig[pos] = secp256k1_zkp_rand_bits(8); + (*len)++; + return; + } else if (action < 4) { + /* Modify a byte. */ + sig[secp256k1_zkp_rand_int(*len)] += 1 + secp256k1_zkp_rand_int(255); + return; + } else { /* action < 8 */ + /* Modify a bit. */ + sig[secp256k1_zkp_rand_int(*len)] ^= 1 << secp256k1_zkp_rand_bits(3); + return; + } +} + +static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly_der, int* certainly_not_der) { + int der; + int nlow[2], nlen[2], nlenlen[2], nhbit[2], nhbyte[2], nzlen[2]; + size_t tlen, elen, glen; + int indet; + int n; + + *len = 0; + der = secp256k1_zkp_rand_bits(2) == 0; + *certainly_der = der; + *certainly_not_der = 0; + indet = der ? 0 : secp256k1_zkp_rand_int(10) == 0; + + for (n = 0; n < 2; n++) { + /* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */ + nlow[n] = der ? 1 : (secp256k1_zkp_rand_bits(3) != 0); + /* The length of the number in bytes (the first byte of which will always be nonzero) */ + nlen[n] = nlow[n] ? secp256k1_zkp_rand_int(33) : 32 + secp256k1_zkp_rand_int(200) * secp256k1_zkp_rand_int(8) / 8; + CHECK(nlen[n] <= 232); + /* The top bit of the number. */ + nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_zkp_rand_bits(1)); + /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */ + nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_zkp_rand_bits(7) : 1 + secp256k1_zkp_rand_int(127)); + /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */ + nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_zkp_rand_int(3) : secp256k1_zkp_rand_int(300 - nlen[n]) * secp256k1_zkp_rand_int(8) / 8); + if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) { + *certainly_not_der = 1; + } + CHECK(nlen[n] + nzlen[n] <= 300); + /* The length of the length descriptor for the number. 0 means short encoding, anything else is long encoding. */ + nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2); + if (!der) { + /* nlenlen[n] max 127 bytes */ + int add = secp256k1_zkp_rand_int(127 - nlenlen[n]) * secp256k1_zkp_rand_int(16) * secp256k1_zkp_rand_int(16) / 256; + nlenlen[n] += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + CHECK(nlen[n] + nzlen[n] + nlenlen[n] <= 427); + } + + /* The total length of the data to go, so far */ + tlen = 2 + nlenlen[0] + nlen[0] + nzlen[0] + 2 + nlenlen[1] + nlen[1] + nzlen[1]; + CHECK(tlen <= 856); + + /* The length of the garbage inside the tuple. */ + elen = (der || indet) ? 0 : secp256k1_zkp_rand_int(980 - tlen) * secp256k1_zkp_rand_int(8) / 8; + if (elen != 0) { + *certainly_not_der = 1; + } + tlen += elen; + CHECK(tlen <= 980); + + /* The length of the garbage after the end of the tuple. */ + glen = der ? 0 : secp256k1_zkp_rand_int(990 - tlen) * secp256k1_zkp_rand_int(8) / 8; + if (glen != 0) { + *certainly_not_der = 1; + } + CHECK(tlen + glen <= 990); + + /* Write the tuple header. */ + sig[(*len)++] = 0x30; + if (indet) { + /* Indeterminate length */ + sig[(*len)++] = 0x80; + *certainly_not_der = 1; + } else { + int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2); + if (!der) { + int add = secp256k1_zkp_rand_int(127 - tlenlen) * secp256k1_zkp_rand_int(16) * secp256k1_zkp_rand_int(16) / 256; + tlenlen += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + if (tlenlen == 0) { + /* Short length notation */ + sig[(*len)++] = tlen; + } else { + /* Long length notation */ + sig[(*len)++] = 128 + tlenlen; + assign_big_endian(sig + *len, tlenlen, tlen); + *len += tlenlen; + } + tlen += tlenlen; + } + tlen += 2; + CHECK(tlen + glen <= 1119); + + for (n = 0; n < 2; n++) { + /* Write the integer header. */ + sig[(*len)++] = 0x02; + if (nlenlen[n] == 0) { + /* Short length notation */ + sig[(*len)++] = nlen[n] + nzlen[n]; + } else { + /* Long length notation. */ + sig[(*len)++] = 128 + nlenlen[n]; + assign_big_endian(sig + *len, nlenlen[n], nlen[n] + nzlen[n]); + *len += nlenlen[n]; + } + /* Write zero padding */ + while (nzlen[n] > 0) { + sig[(*len)++] = 0x00; + nzlen[n]--; + } + if (nlen[n] == 32 && !nlow[n]) { + /* Special extra 16 0xFF bytes in "high" 32-byte numbers */ + int i; + for (i = 0; i < 16; i++) { + sig[(*len)++] = 0xFF; + } + nlen[n] -= 16; + } + /* Write first byte of number */ + if (nlen[n] > 0) { + sig[(*len)++] = nhbyte[n]; + nlen[n]--; + } + /* Generate remaining random bytes of number */ + secp256k1_zkp_rand_bytes_test(sig + *len, nlen[n]); + *len += nlen[n]; + nlen[n] = 0; + } + + /* Generate random garbage inside tuple. */ + secp256k1_zkp_rand_bytes_test(sig + *len, elen); + *len += elen; + + /* Generate end-of-contents bytes. */ + if (indet) { + sig[(*len)++] = 0; + sig[(*len)++] = 0; + tlen += 2; + } + CHECK(tlen + glen <= 1121); + + /* Generate random garbage outside tuple. */ + secp256k1_zkp_rand_bytes_test(sig + *len, glen); + *len += glen; + tlen += glen; + CHECK(tlen <= 1121); + CHECK(tlen == *len); +} + +void run_ecdsa_der_parse(void) { + int i,j; + for (i = 0; i < 200 * count; i++) { + unsigned char buffer[2048]; + size_t buflen = 0; + int certainly_der = 0; + int certainly_not_der = 0; + random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der); + CHECK(buflen <= 2048); + for (j = 0; j < 16; j++) { + int ret = 0; + if (j > 0) { + damage_array(buffer, &buflen); + /* We don't know anything anymore about the DERness of the result */ + certainly_der = 0; + certainly_not_der = 0; + } + ret = test_ecdsa_der_parse(buffer, buflen, certainly_der, certainly_not_der); + if (ret != 0) { + size_t k; + fprintf(stderr, "Failure %x on ", ret); + for (k = 0; k < buflen; k++) { + fprintf(stderr, "%02x ", buffer[k]); + } + fprintf(stderr, "\n"); + } + CHECK(ret == 0); + } + } +} + +/* Tests several edge cases. */ +void test_ecdsa_edge_cases(void) { + int t; + secp256k1_zkp_ecdsa_signature sig; + + /* Test the case where ECDSA recomputes a point that is infinity. */ + { + secp256k1_zkp_gej keyj; + secp256k1_zkp_ge key; + secp256k1_zkp_scalar msg; + secp256k1_zkp_scalar sr, ss; + secp256k1_zkp_scalar_set_int(&ss, 1); + secp256k1_zkp_scalar_negate(&ss, &ss); + secp256k1_zkp_scalar_inverse(&ss, &ss); + secp256k1_zkp_scalar_set_int(&sr, 1); + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr); + secp256k1_zkp_ge_set_gej(&key, &keyj); + msg = ss; + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with r of zero fails. */ + { + const unsigned char pubkey_mods_zero[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x41 + }; + secp256k1_zkp_ge key; + secp256k1_zkp_scalar msg; + secp256k1_zkp_scalar sr, ss; + secp256k1_zkp_scalar_set_int(&ss, 1); + secp256k1_zkp_scalar_set_int(&msg, 0); + secp256k1_zkp_scalar_set_int(&sr, 0); + CHECK(secp256k1_zkp_eckey_pubkey_parse(&key, pubkey_mods_zero, 33)); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with s of zero fails. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01 + }; + secp256k1_zkp_ge key; + secp256k1_zkp_scalar msg; + secp256k1_zkp_scalar sr, ss; + secp256k1_zkp_scalar_set_int(&ss, 0); + secp256k1_zkp_scalar_set_int(&msg, 0); + secp256k1_zkp_scalar_set_int(&sr, 1); + CHECK(secp256k1_zkp_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with message 0 passes. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02 + }; + const unsigned char pubkey2[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x43 + }; + secp256k1_zkp_ge key; + secp256k1_zkp_ge key2; + secp256k1_zkp_scalar msg; + secp256k1_zkp_scalar sr, ss; + secp256k1_zkp_scalar_set_int(&ss, 2); + secp256k1_zkp_scalar_set_int(&msg, 0); + secp256k1_zkp_scalar_set_int(&sr, 2); + CHECK(secp256k1_zkp_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_zkp_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_zkp_scalar_negate(&ss, &ss); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_zkp_scalar_set_int(&ss, 1); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message 1 passes. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x14, 0x4e, 0x5a, 0x58, 0xef, 0x5b, 0x22, + 0x6f, 0xd2, 0xe2, 0x07, 0x6a, 0x77, 0xcf, 0x05, + 0xb4, 0x1d, 0xe7, 0x4a, 0x30, 0x98, 0x27, 0x8c, + 0x93, 0xe6, 0xe6, 0x3c, 0x0b, 0xc4, 0x73, 0x76, + 0x25 + }; + const unsigned char pubkey2[33] = { + 0x02, 0x8a, 0xd5, 0x37, 0xed, 0x73, 0xd9, 0x40, + 0x1d, 0xa0, 0x33, 0xd2, 0xdc, 0xf0, 0xaf, 0xae, + 0x34, 0xcf, 0x5f, 0x96, 0x4c, 0x73, 0x28, 0x0f, + 0x92, 0xc0, 0xf6, 0x9d, 0xd9, 0xb2, 0x09, 0x10, + 0x62 + }; + const unsigned char csr[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xeb + }; + secp256k1_zkp_ge key; + secp256k1_zkp_ge key2; + secp256k1_zkp_scalar msg; + secp256k1_zkp_scalar sr, ss; + secp256k1_zkp_scalar_set_int(&ss, 1); + secp256k1_zkp_scalar_set_int(&msg, 1); + secp256k1_zkp_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_zkp_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_zkp_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_zkp_scalar_negate(&ss, &ss); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_zkp_scalar_set_int(&ss, 2); + secp256k1_zkp_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message -1 passes. */ + { + const unsigned char pubkey[33] = { + 0x03, 0xaf, 0x97, 0xff, 0x7d, 0x3a, 0xf6, 0xa0, + 0x02, 0x94, 0xbd, 0x9f, 0x4b, 0x2e, 0xd7, 0x52, + 0x28, 0xdb, 0x49, 0x2a, 0x65, 0xcb, 0x1e, 0x27, + 0x57, 0x9c, 0xba, 0x74, 0x20, 0xd5, 0x1d, 0x20, + 0xf1 + }; + const unsigned char csr[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xee + }; + secp256k1_zkp_ge key; + secp256k1_zkp_scalar msg; + secp256k1_zkp_scalar sr, ss; + secp256k1_zkp_scalar_set_int(&ss, 1); + secp256k1_zkp_scalar_set_int(&msg, 1); + secp256k1_zkp_scalar_negate(&msg, &msg); + secp256k1_zkp_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_zkp_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + secp256k1_zkp_scalar_negate(&ss, &ss); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + secp256k1_zkp_scalar_set_int(&ss, 3); + secp256k1_zkp_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Signature where s would be zero. */ + { + secp256k1_zkp_pubkey pubkey; + size_t siglen; + int32_t ecount; + unsigned char signature[72]; + static const unsigned char nonce[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + static const unsigned char nonce2[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40 + }; + const unsigned char key[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + }; + unsigned char msg[32] = { + 0x86, 0x41, 0x99, 0x81, 0x06, 0x23, 0x44, 0x53, + 0xaa, 0x5f, 0x9d, 0x6a, 0x31, 0x78, 0xf4, 0xf7, + 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, + 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, + }; + ecount = 0; + secp256k1_zkp_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0); + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); + msg[31] = 0xaa; + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_zkp_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, key) == 1); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, NULL, msg, &pubkey) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &sig, NULL, &pubkey) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &sig, msg, NULL) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1); + CHECK(ecount == 6); + CHECK(secp256k1_zkp_ec_pubkey_create(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 7); + /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */ + CHECK(secp256k1_zkp_ecdsa_verify(ctx, &sig, msg, &pubkey) == 0); + CHECK(ecount == 8); + siglen = 72; + CHECK(secp256k1_zkp_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig) == 0); + CHECK(ecount == 9); + CHECK(secp256k1_zkp_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig) == 0); + CHECK(ecount == 10); + CHECK(secp256k1_zkp_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL) == 0); + CHECK(ecount == 11); + CHECK(secp256k1_zkp_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1); + CHECK(ecount == 11); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, NULL, signature, siglen) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, NULL, siglen) == 0); + CHECK(ecount == 13); + CHECK(secp256k1_zkp_ecdsa_signature_parse_der(ctx, &sig, signature, siglen) == 1); + CHECK(ecount == 13); + siglen = 10; + /* Too little room for a signature does not fail via ARGCHECK. */ + CHECK(secp256k1_zkp_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0); + CHECK(ecount == 13); + ecount = 0; + CHECK(secp256k1_zkp_ecdsa_signature_normalize(ctx, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_zkp_ecdsa_signature_serialize_compact(ctx, NULL, &sig) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_zkp_ecdsa_signature_serialize_compact(ctx, signature, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_ecdsa_signature_serialize_compact(ctx, signature, &sig) == 1); + CHECK(ecount == 3); + CHECK(secp256k1_zkp_ecdsa_signature_parse_compact(ctx, NULL, signature) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_zkp_ecdsa_signature_parse_compact(ctx, &sig, NULL) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_zkp_ecdsa_signature_parse_compact(ctx, &sig, signature) == 1); + CHECK(ecount == 5); + memset(signature, 255, 64); + CHECK(secp256k1_zkp_ecdsa_signature_parse_compact(ctx, &sig, signature) == 0); + CHECK(ecount == 5); + secp256k1_zkp_context_set_illegal_callback(ctx, NULL, NULL); + } + + /* Nonce function corner cases. */ + for (t = 0; t < 2; t++) { + static const unsigned char zero[32] = {0x00}; + int i; + unsigned char key[32]; + unsigned char msg[32]; + secp256k1_zkp_ecdsa_signature sig2; + secp256k1_zkp_scalar sr[512], ss; + const unsigned char *extra; + extra = t == 0 ? NULL : zero; + memset(msg, 0, 32); + msg[31] = 1; + /* High key results in signature failure. */ + memset(key, 0xFF, 32); + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); + /* Zero key results in signature failure. */ + memset(key, 0, 32); + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); + /* Nonce function failure results in signature failure. */ + key[31] = 1; + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_fail, extra) == 0); + CHECK(is_empty_signature(&sig)); + /* The retry loop successfully makes its way to the first good value. */ + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_retry, extra) == 1); + CHECK(!is_empty_signature(&sig)); + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); + /* The default nonce function is deterministic. */ + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); + /* The default nonce function changes output with different messages. */ + for(i = 0; i < 256; i++) { + int j; + msg[0] = i; + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_zkp_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); + for (j = 0; j < i; j++) { + CHECK(!secp256k1_zkp_scalar_eq(&sr[i], &sr[j])); + } + } + msg[0] = 0; + msg[31] = 2; + /* The default nonce function changes output with different keys. */ + for(i = 256; i < 512; i++) { + int j; + key[0] = i - 256; + CHECK(secp256k1_zkp_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_zkp_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); + for (j = 0; j < i; j++) { + CHECK(!secp256k1_zkp_scalar_eq(&sr[i], &sr[j])); + } + } + key[0] = 0; + } + + { + /* Check that optional nonce arguments do not have equivalent effect. */ + const unsigned char zeros[32] = {0}; + unsigned char nonce[32]; + unsigned char nonce2[32]; + unsigned char nonce3[32]; + unsigned char nonce4[32]; + VG_UNDEF(nonce,32); + VG_UNDEF(nonce2,32); + VG_UNDEF(nonce3,32); + VG_UNDEF(nonce4,32); + CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1); + VG_CHECK(nonce,32); + CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1); + VG_CHECK(nonce2,32); + CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1); + VG_CHECK(nonce3,32); + CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1); + VG_CHECK(nonce4,32); + CHECK(memcmp(nonce, nonce2, 32) != 0); + CHECK(memcmp(nonce, nonce3, 32) != 0); + CHECK(memcmp(nonce, nonce4, 32) != 0); + CHECK(memcmp(nonce2, nonce3, 32) != 0); + CHECK(memcmp(nonce2, nonce4, 32) != 0); + CHECK(memcmp(nonce3, nonce4, 32) != 0); + } + + + /* Privkey export where pubkey is the point at infinity. */ + { + unsigned char privkey[300]; + unsigned char seckey[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, + }; + size_t outlen = 300; + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0)); + outlen = 300; + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1)); + } +} + +void run_ecdsa_edge_cases(void) { + test_ecdsa_edge_cases(); +} + +#ifdef ENABLE_OPENSSL_TESTS +EC_KEY *get_openssl_key(const unsigned char *key32) { + unsigned char privkey[300]; + size_t privkeylen; + const unsigned char* pbegin = privkey; + int compr = secp256k1_zkp_rand_bits(1); + EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); + CHECK(ec_privkey_export_der(ctx, privkey, &privkeylen, key32, compr)); + CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen)); + CHECK(EC_KEY_check_key(ec_key)); + return ec_key; +} + +void test_ecdsa_openssl(void) { + secp256k1_zkp_gej qj; + secp256k1_zkp_ge q; + secp256k1_zkp_scalar sigr, sigs; + secp256k1_zkp_scalar one; + secp256k1_zkp_scalar msg2; + secp256k1_zkp_scalar key, msg; + EC_KEY *ec_key; + unsigned int sigsize = 80; + size_t secp_sigsize = 80; + unsigned char message[32]; + unsigned char signature[80]; + unsigned char key32[32]; + secp256k1_zkp_rand256_test(message); + secp256k1_zkp_scalar_set_b32(&msg, message, NULL); + random_scalar_order_test(&key); + secp256k1_zkp_scalar_get_b32(key32, &key); + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &qj, &key); + secp256k1_zkp_ge_set_gej(&q, &qj); + ec_key = get_openssl_key(key32); + CHECK(ec_key != NULL); + CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); + CHECK(secp256k1_zkp_ecdsa_sig_parse(&sigr, &sigs, signature, sigsize)); + CHECK(secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg)); + secp256k1_zkp_scalar_set_int(&one, 1); + secp256k1_zkp_scalar_add(&msg2, &msg, &one); + CHECK(!secp256k1_zkp_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg2)); + + random_sign(&sigr, &sigs, &key, &msg, NULL); + CHECK(secp256k1_zkp_ecdsa_sig_serialize(signature, &secp_sigsize, &sigr, &sigs)); + CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1); + + EC_KEY_free(ec_key); +} + +void run_ecdsa_openssl(void) { + int i; + for (i = 0; i < 10*count; i++) { + test_ecdsa_openssl(); + } +} +#endif + +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG +# include "modules/schnorrsig/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_MUSIG +# include "modules/musig/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_GENERATOR +# include "modules/generator/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_RANGEPROOF +# include "modules/rangeproof/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_WHITELIST +# include "modules/whitelist/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_SURJECTIONPROOF +# include "modules/surjection/tests_impl.h" +#endif + +int main(int argc, char **argv) { + unsigned char seed16[16] = {0}; + unsigned char run32[32] = {0}; + /* find iteration count */ + if (argc > 1) { + count = strtol(argv[1], NULL, 0); + } + + /* find random seed */ + if (argc > 2) { + int pos = 0; + const char* ch = argv[2]; + while (pos < 16 && ch[0] != 0 && ch[1] != 0) { + unsigned short sh; + if (sscanf(ch, "%2hx", &sh)) { + seed16[pos] = sh; + } else { + break; + } + ch += 2; + pos++; + } + } else { + FILE *frand = fopen("/dev/urandom", "r"); + if ((frand == NULL) || fread(&seed16, sizeof(seed16), 1, frand) != sizeof(seed16)) { + uint64_t t = time(NULL) * (uint64_t)1337; + seed16[0] ^= t; + seed16[1] ^= t >> 8; + seed16[2] ^= t >> 16; + seed16[3] ^= t >> 24; + seed16[4] ^= t >> 32; + seed16[5] ^= t >> 40; + seed16[6] ^= t >> 48; + seed16[7] ^= t >> 56; + } + if (frand) { + fclose(frand); + } + } + secp256k1_zkp_rand_seed(seed16); + + printf("test count = %i\n", count); + printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); + + /* initialize */ + run_context_tests(0); + run_context_tests(1); + run_scratch_tests(); + ctx = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + if (secp256k1_zkp_rand_bits(1)) { + secp256k1_zkp_rand256(run32); + CHECK(secp256k1_zkp_context_randomize(ctx, secp256k1_zkp_rand_bits(1) ? run32 : NULL)); + } + + run_rand_bits(); + run_rand_int(); + run_util_tests(); + + run_sha256_tests(); + run_hmac_sha256_tests(); + run_rfc6979_hmac_sha256_tests(); + +#ifndef USE_NUM_NONE + /* num tests */ + run_num_smalltests(); +#endif + + /* scalar tests */ + run_scalar_tests(); + + /* field tests */ + run_field_inv(); + run_field_inv_var(); + run_field_inv_all_var(); + run_field_misc(); + run_field_convert(); + run_sqr(); + run_sqrt(); + + /* group tests */ + run_ge(); + run_group_decompress(); + + /* ecmult tests */ + run_wnaf(); + run_point_times_order(); + run_ecmult_chain(); + run_ecmult_constants(); + run_ecmult_gen_blind(); + run_ecmult_const_tests(); + run_ecmult_multi_tests(); + run_ec_combine(); + + /* endomorphism tests */ +#ifdef USE_ENDOMORPHISM + run_endomorphism_tests(); +#endif + + /* EC point parser test */ + run_ec_pubkey_parse_test(); + + /* EC key edge cases */ + run_eckey_edge_case_test(); + +#ifdef ENABLE_MODULE_ECDH + /* ecdh tests */ + run_ecdh_tests(); +#endif + +#ifdef ENABLE_MODULE_SCHNORRSIG + /* Schnorrsig tests */ + run_schnorrsig_tests(); +#endif + +#ifdef ENABLE_MODULE_MUSIG + run_musig_tests(); +#endif + + /* ecdsa tests */ + run_random_pubkeys(); + run_ecdsa_der_parse(); + run_ecdsa_sign_verify(); + run_ecdsa_end_to_end(); + run_ecdsa_edge_cases(); +#ifdef ENABLE_OPENSSL_TESTS + run_ecdsa_openssl(); +#endif + +#ifdef ENABLE_MODULE_RECOVERY + /* ECDSA pubkey recovery tests */ + run_recovery_tests(); +#endif + +#ifdef ENABLE_MODULE_GENERATOR + run_generator_tests(); +#endif + +#ifdef ENABLE_MODULE_RANGEPROOF + run_rangeproof_tests(); +#endif + +#ifdef ENABLE_MODULE_WHITELIST + /* Key whitelisting tests */ + run_whitelist_tests(); +#endif + +#ifdef ENABLE_MODULE_SURJECTIONPROOF + run_surjection_tests(); +#endif + + secp256k1_zkp_rand256(run32); + printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); + + /* shutdown */ + secp256k1_zkp_context_destroy(ctx); + + printf("no problems found\n"); + return 0; +} diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/tests_exhaustive.c b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/tests_exhaustive.c new file mode 100644 index 00000000..da355b7b --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/tests_exhaustive.c @@ -0,0 +1,511 @@ +/*********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include +#include + +#include + +#undef USE_ECMULT_STATIC_PRECOMPUTATION + +#ifndef EXHAUSTIVE_TEST_ORDER +/* see group_impl.h for allowable values */ +#define EXHAUSTIVE_TEST_ORDER 13 +#define EXHAUSTIVE_TEST_LAMBDA 9 /* cube root of 1 mod 13 */ +#endif + +#include "include/secp256k1.h" +#include "group.h" +#include "secp256k1.c" +#include "testrand_impl.h" + +#ifdef ENABLE_MODULE_RECOVERY +#include "src/modules/recovery/main_impl.h" +#include "include/secp256k1_recovery.h" +#endif + +/** stolen from tests.c */ +void ge_equals_ge(const secp256k1_zkp_ge *a, const secp256k1_zkp_ge *b) { + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + CHECK(secp256k1_zkp_fe_equal_var(&a->x, &b->x)); + CHECK(secp256k1_zkp_fe_equal_var(&a->y, &b->y)); +} + +void ge_equals_gej(const secp256k1_zkp_ge *a, const secp256k1_zkp_gej *b) { + secp256k1_zkp_fe z2s; + secp256k1_zkp_fe u1, u2, s1, s2; + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ + secp256k1_zkp_fe_sqr(&z2s, &b->z); + secp256k1_zkp_fe_mul(&u1, &a->x, &z2s); + u2 = b->x; secp256k1_zkp_fe_normalize_weak(&u2); + secp256k1_zkp_fe_mul(&s1, &a->y, &z2s); secp256k1_zkp_fe_mul(&s1, &s1, &b->z); + s2 = b->y; secp256k1_zkp_fe_normalize_weak(&s2); + CHECK(secp256k1_zkp_fe_equal_var(&u1, &u2)); + CHECK(secp256k1_zkp_fe_equal_var(&s1, &s2)); +} + +void random_fe(secp256k1_zkp_fe *x) { + unsigned char bin[32]; + do { + secp256k1_zkp_rand256(bin); + if (secp256k1_zkp_fe_set_b32(x, bin)) { + return; + } + } while(1); +} +/** END stolen from tests.c */ + +int secp256k1_zkp_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, + const unsigned char *key32, const unsigned char *algo16, + void *data, unsigned int attempt) { + secp256k1_zkp_scalar s; + int *idata = data; + (void)msg32; + (void)key32; + (void)algo16; + /* Some nonces cannot be used because they'd cause s and/or r to be zero. + * The signing function has retry logic here that just re-calls the nonce + * function with an increased `attempt`. So if attempt > 0 this means we + * need to change the nonce to avoid an infinite loop. */ + if (attempt > 0) { + *idata = (*idata + 1) % EXHAUSTIVE_TEST_ORDER; + } + secp256k1_zkp_scalar_set_int(&s, *idata); + secp256k1_zkp_scalar_get_b32(nonce32, &s); + return 1; +} + +#ifdef USE_ENDOMORPHISM +void test_exhaustive_endomorphism(const secp256k1_zkp_ge *group, int order) { + int i; + for (i = 0; i < order; i++) { + secp256k1_zkp_ge res; + secp256k1_zkp_ge_mul_lambda(&res, &group[i]); + ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res); + } +} +#endif + +void test_exhaustive_addition(const secp256k1_zkp_ge *group, const secp256k1_zkp_gej *groupj, int order) { + int i, j; + + /* Sanity-check (and check infinity functions) */ + CHECK(secp256k1_zkp_ge_is_infinity(&group[0])); + CHECK(secp256k1_zkp_gej_is_infinity(&groupj[0])); + for (i = 1; i < order; i++) { + CHECK(!secp256k1_zkp_ge_is_infinity(&group[i])); + CHECK(!secp256k1_zkp_gej_is_infinity(&groupj[i])); + } + + /* Check all addition formulae */ + for (j = 0; j < order; j++) { + secp256k1_zkp_fe fe_inv; + secp256k1_zkp_fe_inv(&fe_inv, &groupj[j].z); + for (i = 0; i < order; i++) { + secp256k1_zkp_ge zless_gej; + secp256k1_zkp_gej tmp; + /* add_var */ + secp256k1_zkp_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL); + ge_equals_gej(&group[(i + j) % order], &tmp); + /* add_ge */ + if (j > 0) { + secp256k1_zkp_gej_add_ge(&tmp, &groupj[i], &group[j]); + ge_equals_gej(&group[(i + j) % order], &tmp); + } + /* add_ge_var */ + secp256k1_zkp_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); + ge_equals_gej(&group[(i + j) % order], &tmp); + /* add_zinv_var */ + zless_gej.infinity = groupj[j].infinity; + zless_gej.x = groupj[j].x; + zless_gej.y = groupj[j].y; + secp256k1_zkp_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv); + ge_equals_gej(&group[(i + j) % order], &tmp); + } + } + + /* Check doubling */ + for (i = 0; i < order; i++) { + secp256k1_zkp_gej tmp; + if (i > 0) { + secp256k1_zkp_gej_double_nonzero(&tmp, &groupj[i], NULL); + ge_equals_gej(&group[(2 * i) % order], &tmp); + } + secp256k1_zkp_gej_double_var(&tmp, &groupj[i], NULL); + ge_equals_gej(&group[(2 * i) % order], &tmp); + } + + /* Check negation */ + for (i = 1; i < order; i++) { + secp256k1_zkp_ge tmp; + secp256k1_zkp_gej tmpj; + secp256k1_zkp_ge_neg(&tmp, &group[i]); + ge_equals_ge(&group[order - i], &tmp); + secp256k1_zkp_gej_neg(&tmpj, &groupj[i]); + ge_equals_gej(&group[order - i], &tmpj); + } +} + +void test_exhaustive_ecmult(const secp256k1_zkp_context *ctx, const secp256k1_zkp_ge *group, const secp256k1_zkp_gej *groupj, int order) { + int i, j, r_log; + for (r_log = 1; r_log < order; r_log++) { + for (j = 0; j < order; j++) { + for (i = 0; i < order; i++) { + secp256k1_zkp_gej tmp; + secp256k1_zkp_scalar na, ng; + secp256k1_zkp_scalar_set_int(&na, i); + secp256k1_zkp_scalar_set_int(&ng, j); + + secp256k1_zkp_ecmult(&ctx->ecmult_ctx, &tmp, &groupj[r_log], &na, &ng); + ge_equals_gej(&group[(i * r_log + j) % order], &tmp); + + if (i > 0) { + secp256k1_zkp_ecmult_const(&tmp, &group[i], &ng, 256); + ge_equals_gej(&group[(i * j) % order], &tmp); + } + } + } + } +} + +typedef struct { + secp256k1_zkp_scalar sc[2]; + secp256k1_zkp_ge pt[2]; +} ecmult_multi_data; + +static int ecmult_multi_callback(secp256k1_zkp_scalar *sc, secp256k1_zkp_ge *pt, size_t idx, void *cbdata) { + ecmult_multi_data *data = (ecmult_multi_data*) cbdata; + *sc = data->sc[idx]; + *pt = data->pt[idx]; + return 1; +} + +void test_exhaustive_ecmult_multi(const secp256k1_zkp_context *ctx, const secp256k1_zkp_ge *group, int order) { + int i, j, k, x, y; + secp256k1_zkp_scratch *scratch = secp256k1_zkp_scratch_create(&ctx->error_callback, 4096); + for (i = 0; i < order; i++) { + for (j = 0; j < order; j++) { + for (k = 0; k < order; k++) { + for (x = 0; x < order; x++) { + for (y = 0; y < order; y++) { + secp256k1_zkp_gej tmp; + secp256k1_zkp_scalar g_sc; + ecmult_multi_data data; + + secp256k1_zkp_scalar_set_int(&data.sc[0], i); + secp256k1_zkp_scalar_set_int(&data.sc[1], j); + secp256k1_zkp_scalar_set_int(&g_sc, k); + data.pt[0] = group[x]; + data.pt[1] = group[y]; + + secp256k1_zkp_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2); + ge_equals_gej(&group[(i * x + j * y + k) % order], &tmp); + } + } + } + } + } + secp256k1_zkp_scratch_destroy(scratch); +} + +void r_from_k(secp256k1_zkp_scalar *r, const secp256k1_zkp_ge *group, int k) { + secp256k1_zkp_fe x; + unsigned char x_bin[32]; + k %= EXHAUSTIVE_TEST_ORDER; + x = group[k].x; + secp256k1_zkp_fe_normalize(&x); + secp256k1_zkp_fe_get_b32(x_bin, &x); + secp256k1_zkp_scalar_set_b32(r, x_bin, NULL); +} + +void test_exhaustive_verify(const secp256k1_zkp_context *ctx, const secp256k1_zkp_ge *group, int order) { + int s, r, msg, key; + for (s = 1; s < order; s++) { + for (r = 1; r < order; r++) { + for (msg = 1; msg < order; msg++) { + for (key = 1; key < order; key++) { + secp256k1_zkp_ge nonconst_ge; + secp256k1_zkp_ecdsa_signature sig; + secp256k1_zkp_pubkey pk; + secp256k1_zkp_scalar sk_s, msg_s, r_s, s_s; + secp256k1_zkp_scalar s_times_k_s, msg_plus_r_times_sk_s; + int k, should_verify; + unsigned char msg32[32]; + + secp256k1_zkp_scalar_set_int(&s_s, s); + secp256k1_zkp_scalar_set_int(&r_s, r); + secp256k1_zkp_scalar_set_int(&msg_s, msg); + secp256k1_zkp_scalar_set_int(&sk_s, key); + + /* Verify by hand */ + /* Run through every k value that gives us this r and check that *one* works. + * Note there could be none, there could be multiple, ECDSA is weird. */ + should_verify = 0; + for (k = 0; k < order; k++) { + secp256k1_zkp_scalar check_x_s; + r_from_k(&check_x_s, group, k); + if (r_s == check_x_s) { + secp256k1_zkp_scalar_set_int(&s_times_k_s, k); + secp256k1_zkp_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + secp256k1_zkp_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + secp256k1_zkp_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= secp256k1_zkp_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + } + } + /* nb we have a "high s" rule */ + should_verify &= !secp256k1_zkp_scalar_is_high(&s_s); + + /* Verify by calling verify */ + secp256k1_zkp_ecdsa_signature_save(&sig, &r_s, &s_s); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + secp256k1_zkp_pubkey_save(&pk, &nonconst_ge); + secp256k1_zkp_scalar_get_b32(msg32, &msg_s); + CHECK(should_verify == + secp256k1_zkp_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} + +void test_exhaustive_sign(const secp256k1_zkp_context *ctx, const secp256k1_zkp_ge *group, int order) { + int i, j, k; + + /* Loop */ + for (i = 1; i < order; i++) { /* message */ + for (j = 1; j < order; j++) { /* key */ + for (k = 1; k < order; k++) { /* nonce */ + const int starting_k = k; + secp256k1_zkp_ecdsa_signature sig; + secp256k1_zkp_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + secp256k1_zkp_scalar_set_int(&msg, i); + secp256k1_zkp_scalar_set_int(&sk, j); + secp256k1_zkp_scalar_get_b32(sk32, &sk); + secp256k1_zkp_scalar_get_b32(msg32, &msg); + + secp256k1_zkp_ecdsa_sign(ctx, &sig, msg32, sk32, secp256k1_zkp_nonce_function_smallint, &k); + + secp256k1_zkp_ecdsa_signature_load(ctx, &r, &s, &sig); + /* Note that we compute expected_r *after* signing -- this is important + * because our nonce-computing function function might change k during + * signing. */ + r_from_k(&expected_r, group, k); + CHECK(r == expected_r); + CHECK((k * s) % order == (i + r * j) % order || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + + /* Overflow means we've tried every possible nonce */ + if (k < starting_k) { + break; + } + } + } + } + + /* We would like to verify zero-knowledge here by counting how often every + * possible (s, r) tuple appears, but because the group order is larger + * than the field order, when coercing the x-values to scalar values, some + * appear more often than others, so we are actually not zero-knowledge. + * (This effect also appears in the real code, but the difference is on the + * order of 1/2^128th the field order, so the deviation is not useful to a + * computationally bounded attacker.) + */ +} + +#ifdef ENABLE_MODULE_RECOVERY +void test_exhaustive_recovery_sign(const secp256k1_zkp_context *ctx, const secp256k1_zkp_ge *group, int order) { + int i, j, k; + + /* Loop */ + for (i = 1; i < order; i++) { /* message */ + for (j = 1; j < order; j++) { /* key */ + for (k = 1; k < order; k++) { /* nonce */ + const int starting_k = k; + secp256k1_zkp_fe r_dot_y_normalized; + secp256k1_zkp_ecdsa_recoverable_signature rsig; + secp256k1_zkp_ecdsa_signature sig; + secp256k1_zkp_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + int expected_recid; + int recid; + secp256k1_zkp_scalar_set_int(&msg, i); + secp256k1_zkp_scalar_set_int(&sk, j); + secp256k1_zkp_scalar_get_b32(sk32, &sk); + secp256k1_zkp_scalar_get_b32(msg32, &msg); + + secp256k1_zkp_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_zkp_nonce_function_smallint, &k); + + /* Check directly */ + secp256k1_zkp_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig); + r_from_k(&expected_r, group, k); + CHECK(r == expected_r); + CHECK((k * s) % order == (i + r * j) % order || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + /* In computing the recid, there is an overflow condition that is disabled in + * scalar_low_impl.h `secp256k1_zkp_scalar_set_b32` because almost every r.y value + * will exceed the group order, and our signing code always holds out for r + * values that don't overflow, so with a proper overflow check the tests would + * loop indefinitely. */ + r_dot_y_normalized = group[k].y; + secp256k1_zkp_fe_normalize(&r_dot_y_normalized); + /* Also the recovery id is flipped depending if we hit the low-s branch */ + if ((k * s) % order == (i + r * j) % order) { + expected_recid = secp256k1_zkp_fe_is_odd(&r_dot_y_normalized) ? 1 : 0; + } else { + expected_recid = secp256k1_zkp_fe_is_odd(&r_dot_y_normalized) ? 0 : 1; + } + CHECK(recid == expected_recid); + + /* Convert to a standard sig then check */ + secp256k1_zkp_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + secp256k1_zkp_ecdsa_signature_load(ctx, &r, &s, &sig); + /* Note that we compute expected_r *after* signing -- this is important + * because our nonce-computing function function might change k during + * signing. */ + r_from_k(&expected_r, group, k); + CHECK(r == expected_r); + CHECK((k * s) % order == (i + r * j) % order || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + + /* Overflow means we've tried every possible nonce */ + if (k < starting_k) { + break; + } + } + } + } +} + +void test_exhaustive_recovery_verify(const secp256k1_zkp_context *ctx, const secp256k1_zkp_ge *group, int order) { + /* This is essentially a copy of test_exhaustive_verify, with recovery added */ + int s, r, msg, key; + for (s = 1; s < order; s++) { + for (r = 1; r < order; r++) { + for (msg = 1; msg < order; msg++) { + for (key = 1; key < order; key++) { + secp256k1_zkp_ge nonconst_ge; + secp256k1_zkp_ecdsa_recoverable_signature rsig; + secp256k1_zkp_ecdsa_signature sig; + secp256k1_zkp_pubkey pk; + secp256k1_zkp_scalar sk_s, msg_s, r_s, s_s; + secp256k1_zkp_scalar s_times_k_s, msg_plus_r_times_sk_s; + int recid = 0; + int k, should_verify; + unsigned char msg32[32]; + + secp256k1_zkp_scalar_set_int(&s_s, s); + secp256k1_zkp_scalar_set_int(&r_s, r); + secp256k1_zkp_scalar_set_int(&msg_s, msg); + secp256k1_zkp_scalar_set_int(&sk_s, key); + secp256k1_zkp_scalar_get_b32(msg32, &msg_s); + + /* Verify by hand */ + /* Run through every k value that gives us this r and check that *one* works. + * Note there could be none, there could be multiple, ECDSA is weird. */ + should_verify = 0; + for (k = 0; k < order; k++) { + secp256k1_zkp_scalar check_x_s; + r_from_k(&check_x_s, group, k); + if (r_s == check_x_s) { + secp256k1_zkp_scalar_set_int(&s_times_k_s, k); + secp256k1_zkp_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + secp256k1_zkp_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + secp256k1_zkp_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= secp256k1_zkp_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + } + } + /* nb we have a "high s" rule */ + should_verify &= !secp256k1_zkp_scalar_is_high(&s_s); + + /* We would like to try recovering the pubkey and checking that it matches, + * but pubkey recovery is impossible in the exhaustive tests (the reason + * being that there are 12 nonzero r values, 12 nonzero points, and no + * overlap between the sets, so there are no valid signatures). */ + + /* Verify by converting to a standard signature and calling verify */ + secp256k1_zkp_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); + secp256k1_zkp_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + secp256k1_zkp_pubkey_save(&pk, &nonconst_ge); + CHECK(should_verify == + secp256k1_zkp_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} +#endif + +int main(void) { + int i; + secp256k1_zkp_gej groupj[EXHAUSTIVE_TEST_ORDER]; + secp256k1_zkp_ge group[EXHAUSTIVE_TEST_ORDER]; + + /* Build context */ + secp256k1_zkp_context *ctx = secp256k1_zkp_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + /* TODO set z = 1, then do num_tests runs with random z values */ + + /* Generate the entire group */ + secp256k1_zkp_gej_set_infinity(&groupj[0]); + secp256k1_zkp_ge_set_gej(&group[0], &groupj[0]); + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + /* Set a different random z-value for each Jacobian point */ + secp256k1_zkp_fe z; + random_fe(&z); + + secp256k1_zkp_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_zkp_ge_const_g); + secp256k1_zkp_ge_set_gej(&group[i], &groupj[i]); + secp256k1_zkp_gej_rescale(&groupj[i], &z); + + /* Verify against ecmult_gen */ + { + secp256k1_zkp_scalar scalar_i; + secp256k1_zkp_gej generatedj; + secp256k1_zkp_ge generated; + + secp256k1_zkp_scalar_set_int(&scalar_i, i); + secp256k1_zkp_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); + secp256k1_zkp_ge_set_gej(&generated, &generatedj); + + CHECK(group[i].infinity == 0); + CHECK(generated.infinity == 0); + CHECK(secp256k1_zkp_fe_equal_var(&generated.x, &group[i].x)); + CHECK(secp256k1_zkp_fe_equal_var(&generated.y, &group[i].y)); + } + } + + /* Run the tests */ +#ifdef USE_ENDOMORPHISM + test_exhaustive_endomorphism(group, EXHAUSTIVE_TEST_ORDER); +#endif + test_exhaustive_addition(group, groupj, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_ecmult(ctx, group, groupj, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_ecmult_multi(ctx, group, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); + +#ifdef ENABLE_MODULE_RECOVERY + test_exhaustive_recovery_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_recovery_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); +#endif + + secp256k1_zkp_context_destroy(ctx); + return 0; +} + diff --git a/secp256k1-zkp-sys/depend/secp256k1-zkp/src/util.h b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/util.h new file mode 100644 index 00000000..76f9e047 --- /dev/null +++ b/secp256k1-zkp-sys/depend/secp256k1-zkp/src/util.h @@ -0,0 +1,188 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille, Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_UTIL_H +#define SECP256K1_UTIL_H + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include +#include +#include + +typedef struct { + void (*fn)(const char *text, void* data); + const void* data; +} secp256k1_zkp_callback; + +static SECP256K1_INLINE void secp256k1_zkp_callback_call(const secp256k1_zkp_callback * const cb, const char * const text) { + cb->fn(text, (void*)cb->data); +} + +#ifdef DETERMINISTIC +#define TEST_FAILURE(msg) do { \ + fprintf(stderr, "%s\n", msg); \ + abort(); \ +} while(0); +#else +#define TEST_FAILURE(msg) do { \ + fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, msg); \ + abort(); \ +} while(0) +#endif + +#ifdef HAVE_BUILTIN_EXPECT +#define EXPECT(x,c) __builtin_expect((x),(c)) +#else +#define EXPECT(x,c) (x) +#endif + +#ifdef DETERMINISTIC +#define CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + TEST_FAILURE("test condition failed"); \ + } \ +} while(0) +#else +#define CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + TEST_FAILURE("test condition failed: " #cond); \ + } \ +} while(0) +#endif + +/* Like assert(), but when VERIFY is defined, and side-effect safe. */ +#if defined(COVERAGE) +#define VERIFY_CHECK(check) +#define VERIFY_SETUP(stmt) +#elif defined(VERIFY) +#define VERIFY_CHECK CHECK +#define VERIFY_SETUP(stmt) do { stmt; } while(0) +#else +#define VERIFY_CHECK(cond) do { (void)(cond); } while(0) +#define VERIFY_SETUP(stmt) +#endif + +static SECP256K1_INLINE void *checked_malloc(const secp256k1_zkp_callback* cb, size_t size) { + void *ret = malloc(size); + if (ret == NULL) { + secp256k1_zkp_callback_call(cb, "Out of memory"); + } + return ret; +} + +static SECP256K1_INLINE void *checked_realloc(const secp256k1_zkp_callback* cb, void *ptr, size_t size) { + void *ret = realloc(ptr, size); + if (ret == NULL) { + secp256k1_zkp_callback_call(cb, "Out of memory"); + } + return ret; +} + +/* Extract the sign of an int64, take the abs and return a uint64, constant time. */ +SECP256K1_INLINE static int secp256k1_zkp_sign_and_abs64(uint64_t *out, int64_t in) { + uint64_t mask0, mask1; + int ret; + ret = in < 0; + mask0 = ret + ~((uint64_t)0); + mask1 = ~mask0; + *out = (uint64_t)in; + *out = (*out & mask0) | ((~*out + 1) & mask1); + return ret; +} + +SECP256K1_INLINE static int secp256k1_zkp_clz64_var(uint64_t x) { + int ret; + if (!x) { + return 64; + } +# if defined(HAVE_BUILTIN_CLZLL) + ret = __builtin_clzll(x); +# else + /*FIXME: debruijn fallback. */ + for (ret = 0; ((x & (1ULL << 63)) == 0); x <<= 1, ret++); +# endif + return ret; +} + +#if defined(__BIGGEST_ALIGNMENT__) +#define ALIGNMENT __BIGGEST_ALIGNMENT__ +#else +/* Using 16 bytes alignment because common architectures never have alignment + * requirements above 8 for any of the types we care about. In addition we + * leave some room because currently we don't care about a few bytes. */ +#define ALIGNMENT 16 +#endif + +#define ROUND_TO_ALIGN(size) (((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT) + +/* Assume there is a contiguous memory object with bounds [base, base + max_size) + * of which the memory range [base, *prealloc_ptr) is already allocated for usage, + * where *prealloc_ptr is an aligned pointer. In that setting, this functions + * reserves the subobject [*prealloc_ptr, *prealloc_ptr + alloc_size) of + * alloc_size bytes by increasing *prealloc_ptr accordingly, taking into account + * alignment requirements. + * + * The function returns an aligned pointer to the newly allocated subobject. + * + * This is useful for manual memory management: if we're simply given a block + * [base, base + max_size), the caller can use this function to allocate memory + * in this block and keep track of the current allocation state with *prealloc_ptr. + * + * It is VERIFY_CHECKed that there is enough space left in the memory object and + * *prealloc_ptr is aligned relative to base. + */ +static SECP256K1_INLINE void *manual_alloc(void** prealloc_ptr, size_t alloc_size, void* base, size_t max_size) { + size_t aligned_alloc_size = ROUND_TO_ALIGN(alloc_size); + void* ret; + VERIFY_CHECK(prealloc_ptr != NULL); + VERIFY_CHECK(*prealloc_ptr != NULL); + VERIFY_CHECK(base != NULL); + VERIFY_CHECK((unsigned char*)*prealloc_ptr >= (unsigned char*)base); + VERIFY_CHECK(((unsigned char*)*prealloc_ptr - (unsigned char*)base) % ALIGNMENT == 0); + VERIFY_CHECK((unsigned char*)*prealloc_ptr - (unsigned char*)base + aligned_alloc_size <= max_size); + ret = *prealloc_ptr; + *((unsigned char**)prealloc_ptr) += aligned_alloc_size; + return ret; +} + +/* Macro for restrict, when available and not in a VERIFY build. */ +#if defined(SECP256K1_BUILD) && defined(VERIFY) +# define SECP256K1_RESTRICT +#else +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(3,0) +# define SECP256K1_RESTRICT __restrict__ +# elif (defined(_MSC_VER) && _MSC_VER >= 1400) +# define SECP256K1_RESTRICT __restrict +# else +# define SECP256K1_RESTRICT +# endif +# else +# define SECP256K1_RESTRICT restrict +# endif +#endif + +#if defined(_WIN32) +# define I64FORMAT "I64d" +# define I64uFORMAT "I64u" +#else +# define I64FORMAT "lld" +# define I64uFORMAT "llu" +#endif + +#if defined(HAVE___INT128) +# if defined(__GNUC__) +# define SECP256K1_GNUC_EXT __extension__ +# else +# define SECP256K1_GNUC_EXT +# endif +SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; +#endif + +#endif /* SECP256K1_UTIL_H */ diff --git a/secp256k1-zkp-sys/src/ffi.rs b/secp256k1-zkp-sys/src/ffi.rs new file mode 100644 index 00000000..45beeeff --- /dev/null +++ b/secp256k1-zkp-sys/src/ffi.rs @@ -0,0 +1,30 @@ +// secp256k1-zkp bindings +// Written in 2019 by +// Jonas Nick +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! # FFI bindings +//! Direct bindings to the underlying C library functions. These should +//! not be needed for most users. +use secp256k1::ffi::Context; + +/// Opaque type for pointers to scratch spaces +pub enum ScratchSpace {} + +extern "C" { + pub fn secp256k1_zkp_scratch_space_create( + cx: *const Context, + max_size: usize, + ) -> *mut ScratchSpace; + + pub fn secp256k1_zkp_scratch_space_destroy(scratch: *mut ScratchSpace); +} diff --git a/secp256k1-zkp-sys/src/lib.rs b/secp256k1-zkp-sys/src/lib.rs new file mode 100644 index 00000000..36b03ee6 --- /dev/null +++ b/secp256k1-zkp-sys/src/lib.rs @@ -0,0 +1,128 @@ +// secp256k1-zkp bindings +// Written in 2019 by +// Jonas Nick +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! # Secp256k1-zkp +//! Rust bindings for the secp256k1-zkp library. + +#![crate_type = "lib"] +#![crate_type = "rlib"] +#![crate_type = "dylib"] +// Coding conventions +#![deny(non_upper_case_globals)] +#![deny(non_camel_case_types)] +#![deny(non_snake_case)] +#![deny(unused_mut)] +#![warn(missing_docs)] +#![cfg_attr(not(test), no_std)] +#![cfg_attr(feature = "dev", allow(unstable_features))] +#![cfg_attr(feature = "dev", feature(plugin))] +#![cfg_attr(feature = "dev", plugin(clippy))] + +#[cfg(any(test))] +pub extern crate rand; + +#[cfg(feature = "serde")] +pub extern crate serde; +#[cfg(all(feature = "serde", test))] +pub extern crate serde_test; + +#[cfg(test)] +extern crate core; +#[cfg(test)] +extern crate secp256k1_zkp_dev; + +pub extern crate secp256k1; + +#[macro_use] +mod macros; +pub mod ffi; +pub mod schnorrsig; +mod types; + +/// The purpose of this rewriteable structure is to replace dynamic memory allocations in the +/// libsecp256k1-zkp library. See its documentation for further information. +pub struct ScratchSpace { + scratch_space: *mut ffi::ScratchSpace, +} + +impl ScratchSpace { + /// Creates a new scratch space which can hold `max_size` bytges. + pub fn new(secp256k1: &secp256k1::Secp256k1, max_size: usize) -> ScratchSpace { + unsafe { + let space = ffi::secp256k1_zkp_scratch_space_create(*secp256k1.ctx(), max_size); + ScratchSpace { + scratch_space: space, + } + } + } + fn scratch_space(&self) -> *mut ffi::ScratchSpace { + self.scratch_space + } +} + +impl Drop for ScratchSpace { + fn drop(&mut self) { + unsafe { + ffi::secp256k1_zkp_scratch_space_destroy(self.scratch_space); + } + } +} + +unsafe impl Send for ScratchSpace {} +unsafe impl Sync for ScratchSpace {} + +/// Utility function used to parse hex into a target u8 buffer. Returns +/// the number of bytes converted or an error if it encounters an invalid +/// character or unexpected end of string. +fn from_hex(hex: &str, target: &mut [u8]) -> Result { + if hex.len() % 2 == 1 || hex.len() > target.len() * 2 { + return Err(()); + } + + let mut b = 0; + let mut idx = 0; + for c in hex.bytes() { + b <<= 4; + match c { + b'A'...b'F' => b |= c - b'A' + 10, + b'a'...b'f' => b |= c - b'a' + 10, + b'0'...b'9' => b |= c - b'0', + _ => return Err(()), + } + if (idx & 1) == 1 { + target[idx / 2] = b; + b = 0; + } + idx += 1; + } + Ok(idx / 2) +} + +#[cfg(test)] +mod tests { + use super::ScratchSpace; + use secp256k1::Secp256k1; + + #[test] + fn scratch_space() { + let s = Secp256k1::new(); + { + let scratch_space1 = ScratchSpace::new(&s, 0); + let scratch_space2 = ScratchSpace::new(&s, 100); + let _ = scratch_space1.scratch_space(); + let _ = scratch_space2.scratch_space(); + // drop + } + } +} diff --git a/secp256k1-zkp-sys/src/macros.rs b/secp256k1-zkp-sys/src/macros.rs new file mode 100644 index 00000000..1e951897 --- /dev/null +++ b/secp256k1-zkp-sys/src/macros.rs @@ -0,0 +1,148 @@ +// Bitcoin secp256k1 bindings +// Written in 2014 by +// Dawid Ciężarkiewicz +// Andrew Poelstra +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +// This is a macro that routinely comes in handy +macro_rules! impl_array_newtype { + ($thing:ident, $ty:ty, $len:expr) => { + impl Copy for $thing {} + + impl $thing { + #[inline] + /// Converts the object to a raw pointer for FFI interfacing + pub fn as_ptr(&self) -> *const $ty { + let &$thing(ref dat) = self; + dat.as_ptr() + } + + #[inline] + /// Converts the object to a mutable raw pointer for FFI interfacing + pub fn as_mut_ptr(&mut self) -> *mut $ty { + let &mut $thing(ref mut dat) = self; + dat.as_mut_ptr() + } + + #[inline] + /// Returns the length of the object as an array + pub fn len(&self) -> usize { + $len + } + + #[inline] + /// Returns whether the object as an array is empty + pub fn is_empty(&self) -> bool { + false + } + } + + impl PartialEq for $thing { + #[inline] + fn eq(&self, other: &$thing) -> bool { + &self[..] == &other[..] + } + } + + impl Eq for $thing {} + + impl PartialOrd for $thing { + #[inline] + fn partial_cmp(&self, other: &$thing) -> Option<::core::cmp::Ordering> { + self[..].partial_cmp(&other[..]) + } + } + + impl Ord for $thing { + #[inline] + fn cmp(&self, other: &$thing) -> ::core::cmp::Ordering { + self[..].cmp(&other[..]) + } + } + + impl Clone for $thing { + #[inline] + fn clone(&self) -> $thing { + unsafe { + use core::intrinsics::copy_nonoverlapping; + use core::mem; + let mut ret: $thing = mem::uninitialized(); + copy_nonoverlapping(self.as_ptr(), ret.as_mut_ptr(), $len); + ret + } + } + } + + impl ::core::ops::Index for $thing { + type Output = $ty; + + #[inline] + fn index(&self, index: usize) -> &$ty { + let &$thing(ref dat) = self; + &dat[index] + } + } + + impl ::core::ops::Index<::core::ops::Range> for $thing { + type Output = [$ty]; + + #[inline] + fn index(&self, index: ::core::ops::Range) -> &[$ty] { + let &$thing(ref dat) = self; + &dat[index] + } + } + + impl ::core::ops::Index<::core::ops::RangeTo> for $thing { + type Output = [$ty]; + + #[inline] + fn index(&self, index: ::core::ops::RangeTo) -> &[$ty] { + let &$thing(ref dat) = self; + &dat[index] + } + } + + impl ::core::ops::Index<::core::ops::RangeFrom> for $thing { + type Output = [$ty]; + + #[inline] + fn index(&self, index: ::core::ops::RangeFrom) -> &[$ty] { + let &$thing(ref dat) = self; + &dat[index] + } + } + + impl ::core::ops::Index<::core::ops::RangeFull> for $thing { + type Output = [$ty]; + + #[inline] + fn index(&self, _: ::core::ops::RangeFull) -> &[$ty] { + let &$thing(ref dat) = self; + &dat[..] + } + } + }; +} + +macro_rules! impl_raw_debug { + ($thing:ident) => { + impl ::core::fmt::Debug for $thing { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + for i in self[..].iter().cloned() { + try!(write!(f, "{:02x}", i)); + } + Ok(()) + } + } + }; +} diff --git a/secp256k1-zkp-sys/src/schnorrsig/ffi.rs b/secp256k1-zkp-sys/src/schnorrsig/ffi.rs new file mode 100644 index 00000000..a732518a --- /dev/null +++ b/secp256k1-zkp-sys/src/schnorrsig/ffi.rs @@ -0,0 +1,80 @@ +// secp256k1-zkp bindings +// Written in 2019 by +// Jonas Nick +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! # FFI bindings +//! Direct bindings to the underlying C library functions. These should +//! not be needed for most users. +use core::mem; + +use secp256k1::ffi::{Context, NonceFn, PublicKey}; + +use ffi::ScratchSpace; +use types::{c_int, c_uchar, c_void}; + +/// Library-internal representation of a Secp256k1 Schnorr signature +#[repr(C)] +pub struct SchnorrSignature([c_uchar; 64]); +impl_array_newtype!(SchnorrSignature, c_uchar, 64); +impl_raw_debug!(SchnorrSignature); + +impl SchnorrSignature { + /// Create a new (zeroed) signature usable for the FFI interface + pub fn new() -> SchnorrSignature { + SchnorrSignature([0; 64]) + } + /// Create a new (uninitialized) signature usable for the FFI interface + pub unsafe fn blank() -> SchnorrSignature { + mem::uninitialized() + } +} + +extern "C" { + pub fn secp256k1_zkp_schnorrsig_parse( + cx: *const Context, + sig: *mut SchnorrSignature, + in64: *const c_uchar, + ) -> c_int; + + pub fn secp256k1_zkp_schnorrsig_serialize( + cx: *const Context, + out64: *mut c_uchar, + sig: *const SchnorrSignature, + ) -> c_int; + + pub fn secp256k1_zkp_schnorrsig_sign( + cx: *const Context, + sig: *mut SchnorrSignature, + nonce_is_negated: *mut c_int, + msg32: *const c_uchar, + sk: *const c_uchar, + noncefn: NonceFn, + noncedata: *mut c_void, + ) -> c_int; + + pub fn secp256k1_zkp_schnorrsig_verify( + cx: *const Context, + sig: *const SchnorrSignature, + msg32: *const c_uchar, + pk: *const PublicKey, + ) -> c_int; + + pub fn secp256k1_zkp_schnorrsig_verify_batch( + cx: *const Context, + scratch: *mut ScratchSpace, + sig: *const *const SchnorrSignature, + msg32: *const *const c_uchar, + pk: *const *const PublicKey, + n_sigs: usize, + ) -> c_int; +} diff --git a/secp256k1-zkp-sys/src/schnorrsig/mod.rs b/secp256k1-zkp-sys/src/schnorrsig/mod.rs new file mode 100644 index 00000000..e918ef36 --- /dev/null +++ b/secp256k1-zkp-sys/src/schnorrsig/mod.rs @@ -0,0 +1,420 @@ +// secp256k1-zkp bindings +// Written in 2019 by +// Jonas Nick +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! # Schnorrsig +//! Support for bip-schnorr compliant signatures +//! + +mod ffi; + +use core::{fmt, ptr, str}; + +use secp256k1::key::{PublicKey, SecretKey}; +use secp256k1::{self, Message, Secp256k1, Signing, Verification}; + +use super::{from_hex, ScratchSpace}; + +/// A Schnorrsig error. This does not implement `std:error::Error` because it's not available with +/// `no_std`. +#[derive(Copy, PartialEq, Eq, Clone, Debug)] +pub enum Error { + /// Signature failed verification + IncorrectSignature, + /// Malformed signature + InvalidSignature, + /// Batch verification arguments don't have same size + ArgumentLength, + /// Too many signatures for batch verification + TooManySignatures, +} + +impl Error { + /// Convert error into string + pub fn as_str(&self) -> &str { + match *self { + Error::IncorrectSignature => "secp schnorrisg: signature failed verification", + Error::InvalidSignature => "secp schnorrsig: malformed signature", + Error::ArgumentLength => { + "secp schnorrsig: batch verification arguments don't have same size" + } + Error::TooManySignatures => "secp schnorrsig: too many signatures for verification", + } + } +} + +// Passthrough Debug to Display, since errors should be user-visible +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + f.write_str(self.as_str()) + } +} + +/// A Schnorr signature +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Signature(ffi::SchnorrSignature); +impl Signature { + #[inline] + /// Converts a byte slice to a signature + pub fn parse(data: &[u8]) -> Result { + if data.len() != 64 { + return Err(Error::InvalidSignature); + } + let mut ret = unsafe { ffi::SchnorrSignature::blank() }; + unsafe { + if ffi::secp256k1_zkp_schnorrsig_parse( + secp256k1::ffi::secp256k1_context_no_precomp, + &mut ret, + data.as_ptr(), + ) == 1 + { + Ok(Signature(ret)) + } else { + Err(Error::InvalidSignature) + } + } + } + + #[inline] + /// Serializes the signature in compact format + pub fn serialize(&self) -> [u8; 64] { + let mut ret = [0; 64]; + unsafe { + let err = ffi::secp256k1_zkp_schnorrsig_serialize( + secp256k1::ffi::secp256k1_context_no_precomp, + ret.as_mut_ptr(), + self.as_ptr(), + ); + debug_assert!(err == 1); + } + ret + } + + /// Obtains a raw pointer suitable for use with FFI functions + #[inline] + pub fn as_ptr(&self) -> *const ffi::SchnorrSignature { + &self.0 as *const _ + } + + /// Obtains a raw mutable pointer suitable for use with FFI functions + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut ffi::SchnorrSignature { + &mut self.0 as *mut _ + } +} + +/// Creates a new signature from a FFI signature +impl From for Signature { + #[inline] + fn from(sig: ffi::SchnorrSignature) -> Signature { + Signature(sig) + } +} + +impl fmt::Debug for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +impl fmt::Display for Signature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let v = self.serialize(); + for ch in &v[..] { + write!(f, "{:02x}", *ch)?; + } + Ok(()) + } +} + +impl str::FromStr for Signature { + type Err = Error; + fn from_str(s: &str) -> Result { + let mut res = [0; 64]; + if s.len() != 64 * 2 { + return Err(Error::InvalidSignature); + } + match from_hex(s, &mut res) { + Ok(x) => Signature::parse(&res[0..x]), + _ => Err(Error::InvalidSignature), + } + } +} + +#[cfg(feature = "serde")] +impl ::serde::Serialize for Signature { + fn serialize(&self, s: S) -> Result { + s.serialize_bytes(&self.serialize()) + } +} + +#[cfg(feature = "serde")] +impl<'de> ::serde::Deserialize<'de> for Signature { + fn deserialize>(d: D) -> Result { + use serde::de::Error; + + let sl: &[u8] = ::serde::Deserialize::deserialize(d)?; + Signature::parse(sl).map_err(D::Error::custom) + } +} + +/// Schnorrsig signing trait +pub trait Sign { + /// Creates a Schnorr signature as defined by BIP-schnorr from a message and a secret key. + fn schnorrsig_sign(&self, msg: &Message, sk: &SecretKey) -> Signature; +} + +/// Schnorrsig verification trait +pub trait Verify { + /// Verifies a Schnorr signature `sig` for `msg` using the public key `pubkey` as defined by + /// BIP-schnorr. + fn schnorrsig_verify( + &self, + msg: &Message, + sig: &Signature, + pk: &PublicKey, + ) -> Result<(), Error>; + /// Takes slices of pointers to messages, Schnorr signatures and public keys and verifies them + /// all at once. That's faster than if they would have been verified one by one. Returns an + /// Error if a single Signature fails verification. + fn schnorrsig_verify_batch( + &self, + scratch_space: &ScratchSpace, + msgs: &[*const Message], + sigs: &[*const Signature], + pks: &[*const PublicKey], + ) -> Result<(), Error>; +} + +impl Sign for Secp256k1 { + fn schnorrsig_sign(&self, msg: &Message, sk: &SecretKey) -> Signature { + let mut ret = unsafe { ffi::SchnorrSignature::blank() }; + unsafe { + // We can assume the return value because it's not possible to construct + // an invalid signature from a valid `Message` and `SecretKey` + assert_eq!( + ffi::secp256k1_zkp_schnorrsig_sign( + *self.ctx(), + &mut ret, + ptr::null_mut(), + msg.as_ptr(), + sk.as_ptr(), + secp256k1::ffi::secp256k1_nonce_function_rfc6979, + ptr::null_mut() + ), + 1 + ); + } + Signature::from(ret) + } +} + +impl Verify for Secp256k1 { + #[inline] + fn schnorrsig_verify( + &self, + msg: &Message, + sig: &Signature, + pk: &PublicKey, + ) -> Result<(), Error> { + unsafe { + if ffi::secp256k1_zkp_schnorrsig_verify( + *self.ctx(), + sig.as_ptr(), + msg.as_ptr(), + pk.as_ptr(), + ) == 0 + { + Err(Error::IncorrectSignature) + } else { + Ok(()) + } + } + } + + fn schnorrsig_verify_batch( + &self, + scratch_space: &ScratchSpace, + msgs: &[*const Message], + sigs: &[*const Signature], + pks: &[*const PublicKey], + ) -> Result<(), Error> { + if msgs.len() != sigs.len() || msgs.len() != pks.len() { + return Err(Error::ArgumentLength); + } + if sigs.len() >= 1 << 31 { + return Err(Error::TooManySignatures); + } + unsafe { + let result = ffi::secp256k1_zkp_schnorrsig_verify_batch( + *self.ctx(), + scratch_space.scratch_space(), + sigs.as_ptr() as *const *const ffi::SchnorrSignature, + msgs.as_ptr() as *const *const u8, + pks.as_ptr() as *const *const secp256k1::ffi::PublicKey, + sigs.len(), + ); + if result == 0 { + Err(Error::IncorrectSignature) + } else { + Ok(()) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::{Error, ScratchSpace, Sign, Signature, Verify}; + use core::str::FromStr; + use rand::{thread_rng, RngCore}; + use secp256k1::{Message, Secp256k1}; + use secp256k1_zkp_dev::GenerateKeypair; + + #[test] + fn serialization_roundtrip() { + let ser_sig = [ + 0x78, 0x7A, 0x84, 0x8E, 0x71, 0x04, 0x3D, 0x28, 0x0C, 0x50, 0x47, 0x0E, 0x8E, 0x15, + 0x32, 0xB2, 0xDD, 0x5D, 0x20, 0xEE, 0x91, 0x2A, 0x45, 0xDB, 0xDD, 0x2B, 0xD1, 0xDF, + 0xBF, 0x18, 0x7E, 0xF6, 0x70, 0x31, 0xA9, 0x88, 0x31, 0x85, 0x9D, 0xC3, 0x4D, 0xFF, + 0xEE, 0xDD, 0xA8, 0x68, 0x31, 0x84, 0x2C, 0xCD, 0x00, 0x79, 0xE1, 0xF9, 0x2A, 0xF1, + 0x77, 0xF7, 0xF2, 0x2C, 0xC1, 0xDC, 0xED, 0x05, + ]; + let sig = Signature::parse(&ser_sig).unwrap(); + let ser_sig2 = Signature::serialize(&sig); + assert_eq!(ser_sig.to_vec(), ser_sig2.to_vec()); + + // Parsing sig where first 32 bytes are not X-coordinate on the curve + let ser_sig = [ + 0x4A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A, 0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, + 0x1D, 0xCB, 0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7, 0x0A, 0x74, 0xF8, 0x22, + 0x04, 0x29, 0xBA, 0x1D, 0x1E, 0x51, 0xA2, 0x2C, 0xCE, 0xC3, 0x55, 0x99, 0xB8, 0xF2, + 0x66, 0x91, 0x22, 0x81, 0xF8, 0x36, 0x5F, 0xFC, 0x2D, 0x03, 0x5A, 0x23, 0x04, 0x34, + 0xA1, 0xA6, 0x4D, 0xC5, 0x9F, 0x70, 0x13, 0xFD, + ]; + // Shouldn't return error right now + let sig = Signature::parse(&ser_sig).unwrap(); + // Parsing wrong number of bytes results in Error + assert_eq!(Signature::parse(&[]), Err(Error::InvalidSignature)); + + let hex_sig = format!("{}", sig); + assert_eq!(sig, Signature::from_str(&hex_sig).unwrap()); + let hex_sig = ""; + assert_eq!(Signature::from_str(&hex_sig), Err(Error::InvalidSignature)); + let hex_sig = "x"; + assert_eq!(Signature::from_str(&hex_sig), Err(Error::InvalidSignature)); + } + + #[cfg(feature = "serde")] + #[test] + fn test_signature_serde() { + use secp256k1::SecretKey; + use serde_test::{assert_tokens, Token}; + + let s = Secp256k1::new(); + + let msg = Message::from_slice(&[1; 32]).unwrap(); + let sk = SecretKey::from_slice(&[2; 32]).unwrap(); + let sig = s.schnorrsig_sign(&msg, &sk); + static SIG_BYTES: [u8; 64] = [ + 0x9D, 0x0B, 0xAD, 0x57, 0x67, 0x19, 0xD3, 0x2A, 0xE7, 0x6B, 0xED, 0xB3, 0x4C, 0x77, + 0x48, 0x66, 0x67, 0x3C, 0xBD, 0xE3, 0xF4, 0xE1, 0x29, 0x51, 0x55, 0x5C, 0x94, 0x08, + 0xE6, 0xCE, 0x77, 0x4B, 0xA2, 0x9B, 0x2E, 0x41, 0x74, 0x30, 0x82, 0x17, 0x1E, 0x35, + 0xD5, 0x63, 0xC9, 0x9D, 0x0F, 0xCE, 0xB6, 0xC4, 0x0B, 0x9A, 0xC2, 0x80, 0x77, 0x33, + 0x59, 0xE7, 0xB5, 0x6C, 0x09, 0x41, 0x8D, 0x6D, + ]; + assert_tokens(&sig, &[Token::BorrowedBytes(&SIG_BYTES[..])]); + } + + #[test] + fn sign_and_verify() { + let s = Secp256k1::new(); + let scratch_space = ScratchSpace::new(&s, 8192); + + let mut msg = [0; 32]; + for _ in 0..100 { + thread_rng().fill_bytes(&mut msg); + let msg = Message::from_slice(&msg).unwrap(); + + let (sk, pk) = s.generate_keypair(&mut thread_rng()); + let sig = s.schnorrsig_sign(&msg, &sk); + assert_eq!(s.schnorrsig_verify(&msg, &sig, &pk), Ok(())); + + let msgptr = &msg as *const _; + let sigptr = &sig as *const _; + let pkptr = &pk as *const _; + assert_eq!( + s.schnorrsig_verify_batch(&scratch_space, &[msgptr], &[sigptr], &[pkptr]), + Ok(()) + ); + + // Verifying signature under different public key should fail + let (_, pk) = s.generate_keypair(&mut thread_rng()); + let pkptr = &pk as *const _; + assert_eq!( + s.schnorrsig_verify(&msg, &sig, &pk), + Err(Error::IncorrectSignature) + ); + assert_eq!( + s.schnorrsig_verify_batch(&scratch_space, &[msgptr], &[sigptr], &[pkptr]), + Err(Error::IncorrectSignature) + ); + } + } + + #[test] + fn batch_verify() { + const N: usize = 100; + let s = Secp256k1::new(); + let scratch_space = ScratchSpace::new(&s, 8192); + + // Test empty input + assert_eq!( + s.schnorrsig_verify_batch(&scratch_space, &[], &[], &[]), + Ok(()) + ); + + // Test that batch verification succeeds with N signatures + let mut msgs = vec![]; + let mut pks = vec![]; + let mut sigs = vec![]; + for _ in 0..N { + let mut msg = [0; 32]; + thread_rng().fill_bytes(&mut msg); + let msg = Message::from_slice(&msg).unwrap(); + + let (sk, pk) = s.generate_keypair(&mut thread_rng()); + let sig = s.schnorrsig_sign(&msg, &sk); + msgs.push(&msg as *const _); + pks.push(&pk as *const _); + sigs.push(&sig as *const _); + } + assert_eq!( + s.schnorrsig_verify_batch(&scratch_space, &msgs, &sigs, &pks), + Ok(()) + ); + + // Test that changing a single message makes batch verification fail + for i in 0..N { + let mut msgs_tmp = msgs.clone(); + let mut msg = [0; 32]; + thread_rng().fill_bytes(&mut msg); + let msg = Message::from_slice(&msg).unwrap(); + msgs_tmp[i] = &msg as *const _; + assert_eq!( + s.schnorrsig_verify_batch(&scratch_space, &msgs_tmp, &sigs, &pks), + Err(Error::IncorrectSignature) + ); + } + } +} diff --git a/secp256k1-zkp-sys/src/types.rs b/secp256k1-zkp-sys/src/types.rs new file mode 100644 index 00000000..26b213e3 --- /dev/null +++ b/secp256k1-zkp-sys/src/types.rs @@ -0,0 +1,24 @@ +#![allow(non_camel_case_types)] + +use core::fmt; + +pub type c_int = i32; +pub type c_uchar = u8; + +/// This is an exact copy of https://doc.rust-lang.org/core/ffi/enum.c_void.html +/// It should be Equivalent to C's void type when used as a pointer. +/// +/// We can replace this with `core::ffi::c_void` once we update the rustc version to >=1.30.0. +#[repr(u8)] +pub enum c_void { + #[doc(hidden)] + __variant1, + #[doc(hidden)] + __variant2, +} + +impl fmt::Debug for c_void { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("c_void") + } +} diff --git a/secp256k1-zkp/Cargo.toml b/secp256k1-zkp/Cargo.toml new file mode 100644 index 00000000..67bc23f1 --- /dev/null +++ b/secp256k1-zkp/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "secp256k1-zkp" +version = "0.1.0" +authors = ["Jonas Nick "] + +license = "CC0-1.0" +homepage = "https://github.com/ElementsProject/rust-secp256k1-zkp/" +repository = "https://github.com/ElementsProject/rust-secp256k1-zkp/" +description = "Rust bindings for the Elements Project's `libsecp256k1-zkp` library. Implements various cryptographic schemes for the SECG elliptic curve group secp256k1 and related utilities. Based on the lower-level, no_std secp256k1-zkp-sys library." +keywords = [ "crypto", "ECDSA", "Schnorr", "secp256k1", "libsecp256k1", "secp256k1-zkp", "libsecp256k1-zkp", "bitcoin" ] +readme = "README.md" + +[features] +serde = ["secp256k1-zkp-sys/serde"] + +[dev-dependencies] +rand = "0.6" + +[dev-dependencies.secp256k1-zkp-dev] +version = "0.1" +path = "../secp256k1-zkp-dev/" + +[dependencies.secp256k1] +version = "0.13" + +[dependencies.secp256k1-zkp-sys] +version = "0.1" +path = "../secp256k1-zkp-sys/" diff --git a/secp256k1-zkp/src/lib.rs b/secp256k1-zkp/src/lib.rs new file mode 100644 index 00000000..d2c23860 --- /dev/null +++ b/secp256k1-zkp/src/lib.rs @@ -0,0 +1,40 @@ +// secp256k1-zkp bindings +// Written in 2019 by +// Jonas Nick +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! # Secp256k1-zkp +//! Rust bindings for the secp256k1-zkp library. + +#![crate_type = "rlib"] +#![crate_type = "dylib"] +// Coding conventions +#![deny(non_upper_case_globals)] +#![deny(non_camel_case_types)] +#![deny(non_snake_case)] +#![deny(unused_mut)] +#![warn(missing_docs)] +#![cfg_attr(feature = "dev", allow(unstable_features))] +#![cfg_attr(feature = "dev", feature(plugin))] +#![cfg_attr(feature = "dev", plugin(clippy))] + +#[cfg(any(test, feature = "rand"))] +pub extern crate rand; +#[cfg(test)] +extern crate secp256k1_zkp_dev; + +pub extern crate secp256k1; +pub extern crate secp256k1_zkp_sys; + +extern crate core; + +pub mod schnorrsig; diff --git a/secp256k1-zkp/src/schnorrsig/mod.rs b/secp256k1-zkp/src/schnorrsig/mod.rs new file mode 100644 index 00000000..63cd7ad6 --- /dev/null +++ b/secp256k1-zkp/src/schnorrsig/mod.rs @@ -0,0 +1,158 @@ +// secp256k1-zkp bindings +// Written in 2019 by +// Jonas Nick +// +// To the extent possible under law, the author(s) have dedicated all +// copyright and related and neighboring rights to this software to +// the public domain worldwide. This software is distributed without +// any warranty. +// +// You should have received a copy of the CC0 Public Domain Dedication +// along with this software. +// If not, see . +// + +//! # Schnorrsig +//! Support for bip-schnorr compliant signatures +//! + +use std::{error, fmt}; + +use secp256k1::key::PublicKey; +use secp256k1::{Message, Secp256k1, Verification}; + +use secp256k1_zkp_sys::schnorrsig as schnorrsig_sys; + +pub use secp256k1_zkp_sys::schnorrsig::Error as SysError; +pub use secp256k1_zkp_sys::schnorrsig::Sign; +pub use secp256k1_zkp_sys::ScratchSpace; + +#[derive(Copy, PartialEq, Eq, Clone, Debug)] +/// A schnorrsig error +pub enum Error { + /// Error from the underlying secp256k_zkp_sys library. + SysError(schnorrsig_sys::Error), +} + +impl error::Error for Error { + fn cause(&self) -> Option<&error::Error> { + None + } + + fn description(&self) -> &str { + match *self { + Error::SysError(ref e) => e.as_str(), + } + } +} + +impl From for Error { + fn from(err: schnorrsig_sys::Error) -> Self { + Error::SysError(err) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + Error::SysError(e) => f.write_str(e.as_str()), + } + } +} + +type Signature = schnorrsig_sys::Signature; + +/// Schnorrsig verification trait +pub trait Verify { + /// Verifies a Schnorr signature as defined by BIP-schnorr + fn schnorrsig_verify( + &self, + msg: &Message, + sig: &Signature, + pk: &PublicKey, + ) -> Result<(), Error>; + + /// Takes slices of messages, Schnorr signatures and public keys and verifies them all at once. + /// That's faster than if they would have been verified one by one. Returns an Error if a + /// single Signature fails verification. If the scratch space is not provided, this function + /// will create a scratch space on its own of size 8192 bytes. + fn schnorrsig_verify_batch( + &self, + scratch_space: Option, + msgs: &[Message], + sigs: &[Signature], + pks: &[PublicKey], + ) -> Result<(), Error>; +} + +impl Verify for Secp256k1 { + fn schnorrsig_verify( + &self, + msg: &Message, + sig: &Signature, + pk: &PublicKey, + ) -> Result<(), Error> { + schnorrsig_sys::Verify::schnorrsig_verify(self, msg, sig, pk).map_err(|e| e.into()) + } + fn schnorrsig_verify_batch( + &self, + scratch_space: Option, + msgs: &[Message], + sigs: &[Signature], + pks: &[PublicKey], + ) -> Result<(), Error> { + if msgs.len() != sigs.len() || msgs.len() != pks.len() { + return Err(schnorrsig_sys::Error::ArgumentLength.into()); + } + let scratch_space = scratch_space.unwrap_or(ScratchSpace::new(self, 8192)); + let n = msgs.len(); + let mut msgptrs = Vec::with_capacity(n); + let mut sigptrs = Vec::with_capacity(n); + let mut pkptrs = Vec::with_capacity(n); + for i in 0..n { + msgptrs.push(msgs[i].as_ptr() as *const _); + sigptrs.push(&sigs[i] as *const _); + pkptrs.push(pks[i].as_ptr() as *const _); + } + schnorrsig_sys::Verify::schnorrsig_verify_batch( + self, + &scratch_space, + &msgptrs[..], + &sigptrs[..], + &pkptrs[..], + ) + .map_err(|e| e.into()) + } +} + +#[cfg(test)] +mod tests { + use super::{Sign, Signature, SysError, Verify}; + use rand::{thread_rng, RngCore}; + use secp256k1::{Message, Secp256k1}; + use secp256k1_zkp_dev::GenerateKeypair; + + #[test] + fn sign_and_verify() { + let s = Secp256k1::new(); + + let mut msg = [0; 32]; + for _ in 0..100 { + thread_rng().fill_bytes(&mut msg); + let msg = Message::from_slice(&msg).unwrap(); + + let (sk, pk) = s.generate_keypair(&mut thread_rng()); + let sig = s.schnorrsig_sign(&msg, &sk); + Signature::serialize(&sig); + assert_eq!(s.schnorrsig_verify(&msg, &sig, &pk), Ok(())); + assert_eq!( + s.schnorrsig_verify_batch(None, &[msg], &[sig], &[pk]), + Ok(()) + ); + assert_eq!( + s.schnorrsig_verify_batch(None, &[msg], &[], &[pk]), + Err(SysError::ArgumentLength.into()) + ); + } + } +}