Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions rust/trezor-client/examples/eth_sign_tx_large.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
fn main() {
Comment thread
romanz marked this conversation as resolved.
tracing_subscriber::fmt().with_max_level(tracing::Level::TRACE).init();

// init with debugging
let mut trezor = trezor_client::unique(false).unwrap();
trezor.init_device(None).unwrap();

let signature = trezor
.ethereum_sign_tx(
// default ETH path
vec![44 + (1 << 31), 60 + (1 << 31), 0 + (1 << 31), 0, 0],
vec![],
vec![],
vec![],
"".to_string(),
vec![],
// 10kB of empty data
vec![0; 10 * 1024],
Some(1u64),
)
.unwrap();
println!("Signature: {:?}", signature);
}
8 changes: 6 additions & 2 deletions rust/trezor-client/src/client/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ impl Trezor {
let mut ack = protos::EthereumTxAck::new();
ack.set_data_chunk(data.splice(..std::cmp::min(1024, data.len()), []).collect());

resp = self.call(ack, Box::new(|_, m: protos::EthereumTxRequest| Ok(m)))?.ok()?;
resp = handle_interaction(
self.call(ack, Box::new(|_, m: protos::EthereumTxRequest| Ok(m)))?,
)?;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

convert_signature(&resp, chain_id)
Expand Down Expand Up @@ -147,7 +149,9 @@ impl Trezor {
let mut ack = protos::EthereumTxAck::new();
ack.set_data_chunk(data.splice(..std::cmp::min(1024, data.len()), []).collect());

resp = self.call(ack, Box::new(|_, m: protos::EthereumTxRequest| Ok(m)))?.ok()?
resp = handle_interaction(
self.call(ack, Box::new(|_, m: protos::EthereumTxRequest| Ok(m)))?,
)?;
}

convert_signature(&resp, chain_id)
Expand Down
8 changes: 8 additions & 0 deletions rust/trezor-client/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ impl Trezor {
self.transport.read_message().map_err(Error::TransportReceiveMessage)
}

/// Sends a message without waiting for a response.
/// Useful for fire-and-forget debug messages such as `DebugLinkDecision`, which the
/// firmware may not reply to.
pub fn send_message<S: TrezorMessage>(&mut self, message: S) -> Result<()> {
let proto_msg = ProtoMessage(S::MESSAGE_TYPE, message.write_to_bytes()?);
self.transport.write_message(proto_msg).map_err(Error::TransportSendMessage)
}

/// Sends a message and returns a TrezorResponse with either the expected response message,
/// a failure or an interaction request.
/// This method is only exported for users that want to expand the features of this library
Expand Down
97 changes: 86 additions & 11 deletions rust/trezor-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,25 @@ pub fn unique(debug: bool) -> Result<Trezor> {

#[cfg(test)]
mod tests {
use serial_test::serial;
use std::str::FromStr;
use std::{
str::FromStr,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread,
};

use crate::{client::handle_interaction, protos::IdentityType};
use bitcoin::{bip32::DerivationPath, hex::FromHex};
use serial_test::serial;

use crate::{
client::handle_interaction,
protos::{
debug_link_decision::DebugButton, DebugLinkDecision, DebugLinkGetState, DebugLinkState,
IdentityType,
},
};

use super::*;

Expand All @@ -155,6 +169,40 @@ mod tests {
emulator
}

/// Spawn a background thread that continuously sends a "YES" decision to the debug link.
fn with_auto_approve<F, T>(f: F) -> T
where
F: FnOnce() -> T,
{
let mut debuglink = find_devices(true)
.into_iter()
.find(|t| t.model == Model::TrezorEmulator)
.expect("No debug emulator found")
.connect()
.expect("Failed to connect to debug emulator");

let stop = Arc::new(AtomicBool::new(false));
let stop_clone = stop.clone();

let mut req = DebugLinkDecision::new();
req.set_button(DebugButton::YES);

thread::scope(|scope| {
scope.spawn(move || {
while !stop_clone.load(Ordering::Relaxed) {
// DebugLinkDecision has no response; send fire-and-forget then poll
// state (which returns when the firmware has processed the decision).
let _ = debuglink.send_message(req.clone());
let _ = debuglink
.call(DebugLinkGetState::new(), Box::new(|_, m: DebugLinkState| Ok(m)));
}
});
let res = f();
stop.store(true, Ordering::Relaxed);
res
})
}

#[test]
#[serial]
fn test_emulator_find() {
Expand Down Expand Up @@ -189,12 +237,9 @@ mod tests {
assert_eq!(address.ok().unwrap().to_string(), "mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q");
}

#[ignore]
#[test]
#[serial]
fn test_ecdh_shared_secret() {
tracing_subscriber::fmt().with_max_level(tracing::Level::TRACE).init();

let mut emulator = init_emulator();
assert_eq!(emulator.features().expect("Failed to get features").label(), "SLIP-0014");

Expand All @@ -208,11 +253,14 @@ mod tests {

let peer_public_key = Vec::from_hex("0407f2c6e5becf3213c1d07df0cfbe8e39f70a8c643df7575e5c56859ec52c45ca950499c019719dae0fda04248d851e52cf9d66eeb211d89a77be40de22b6c89d").unwrap();
let curve_name = "secp256k1".to_owned();
let response = handle_interaction(
emulator
.get_ecdh_session_key(ident, peer_public_key, curve_name)
.expect("Failed to get ECDH shared secret"),
)

let response = with_auto_approve(|| {
handle_interaction(
emulator
.get_ecdh_session_key(ident, peer_public_key, curve_name)
.expect("Failed to get ECDH shared secret"),
)
})
.unwrap();

let expected_session_key = Vec::from_hex("048125883b086746244b0d2c548860ecc723346e14c87e51dc7ba32791bc780d132dbd814fbee77134f318afac6ad6db3c5334efe6a8798628a1038195b96e82e2").unwrap();
Expand All @@ -223,4 +271,31 @@ mod tests {
.unwrap();
assert_eq!(response.public_key(), &expected_public_key);
}

#[test]
#[serial]
fn test_ethereum_sign_tx_large() {
let mut emulator = init_emulator();
assert_eq!(emulator.features().expect("Failed to get features").label(), "SLIP-0014");

let signature = with_auto_approve(|| {
emulator.ethereum_sign_tx(
// default ETH path
vec![44 + (1 << 31), 60 + (1 << 31), 0 + (1 << 31), 0, 0],
vec![],
vec![],
vec![],
"".to_string(),
vec![],
// 10kB of empty data
vec![0; 10 * 1024],
Some(1u64),
)
})
.unwrap();

assert_eq!(signature.r.len(), 32);
assert_eq!(signature.s.len(), 32);
assert_eq!(signature.v, 38);
}
}
Loading