diff --git a/fog/sample-paykit/src/cached_tx_data/memo_handler.rs b/fog/sample-paykit/src/cached_tx_data/memo_handler.rs index a9e2629460..5b950d25aa 100644 --- a/fog/sample-paykit/src/cached_tx_data/memo_handler.rs +++ b/fog/sample-paykit/src/cached_tx_data/memo_handler.rs @@ -86,21 +86,6 @@ impl MemoHandler { Err(MemoHandlerError::UnknownSender) } } - MemoType::AuthenticatedSenderWithData(memo) => { - if let Some(addr) = self.contacts.get(&memo.sender_address_hash()) { - if bool::from(memo.validate( - addr, - &account_key.default_subaddress_view_private(), - &tx_out.public_key, - )) { - Ok(Some(memo_type)) - } else { - Err(MemoHandlerError::FailedHmacValidation) - } - } else { - Err(MemoHandlerError::UnknownSender) - } - } MemoType::AuthenticatedSenderWithPaymentIntentId(memo) => { if let Some(addr) = self.contacts.get(&memo.sender_address_hash()) { if bool::from(memo.validate( @@ -138,13 +123,6 @@ impl MemoHandler { Err(MemoHandlerError::FailedSubaddressValidation) } } - MemoType::DestinationWithData(_) => { - if subaddress_matches_tx_out(account_key, CHANGE_SUBADDRESS_INDEX, tx_out)? { - Ok(Some(memo_type)) - } else { - Err(MemoHandlerError::FailedSubaddressValidation) - } - } MemoType::DestinationWithPaymentRequestId(_) => { if subaddress_matches_tx_out(account_key, CHANGE_SUBADDRESS_INDEX, tx_out)? { Ok(Some(memo_type)) diff --git a/transaction/extra/src/lib.rs b/transaction/extra/src/lib.rs index a4e7da75cd..99c559b286 100644 --- a/transaction/extra/src/lib.rs +++ b/transaction/extra/src/lib.rs @@ -21,10 +21,9 @@ mod unsigned_tx; pub use memo::{ compute_authenticated_sender_memo, compute_destination_memo, AuthenticatedSenderMemo, - AuthenticatedSenderWithDataMemo, AuthenticatedSenderWithPaymentIntentIdMemo, - AuthenticatedSenderWithPaymentRequestIdMemo, BurnRedemptionMemo, DefragmentationMemo, - DefragmentationMemoError, DestinationMemo, DestinationMemoError, DestinationWithDataMemo, - DestinationWithPaymentIntentIdMemo, DestinationWithPaymentRequestIdMemo, + AuthenticatedSenderWithPaymentIntentIdMemo, AuthenticatedSenderWithPaymentRequestIdMemo, + BurnRedemptionMemo, DefragmentationMemo, DefragmentationMemoError, DestinationMemo, + DestinationMemoError, DestinationWithPaymentIntentIdMemo, DestinationWithPaymentRequestIdMemo, GiftCodeCancellationMemo, GiftCodeFundingMemo, GiftCodeSenderMemo, MemoDecodingError, MemoType, RegisteredMemoType, SenderMemoCredential, UnusedMemo, }; diff --git a/transaction/extra/src/memo/authenticated_sender_with_data.rs b/transaction/extra/src/memo/authenticated_sender_with_data.rs deleted file mode 100644 index dd4964918c..0000000000 --- a/transaction/extra/src/memo/authenticated_sender_with_data.rs +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2018-2023 The MobileCoin Foundation - -//! Object for 0x0103 Authenticated Sender With Data memo type -//! -//! This was proposed for standardization in mobilecoinfoundation/mcips/pull/60 - -use super::{ - authenticated_common::{compute_authenticated_sender_memo, validate_authenticated_sender}, - credential::SenderMemoCredential, - RegisteredMemoType, -}; -use crate::impl_memo_type_conversions; -use mc_account_keys::{PublicAddress, ShortAddressHash}; -use mc_crypto_keys::{CompressedRistrettoPublic, RistrettoPrivate, RistrettoPublic}; -use subtle::Choice; - -/// A memo that the sender writes to convey their identity in an authenticated -/// but deniable way, for the recipient of a TxOut, which also includes data -/// -/// See mobilecoinfoundation/mcips/pull/4 for a discussion of the deniability -/// property. -/// -/// The recipient of this memo type should: -/// * First, use sender_address_hash to look up the address of the sender, from -/// among their contacts. If the sender isn't known then we can't validate. -/// * Then, call validate to check the mac and confirm authenticity. -/// * We can extract the data for use with other applications like moby. -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] -pub struct AuthenticatedSenderWithDataMemo { - /// The memo data - memo_data: [u8; 64], -} - -impl RegisteredMemoType for AuthenticatedSenderWithDataMemo { - const MEMO_TYPE_BYTES: [u8; 2] = [0x01, 0x03]; -} - -impl AuthenticatedSenderWithDataMemo { - /// Create a new AuthenticatedSenderMemo given credential, recipient public - /// key, and tx out public key and data - /// - /// # Arguments: - /// * cred: A sender memo credential tied to the address we wish to identify - /// ourselves as - /// * receiving_subaddress_view_public_key: This is the view public key from - /// the public address of recipient - /// * tx_out_public_key: The public_key of the TxOut to which we will attach - /// this memo - /// * data: The data - pub fn new( - cred: &SenderMemoCredential, - receiving_subaddress_view_public_key: &RistrettoPublic, - tx_out_public_key: &CompressedRistrettoPublic, - data: &[u8], - ) -> Self { - // The layout of the memo is: - // [0-16) address hash - // [16-48) data - // [48-64) HMAC - let memo_data = compute_authenticated_sender_memo( - Self::MEMO_TYPE_BYTES, - cred, - receiving_subaddress_view_public_key, - tx_out_public_key, - data, - ); - Self { memo_data } - } - - /// Get the sender address hash from the memo - pub fn sender_address_hash(&self) -> ShortAddressHash { - let bytes: [u8; 16] = self.memo_data[0..16].try_into().unwrap(); - ShortAddressHash::from(bytes) - } - - /// Get the data from the memo - pub fn data(&self) -> &[u8] { - self.memo_data[16..48].try_into().unwrap() - } - - /// Validate an AuthenticatedSenderMemo - /// - /// First, the client should look up the sender's Public Address from their - /// hash. If it isn't a known contact we won't be able to authenticate - /// them. - /// - /// Then they need to get the view private key corresponding to the - /// subaddress that this TxOut was sent to. This is usually our default - /// subaddress view private key. - /// - /// Finally we can validate the memo against these data. The - /// tx_out_public_key is also under the mac, which prevents replay - /// attacks. - /// - /// Arguments: - /// * sender_address: The public address of the sender. This can be looked - /// up by the ShortAddressHash provided. - /// * receiving_subaddress_view_private_key: This is usually our - /// default_subaddress_view_private_key, but should correspond to whatever - /// subaddress received this TxOut. - /// * tx_out_public_key: The public key of the TxOut to which this memo is - /// attached. - /// - /// Returns: - /// * subtle::Choice(1u8) if validation passed, subtle::Choice(0u8) if HMAC - /// comparison failed. - /// - /// This function is constant-time. - pub fn validate( - &self, - sender_address: &PublicAddress, - receiving_subaddress_view_private_key: &RistrettoPrivate, - tx_out_public_key: &CompressedRistrettoPublic, - ) -> Choice { - validate_authenticated_sender( - sender_address, - receiving_subaddress_view_private_key, - tx_out_public_key, - Self::MEMO_TYPE_BYTES, - &self.memo_data, - ) - } -} - -impl From<&[u8; 64]> for AuthenticatedSenderWithDataMemo { - fn from(src: &[u8; 64]) -> Self { - let mut memo_data = [0u8; 64]; - memo_data.copy_from_slice(src); - Self { memo_data } - } -} - -impl From for [u8; 64] { - fn from(src: AuthenticatedSenderWithDataMemo) -> [u8; 64] { - src.memo_data - } -} - -impl_memo_type_conversions! { AuthenticatedSenderWithDataMemo } diff --git a/transaction/extra/src/memo/destination_with_data.rs b/transaction/extra/src/memo/destination_with_data.rs deleted file mode 100644 index 5cc76e1728..0000000000 --- a/transaction/extra/src/memo/destination_with_data.rs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) 2018-2023 The MobileCoin Foundation - -//! Object for 0x0205 Destination With Data memo type -//! -//! This was proposed for standardization in mobilecoinfoundation/mcips/pull/60 - -use super::{compute_destination_memo, DestinationMemoError, RegisteredMemoType}; -use crate::impl_memo_type_conversions; -use mc_account_keys::ShortAddressHash; - -/// A memo that the sender writes to themselves to record details of the -/// transaction, and attaches to the change TxOut so that they can recover it -/// later. -/// -/// See RFC for extended discussion. -/// -/// This memo should be validated by confirming that the TxOut matches to the -/// change subaddress. -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] -pub struct DestinationWithDataMemo { - /// The address hash of the recipient to whom the payment is attributed - address_hash: ShortAddressHash, - /// The number of recipients of the transaction (ignoring the change output - /// and fee). For a typical transaction, this is one, and the address - /// hash refers to that recipient. When there is more than one - /// recipient, one of them can be chosen arbitrarily. - num_recipients: u8, - /// The total fee paid in the transaction (in the smallest unit for the - /// currency) - /// - /// Note: We assume that the high order byte of fee is zero, and use this - /// to compress the memo into 32 bytes. For this assumption not to be - /// correct, there would have to be a transaction that spends more than - /// 1% of all of MOB as the fee, which is considered not an important - /// scenario. - fee: u64, - /// The sum of all outlays of the transaction (in the smallest unit for the - /// currency) Here outlay means, the total amount that is deducted from - /// the sender's balance because of this transaction. This includes - /// outgoing payments, and the transaction fee, and does not include any - /// change amounts. - /// - /// For a typical transaction with one recipient, this refers to the amount - /// of a single TxOut, plus the fee. - /// - /// This memo is attached to the change TxOut of the transaction, and from - /// the amount of that, and this memo, the owner can determine the sum of - /// the inputs spent in the transaction by adding change + total_outlay - /// - /// Note: It is technically possible the total outlay is not representable - /// as a u64. In that case, the memo builder is responsible to signal an - /// an error. The client may disable destination memos for this transaction. - total_outlay: u64, - /// Some data - /// - /// This is generated data. - data: [u8; 32], -} - -impl RegisteredMemoType for DestinationWithDataMemo { - const MEMO_TYPE_BYTES: [u8; 2] = [0x02, 0x05]; -} - -impl DestinationWithDataMemo { - /// Create a new destination memo set up for a single recipient - /// (To create a memo for multiple recipients, use set_num_recipients) - /// - /// Returns an error if the data are out of bounds - pub fn new( - address_hash: ShortAddressHash, - total_outlay: u64, - fee: u64, - data: &[u8], - ) -> Result { - let mut memo_data = [0u8; 32]; - memo_data.copy_from_slice(data); - - let mut result = Self { - address_hash, - num_recipients: 1, - total_outlay, - fee: 0, - data: memo_data, - }; - result.set_fee(fee)?; - Ok(result) - } - - /// Get the address hash - pub fn get_address_hash(&self) -> &ShortAddressHash { - &self.address_hash - } - /// Set the address hash - pub fn set_address_hash(&mut self, val: ShortAddressHash) { - self.address_hash = val; - } - /// Get the number of recipients - pub fn get_num_recipients(&self) -> u8 { - self.num_recipients - } - /// Set the number of recipients - pub fn set_num_recipients(&mut self, val: u8) { - self.num_recipients = val; - } - /// Get the fee - pub fn get_fee(&self) -> u64 { - self.fee - } - /// Set the fee. Returns an error if the fee is too large to be represented. - pub fn set_fee(&mut self, val: u64) -> Result<(), DestinationMemoError> { - if val.to_be_bytes()[0] != 0u8 { - return Err(DestinationMemoError::FeeTooLarge); - } - self.fee = val; - Ok(()) - } - /// Get the total outlay - pub fn get_total_outlay(&self) -> u64 { - self.total_outlay - } - /// Set the total outlay - pub fn set_total_outlay(&mut self, val: u64) { - self.total_outlay = val; - } - /// Get the data - pub fn get_data(&self) -> &[u8] { - &self.data - } - /// Set the data - pub fn set_data(&mut self, val: &[u8]) { - self.data.copy_from_slice(val); - } -} - -impl From<&[u8; 64]> for DestinationWithDataMemo { - // The layout of the memo data in 64 bytes is: - // [0-16): sender_address_hash - // [16]: num_recipients - // [17-24): fee - // [24-32): total outlay - // [32-64): data - fn from(src: &[u8; 64]) -> Self { - let address_hash: [u8; 16] = src[0..16].try_into().expect("arithmetic error"); - let num_recipients = src[16]; - let fee = { - let mut fee_bytes = [0u8; 8]; - fee_bytes[1..].copy_from_slice(&src[17..24]); - u64::from_be_bytes(fee_bytes) - }; - let total_outlay = u64::from_be_bytes(src[24..32].try_into().expect("arithmetic error")); - let mut data = [0u8; 32]; - data.copy_from_slice(&src[32..64]); - - Self { - address_hash: address_hash.into(), - num_recipients, - fee, - total_outlay, - data, - } - } -} - -impl From for [u8; 64] { - fn from(src: DestinationWithDataMemo) -> [u8; 64] { - compute_destination_memo( - src.address_hash, - src.fee, - src.num_recipients, - src.total_outlay, - src.data, - ) - } -} - -impl_memo_type_conversions! { DestinationWithDataMemo } diff --git a/transaction/extra/src/memo/mod.rs b/transaction/extra/src/memo/mod.rs index 54f6d86043..38a0e7d9fd 100644 --- a/transaction/extra/src/memo/mod.rs +++ b/transaction/extra/src/memo/mod.rs @@ -50,14 +50,12 @@ pub use self::{ authenticated_common::{compute_authenticated_sender_memo, compute_category1_hmac}, authenticated_sender::AuthenticatedSenderMemo, - authenticated_sender_with_data::AuthenticatedSenderWithDataMemo, authenticated_sender_with_payment_intent_id::AuthenticatedSenderWithPaymentIntentIdMemo, authenticated_sender_with_payment_request_id::AuthenticatedSenderWithPaymentRequestIdMemo, burn_redemption::BurnRedemptionMemo, credential::SenderMemoCredential, defragmentation::{DefragmentationMemo, DefragmentationMemoError}, destination::{compute_destination_memo, DestinationMemo, DestinationMemoError}, - destination_with_data::DestinationWithDataMemo, destination_with_payment_intent_id::DestinationWithPaymentIntentIdMemo, destination_with_payment_request_id::DestinationWithPaymentRequestIdMemo, gift_code_cancellation::GiftCodeCancellationMemo, @@ -68,14 +66,12 @@ pub use self::{ mod authenticated_common; mod authenticated_sender; -mod authenticated_sender_with_data; mod authenticated_sender_with_payment_intent_id; mod authenticated_sender_with_payment_request_id; mod burn_redemption; mod credential; mod defragmentation; mod destination; -mod destination_with_data; mod destination_with_payment_intent_id; mod destination_with_payment_request_id; mod gift_code_cancellation; @@ -113,13 +109,11 @@ impl_memo_enum! { MemoType, AuthenticatedSender(AuthenticatedSenderMemo), //[0x01, 0x00] AuthenticatedSenderWithPaymentRequestId(AuthenticatedSenderWithPaymentRequestIdMemo), //[0x01, 0x01] AuthenticatedSenderWithPaymentIntentId(AuthenticatedSenderWithPaymentIntentIdMemo), //[0x01, 0x02] - AuthenticatedSenderWithData(AuthenticatedSenderWithDataMemo), //[0x01, 0x03] BurnRedemption(BurnRedemptionMemo), //[0x00, 0x01] Defragmentation(DefragmentationMemo), //[0x00, 0x03] Destination(DestinationMemo), //[0x02, 0x00] DestinationWithPaymentRequestId(DestinationWithPaymentRequestIdMemo), //[0x02, 0x03] DestinationWithPaymentIntentId(DestinationWithPaymentIntentIdMemo), //[0x02, 0x04] - DestinationWithData(DestinationWithDataMemo), //[0x02, 0x05] GiftCodeCancellation(GiftCodeCancellationMemo), //[0x02, 0x02] GiftCodeFunding(GiftCodeFundingMemo), //[0x02, 0x01] GiftCodeSender(GiftCodeSenderMemo), //[0x00, 0x02]