diff --git a/common/src/chain/transaction/signature/inputsig/arbitrary_message/mod.rs b/common/src/chain/transaction/signature/inputsig/arbitrary_message/mod.rs index f8d568541..3fee9030d 100644 --- a/common/src/chain/transaction/signature/inputsig/arbitrary_message/mod.rs +++ b/common/src/chain/transaction/signature/inputsig/arbitrary_message/mod.rs @@ -74,8 +74,8 @@ impl ArbitraryMessageSignature { Self { raw_signature } } - pub fn to_hex(self) -> String { - hex::encode(self.raw_signature) + pub fn to_hex(&self) -> String { + self.as_ref().to_hex() } pub fn as_raw(&self) -> &[u8] { @@ -86,35 +86,17 @@ impl ArbitraryMessageSignature { self.raw_signature } + pub fn as_ref(&self) -> ArbitraryMessageSignatureRef<'_> { + ArbitraryMessageSignatureRef::from_data(&self.raw_signature) + } + pub fn verify_signature( &self, chain_config: &ChainConfig, destination: &Destination, challenge: &H256, ) -> Result<(), DestinationSigError> { - match destination { - Destination::PublicKeyHash(addr) => { - let sig_components = AuthorizedPublicKeyHashSpend::from_data(&self.raw_signature)?; - verify_public_key_hash_spending(addr, &sig_components, challenge)? - } - Destination::PublicKey(pubkey) => { - let sig_components = AuthorizedPublicKeySpend::from_data(&self.raw_signature)?; - verify_public_key_spending(pubkey, &sig_components, challenge)? - } - Destination::ScriptHash(_) => return Err(DestinationSigError::Unsupported), - Destination::AnyoneCanSpend => { - // AnyoneCanSpend makes no sense for signing and verification. - return Err( - DestinationSigError::AttemptedToVerifyStandardSignatureForAnyoneCanSpend, - ); - } - Destination::ClassicMultisig(h) => { - let sig_components = - AuthorizedClassicalMultisigSpend::from_data(&self.raw_signature)?; - verify_classical_multisig_spending(chain_config, h, &sig_components, challenge)? - } - } - Ok(()) + self.as_ref().verify_signature(chain_config, destination, challenge) } pub fn produce_uniparty_signature( @@ -165,5 +147,55 @@ impl ArbitraryMessageSignature { } } +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ArbitraryMessageSignatureRef<'a> { + raw_signature: &'a [u8], +} + +impl<'a> ArbitraryMessageSignatureRef<'a> { + pub fn from_data(raw_signature: &'a [u8]) -> Self { + Self { raw_signature } + } + + pub fn to_hex(&self) -> String { + hex::encode(self.raw_signature) + } + + pub fn as_raw(&self) -> &[u8] { + self.raw_signature + } + + pub fn verify_signature( + &self, + chain_config: &ChainConfig, + destination: &Destination, + challenge: &H256, + ) -> Result<(), DestinationSigError> { + match destination { + Destination::PublicKeyHash(addr) => { + let sig_components = AuthorizedPublicKeyHashSpend::from_data(self.raw_signature)?; + verify_public_key_hash_spending(addr, &sig_components, challenge)? + } + Destination::PublicKey(pubkey) => { + let sig_components = AuthorizedPublicKeySpend::from_data(self.raw_signature)?; + verify_public_key_spending(pubkey, &sig_components, challenge)? + } + Destination::ScriptHash(_) => return Err(DestinationSigError::Unsupported), + Destination::AnyoneCanSpend => { + // AnyoneCanSpend makes no sense for signing and verification. + return Err( + DestinationSigError::AttemptedToVerifyStandardSignatureForAnyoneCanSpend, + ); + } + Destination::ClassicMultisig(h) => { + let sig_components = + AuthorizedClassicalMultisigSpend::from_data(self.raw_signature)?; + verify_classical_multisig_spending(chain_config, h, &sig_components, challenge)? + } + } + Ok(()) + } +} + #[cfg(test)] mod tests; diff --git a/common/src/chain/transaction/signature/inputsig/authorize_pubkeyhash_spend.rs b/common/src/chain/transaction/signature/inputsig/authorize_pubkeyhash_spend.rs index 819aa73d6..d1da0e5c1 100644 --- a/common/src/chain/transaction/signature/inputsig/authorize_pubkeyhash_spend.rs +++ b/common/src/chain/transaction/signature/inputsig/authorize_pubkeyhash_spend.rs @@ -59,7 +59,7 @@ pub fn verify_public_key_hash_spending( } pub fn sign_public_key_hash_spending( - private_key: &crypto::key::PrivateKey, + private_key: &PrivateKey, spendee_addr: &PublicKeyHash, sighash: &H256, rng: R, @@ -69,16 +69,16 @@ pub fn sign_public_key_hash_spending( if calculated_addr != *spendee_addr { return Err(DestinationSigError::PublicKeyToAddressMismatch); } - sign_public_key_hash_spending_impl(&private_key, public_key, sighash, rng) + sign_public_key_hash_spending_impl(private_key, public_key, sighash, rng) } pub fn sign_public_key_hash_spending_unchecked( - private_key: &crypto::key::PrivateKey, + private_key: &PrivateKey, sighash: &H256, rng: R, ) -> Result { let public_key = PublicKey::from_private_key(private_key); - sign_public_key_hash_spending_impl(&private_key, public_key, sighash, rng) + sign_public_key_hash_spending_impl(private_key, public_key, sighash, rng) } fn sign_public_key_hash_spending_impl( diff --git a/common/src/chain/transaction/signed_transaction_intent.rs b/common/src/chain/transaction/signed_transaction_intent.rs index cf397b710..6b68536dc 100644 --- a/common/src/chain/transaction/signed_transaction_intent.rs +++ b/common/src/chain/transaction/signed_transaction_intent.rs @@ -20,7 +20,9 @@ use utils::ensure; use crate::{ chain::{ - signature::inputsig::arbitrary_message::{self, ArbitraryMessageSignature}, + signature::inputsig::arbitrary_message::{ + self, ArbitraryMessageSignature, ArbitraryMessageSignatureRef, + }, ChainConfig, Destination, Transaction, }, primitives::{Id, Idable as _}, @@ -192,8 +194,7 @@ impl SignedTransactionIntent { | Destination::ClassicMultisig(_)) => dest.clone(), }; - // FIXME avoid extra copy by introducing ArbitraryMessageSignatureRef and moving `verify_signature` there. - let signature = ArbitraryMessageSignature::from_data(signature.clone()); + let signature = ArbitraryMessageSignatureRef::from_data(signature); signature .verify_signature(chain_config, &destination, &signed_challenge) diff --git a/wallet/src/signer/software_signer/mod.rs b/wallet/src/signer/software_signer/mod.rs index 754ff3502..06f8bab5e 100644 --- a/wallet/src/signer/software_signer/mod.rs +++ b/wallet/src/signer/software_signer/mod.rs @@ -371,9 +371,8 @@ impl<'a, T: WalletStorageReadUnlocked> Signer for SoftwareSigner<'a, T> { input_destinations, intent, |dest| { - Ok(self - .get_private_key_for_destination(dest, key_chain)? - .ok_or(SignerError::DestinationNotFromThisWallet)?) + self.get_private_key_for_destination(dest, key_chain)? + .ok_or(SignerError::DestinationNotFromThisWallet) }, make_true_rng(), ) diff --git a/wallet/wallet-rpc-daemon/docs/RPC.md b/wallet/wallet-rpc-daemon/docs/RPC.md index 3750bd5c2..55683f7da 100644 --- a/wallet/wallet-rpc-daemon/docs/RPC.md +++ b/wallet/wallet-rpc-daemon/docs/RPC.md @@ -1130,8 +1130,8 @@ Returns: Create a transaction for sending tokens to the given address, without submitting it. The wallet will automatically calculate the required information. -The optional "intent" is an arbitrary string that will concatenated with the id of the created transaction -and signed by one of the keys that were used to sign the transaction itself; this can be used to declare +The "intent" is an arbitrary string that will be concatenated with the id of the created transaction +and signed by all the keys that were used to sign the transaction itself; this can be used to declare the intent of the transaction. E.g. when bridging Mintlayer tokens to another chain, you need to send tokens to an address provided by the bridge and provide the bridge with the destination address on the foreign chain where you want @@ -1148,9 +1148,7 @@ Parameters: "amount": EITHER OF 1) { "atoms": number string } 2) { "decimal": decimal string }, - "intent": EITHER OF - 1) string - 2) null, + "intent": string, "options": { "in_top_x_mb": EITHER OF 1) number 2) null }, @@ -1159,7 +1157,10 @@ Parameters: Returns: ``` -hex string +[ + hex string, + hex string, +] ``` ### Method `make_tx_to_send_tokens_from_multisig_address`