Skip to content

Commit

Permalink
Implemented MASP signing using the hardware wallet.
Browse files Browse the repository at this point in the history
  • Loading branch information
murisi committed Sep 23, 2024
1 parent 8d11769 commit 3fe7ee9
Show file tree
Hide file tree
Showing 24 changed files with 578 additions and 90 deletions.
9 changes: 5 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,15 @@ konst = { version = "0.3.8", default-features = false }
lazy_static = "1.4.0"
# TODO: upstreamed in https://github.com/ledger-community/rust-ledger/pull/9
ledger-lib = { git = "https://github.com/heliaxdev/rust-ledger", rev = "f96f4559b3237d09218f7583df01acf36034ea79", default-features = false, features = ["transport_tcp"] }
ledger-namada-rs = { git = "https://github.com/Zondax/ledger-namada", tag = "v0.0.24" }
ledger-namada-rs = { git = "https://github.com/Zondax/ledger-namada", rev = "f54b76adcc1430db0496e894ad72cd74cfb6eb88" }
ledger-transport = "0.10.0"
ledger-transport-hid = "0.10.0"
libc = "0.2.97"
libloading = "0.7.2"
linkme = "0.3.24"
# branch = "tomas/arbitrary"
masp_primitives = { git = "https://github.com/anoma/masp", rev = "12ed8b060b295c06502a2ff8468e4a941cb7cca4" }
masp_proofs = { git = "https://github.com/anoma/masp", rev = "12ed8b060b295c06502a2ff8468e4a941cb7cca4", default-features = false, features = ["local-prover"] }
masp_primitives = { git = "https://github.com/anoma/masp", rev = "a35f73be69b21ee62cd4940f37855161cbed2a56" }
masp_proofs = { git = "https://github.com/anoma/masp", rev = "a35f73be69b21ee62cd4940f37855161cbed2a56", default-features = false, features = ["local-prover"] }
num256 = "0.3.5"
num_cpus = "1.13.0"
num-derive = "0.4"
Expand Down
1 change: 1 addition & 0 deletions crates/apps_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ fd-lock.workspace = true
flate2.workspace = true
futures.workspace = true
itertools.workspace = true
jubjub.workspace = true
kdam.workspace = true
lazy_static = { workspace = true, optional = true }
linkme = { workspace = true, optional = true }
Expand Down
63 changes: 60 additions & 3 deletions crates/apps_lib/src/cli/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ use std::path::{Path, PathBuf};
use std::str::FromStr;

use color_eyre::eyre::Result;
use masp_primitives::zip32::sapling::PseudoExtendedKey;
use masp_primitives::zip32::{
ExtendedFullViewingKey as MaspExtendedViewingKey,
ExtendedSpendingKey as MaspExtendedSpendingKey,
};
use namada_core::masp::{
BalanceOwner, ExtendedSpendingKey, ExtendedViewingKey, PaymentAddress,
TransferSource, TransferTarget,
Expand Down Expand Up @@ -47,7 +52,7 @@ pub type WalletAddrOrNativeToken = FromContext<AddrOrNativeToken>;

/// A raw extended spending key (bech32m encoding) or an alias of an extended
/// spending key in the wallet
pub type WalletSpendingKey = FromContext<ExtendedSpendingKey>;
pub type WalletSpendingKey = FromContext<PseudoExtendedKey>;

/// A raw dated extended spending key (bech32m encoding) or an alias of an
/// extended spending key in the wallet
Expand Down Expand Up @@ -588,6 +593,48 @@ impl ArgFromMutContext for ExtendedSpendingKey {
}
}

impl ArgFromMutContext for PseudoExtendedKey {
fn arg_from_mut_ctx(
ctx: &mut ChainContext,
raw: impl AsRef<str>,
) -> Result<Self, String> {
let raw = raw.as_ref();
// Either the string is a raw extended spending key
ExtendedSpendingKey::from_str(raw)
.map(|x| PseudoExtendedKey::from(MaspExtendedSpendingKey::from(x)))
.or_else(|_parse_err| {
ExtendedViewingKey::from_str(raw).map(|x| {
PseudoExtendedKey::from(MaspExtendedViewingKey::from(x))
})
})
.or_else(|_parse_err| {
// Or it is a stored alias of one
ctx.wallet
.find_spending_key(raw, None)
.map(|k| {
PseudoExtendedKey::from(MaspExtendedSpendingKey::from(
k.key,
))
})
.map_err(|_find_err| {
format!("Unknown spending key {}", raw)
})
})
.or_else(|_parse_err| {
// Or it is a stored alias of one
ctx.wallet
.find_viewing_key(raw)
.copied()
.map(|k| {
PseudoExtendedKey::from(MaspExtendedViewingKey::from(
k.key,
))
})
.map_err(|_find_err| format!("Unknown viewing key {}", raw))
})
}
}

impl ArgFromMutContext for DatedSpendingKey {
fn arg_from_mut_ctx(
ctx: &mut ChainContext,
Expand Down Expand Up @@ -666,8 +713,18 @@ impl ArgFromMutContext for TransferSource {
Address::arg_from_ctx(ctx, raw)
.map(Self::Address)
.or_else(|_| {
ExtendedSpendingKey::arg_from_mut_ctx(ctx, raw)
.map(Self::ExtendedSpendingKey)
ExtendedSpendingKey::arg_from_mut_ctx(ctx, raw).map(|x| {
Self::ExtendedSpendingKey(PseudoExtendedKey::from(
MaspExtendedSpendingKey::from(x),
))
})
})
.or_else(|_| {
ExtendedViewingKey::arg_from_mut_ctx(ctx, raw).map(|x| {
Self::ExtendedSpendingKey(PseudoExtendedKey::from(
MaspExtendedViewingKey::from(x),
))
})
})
}
}
Expand Down
70 changes: 63 additions & 7 deletions crates/apps_lib/src/cli/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use borsh::BorshDeserialize;
use borsh_ext::BorshSerializeExt;
use color_eyre::eyre::Result;
use itertools::sorted;
use ledger_namada_rs::{BIP44Path, NamadaApp};
use ledger_namada_rs::{BIP44Path, KeyResponse, NamadaApp, NamadaKeys};
use ledger_transport_hid::hidapi::HidApi;
use ledger_transport_hid::TransportNativeHID;
use masp_primitives::zip32::ExtendedFullViewingKey;
use namada_core::chain::BlockHeight;
use namada_core::masp::{ExtendedSpendingKey, MaspValue, PaymentAddress};
use namada_sdk::address::{Address, DecodeError};
Expand Down Expand Up @@ -184,7 +187,7 @@ fn payment_addresses_list(
}

/// Derives a masp spending key from the mnemonic code in the wallet.
fn shielded_key_derive(
async fn shielded_key_derive(
ctx: Context,
io: &impl Io,
args::KeyDerive {
Expand Down Expand Up @@ -232,9 +235,56 @@ fn shielded_key_derive(
})
.0
} else {
display_line!(io, "Not implemented.");
display_line!(io, "No changes are persisted. Exiting.");
cli::safe_exit(1)
let hidapi = HidApi::new().unwrap_or_else(|err| {
edisplay_line!(io, "Failed to create HidApi: {}", err);
cli::safe_exit(1)
});
let app = NamadaApp::new(
TransportNativeHID::new(&hidapi).unwrap_or_else(|err| {
edisplay_line!(io, "Unable to connect to Ledger: {}", err);
cli::safe_exit(1)
}),
);
let response = app
.retrieve_keys(
&BIP44Path {
path: derivation_path.to_string(),
},
NamadaKeys::ViewKey,
true,
)
.await
.unwrap_or_else(|err| {
edisplay_line!(
io,
"Unable to connect to query address and public key from \
Ledger: {}",
err
);
cli::safe_exit(1)
});
let KeyResponse::ViewKey(response_key) = response else {
edisplay_line!(io, "Unexpected response from Ledger");
cli::safe_exit(1)
};
let xfvk = ExtendedFullViewingKey::try_from_slice(&response_key.xfvk)
.expect(
"unable to decode extended full viewing key from the hardware \
wallet",
);

wallet
.insert_viewing_key(
alias,
xfvk.into(),
birthday,
alias_force,
Some(derivation_path),
)
.unwrap_or_else(|| {
display_line!(io, "No changes are persisted. Exiting.");
cli::safe_exit(1)
})
};
wallet
.save()
Expand Down Expand Up @@ -367,7 +417,13 @@ fn shielded_key_address_add(
let (alias, typ) = match masp_value {
MaspValue::FullViewingKey(viewing_key) => {
let alias = wallet
.insert_viewing_key(alias, viewing_key, birthday, alias_force)
.insert_viewing_key(
alias,
viewing_key,
birthday,
alias_force,
None,
)
.unwrap_or_else(|| {
edisplay_line!(io, "Viewing key not added");
cli::safe_exit(1);
Expand Down Expand Up @@ -638,7 +694,7 @@ async fn key_derive(
if !args_key_derive.shielded {
transparent_key_and_address_derive(ctx, io, args_key_derive).await
} else {
shielded_key_derive(ctx, io, args_key_derive)
shielded_key_derive(ctx, io, args_key_derive).await
}
}

Expand Down
Loading

0 comments on commit 3fe7ee9

Please sign in to comment.