Skip to content

Commit c4e0a98

Browse files
committed
Update ledger signer to refer to the latest version of ledger app (post cleanup); add a test for signing a tx with no outputs
1 parent 6c8a080 commit c4e0a98

10 files changed

Lines changed: 314 additions & 111 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,8 @@ rev = "c8ed12e89788e78d77cdc0dc9fb8a4bd4dc24b89"
300300

301301
[workspace.dependencies.mintlayer-ledger-messages]
302302
git = "https://github.com/mintlayer/mintlayer-ledger-app"
303-
# The commit "Add technical specification"
304-
rev = "16dce6ab619529d5b8f506cb6c2e4f62199b25d7"
303+
# The commit "Fix CI"
304+
rev = "929b3b600f513dec75975c2428d6d809319aa8ee"
305305
package = "mintlayer-messages"
306306

307307
[workspace.dependencies.trezor-client]

common/src/chain/transaction/signature/sighash/input_commitments/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ pub use info_providers::{
4444
/// with the `Option`, provided that only `None` and `Utxo` variants are used.
4545
/// 2) The `ProduceBlockFromStakeUtxo`, `FillOrderAccountCommand` and `ConcludeOrderAccountCommand`
4646
/// commitments are enabled since `SighashInputCommitmentVersion::V1`.
47+
///
48+
/// TODO: next time there is a need to update input commitments, consider also committing to
49+
/// the destination that the input is signed against (i.e. order conclude key, token authority,
50+
/// delegation owner); this will allow hardware wallets to prove (and therefore claim on the screen
51+
/// during input review) that a particular input is signed with a particular key (note that in the
52+
/// SigHashType::ALL case each input signature is a signature over the entire tx, so the host may
53+
/// claim that inputs x and y are signed with keys A and B respectively, while in reality it's vice
54+
/// versa, and hardware wallets have no way of verifying this in the general case).
4755
#[derive(Clone, Debug, Encode, Decode, Eq, PartialEq, EnumDiscriminants)]
4856
#[strum_discriminants(name(SighashInputCommitmentTag), derive(EnumIter))]
4957
pub enum SighashInputCommitment<'a> {

wallet/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ bip39 = { workspace = true, default-features = false, features = [
3333
derive_more.workspace = true
3434
hex.workspace = true
3535
itertools.workspace = true
36-
ml_primitives.workspace = true
3736
parity-scale-codec.workspace = true
3837
semver.workspace = true
3938
serde.workspace = true

wallet/src/signer/ledger_signer/ledger_messages.rs

Lines changed: 45 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use utils::ensure;
2727

2828
use crate::signer::ledger_signer::LedgerError;
2929

30-
use super::{LSighashInputCommitment, LedgerSignature};
30+
use super::LedgerSignature;
3131

3232
macro_rules! ensure_response_type {
3333
($resp:expr, $pattern:pat $(if $guard:expr)?, $out:expr) => {
@@ -132,8 +132,8 @@ pub async fn sign_challenge<L: Exchange>(
132132
path: ledger_msg::Bip32Path,
133133
addr_type: ledger_msg::AddrType,
134134
message: &[u8],
135-
) -> Result<ledger_msg::SignatureResponse, LedgerError> {
136-
let req = ledger_msg::SignMessageReq {
135+
) -> Result<ledger_msg::Signature, LedgerError> {
136+
let req = ledger_msg::SignMessageStartReq {
137137
coin,
138138
addr_type,
139139
path,
@@ -142,7 +142,7 @@ pub async fn sign_challenge<L: Exchange>(
142142
let resp = send_chunked(
143143
ledger,
144144
ledger_msg::Ins::SIGN_MSG,
145-
ledger_msg::SignP1::Start.into(),
145+
ledger_msg::SignMsgP1::Start.into(),
146146
&ledger_msg::encode(req),
147147
)
148148
.await?;
@@ -152,7 +152,7 @@ pub async fn sign_challenge<L: Exchange>(
152152
let resp = send_chunked(
153153
ledger,
154154
ledger_msg::Ins::SIGN_MSG,
155-
ledger_msg::SignP1::Next.into(),
155+
ledger_msg::SignMsgP1::Next.into(),
156156
message,
157157
)
158158
.await?;
@@ -176,7 +176,7 @@ pub async fn check_current_app<L: Exchange + Device + Send>(
176176
}
177177

178178
pub async fn ping<L: Exchange>(ledger: &mut L) -> Result<(), LedgerError> {
179-
let apdu = make_apdu(ledger_msg::Ins::PING, ledger_msg::PingP1::Start.into(), &[])?;
179+
let apdu = make_apdu(ledger_msg::Ins::PING, ledger_msg::PingP1::Dummy.into(), &[])?;
180180

181181
let mut msg_buf = Vec::with_capacity(apdu.bytes_count());
182182
apdu.write_bytes(&mut msg_buf);
@@ -196,12 +196,12 @@ pub async fn get_extended_public_key<L: Exchange>(
196196
let path = ledger_msg::Bip32Path(
197197
derivation_path.as_slice().iter().map(|c| c.into_encoded_index()).collect(),
198198
);
199-
let req = ledger_msg::PublicKeyReq { coin_type, path };
199+
let req = ledger_msg::GetPubKeyReq { coin_type, path };
200200

201201
let resp = send_chunked(
202202
ledger,
203-
ledger_msg::Ins::PUB_KEY,
204-
ledger_msg::PubKeyP1::NoDisplayAddress.into(),
203+
ledger_msg::Ins::GET_PUB_KEY,
204+
ledger_msg::GetPubKeyP1::NoDisplayAddress.into(),
205205
&ledger_msg::encode(req),
206206
)
207207
.await?;
@@ -221,34 +221,33 @@ pub async fn get_extended_public_key<L: Exchange>(
221221
pub async fn sign_tx<L: Exchange>(
222222
ledger: &mut L,
223223
chain_type: ledger_msg::CoinType,
224-
inputs: Vec<ledger_msg::TxInputReq>,
225-
input_commitments: Vec<LSighashInputCommitment>,
226-
outputs: Vec<ledger_msg::TxOutputReq>,
224+
inputs: Vec<ledger_msg::TxInputData>,
225+
input_commitments: Vec<ledger_msg::SighashInputCommitment>,
226+
outputs: Vec<ledger_msg::TxOutputData>,
227227
) -> Result<BTreeMap<usize, Vec<LedgerSignature>>, LedgerError> {
228-
let metadata = ledger_msg::encode(ledger_msg::TxMetadataReq {
228+
let start_req = ledger_msg::encode(ledger_msg::SignTxStartReq {
229229
coin: chain_type,
230-
version: ledger_msg::TxMetadataVersionReq::V1(ledger_msg::TxMetadataV1Req {
231-
num_inputs: inputs.len() as u32,
232-
num_outputs: outputs.len() as u32,
233-
}),
230+
version: ledger_msg::TransactionVersion::V1,
231+
num_inputs: inputs.len() as u32,
232+
num_outputs: outputs.len() as u32,
234233
});
235234

236235
let resp = send_chunked(
237236
ledger,
238237
ledger_msg::Ins::SIGN_TX,
239-
ledger_msg::SignP1::Start.into(),
240-
&metadata,
238+
ledger_msg::SignTxP1::Start.into(),
239+
&start_req,
241240
)
242241
.await?;
243242
let resp = decode_response(&resp)?;
244243
ensure_response_type!(resp, ledger_msg::Response::TxSetup, ());
245244

246-
for inp in inputs {
245+
for input in inputs {
247246
let resp = send_chunked(
248247
ledger,
249248
ledger_msg::Ins::SIGN_TX,
250-
ledger_msg::SignP1::Next.into(),
251-
&ledger_msg::encode(ledger_msg::SignTxReq::Input(Box::new(inp))),
249+
ledger_msg::SignTxP1::Next.into(),
250+
&ledger_msg::encode(ledger_msg::SignTxNextReq::ProcessInput(Box::new(input))),
252251
)
253252
.await?;
254253
let resp = decode_response(&resp)?;
@@ -259,51 +258,49 @@ pub async fn sign_tx<L: Exchange>(
259258
let resp = send_chunked(
260259
ledger,
261260
ledger_msg::Ins::SIGN_TX,
262-
ledger_msg::SignP1::Next.into(),
263-
&ledger_msg::encode(ledger_msg::SignTxReq::InputCommitment(Box::new(commitment))),
261+
ledger_msg::SignTxP1::Next.into(),
262+
&ledger_msg::encode(ledger_msg::SignTxNextReq::ProcessInputCommitment(Box::new(
263+
ledger_msg::TxInputCommitmentData { commitment },
264+
))),
264265
)
265266
.await?;
266267
let resp = decode_response(&resp)?;
267268
ensure_response_type!(resp, ledger_msg::Response::TxNext, ());
268269
}
269270

270-
// Send tx outputs and retrieve the first signature from the response for the last output.
271-
// TODO: this won't work if the tx has zero outputs.
272-
let mut sig_resp = vec![];
273-
let num_outputs = outputs.len();
274-
for (idx, o) in outputs.into_iter().enumerate() {
271+
for output in outputs {
275272
let resp = send_chunked(
276273
ledger,
277274
ledger_msg::Ins::SIGN_TX,
278-
ledger_msg::SignP1::Next.into(),
279-
&ledger_msg::encode(ledger_msg::SignTxReq::Output(Box::new(o))),
275+
ledger_msg::SignTxP1::Next.into(),
276+
&ledger_msg::encode(ledger_msg::SignTxNextReq::ProcessOutput(Box::new(output))),
280277
)
281278
.await?;
282279

283-
if idx < num_outputs - 1 {
284-
let resp = decode_response(&resp)?;
285-
ensure_response_type!(resp, ledger_msg::Response::TxNext, ());
286-
} else {
287-
// the response from the last output will have the first signature returned
288-
sig_resp = resp;
289-
};
280+
let resp = decode_response(&resp)?;
281+
ensure_response_type!(resp, ledger_msg::Response::TxNext, ());
290282
}
291283

292-
let mut signatures: BTreeMap<_, Vec<_>> = BTreeMap::new();
284+
let next_sig_raw_req = {
285+
let next_sig = ledger_msg::encode(ledger_msg::SignTxNextReq::ReturnNextSignature);
286+
let apdu = make_apdu(
287+
ledger_msg::Ins::SIGN_TX,
288+
ledger_msg::SignTxP1::Next.into(),
289+
&next_sig,
290+
)?;
293291

294-
let next_sig = ledger_msg::encode(ledger_msg::SignTxReq::NextSignature);
295-
let apdu = make_apdu(
296-
ledger_msg::Ins::SIGN_TX,
297-
ledger_msg::SignP1::Next.into(),
298-
&next_sig,
299-
)?;
292+
let mut msg_buf = Vec::with_capacity(apdu.bytes_count());
293+
apdu.write_bytes(&mut msg_buf);
294+
msg_buf
295+
};
300296

301-
let mut msg_buf = Vec::with_capacity(apdu.bytes_count());
302-
apdu.write_bytes(&mut msg_buf);
297+
let mut signatures: BTreeMap<_, Vec<_>> = BTreeMap::new();
303298

304299
loop {
300+
let sig_resp = exchange_message(ledger, &next_sig_raw_req).await?;
301+
305302
let resp = decode_response(&sig_resp)?;
306-
let resp = ensure_response_type!(resp, ledger_msg::Response::TxSignature(resp), resp);
303+
let resp = ensure_response_type!(resp, ledger_msg::Response::TxInputSignature(resp), resp);
307304

308305
signatures.entry(resp.input_idx as usize).or_default().push(LedgerSignature {
309306
signature: resp.signature,
@@ -313,8 +310,6 @@ pub async fn sign_tx<L: Exchange>(
313310
if !resp.has_next {
314311
break;
315312
}
316-
317-
sig_resp = exchange_message(ledger, &msg_buf).await?;
318313
}
319314

320315
Ok(signatures)

0 commit comments

Comments
 (0)