From c1656f7660d84da2fff7116382c0bb3ec0a69e7b Mon Sep 17 00:00:00 2001 From: AntiochP <30642645+antiochp@users.noreply.github.com> Date: Thu, 9 Nov 2017 14:26:45 -0500 Subject: [PATCH] use the static secp instance everywhere (except the wallet) (#250) --- chain/src/pipe.rs | 4 +- core/src/core/block.rs | 72 +++++++++++++++++++++--------------- core/src/core/build.rs | 12 ++++-- core/src/core/mod.rs | 49 +++++++++++++----------- core/src/core/transaction.rs | 27 +++++++++----- grin/src/miner.rs | 4 +- keychain/src/keychain.rs | 4 +- pool/src/pool.rs | 4 +- wallet/src/receiver.rs | 2 +- wallet/src/sender.rs | 2 +- 10 files changed, 102 insertions(+), 78 deletions(-) diff --git a/chain/src/pipe.rs b/chain/src/pipe.rs index f24bf6b12..2e8e04c85 100644 --- a/chain/src/pipe.rs +++ b/chain/src/pipe.rs @@ -16,7 +16,6 @@ use std::sync::{Arc, RwLock}; -use util::secp; use time; use core::consensus; @@ -209,8 +208,7 @@ fn validate_block( } // main isolated block validation, checks all commitment sums and sigs - let curve = secp::Secp256k1::with_caps(secp::ContextFlag::Commit); - try!(b.validate(&curve).map_err(&Error::InvalidBlockProof)); + try!(b.validate().map_err(&Error::InvalidBlockProof)); // apply the new block to the MMR trees and check the new root hashes if b.header.previous == ctx.head.last_block_h { diff --git a/core/src/core/block.rs b/core/src/core/block.rs index 0cd9ff149..f62900f2c 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -16,7 +16,7 @@ use time; use util; -use util::secp::{self, Secp256k1}; +use util::{secp, static_secp_instance}; use std::collections::HashSet; use core::Committed; @@ -299,8 +299,6 @@ impl Block { reward_out: Output, reward_kern: TxKernel, ) -> Result { - let secp = Secp256k1::with_caps(secp::ContextFlag::Commit); - let mut kernels = vec![]; let mut inputs = vec![]; let mut outputs = vec![]; @@ -311,7 +309,7 @@ impl Block { // to build the block (which we can sort of think of as one big tx?) for tx in txs { // validate each transaction and gather their kernels - let excess = tx.validate(&secp)?; + let excess = tx.validate()?; let kernel = tx.build_kernel(excess); kernels.push(kernel); @@ -333,7 +331,7 @@ impl Block { outputs.sort(); kernels.sort(); - // calculate the overall Merkle tree and fees + // calculate the overall Merkle tree and fees (todo?) Ok( Block { @@ -447,19 +445,19 @@ impl Block { /// /// TODO - performs various verification steps - discuss renaming this to "verify" /// - pub fn validate(&self, secp: &Secp256k1) -> Result<(), Error> { + pub fn validate(&self) -> Result<(), Error> { if exceeds_weight(self.inputs.len(), self.outputs.len(), self.kernels.len()) { return Err(Error::WeightExceeded); } - self.verify_coinbase(secp)?; - self.verify_kernels(secp, false)?; + self.verify_coinbase()?; + self.verify_kernels(false)?; Ok(()) } /// Verifies the sum of input/output commitments match the sum in kernels /// and that all kernel signatures are valid. /// TODO - when would we skip_sig? Is this needed or used anywhere? - fn verify_kernels(&self, secp: &Secp256k1, skip_sig: bool) -> Result<(), Error> { + fn verify_kernels(&self, skip_sig: bool) -> Result<(), Error> { for k in &self.kernels { if k.fee & 1 != 0 { return Err(Error::OddKernelFee); @@ -471,11 +469,16 @@ impl Block { } // sum all inputs and outs commitments - let io_sum = self.sum_commitments(secp)?; + let io_sum = self.sum_commitments()?; // sum all kernels commitments let proof_commits = map_vec!(self.kernels, |proof| proof.excess); - let proof_sum = secp.commit_sum(proof_commits, vec![])?; + + let proof_sum = { + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); + secp.commit_sum(proof_commits, vec![])? + }; // both should be the same if proof_sum != io_sum { @@ -485,7 +488,7 @@ impl Block { // verify all signatures with the commitment as pk if !skip_sig { for proof in &self.kernels { - proof.verify(secp)?; + proof.verify()?; } } Ok(()) @@ -496,7 +499,7 @@ impl Block { // * That the sum of all coinbase-marked outputs equal the supply. // * That the sum of blinding factors for all coinbase-marked outputs match // the coinbase-marked kernels. - fn verify_coinbase(&self, secp: &Secp256k1) -> Result<(), Error> { + fn verify_coinbase(&self) -> Result<(), Error> { let cb_outs = filter_map_vec!(self.outputs, |out| if out.features.contains( COINBASE_OUTPUT, ) @@ -511,10 +514,17 @@ impl Block { None }); - let over_commit = secp.commit_value(reward(self.total_fees()))?; - let out_adjust_sum = secp.commit_sum(cb_outs, vec![over_commit])?; + let over_commit; + let out_adjust_sum; + let kerns_sum; + { + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); + over_commit = secp.commit_value(reward(self.total_fees()))?; + out_adjust_sum = secp.commit_sum(cb_outs, vec![over_commit])?; + kerns_sum = secp.commit_sum(cb_kerns, vec![])?; + } - let kerns_sum = secp.commit_sum(cb_kerns, vec![])?; if kerns_sum != out_adjust_sum { return Err(Error::CoinbaseSumMismatch); } @@ -527,8 +537,6 @@ impl Block { key_id: &keychain::Identifier, fees: u64, ) -> Result<(Output, TxKernel), keychain::Error> { - let secp = keychain.secp(); - let commit = keychain.commit(reward(fees), key_id)?; let switch_commit = keychain.switch_commit(key_id)?; let switch_commit_hash = SwitchCommitHash::from_switch_commit(switch_commit); @@ -553,6 +561,8 @@ impl Block { proof: rproof, }; + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); let over_commit = secp.commit_value(reward(fees))?; let out_commit = output.commitment(); let excess = secp.commit_sum(vec![out_commit], vec![over_commit])?; @@ -560,10 +570,12 @@ impl Block { let msg = util::secp::Message::from_slice(&[0; secp::constants::MESSAGE_SIZE])?; let sig = keychain.sign(&msg, &key_id)?; + let excess_sig = sig.serialize_der(&secp); + let proof = TxKernel { features: COINBASE_KERNEL, excess: excess, - excess_sig: sig.serialize_der(&secp), + excess_sig: excess_sig, fee: 0, lock_height: 0, }; @@ -628,7 +640,7 @@ mod test { println!("Build tx: {}", now.elapsed().as_secs()); let b = new_block(vec![&mut tx], &keychain); - assert!(b.validate(&keychain.secp()).is_err()); + assert!(b.validate().is_err()); } #[test] @@ -652,7 +664,7 @@ mod test { // block should have been automatically compacted (including reward // output) and should still be valid - b.validate(&keychain.secp()).unwrap(); + b.validate().unwrap(); assert_eq!(b.inputs.len(), 3); assert_eq!(b.outputs.len(), 3); } @@ -677,10 +689,10 @@ mod test { let mut btx3 = txspend1i1o(5, &keychain, key_id2.clone(), key_id3); let b1 = new_block(vec![&mut btx1, &mut btx2], &keychain); - b1.validate(&keychain.secp()).unwrap(); + b1.validate().unwrap(); let b2 = new_block(vec![&mut btx3], &keychain); - b2.validate(&keychain.secp()).unwrap(); + b2.validate().unwrap(); // block should have been automatically compacted and should still be valid let b3 = b1.merge(b2); @@ -713,7 +725,7 @@ mod test { // the block should be valid here (single coinbase output with corresponding // txn kernel) - assert_eq!(b.validate(&keychain.secp()), Ok(())); + assert_eq!(b.validate(), Ok(())); } #[test] @@ -728,13 +740,13 @@ mod test { b.outputs[0].features.remove(COINBASE_OUTPUT); assert_eq!( - b.verify_coinbase(&keychain.secp()), + b.verify_coinbase(), Err(Error::CoinbaseSumMismatch) ); - assert_eq!(b.verify_kernels(&keychain.secp(), false), Ok(())); + assert_eq!(b.verify_kernels(false), Ok(())); assert_eq!( - b.validate(&keychain.secp()), + b.validate(), Err(Error::CoinbaseSumMismatch) ); } @@ -750,13 +762,13 @@ mod test { b.kernels[0].features.remove(COINBASE_KERNEL); assert_eq!( - b.verify_coinbase(&keychain.secp()), + b.verify_coinbase(), Err(Error::Secp(secp::Error::IncorrectCommitSum)) ); - assert_eq!(b.verify_kernels(&keychain.secp(), true), Ok(())); + assert_eq!(b.verify_kernels(true), Ok(())); assert_eq!( - b.validate(&keychain.secp()), + b.validate(), Err(Error::Secp(secp::Error::IncorrectCommitSum)) ); } diff --git a/core/src/core/build.rs b/core/src/core/build.rs index aeeba36eb..90044d79c 100644 --- a/core/src/core/build.rs +++ b/core/src/core/build.rs @@ -25,7 +25,7 @@ //! build::transaction(vec![input_rand(75), output_rand(42), output_rand(32), //! with_fee(1)]) -use util::secp; +use util::{secp, static_secp_instance}; use core::{Input, Output, SwitchCommitHash, Transaction, DEFAULT_OUTPUT}; use core::transaction::kernel_sig_msg; @@ -139,7 +139,11 @@ pub fn transaction( let blind_sum = ctx.keychain.blind_sum(&sum)?; let msg = secp::Message::from_slice(&kernel_sig_msg(tx.fee, tx.lock_height))?; let sig = ctx.keychain.sign_with_blinding(&msg, &blind_sum)?; - tx.excess_sig = sig.serialize_der(&ctx.keychain.secp()); + + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); + tx.excess_sig = sig.serialize_der(&secp); + Ok((tx, blind_sum)) } @@ -165,7 +169,7 @@ mod test { &keychain, ).unwrap(); - tx.verify_sig(&keychain.secp()).unwrap(); + tx.verify_sig().unwrap(); } #[test] @@ -179,6 +183,6 @@ mod test { &keychain, ).unwrap(); - tx.verify_sig(&keychain.secp()).unwrap(); + tx.verify_sig().unwrap(); } } diff --git a/core/src/core/mod.rs b/core/src/core/mod.rs index a0167a0b2..798da30a3 100644 --- a/core/src/core/mod.rs +++ b/core/src/core/mod.rs @@ -28,7 +28,7 @@ use std::cmp::Ordering; use std::num::ParseFloatError; use consensus::GRIN_BASE; -use util::secp::{self, Secp256k1}; +use util::{secp, static_secp_instance}; use util::secp::pedersen::*; pub use self::block::*; @@ -36,18 +36,17 @@ pub use self::transaction::*; use self::hash::Hashed; use ser::{Error, Readable, Reader, Writeable, Writer}; use global; -// use keychain; /// Implemented by types that hold inputs and outputs including Pedersen /// commitments. Handles the collection of the commitments as well as their /// summing, taking potential explicit overages of fees into account. pub trait Committed { /// Gathers commitments and sum them. - fn sum_commitments(&self, secp: &Secp256k1) -> Result { + fn sum_commitments(&self) -> Result { // first, verify each range proof let ref outputs = self.outputs_committed(); for output in *outputs { - try!(output.verify_proof(secp)) + try!(output.verify_proof()) } // then gather the commitments @@ -58,7 +57,11 @@ pub trait Committed { // negative let overage = self.overage(); if overage != 0 { - let over_commit = secp.commit_value(overage.abs() as u64).unwrap(); + let over_commit = { + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); + secp.commit_value(overage.abs() as u64).unwrap() + }; if overage < 0 { input_commits.push(over_commit); } else { @@ -67,7 +70,11 @@ pub trait Committed { } // sum all that stuff - secp.commit_sum(output_commits, input_commits) + { + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); + secp.commit_sum(output_commits, input_commits) + } } /// Vector of committed inputs to verify @@ -310,14 +317,16 @@ mod test { #[test] fn blind_tx() { - let keychain = Keychain::from_random_seed().unwrap(); - let btx = tx2i1o(); - btx.verify_sig(&keychain.secp()).unwrap(); // unwrap will panic if invalid + btx.verify_sig().unwrap(); // unwrap will panic if invalid // checks that the range proof on our blind output is sufficiently hiding let Output { proof, .. } = btx.outputs[0]; - let info = &keychain.secp().range_proof_info(proof); + + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); + let info = secp.range_proof_info(proof); + assert!(info.min == 0); assert!(info.max == u64::max_value()); } @@ -371,7 +380,7 @@ mod test { &keychain, ).unwrap(); - tx_final.validate(&keychain.secp()).unwrap(); + tx_final.validate().unwrap(); } #[test] @@ -380,7 +389,7 @@ mod test { let key_id = keychain.derive_key_id(1).unwrap(); let b = Block::new(&BlockHeader::default(), vec![], &keychain, &key_id).unwrap(); - b.compact().validate(&keychain.secp()).unwrap(); + b.compact().validate().unwrap(); } #[test] @@ -389,10 +398,10 @@ mod test { let key_id = keychain.derive_key_id(1).unwrap(); let mut tx1 = tx2i1o(); - tx1.verify_sig(keychain.secp()).unwrap(); + tx1.verify_sig().unwrap(); let b = Block::new(&BlockHeader::default(), vec![&mut tx1], &keychain, &key_id).unwrap(); - b.compact().validate(keychain.secp()).unwrap(); + b.compact().validate().unwrap(); } #[test] @@ -409,7 +418,7 @@ mod test { &keychain, &key_id, ).unwrap(); - b.validate(keychain.secp()).unwrap(); + b.validate().unwrap(); } #[test] @@ -439,7 +448,7 @@ mod test { &keychain, &key_id3.clone(), ).unwrap(); - b.validate(keychain.secp()).unwrap(); + b.validate().unwrap(); // now try adding a timelocked tx where lock height is greater than current block height let tx1 = build::transaction( @@ -459,7 +468,7 @@ mod test { &keychain, &key_id3.clone(), ).unwrap(); - match b.validate(keychain.secp()) { + match b.validate() { Err(KernelLockHeight { lock_height: height }) => { assert_eq!(height, 2); } @@ -469,16 +478,14 @@ mod test { #[test] pub fn test_verify_1i1o_sig() { - let keychain = keychain::Keychain::from_random_seed().unwrap(); let tx = tx1i1o(); - tx.verify_sig(keychain.secp()).unwrap(); + tx.verify_sig().unwrap(); } #[test] pub fn test_verify_2i1o_sig() { - let keychain = keychain::Keychain::from_random_seed().unwrap(); let tx = tx2i1o(); - tx.verify_sig(keychain.secp()).unwrap(); + tx.verify_sig().unwrap(); } // utility producing a transaction with 2 inputs and a single outputs diff --git a/core/src/core/transaction.rs b/core/src/core/transaction.rs index 499232de5..4df725e91 100644 --- a/core/src/core/transaction.rs +++ b/core/src/core/transaction.rs @@ -16,7 +16,7 @@ use byteorder::{BigEndian, ByteOrder}; use blake2::blake2b::blake2b; -use util::secp::{self, Message, Secp256k1, Signature}; +use util::secp::{self, Message, Signature}; use util::static_secp_instance; use util::secp::pedersen::{Commitment, RangeProof}; use std::cmp::Ordering; @@ -147,11 +147,13 @@ impl TxKernel { /// Verify the transaction proof validity. Entails handling the commitment /// as a public key and checking the signature verifies with the fee as /// message. - pub fn verify(&self, secp: &Secp256k1) -> Result<(), secp::Error> { + pub fn verify(&self) -> Result<(), secp::Error> { let msg = try!(Message::from_slice( &kernel_sig_msg(self.fee, self.lock_height), )); - let sig = try!(Signature::from_der(secp, &self.excess_sig)); + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); + let sig = try!(Signature::from_der(&secp, &self.excess_sig)); secp.verify_from_commit(&msg, &sig, &self.excess) } } @@ -306,11 +308,14 @@ impl Transaction { /// sum to zero as they should in r.G + v.H then only k.G the excess /// of the sum of r.G should be left. And r.G is the definition of a /// public key generated using r as a private key. - pub fn verify_sig(&self, secp: &Secp256k1) -> Result { - let rsum = self.sum_commitments(secp)?; + pub fn verify_sig(&self) -> Result { + let rsum = self.sum_commitments()?; let msg = Message::from_slice(&kernel_sig_msg(self.fee, self.lock_height))?; - let sig = Signature::from_der(secp, &self.excess_sig)?; + + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); + let sig = Signature::from_der(&secp, &self.excess_sig)?; // pretend the sum is a public key (which it is, being of the form r.G) and // verify the transaction sig with it @@ -338,14 +343,14 @@ impl Transaction { /// Validates all relevant parts of a fully built transaction. Checks the /// excess value against the signature as well as range proofs for each /// output. - pub fn validate(&self, secp: &Secp256k1) -> Result { + pub fn validate(&self) -> Result { if self.fee & 1 != 0 { return Err(Error::OddFee); } for out in &self.outputs { - out.verify_proof(secp)?; + out.verify_proof()?; } - let excess = self.verify_sig(secp)?; + let excess = self.verify_sig()?; Ok(excess) } } @@ -514,7 +519,9 @@ impl Output { } /// Validates the range proof using the commitment - pub fn verify_proof(&self, secp: &Secp256k1) -> Result<(), secp::Error> { + pub fn verify_proof(&self) -> Result<(), secp::Error> { + let secp = static_secp_instance(); + let secp = secp.lock().unwrap(); secp.verify_range_proof(self.commit, self.proof).map(|_| ()) } diff --git a/grin/src/miner.rs b/grin/src/miner.rs index 8627b53b9..4d1730e61 100644 --- a/grin/src/miner.rs +++ b/grin/src/miner.rs @@ -37,7 +37,6 @@ use util::LOGGER; use types::Error; use chain; -use util::secp; use pool; use util; use keychain::{Identifier, Keychain}; @@ -574,8 +573,7 @@ impl Miner { ); // making sure we're not spending time mining a useless block - let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit); - b.validate(&secp).expect("Built an invalid block!"); + b.validate().expect("Built an invalid block!"); let mut rng = rand::OsRng::new().unwrap(); b.header.nonce = rng.gen(); diff --git a/keychain/src/keychain.rs b/keychain/src/keychain.rs index d5297f387..aa50e8b09 100644 --- a/keychain/src/keychain.rs +++ b/keychain/src/keychain.rs @@ -100,7 +100,7 @@ impl Keychain { } trace!(LOGGER, "Derived Key key_id: {}", key_id); - + if let Some(n) = n_child{ let extkey = self.extkey.derive(&self.secp, n)?; return Ok(extkey.key); @@ -222,8 +222,8 @@ mod test { #[test] fn test_key_derivation() { - let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit); let keychain = Keychain::from_random_seed().unwrap(); + let secp = keychain.secp(); // use the keychain to derive a "key_id" based on the underlying seed let key_id = keychain.derive_key_id(1).unwrap(); diff --git a/pool/src/pool.rs b/pool/src/pool.rs index 9d8086b8e..a6bd121dd 100644 --- a/pool/src/pool.rs +++ b/pool/src/pool.rs @@ -22,7 +22,6 @@ use core::core::block; use core::core::hash; use core::global; -use util::secp; use util::secp::pedersen::Commitment; use std::sync::Arc; @@ -145,8 +144,7 @@ where } // Making sure the transaction is valid before anything else. - let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit); - tx.validate(&secp).map_err(|_e| PoolError::Invalid)?; + tx.validate().map_err(|_e| PoolError::Invalid)?; // The first check involves ensuring that an identical transaction is // not already in the pool's transaction set. diff --git a/wallet/src/receiver.rs b/wallet/src/receiver.rs index 5428466d1..7eb015cbf 100644 --- a/wallet/src/receiver.rs +++ b/wallet/src/receiver.rs @@ -205,7 +205,7 @@ fn receive_transaction( // make sure the resulting transaction is valid (could have been lied to on // excess). - tx_final.validate(&keychain.secp())?; + tx_final.validate()?; // operate within a lock on wallet data WalletData::with_wallet(&config.data_file_dir, |wallet_data| { diff --git a/wallet/src/sender.rs b/wallet/src/sender.rs index 8b3dcfea5..a583a3a4f 100644 --- a/wallet/src/sender.rs +++ b/wallet/src/sender.rs @@ -135,7 +135,7 @@ pub fn issue_burn_tx( // finalize the burn transaction and send let (tx_burn, _) = build::transaction(parts, &keychain)?; - tx_burn.validate(&keychain.secp())?; + tx_burn.validate()?; let tx_hex = util::to_hex(ser::ser_vec(&tx_burn).unwrap()); let url = format!("{}/v1/pool/push", config.check_node_api_http_addr.as_str());