1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
// Copyright (c) 2022-2023 The MobileCoin Foundation
//! Memo signing API
//!
//!
use futures::executor::block_on;
use ledger_lib::Device;
use ledger_mob_apdu::{
state::{Digest, TxState},
tx::{TxMemoSig, TxMemoSign},
};
use mc_core::{account::PublicSubaddress, keys::TxOutPublic};
use mc_transaction_signer::traits::MemoHmacSigner;
use super::{check_digest, check_state, Error, TransactionHandle};
/// Sync [MemoHmacSigner] implementation for [TransactionHandle]
///
/// Note: this MUST be called from a tokio context
impl<T: Device> MemoHmacSigner for TransactionHandle<T> {
type Error = Error;
/// Compute the HMAC signature for the provided memo and target address
fn compute_memo_hmac_sig(
&self,
sender_subaddress_index: u64,
tx_public_key: &TxOutPublic,
target_subaddress: PublicSubaddress,
memo_type: &[u8; 2],
memo_data_sans_hmac: &[u8; 48],
) -> Result<[u8; 16], Self::Error> {
tokio::task::block_in_place(|| {
block_on(async {
self.memo_sign(
sender_subaddress_index,
tx_public_key,
target_subaddress,
memo_type,
memo_data_sans_hmac,
)
.await
})
})
}
}
impl<T: Device> TransactionHandle<T> {
/// Asynchronously compute the HMAC signature for the provided memo
/// and target address.
///
/// See [MemoHmacSigner] for the public blocking API.
pub async fn memo_sign(
&self,
sender_subaddress_index: u64,
tx_public_key: &TxOutPublic,
target_subaddress: PublicSubaddress,
memo_type: &[u8; 2],
memo_data_sans_hmac: &[u8; 48],
) -> Result<[u8; 16], Error> {
let mut buff = [0u8; 256];
// TODO: device state has tx_out_private_key,
// other memo keys recoverable from target_subaddress,
// though this doesn't match proposed API?
let mut t = self.t.lock().await;
// TODO: check transaction / engine state is correct for memo signing
// Build memo signing request
let tx_memo_sign = TxMemoSign::new(
sender_subaddress_index,
tx_public_key.clone(),
&target_subaddress,
*memo_type,
*memo_data_sans_hmac,
);
// Update transaction digest
let digest = {
let mut state = self.state.borrow_mut();
Digest::update(&mut state.digest, &tx_memo_sign.hash()).clone()
};
// Execute memo signing
let r = t
.request::<TxMemoSig>(tx_memo_sign, &mut buff, self.info.request_timeout)
.await?;
// Check state and expected digest
check_state(r.state, TxState::SignMemos)?;
check_digest(&r.digest, &digest)?;
// Update submitted memo count
{
let mut state = self.state.borrow_mut();
state.memo_count += 1;
}
Ok(r.hmac)
}
}