Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(hashing): improve byte array conversion methods #2279

Open
wants to merge 11 commits into
base: dev
Choose a base branch
from
15 changes: 8 additions & 7 deletions mm2src/coins/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1500,7 +1500,7 @@ impl SwapOps for EthCoin {
_secret_hash: &[u8],
spend_tx: &[u8],
watcher_reward: bool,
) -> Result<Vec<u8>, String> {
) -> Result<[u8; 32], String> {
let unverified: UnverifiedTransactionWrapper = try_s!(rlp::decode(spend_tx));
let function_name = get_function_name("receiverSpend", watcher_reward);
let function = try_s!(SWAP_CONTRACT.function(&function_name));
Expand All @@ -1522,7 +1522,7 @@ impl SwapOps for EthCoin {
return ERR!("Invalid arguments in 'receiverSpend' call: {:?}", tokens);
}
match &tokens[2] {
Token::FixedBytes(secret) => Ok(secret.to_vec()),
Token::FixedBytes(secret) => Ok(try_s!(secret.as_slice().try_into())),
_ => ERR!(
"Expected secret to be fixed bytes, decoded function data is {:?}",
tokens
Expand Down Expand Up @@ -1572,27 +1572,28 @@ impl SwapOps for EthCoin {
| EthPrivKeyPolicy::HDWallet {
activated_key: ref key_pair,
..
} => key_pair_from_secret(key_pair.secret().as_bytes()).expect("valid key"),
} => key_pair_from_secret(key_pair.secret().as_fixed_bytes()).expect("valid key"),
EthPrivKeyPolicy::Trezor => todo!(),
#[cfg(target_arch = "wasm32")]
EthPrivKeyPolicy::Metamask(_) => todo!(),
}
}

#[inline]
fn derive_htlc_pubkey(&self, _swap_unique_data: &[u8]) -> Vec<u8> {
fn derive_htlc_pubkey(&self, _swap_unique_data: &[u8]) -> [u8; 33] {
match self.priv_key_policy {
EthPrivKeyPolicy::Iguana(ref key_pair)
| EthPrivKeyPolicy::HDWallet {
activated_key: ref key_pair,
..
} => key_pair_from_secret(key_pair.secret().as_bytes())
} => key_pair_from_secret(&key_pair.secret().to_fixed_bytes())
.expect("valid key")
.public_slice()
.to_vec(),
.try_into()
.expect("valid key length!"),
EthPrivKeyPolicy::Trezor => todo!(),
#[cfg(target_arch = "wasm32")]
EthPrivKeyPolicy::Metamask(ref metamask_policy) => metamask_policy.public_key.as_bytes().to_vec(),
EthPrivKeyPolicy::Metamask(ref metamask_policy) => metamask_policy.public_key.0,
}
}

Expand Down
18 changes: 10 additions & 8 deletions mm2src/coins/lightning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ use secp256k1v24::PublicKey;
use serde::Deserialize;
use serde_json::Value as Json;
use std::collections::{HashMap, HashSet};
use std::convert::TryInto;
use std::convert::{TryFrom, TryInto};
use std::fmt;
use std::io::Cursor;
use std::net::SocketAddr;
Expand Down Expand Up @@ -793,13 +793,13 @@ impl SwapOps for LightningCoin {
_secret_hash: &[u8],
spend_tx: &[u8],
_watcher_reward: bool,
) -> Result<Vec<u8>, String> {
) -> Result<[u8; 32], String> {
let payment_hash = payment_hash_from_slice(spend_tx).map_err(|e| e.to_string())?;
let payment_hex = hex::encode(payment_hash.0);

match self.db.get_payment_from_db(payment_hash).await {
Ok(Some(payment)) => match payment.preimage {
Some(preimage) => Ok(preimage.0.to_vec()),
Some(preimage) => Ok(preimage.0),
None => ERR!("Preimage for payment {} should be found on the database", payment_hex),
},
Ok(None) => ERR!("Payment {} is not in the database when it should be!", payment_hex),
Expand Down Expand Up @@ -857,8 +857,8 @@ impl SwapOps for LightningCoin {
}

#[inline]
fn derive_htlc_pubkey(&self, _swap_unique_data: &[u8]) -> Vec<u8> {
self.channel_manager.get_our_node_id().serialize().to_vec()
fn derive_htlc_pubkey(&self, _swap_unique_data: &[u8]) -> [u8; 33] {
self.channel_manager.get_our_node_id().serialize()
}

#[inline]
Expand Down Expand Up @@ -1046,7 +1046,8 @@ impl MarketCoinOps for LightningCoin {
.map_err(|_| SignatureError::InternalError("Error accessing node keys".to_string()))?;
let private = Private {
prefix: 239,
secret: H256::from(*secret_key.as_ref()),
secret: H256::from_slice(secret_key.as_ref())
.map_to_mm(|err| SignatureError::InvalidRequest(err.to_string()))?,
compressed: true,
checksum_type: ChecksumType::DSHA256,
};
Expand All @@ -1058,10 +1059,11 @@ impl MarketCoinOps for LightningCoin {
let message_hash = self
.sign_message_hash(message)
.ok_or(VerificationError::PrefixNotFound)?;
let signature = CompactSignature::from(
let signature = CompactSignature::try_from(
zbase32::decode_full_bytes_str(signature)
.map_err(|e| VerificationError::SignatureDecodingError(e.to_string()))?,
);
)
.map_to_mm(|err| VerificationError::SignatureDecodingError(err.to_string()))?;
let recovered_pubkey = Public::recover_compact(&H256::from(message_hash), &signature)?;
Ok(recovered_pubkey.to_string() == pubkey)
}
Expand Down
2 changes: 1 addition & 1 deletion mm2src/coins/lightning/ln_platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub async fn update_best_block(
)
},
ElectrumBlockHeader::V14(h) => {
let block_header = match deserialize(&h.hex.into_vec()) {
let block_header = match deserialize(&h.hex.0) {
Ok(header) => header,
Err(e) => {
error!("Block header deserialization error: {}", e.to_string());
Expand Down
4 changes: 2 additions & 2 deletions mm2src/coins/lp_coins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1119,7 +1119,7 @@ pub trait SwapOps {
secret_hash: &[u8],
spend_tx: &[u8],
watcher_reward: bool,
) -> Result<Vec<u8>, String>;
) -> Result<[u8; 32], String>;

fn check_tx_signed_by_pub(&self, tx: &[u8], expected_pub: &[u8]) -> Result<bool, MmError<ValidatePaymentError>>;

Expand Down Expand Up @@ -1151,7 +1151,7 @@ pub trait SwapOps {
fn derive_htlc_key_pair(&self, swap_unique_data: &[u8]) -> KeyPair;

/// Derives an HTLC key-pair and returns a public key corresponding to that key.
fn derive_htlc_pubkey(&self, swap_unique_data: &[u8]) -> Vec<u8>;
fn derive_htlc_pubkey(&self, swap_unique_data: &[u8]) -> [u8; 33];

fn validate_other_pubkey(&self, raw_pubkey: &[u8]) -> MmResult<(), ValidateOtherPubKeyErr>;

Expand Down
4 changes: 2 additions & 2 deletions mm2src/coins/qrc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -992,7 +992,7 @@ impl SwapOps for Qrc20Coin {
secret_hash: &[u8],
spend_tx: &[u8],
_watcher_reward: bool,
) -> Result<Vec<u8>, String> {
) -> Result<[u8; 32], String> {
self.extract_secret_impl(secret_hash, spend_tx)
}

Expand Down Expand Up @@ -1034,7 +1034,7 @@ impl SwapOps for Qrc20Coin {
utxo_common::derive_htlc_key_pair(self.as_ref(), swap_unique_data)
}

fn derive_htlc_pubkey(&self, swap_unique_data: &[u8]) -> Vec<u8> {
fn derive_htlc_pubkey(&self, swap_unique_data: &[u8]) -> [u8; 33] {
utxo_common::derive_htlc_pubkey(self, swap_unique_data)
}

Expand Down
75 changes: 40 additions & 35 deletions mm2src/coins/qrc20/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ impl TxInternalId {
return ERR!("Incorrect bytes len {}, expected {}", bytes.len(), EXPECTED_LEN);
}

let tx_hash: H256Json = bytes[0..32].into();
let mut tx_hash = [0u8; 32];
tx_hash.copy_from_slice(&bytes[0..32]);
let tx_hash = H256Json::from(tx_hash);

let buf = bytes[32..].to_vec();
let mut cursor = Cursor::new(buf);
Expand Down Expand Up @@ -192,7 +194,7 @@ impl Qrc20Coin {
let receipts = try_s!(self.utxo.rpc_client.get_transaction_receipts(&tx_hash).compat().await);
// request Qtum transaction details to get a tx_hex, timestamp, block_height and calculate a miner_fee
let mut input_transactions = HistoryUtxoTxMap::new();
let qtum_details = try_s!(utxo_common::tx_details_by_hash(self, &tx_hash.0, &mut input_transactions).await);
let qtum_details = try_s!(utxo_common::tx_details_by_hash(self, &tx_hash, &mut input_transactions).await);
// Deserialize the UtxoTx to get a script pubkey
let qtum_tx: UtxoTx = try_s!(deserialize(
try_s!(qtum_details.tx.tx_hex().ok_or("unexpected tx type")).as_slice()
Expand Down Expand Up @@ -823,17 +825,21 @@ fn is_transfer_event_log(log: &LogEntry) -> bool {
mod tests {
use super::*;
use common::block_on;
use hex::FromHex;
use mm2_metrics::{MetricType, MetricsJson, MetricsOps};
use mm2_test_helpers::for_tests::find_metrics_in_json;
use qrc20_tests::qrc20_coin_for_test;

#[test]
fn test_tx_internal_id() {
let tx_hash = hex::decode("39104d29d77ba83c5c6c63ab7a0f096301c443b4538dc6b30140453a40caa80a").unwrap();
let expected_id = TxInternalId::new(tx_hash.as_slice().into(), 13, 257);
let tx_hash: [u8; 32] = hex::decode("39104d29d77ba83c5c6c63ab7a0f096301c443b4538dc6b30140453a40caa80a")
.unwrap()
.try_into()
.unwrap();
let expected_id = TxInternalId::new(tx_hash.into(), 13, 257);
let actual_bytes: BytesJson = expected_id.clone().into();

let mut expected_bytes = tx_hash;
let mut expected_bytes = Vec::from(tx_hash);
expected_bytes.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 13]);
expected_bytes.extend_from_slice(&[0, 0, 0, 0, 0, 0, 1, 1]);
assert_eq!(actual_bytes, expected_bytes.into());
Expand All @@ -852,10 +858,10 @@ mod tests {
let (ctx, coin) = qrc20_coin_for_test(priv_key, None);
ctx.metrics.init();

let tx_hash: H256Json = hex::decode("85ede12ccc12fb1709c4d9e403e96c0c394b0916f2f6098d41d8dfa00013fcdb")
.unwrap()
.as_slice()
.into();
let tx_hash: H256Json =
<[u8; 32]>::from_hex("85ede12ccc12fb1709c4d9e403e96c0c394b0916f2f6098d41d8dfa00013fcdb")
.unwrap()
.into();
let tx_height = 699545;
let transfer_map_expected = block_on(coin.transfer_details_by_hash(tx_hash)).unwrap();

Expand Down Expand Up @@ -884,10 +890,10 @@ mod tests {
let (ctx, coin) = qrc20_coin_for_test(priv_key, None);
ctx.metrics.init();

let tx_hash: H256Json = hex::decode("85ede12ccc12fb1709c4d9e403e96c0c394b0916f2f6098d41d8dfa00013fcdb")
.unwrap()
.as_slice()
.into();
let tx_hash: H256Json =
<[u8; 32]>::from_hex("85ede12ccc12fb1709c4d9e403e96c0c394b0916f2f6098d41d8dfa00013fcdb")
.unwrap()
.into();
let tx_height = 699545;
let transfer_map_expected = block_on(coin.transfer_details_by_hash(tx_hash)).unwrap();

Expand Down Expand Up @@ -926,20 +932,19 @@ mod tests {
let (ctx, coin) = qrc20_coin_for_test(priv_key, None);
ctx.metrics.init();

let tx_hash: H256Json = hex::decode("85ede12ccc12fb1709c4d9e403e96c0c394b0916f2f6098d41d8dfa00013fcdb")
.unwrap()
.as_slice()
.into();
let tx_hash: H256Json =
<[u8; 32]>::from_hex("85ede12ccc12fb1709c4d9e403e96c0c394b0916f2f6098d41d8dfa00013fcdb")
.unwrap()
.into();
let tx_height = 699545;
let transfer_map_expected = block_on(coin.transfer_details_by_hash(tx_hash)).unwrap();

let mut transfer_map_unexpected_tx_id = transfer_map_expected
.into_iter()
.map(|(mut id, tx)| {
// just another tx_hash
id.tx_hash = hex::decode("8a7270110ab7b56142b3bac89999276beb70320a7fe7666f460a05aa615eb0a0")
id.tx_hash = <[u8; 32]>::from_hex("8a7270110ab7b56142b3bac89999276beb70320a7fe7666f460a05aa615eb0a0")
.unwrap()
.as_slice()
.into();
(id, tx)
})
Expand All @@ -966,10 +971,10 @@ mod tests {
];
let (ctx, coin) = qrc20_coin_for_test(priv_key, None);

let tx_hash: H256Json = hex::decode("35e03bc529528a853ee75dde28f27eec8ed7b152b6af7ab6dfa5d55ea46f25ac")
.unwrap()
.as_slice()
.into();
let tx_hash: H256Json =
<[u8; 32]>::from_hex("35e03bc529528a853ee75dde28f27eec8ed7b152b6af7ab6dfa5d55ea46f25ac")
.unwrap()
.into();
let tx_height = 681443;
let transfer_map_expected = block_on(coin.transfer_details_by_hash(tx_hash)).unwrap();
let mut history_map_expected = HistoryMapByHash::new();
Expand All @@ -991,10 +996,10 @@ mod tests {
];
let (ctx, coin) = qrc20_coin_for_test(priv_key, None);

let tx_hash: H256Json = hex::decode("85ede12ccc12fb1709c4d9e403e96c0c394b0916f2f6098d41d8dfa00013fcdb")
.unwrap()
.as_slice()
.into();
let tx_hash: H256Json =
<[u8; 32]>::from_hex("85ede12ccc12fb1709c4d9e403e96c0c394b0916f2f6098d41d8dfa00013fcdb")
.unwrap()
.into();
let tx_height = 699545;
let transfer_map_expected = block_on(coin.transfer_details_by_hash(tx_hash)).unwrap();
let mut history_map_expected = HistoryMapByHash::new();
Expand All @@ -1019,14 +1024,14 @@ mod tests {
let metrics = MetricsArc::new();
metrics.init();

let tx_hash_invalid: H256Json = hex::decode("0000000000000000000000000000000000000000000000000000000000000000")
.unwrap()
.as_slice()
.into();
let tx_hash: H256Json = hex::decode("85ede12ccc12fb1709c4d9e403e96c0c394b0916f2f6098d41d8dfa00013fcdb")
.unwrap()
.as_slice()
.into();
let tx_hash_invalid: H256Json =
<[u8; 32]>::from_hex("0000000000000000000000000000000000000000000000000000000000000000")
.unwrap()
.into();
let tx_hash: H256Json =
<[u8; 32]>::from_hex("85ede12ccc12fb1709c4d9e403e96c0c394b0916f2f6098d41d8dfa00013fcdb")
.unwrap()
.into();
let tx_height = 699545;
let transfer_map_expected = block_on(coin.transfer_details_by_hash(tx_hash)).unwrap();
let mut history_map_expected = HistoryMapByHash::new();
Expand Down
14 changes: 7 additions & 7 deletions mm2src/coins/qrc20/qrc20_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,8 +481,8 @@ fn test_extract_secret() {
];
let (_ctx, coin) = qrc20_coin_for_test(priv_key, None);

let expected_secret = &[1; 32];
let secret_hash = &*dhash160(expected_secret);
let expected_secret = [1; 32];
let secret_hash = &*dhash160(&expected_secret);

// taker spent maker payment - d3f5dab4d54c14b3d7ed8c7f5c8cc7f47ccf45ce589fdc7cd5140a3c1c3df6e1
let tx_hex = hex::decode("01000000033f56ecafafc8602fde083ba868d1192d6649b8433e42e1a2d79ba007ea4f7abb010000006b48304502210093404e90e40d22730013035d31c404c875646dcf2fad9aa298348558b6d65ba60220297d045eac5617c1a3eddb71d4bca9772841afa3c4c9d6c68d8d2d42ee6de3950121022b00078841f37b5d30a6a1defb82b3af4d4e2d24dd4204d41f0c9ce1e875de1affffffff9cac7fe90d597922a1d92e05306c2215628e7ea6d5b855bfb4289c2944f4c73a030000006b483045022100b987da58c2c0c40ce5b6ef2a59e8124ed4ef7a8b3e60c7fb631139280019bc93022069649bcde6fe4dd5df9462a1fcae40598488d6af8c324cd083f5c08afd9568be0121022b00078841f37b5d30a6a1defb82b3af4d4e2d24dd4204d41f0c9ce1e875de1affffffff70b9870f2b0c65d220a839acecebf80f5b44c3ca4c982fa2fdc5552c037f5610010000006a473044022071b34dd3ebb72d29ca24f3fa0fc96571c815668d3b185dd45cc46a7222b6843f02206c39c030e618d411d4124f7b3e7ca1dd5436775bd8083a85712d123d933a51300121022b00078841f37b5d30a6a1defb82b3af4d4e2d24dd4204d41f0c9ce1e875de1affffffff020000000000000000c35403a0860101284ca402ed292b806a1835a1b514ad643f2acdb5c8db6b6a9714accff3275ea0d79a3f23be8fd00000000000000000000000000000000000000000000000000000000001312d000101010101010101010101010101010101010101010101010101010101010101000000000000000000000000d362e096e873eb7907e205fadc6175c6fec7bc440000000000000000000000009e032d4b0090a11dc40fe6c47601499a35d55fbb14ba8b71f3544b93e2f681f996da519a98ace0107ac2c02288d4010000001976a914783cf0be521101942da509846ea476e683aad83288ac0f047f5f").unwrap();
Expand All @@ -505,10 +505,10 @@ fn test_extract_secret_malicious() {
// 1 - with an invalid secret (this case should be processed correctly)
// 2 - correct spend tx
let spend_tx = hex::decode("01000000022bc8299981ec0cea664cdf9df4f8306396a02e2067d6ac2d3770b34646d2bc2a010000006b483045022100eb13ef2d99ac1cd9984045c2365654b115dd8a7815b7fbf8e2a257f0b93d1592022060d648e73118c843e97f75fafc94e5ff6da70ec8ba36ae255f8c96e2626af6260121022b00078841f37b5d30a6a1defb82b3af4d4e2d24dd4204d41f0c9ce1e875de1affffffffd92a0a10ac6d144b36033916f67ae79889f40f35096629a5cd87be1a08f40ee7010000006b48304502210080cdad5c4770dfbeb760e215494c63cc30da843b8505e75e7bf9e8dad18568000220234c0b11c41bfbcdd50046c69059976aedabe17657fe43d809af71e9635678e20121022b00078841f37b5d30a6a1defb82b3af4d4e2d24dd4204d41f0c9ce1e875de1affffffff030000000000000000c35403a0860101284ca402ed292b8620ad3b72361a5aeba5dffd333fb64750089d935a1ec974d6a91ef4f24ff6ba0000000000000000000000000000000000000000000000000000000001312d000202020202020202020202020202020202020202020202020202020202020202000000000000000000000000d362e096e873eb7907e205fadc6175c6fec7bc440000000000000000000000009e032d4b0090a11dc40fe6c47601499a35d55fbb14ba8b71f3544b93e2f681f996da519a98ace0107ac20000000000000000c35403a0860101284ca402ed292b8620ad3b72361a5aeba5dffd333fb64750089d935a1ec974d6a91ef4f24ff6ba0000000000000000000000000000000000000000000000000000000001312d000101010101010101010101010101010101010101010101010101010101010101000000000000000000000000d362e096e873eb7907e205fadc6175c6fec7bc440000000000000000000000009e032d4b0090a11dc40fe6c47601499a35d55fbb14ba8b71f3544b93e2f681f996da519a98ace0107ac2b8ea82d3010000001976a914783cf0be521101942da509846ea476e683aad83288ac735d855f").unwrap();
let expected_secret = &[1; 32];
let secret_hash = &*dhash160(expected_secret);
let expected_secret = [1; 32];
let secret_hash = &*dhash160(&expected_secret);
let actual = block_on(coin.extract_secret(secret_hash, &spend_tx, false));
assert_eq!(actual, Ok(expected_secret.to_vec()));
assert_eq!(actual, Ok(expected_secret));
}

#[test]
Expand Down Expand Up @@ -569,10 +569,10 @@ fn test_transfer_details_by_hash() {
];
let (_ctx, coin) = qrc20_coin_for_test(priv_key, None);
let tx_hash_bytes = hex::decode("85ede12ccc12fb1709c4d9e403e96c0c394b0916f2f6098d41d8dfa00013fcdb").unwrap();
let tx_hash: H256Json = tx_hash_bytes.as_slice().into();
let tx_hash: [u8; 32] = tx_hash_bytes.clone().try_into().unwrap();
let tx_hex:BytesJson = hex::decode("0100000001426d27fde82e12e1ce84e73ca41e2a30420f4c94aaa37b30d4c5b8b4f762c042040000006a473044022032665891693ee732571cefaa6d322ec5114c78259f2adbe03a0d7e6b65fbf40d022035c9319ca41e5423e09a8a613ac749a20b8f5ad6ba4ad6bb60e4a020b085d009012103693bff1b39e8b5a306810023c29b95397eb395530b106b1820ea235fd81d9ce9ffffffff050000000000000000625403a08601012844095ea7b30000000000000000000000001549128bbfb33b997949b4105b6a6371c998e212000000000000000000000000000000000000000000000000000000000000000014d362e096e873eb7907e205fadc6175c6fec7bc44c20000000000000000625403a08601012844095ea7b30000000000000000000000001549128bbfb33b997949b4105b6a6371c998e21200000000000000000000000000000000000000000000000000000000000927c014d362e096e873eb7907e205fadc6175c6fec7bc44c20000000000000000835403a0860101284c640c565ae300000000000000000000000000000000000000000000000000000000000493e0000000000000000000000000d362e096e873eb7907e205fadc6175c6fec7bc440000000000000000000000000000000000000000000000000000000000000000141549128bbfb33b997949b4105b6a6371c998e212c20000000000000000835403a0860101284c640c565ae300000000000000000000000000000000000000000000000000000000000493e0000000000000000000000000d362e096e873eb7907e205fadc6175c6fec7bc440000000000000000000000000000000000000000000000000000000000000001141549128bbfb33b997949b4105b6a6371c998e212c231754b04000000001976a9149e032d4b0090a11dc40fe6c47601499a35d55fbb88acf7cd8b5f").unwrap().into();

let details = block_on(coin.transfer_details_by_hash(tx_hash)).unwrap();
let details = block_on(coin.transfer_details_by_hash(tx_hash.into())).unwrap();
let mut it = details.into_iter().sorted_by(|(id_x, _), (id_y, _)| id_x.cmp(id_y));

let expected_fee_details = |total_gas_fee: &str| -> TxFeeDetails {
Expand Down
Loading
Loading