use the static secp instance everywhere (except the wallet) (#250)

This commit is contained in:
AntiochP 2017-11-09 14:26:45 -05:00 committed by GitHub
parent a0c0d6f382
commit c1656f7660
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 102 additions and 78 deletions

View file

@ -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 {

View file

@ -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<Block, Error> {
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))
);
}

View file

@ -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();
}
}

View file

@ -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<Commitment, secp::Error> {
fn sum_commitments(&self) -> Result<Commitment, secp::Error> {
// 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

View file

@ -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<Commitment, secp::Error> {
let rsum = self.sum_commitments(secp)?;
pub fn verify_sig(&self) -> Result<Commitment, secp::Error> {
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<Commitment, Error> {
pub fn validate(&self) -> Result<Commitment, Error> {
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(|_| ())
}

View file

@ -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();

View file

@ -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();

View file

@ -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.

View file

@ -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| {

View file

@ -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());