diff --git a/Cargo.toml b/Cargo.toml index 6675cc3..7ea24d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ unstable = [] default = [] bullet-proof-sizing = [] dev = ["clippy"] +lowmemory = [] [dependencies] arrayvec = "0.3" diff --git a/build.rs b/build.rs index b82a7a2..287d515 100644 --- a/build.rs +++ b/build.rs @@ -21,21 +21,39 @@ #![deny(unused_mut)] #![warn(missing_docs)] +use std::env; fn main() { + if cfg!(feature = "external-symbols") { + println!("cargo:rustc-link-lib=static=secp256k1-zkp"); + return; + } + + // 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") - .flag("-g") + .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")) - // TODO these should use 64-bit variants on 64-bit systems - .define("USE_FIELD_10X26", Some("1")) - .define("USE_SCALAR_8X32", Some("1")) .define("USE_ENDOMORPHISM", Some("1")) - // These all are OK. .define("ENABLE_MODULE_ECDH", Some("1")) .define("ENABLE_MODULE_GENERATOR", Some("1")) .define("ENABLE_MODULE_RECOVERY", Some("1")) @@ -44,6 +62,27 @@ fn main() { .define("ENABLE_MODULE_AGGSIG", Some("1")) .define("ENABLE_MODULE_SCHNORRSIG", Some("1")); + if cfg!(feature = "lowmemory") { + base_config.define("ECMULT_WINDOW_SIZE", Some("4")); // A low-enough value to consume neglible memory + } else { + base_config.define("ECMULT_WINDOW_SIZE", Some("15")); // This is the default in the configure file (`auto`) + } + + 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-zkp base_config.file("depend/secp256k1-zkp/contrib/lax_der_parsing.c") .file("depend/secp256k1-zkp/src/secp256k1.c") diff --git a/depend/check_uint128_t.c b/depend/check_uint128_t.c new file mode 100644 index 0000000..4d90955 --- /dev/null +++ b/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/src/ecdh.rs b/src/ecdh.rs index 0b01113..da9e0cc 100644 --- a/src/ecdh.rs +++ b/src/ecdh.rs @@ -120,10 +120,9 @@ mod benches { #[bench] pub fn bench_ecdh(bh: &mut Bencher) { - let s = Secp256k1::with_caps(::ContextFlag::SignOnly); + let s = Secp256k1::new(); let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap(); - let s = Secp256k1::new(); bh.iter( || { let res = SharedSecret::new(&s, &pk, &sk); black_box(res); diff --git a/src/lib.rs b/src/lib.rs index d8486d5..5aa2f21 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1050,20 +1050,40 @@ mod tests { } } + #[cfg(all(test, feature = "unstable"))] mod benches { - use rand::{Rng, thread_rng}; + use rand::{thread_rng, RngCore}; use test::{Bencher, black_box}; use super::{Secp256k1, Message}; #[bench] pub fn generate(bh: &mut Bencher) { - struct CounterRng(u32); - impl Rng for CounterRng { - fn next_u32(&mut self) -> u32 { self.0 += 1; self.0 } + struct CounterRng(u64); + impl RngCore for CounterRng { + fn next_u32(&mut self) -> u32 { + self.next_u64() as u32 + } + + fn next_u64(&mut self) -> u64 { + self.0 += 1; + self.0 + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + for chunk in dest.chunks_mut(64/8) { + let rand: [u8; 64/8] = unsafe {std::mem::transmute(self.next_u64())}; + chunk.copy_from_slice(&rand[..chunk.len()]); + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { + Ok(self.fill_bytes(dest)) + } } + let s = Secp256k1::new(); let mut r = CounterRng(0); bh.iter( || { @@ -1077,12 +1097,12 @@ mod benches { pub fn bench_sign(bh: &mut Bencher) { let s = Secp256k1::new(); let mut msg = [0u8; 32]; - thread_rng().fill(&mut msg); + thread_rng().fill_bytes(&mut msg); let msg = Message::from_slice(&msg).unwrap(); let (sk, _) = s.generate_keypair(&mut thread_rng()).unwrap(); bh.iter(|| { - let sig = s.sign(&msg, &sk).unwrap(); + let sig = s.sign(&msg, &sk); black_box(sig); }); } @@ -1091,7 +1111,7 @@ mod benches { pub fn bench_verify(bh: &mut Bencher) { let s = Secp256k1::new(); let mut msg = [0u8; 32]; - thread_rng().fill(&mut msg); + thread_rng().fill_bytes(&mut msg); let msg = Message::from_slice(&msg).unwrap(); let (sk, pk) = s.generate_keypair(&mut thread_rng()).unwrap(); let sig = s.sign(&msg, &sk).unwrap(); @@ -1101,19 +1121,4 @@ mod benches { black_box(res); }); } - - #[bench] - pub fn bench_recover(bh: &mut Bencher) { - let s = Secp256k1::new(); - let mut msg = [0u8; 32]; - thread_rng().fill(&mut msg); - let msg = Message::from_slice(&msg).unwrap(); - let (sk, _) = s.generate_keypair(&mut thread_rng()).unwrap(); - let sig = s.sign_recoverable(&msg, &sk).unwrap(); - - bh.iter(|| { - let res = s.recover(&msg, &sig).unwrap(); - black_box(res); - }); - } } diff --git a/src/pedersen.rs b/src/pedersen.rs index aa7adb4..654178f 100644 --- a/src/pedersen.rs +++ b/src/pedersen.rs @@ -2026,3 +2026,31 @@ mod tests { assert_eq!(errs, 0); } } + + + + +#[cfg(all(test, feature = "unstable"))] +mod benches { + use rand::thread_rng; + use test::{Bencher, black_box}; + use super::{ContextFlag, SecretKey, Secp256k1}; + + #[bench] + pub fn bench_bullet_proof_verification(bh: &mut Bencher) { + // Test Bulletproofs without message + let secp = Secp256k1::with_caps(ContextFlag::Commit); + let blinding = SecretKey::new(&secp, &mut thread_rng()); + let value = 12345678; + let commit = secp.commit(value, blinding.clone()).unwrap(); + let bullet_proof = secp.bullet_proof(value, blinding.clone(), blinding.clone(), blinding.clone(), None, None); + bh.iter( || { + let proof_range = secp.verify_bullet_proof(commit, bullet_proof, None).unwrap(); + assert_eq!(proof_range.min, 0); + }); + } +} + + + +