diff --git a/Cargo.lock b/Cargo.lock index afe0a7c6c..2d09bb061 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -749,7 +749,7 @@ dependencies = [ "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "secp256k1zkp 0.7.1 (git+https://github.com/mimblewimble/rust-secp256k1-zkp?tag=grin_integration_19)", + "secp256k1zkp 0.7.1 (git+https://github.com/mimblewimble/rust-secp256k1-zkp?branch=testnet3)", "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1617,7 +1617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "secp256k1zkp" version = "0.7.1" -source = "git+https://github.com/mimblewimble/rust-secp256k1-zkp?tag=grin_integration_19#800e9b3ea4a8b2df7b999980ae78b224a6ad07ce" +source = "git+https://github.com/mimblewimble/rust-secp256k1-zkp?branch=testnet3#748296c61341461e46e7b2c05db494d60f96ac44" dependencies = [ "arrayvec 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2429,7 +2429,7 @@ dependencies = [ "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" "checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum secp256k1zkp 0.7.1 (git+https://github.com/mimblewimble/rust-secp256k1-zkp?tag=grin_integration_19)" = "" +"checksum secp256k1zkp 0.7.1 (git+https://github.com/mimblewimble/rust-secp256k1-zkp?branch=testnet3)" = "" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum sequence_trie 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c915714ca833b1d4d6b8f6a9d72a3ff632fe45b40a8d184ef79c81bec6327eed" diff --git a/core/src/core/transaction.rs b/core/src/core/transaction.rs index 74cef1bdb..bb06a8093 100644 --- a/core/src/core/transaction.rs +++ b/core/src/core/transaction.rs @@ -917,114 +917,6 @@ impl Readable for OutputIdentifier { } } -/// A structure which contains fields that are to be committed to within -/// an Output's range (bullet) proof. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] -pub struct ProofMessageElements { - /// The amount, stored to allow for wallet reconstruction as - /// rewinding isn't supported in bulletproofs just yet - /// This is going to be written 3 times, to facilitate checking - /// values on rewind - /// Note that rewinding with only the nonce will give you back - /// the first 32 bytes of the message. To get the second - /// 32 bytes, you need to provide the correct blinding factor as well - value: u64, - /// another copy of the value, to check on rewind - value_copy_1: u64, - /// another copy of the value - value_copy_2: u64, - /// the first 8 bytes of the blinding factor, used to avoid having to grind - /// through a proof each time you want to check against key possibilities - bf_first_8: Vec, - /// unused portion of message, used to test whether we have both nonce - /// and blinding correct - zeroes: Vec, -} - -impl Writeable for ProofMessageElements { - fn write(&self, writer: &mut W) -> Result<(), ser::Error> { - writer.write_u64(self.value)?; - writer.write_u64(self.value_copy_1)?; - writer.write_u64(self.value_copy_2)?; - writer.write_fixed_bytes(&self.bf_first_8)?; - for i in 0..32 { - let _ = writer.write_u8(self.zeroes[i]); - } - Ok(()) - } -} - -impl Readable for ProofMessageElements { - fn read(reader: &mut Reader) -> Result { - // if the value isn't repeated 3 times, it's most likely not the value, - // so reject - Ok(ProofMessageElements { - value: reader.read_u64()?, - value_copy_1: reader.read_u64()?, - value_copy_2: reader.read_u64()?, - bf_first_8: reader.read_fixed_bytes(8)?, - zeroes: reader.read_fixed_bytes(32)?, - }) - } -} - -impl ProofMessageElements { - /// Create a new proof message - pub fn new(value: u64, blinding: &keychain::Identifier) -> ProofMessageElements { - ProofMessageElements { - value: value, - value_copy_1: value, - value_copy_2: value, - bf_first_8: blinding.to_bytes()[0..8].to_vec(), - zeroes: [0u8; 32].to_vec(), - } - } - - /// Return the value if it's valid, an error otherwise - pub fn value(&self) -> Result { - if self.value == self.value_copy_1 && self.value == self.value_copy_2 { - Ok(self.value) - } else { - Err(Error::InvalidProofMessage) - } - } - - /// Compare given identifier with first 8 bytes of what's stored - pub fn compare_bf_first_8(&self, in_id: &keychain::Identifier) -> bool { - let in_id_vec = in_id.to_bytes()[0..8].to_vec(); - for i in 0..8 { - if in_id_vec[i] != self.bf_first_8[i] { - return false; - } - } - true - } - - /// Whether our remainder is zero (as it should be if the BF and nonce used - /// to unwind are correct - pub fn zeroes_correct(&self) -> bool { - for i in 0..self.zeroes.len() { - if self.zeroes[i] != 0 { - return false; - } - } - true - } - - /// Serialize and return a ProofMessage - pub fn to_proof_message(&self) -> ProofMessage { - ProofMessage::from_bytes(&ser_vec(self).unwrap()) - } - - /// Deserialize and return the message elements - pub fn from_proof_message( - proof_message: &ProofMessage, - ) -> Result { - let mut c = Cursor::new(proof_message.as_bytes()); - ser::deserialize::(&mut c) - } -} - #[cfg(test)] mod test { use super::*; diff --git a/core/tests/block.rs b/core/tests/block.rs index d5be2765b..942a9d065 100644 --- a/core/tests/block.rs +++ b/core/tests/block.rs @@ -233,7 +233,7 @@ fn empty_block_serialized_size() { let b = new_block(vec![], &keychain, &prev, &key_id); let mut vec = Vec::new(); ser::serialize(&mut vec, &b).expect("serialization failed"); - let target_len = 1_265; + let target_len = 1_266; assert_eq!(vec.len(), target_len,); } @@ -246,7 +246,7 @@ fn block_single_tx_serialized_size() { let b = new_block(vec![&tx1], &keychain, &prev, &key_id); let mut vec = Vec::new(); ser::serialize(&mut vec, &b).expect("serialization failed"); - let target_len = 2_845; + let target_len = 2_848; assert_eq!(vec.len(), target_len); } @@ -258,7 +258,7 @@ fn empty_compact_block_serialized_size() { let b = new_block(vec![], &keychain, &prev, &key_id); let mut vec = Vec::new(); ser::serialize(&mut vec, &b.as_compact_block()).expect("serialization failed"); - let target_len = 1_273; + let target_len = 1_274; assert_eq!(vec.len(), target_len,); } @@ -271,7 +271,7 @@ fn compact_block_single_tx_serialized_size() { let b = new_block(vec![&tx1], &keychain, &prev, &key_id); let mut vec = Vec::new(); ser::serialize(&mut vec, &b.as_compact_block()).expect("serialization failed"); - let target_len = 1_279; + let target_len = 1_280; assert_eq!(vec.len(), target_len,); } @@ -290,7 +290,7 @@ fn block_10_tx_serialized_size() { let b = new_block(txs.iter().collect(), &keychain, &prev, &key_id); let mut vec = Vec::new(); ser::serialize(&mut vec, &b).expect("serialization failed"); - let target_len = 17_065; + let target_len = 17_086; assert_eq!(vec.len(), target_len,); } @@ -308,7 +308,7 @@ fn compact_block_10_tx_serialized_size() { let b = new_block(txs.iter().collect(), &keychain, &prev, &key_id); let mut vec = Vec::new(); ser::serialize(&mut vec, &b.as_compact_block()).expect("serialization failed"); - let target_len = 1_333; + let target_len = 1_334; assert_eq!(vec.len(), target_len,); } diff --git a/core/tests/core.rs b/core/tests/core.rs index 145f768d2..811cd9402 100644 --- a/core/tests/core.rs +++ b/core/tests/core.rs @@ -36,7 +36,7 @@ fn simple_tx_ser() { let tx = tx2i1o(); let mut vec = Vec::new(); ser::serialize(&mut vec, &tx).expect("serialization failed"); - let target_len = 954; + let target_len = 955; assert_eq!(vec.len(), target_len,); } diff --git a/core/tests/transaction.rs b/core/tests/transaction.rs index cbad8b965..a4c8c11c9 100644 --- a/core/tests/transaction.rs +++ b/core/tests/transaction.rs @@ -23,7 +23,6 @@ pub mod common; use grin_core::core::{Output, OutputFeatures}; use grin_core::ser; use keychain::{ExtKeychain, Keychain}; -use util::secp; use wallet::libtx::proof; #[test] @@ -31,8 +30,7 @@ fn test_output_ser_deser() { let keychain = ExtKeychain::from_random_seed().unwrap(); let key_id = keychain.derive_key_id(1).unwrap(); let commit = keychain.commit(5, &key_id).unwrap(); - let msg = secp::pedersen::ProofMessage::empty(); - let proof = proof::create(&keychain, 5, &key_id, commit, None, msg).unwrap(); + let proof = proof::create(&keychain, 5, &key_id, commit, None).unwrap(); let out = Output { features: OutputFeatures::DEFAULT_OUTPUT, diff --git a/util/Cargo.toml b/util/Cargo.toml index 523159c69..c83574555 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -20,6 +20,6 @@ zip = "0.4" [dependencies.secp256k1zkp] git = "https://github.com/mimblewimble/rust-secp256k1-zkp" -tag = "grin_integration_19" +branch = "testnet3" #path = "../../rust-secp256k1-zkp" features = ["bullet-proof-sizing"] diff --git a/wallet/src/libtx/build.rs b/wallet/src/libtx/build.rs index a60a8591c..b1ed5ece6 100644 --- a/wallet/src/libtx/build.rs +++ b/wallet/src/libtx/build.rs @@ -29,7 +29,7 @@ use util::{kernel_sig_msg, secp}; use core::core::hash::Hash; use core::core::merkle_proof::MerkleProof; -use core::core::{Input, Output, OutputFeatures, ProofMessageElements, Transaction, TxKernel}; +use core::core::{Input, Output, OutputFeatures, Transaction, TxKernel}; use keychain::{self, BlindSum, BlindingFactor, Identifier, Keychain}; use libtx::{aggsig, proof}; use util::LOGGER; @@ -118,15 +118,12 @@ where let commit = build.keychain.commit(value, &key_id).unwrap(); trace!(LOGGER, "Builder - Pedersen Commit is: {:?}", commit,); - let msg = ProofMessageElements::new(value, &key_id); - let rproof = proof::create( build.keychain, value, &key_id, commit, None, - msg.to_proof_message(), ).unwrap(); ( diff --git a/wallet/src/libtx/proof.rs b/wallet/src/libtx/proof.rs index 4f362d25f..3b010b335 100644 --- a/wallet/src/libtx/proof.rs +++ b/wallet/src/libtx/proof.rs @@ -17,7 +17,6 @@ use blake2; use keychain::{Identifier, Keychain}; use libtx::error::{Error, ErrorKind}; -use util::logger::LOGGER; use util::secp::key::SecretKey; use util::secp::pedersen::{Commitment, ProofInfo, ProofMessage, RangeProof}; use util::secp::{self, Secp256k1}; @@ -42,16 +41,13 @@ where } } -/// So we want this to take an opaque structure that can be called -/// back to get the sensitive data - +/// Create a bulletproof pub fn create( k: &K, amount: u64, key_id: &Identifier, _commit: Commitment, extra_data: Option>, - msg: ProofMessage, ) -> Result where K: Keychain, @@ -59,18 +55,7 @@ where let commit = k.commit(amount, key_id)?; let skey = k.derived_key(key_id)?; let nonce = create_nonce(k, &commit)?; - if msg.len() == 0 { - return Ok(k.secp().bullet_proof(amount, skey, nonce, extra_data, None)); - } else { - if msg.len() != 64 { - error!(LOGGER, "Bullet proof message must be 64 bytes."); - return Err(ErrorKind::RangeProof( - "Bullet proof message must be 64 bytes".to_string(), - ))?; - } - } - return Ok(k.secp() - .bullet_proof(amount, skey, nonce, extra_data, Some(msg))); + Ok(k.secp().bullet_proof(amount, skey, nonce, extra_data)) } /// Verify a proof @@ -90,7 +75,6 @@ pub fn verify( /// Rewind a rangeproof to retrieve the amount pub fn rewind( k: &K, - key_id: &Identifier, commit: Commitment, extra_data: Option>, proof: RangeProof, @@ -98,25 +82,16 @@ pub fn rewind( where K: Keychain, { - let skey = k.derived_key(key_id)?; let nonce = create_nonce(k, &commit)?; let proof_message = k.secp() - .unwind_bullet_proof(commit, skey, nonce, extra_data, proof); + .rewind_bullet_proof(commit, nonce, extra_data, proof); let proof_info = match proof_message { - Ok(p) => ProofInfo { - success: true, - value: 0, - message: p, - mlen: 0, - min: 0, - max: 0, - exp: 0, - mantissa: 0, - }, + Ok(p) => p, Err(_) => ProofInfo { success: false, value: 0, message: ProofMessage::empty(), + blinding: SecretKey([0; secp::constants::SECRET_KEY_SIZE]), mlen: 0, min: 0, max: 0, diff --git a/wallet/src/libtx/reward.rs b/wallet/src/libtx/reward.rs index 90441cf25..ceea62459 100644 --- a/wallet/src/libtx/reward.rs +++ b/wallet/src/libtx/reward.rs @@ -18,7 +18,7 @@ use keychain::{Identifier, Keychain}; use core::consensus::reward; use core::core::KernelFeatures; -use core::core::{Output, OutputFeatures, ProofMessageElements, TxKernel}; +use core::core::{Output, OutputFeatures, TxKernel}; use libtx::error::Error; use libtx::{aggsig, proof}; use util::{kernel_sig_msg, secp, static_secp_instance, LOGGER}; @@ -35,7 +35,6 @@ where { let value = reward(fees); let commit = keychain.commit(value, key_id)?; - let msg = ProofMessageElements::new(value, key_id); trace!(LOGGER, "Block reward - Pedersen Commit is: {:?}", commit,); @@ -45,7 +44,6 @@ where key_id, commit, None, - msg.to_proof_message(), )?; let output = Output { diff --git a/wallet/src/libwallet/internal/restore.rs b/wallet/src/libwallet/internal/restore.rs index 81056790e..06c3dd703 100644 --- a/wallet/src/libwallet/internal/restore.rs +++ b/wallet/src/libwallet/internal/restore.rs @@ -16,10 +16,9 @@ /// TODO: Remove api use api; use byteorder::{BigEndian, ByteOrder}; -use core::core::transaction::ProofMessageElements; use core::global; use error::{Error, ErrorKind}; -use failure::{Fail, ResultExt}; +use failure::Fail; use keychain::{Identifier, Keychain}; use libtx::proof; use libwallet::types::*; @@ -77,8 +76,7 @@ where // TODO - wrap the many return values in a struct fn find_outputs_with_key( wallet: &mut T, - outputs: Vec, - found_key_index: &mut Vec, + outputs: Vec ) -> Vec<( pedersen::Commitment, Identifier, @@ -109,76 +107,41 @@ where info!(LOGGER, "Scanning {} outputs", outputs.len(),); let current_chain_height = wallet.get_chain_height(wallet.node_url()).unwrap(); - // skey doesn't matter in this case - let skey = wallet.keychain().derive_key_id(1).unwrap(); for output in outputs.iter().filter(|x| !x.spent) { - // attempt to unwind message from the RP and get a value.. note - // this will only return okay if the value is included in the - // message 3 times, indicating a strong match. Also, sec_key provided - // to unwind in this case will be meaningless. With only the nonce known - // only the first 32 bytes of the recovered message will be accurate + // attempt to unwind message from the RP and get a value + // will fail if it's not ours let info = proof::rewind( wallet.keychain(), - &skey, output.commit, None, output.range_proof().unwrap(), ).unwrap(); - let message = ProofMessageElements::from_proof_message(&info.message).unwrap(); - let value = message.value(); - if value.is_err() { + + if !info.success { continue; } - // we have a match, now check through our key iterations to find a partial match - let mut found = false; + // we have a match, now check through our key iterations to find out which one it was + let mut found = false; let mut start_index = 1; - // TODO: This assumption only holds with current wallet software assuming - // wallet doesn't go back and re-use gaps in its key index, ie. every - // new key index produced is always greater than the previous max key index - if let Some(m) = found_key_index.iter().max() { - start_index = *m as usize + 1; - } - for i in start_index..max_derivations { - // much faster than calling EC functions for each found key - // Shouldn't be needed if assumption about wallet key 'gaps' above - // holds.. otherwise this is a good optimization.. perhaps - // provide a command line switch - /*if found_key_index.contains(&(i as u32)) { - continue; - }*/ let key_id = &wallet.keychain().derive_key_id(i as u32).unwrap(); - if !message.compare_bf_first_8(key_id) { + let b = wallet.keychain().derived_key(key_id).unwrap(); + if info.blinding != b { continue; } found = true; // we have a partial match, let's just confirm - let info = proof::rewind( - wallet.keychain(), - key_id, - output.commit, - None, - output.range_proof().unwrap(), - ).unwrap(); - let message = ProofMessageElements::from_proof_message(&info.message).unwrap(); - let value = message.value(); - if value.is_err() || !message.zeroes_correct() { - continue; - } - let value = value.unwrap(); info!( LOGGER, "Output found: {:?}, key_index: {:?}", output.commit, i, ); - found_key_index.push(i as u32); // add it to result set here let commit_id = output.commit.0; - let is_coinbase = coinbase_status(output); - info!(LOGGER, "Amount: {}", value); + info!(LOGGER, "Amount: {}", info.value); let commit = wallet .keychain() @@ -204,7 +167,7 @@ where commit, key_id.clone(), i as u32, - value, + info.value, height, lock_height, is_coinbase, @@ -218,7 +181,7 @@ where LOGGER, "Very probable matching output found with amount: {} \ but didn't match key child key up to {}", - message.value().unwrap(), + info.value, max_derivations, ); } @@ -248,9 +211,6 @@ where let batch_size = 1000; let mut start_index = 1; - // Keep a set of keys we've already claimed (cause it's far faster than - // deriving a key for each one) - let mut found_key_index: Vec = vec![]; // this will start here, then lower as outputs are found, moving backwards on // the chain loop { @@ -265,10 +225,10 @@ where let root_key_id = wallet.keychain().root_key_id(); let result_vec = - find_outputs_with_key(wallet, output_listing.outputs.clone(), &mut found_key_index); + find_outputs_with_key(wallet, output_listing.outputs.clone()); let mut batch = wallet.batch()?; for output in result_vec { - batch.save(OutputData { + let _ = batch.save(OutputData { root_key_id: root_key_id.clone(), key_id: output.1.clone(), n_child: output.2, diff --git a/wallet/tests/libwallet.rs b/wallet/tests/libwallet.rs index d03454d58..81db7eae6 100644 --- a/wallet/tests/libwallet.rs +++ b/wallet/tests/libwallet.rs @@ -22,7 +22,6 @@ extern crate uuid; use keychain::{BlindSum, BlindingFactor, ExtKeychain, Keychain}; use util::secp::key::{PublicKey, SecretKey}; -use util::secp::pedersen::ProofMessage; use util::{kernel_sig_msg, secp}; use wallet::libtx::{aggsig, proof}; use wallet::libwallet::internal::sigcontext; @@ -408,8 +407,8 @@ fn aggsig_sender_receiver_interaction_offset() { fn test_rewind_range_proof() { let keychain = ExtKeychain::from_random_seed().unwrap(); let key_id = keychain.derive_key_id(1).unwrap(); + let key_id2 = keychain.derive_key_id(2).unwrap(); let commit = keychain.commit(5, &key_id).unwrap(); - let msg = ProofMessage::from_bytes(&[0u8; 64]); let extra_data = [99u8; 64]; let proof = proof::create( @@ -418,65 +417,24 @@ fn test_rewind_range_proof() { &key_id, commit, Some(extra_data.to_vec().clone()), - msg, - ).unwrap(); - let proof_info = proof::rewind( - &keychain, - &key_id, - commit, - Some(extra_data.to_vec().clone()), - proof, ).unwrap(); + let proof_info = + proof::rewind(&keychain, commit, Some(extra_data.to_vec().clone()), proof).unwrap(); assert_eq!(proof_info.success, true); + assert_eq!(proof_info.value, 5); - // now check the recovered message is "empty" (but not truncated) i.e. all - // zeroes - //Value is in the message in this case - assert_eq!( - proof_info.message, - secp::pedersen::ProofMessage::from_bytes(&[0; secp::constants::BULLET_PROOF_MSG_SIZE]) - ); - - let key_id2 = keychain.derive_key_id(2).unwrap(); - - // cannot rewind with a different nonce - let proof_info = proof::rewind( - &keychain, - &key_id2, - commit, - Some(extra_data.to_vec().clone()), - proof, - ).unwrap(); - // With bullet proofs, if you provide the wrong nonce you'll get gibberish back - // as opposed to a failure to recover the message - assert_ne!( - proof_info.message, - secp::pedersen::ProofMessage::from_bytes(&[0; secp::constants::BULLET_PROOF_MSG_SIZE]) - ); - assert_eq!(proof_info.value, 0); - - // cannot rewind with a commitment to the same value using a different key + // cannot rewind with a different commit let commit2 = keychain.commit(5, &key_id2).unwrap(); - let proof_info = proof::rewind( - &keychain, - &key_id, - commit2, - Some(extra_data.to_vec().clone()), - proof, - ).unwrap(); + let proof_info = + proof::rewind(&keychain, commit2, Some(extra_data.to_vec().clone()), proof).unwrap(); assert_eq!(proof_info.success, false); assert_eq!(proof_info.value, 0); // cannot rewind with a commitment to a different value let commit3 = keychain.commit(4, &key_id).unwrap(); - let proof_info = proof::rewind( - &keychain, - &key_id, - commit3, - Some(extra_data.to_vec().clone()), - proof, - ).unwrap(); + let proof_info = + proof::rewind(&keychain, commit3, Some(extra_data.to_vec().clone()), proof).unwrap(); assert_eq!(proof_info.success, false); assert_eq!(proof_info.value, 0); @@ -485,7 +443,6 @@ fn test_rewind_range_proof() { let wrong_extra_data = [98u8; 64]; let _should_err = proof::rewind( &keychain, - &key_id, commit3, Some(wrong_extra_data.to_vec().clone()), proof,