Skip to content

Commit

Permalink
Now query the proof generation key from the hardware wallet and use i…
Browse files Browse the repository at this point in the history
…t to generate proofs.
  • Loading branch information
murisi committed Sep 4, 2024
1 parent 14345b5 commit 5d3c4c6
Show file tree
Hide file tree
Showing 13 changed files with 179 additions and 32 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ libc = "0.2.97"
libloading = "0.7.2"
linkme = "0.3.24"
# branch = "tomas/arbitrary"
masp_primitives = { git = "https://github.com/anoma/masp", rev = "c08d0226c3b9370e8eee052f928b4504aecaffa9" }
masp_proofs = { git = "https://github.com/anoma/masp", rev = "c08d0226c3b9370e8eee052f928b4504aecaffa9", default-features = false, features = ["local-prover"] }
masp_primitives = { git = "https://github.com/anoma/masp", rev = "9bc6dec4d4b3f5a0344aa94b739a122c3e0989f3" }
masp_proofs = { git = "https://github.com/anoma/masp", rev = "9bc6dec4d4b3f5a0344aa94b739a122c3e0989f3", default-features = false, features = ["local-prover"] }
num256 = "0.3.5"
num_cpus = "1.13.0"
num-derive = "0.4"
Expand Down
39 changes: 37 additions & 2 deletions crates/apps_lib/src/cli/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use namada_sdk::masp::fs::FsShieldedUtils;
use namada_sdk::masp::{ShieldedContext, *};
use namada_sdk::wallet::{DatedSpendingKey, DatedViewingKey, Wallet};
use namada_sdk::{Namada, NamadaImpl};
use masp_primitives::zip32::sapling::PseudoExtendedSpendingKey;

use super::args;
use crate::cli::utils;
Expand Down Expand Up @@ -43,7 +44,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<PseudoExtendedSpendingKey>;

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

impl ArgFromMutContext for PseudoExtendedSpendingKey {
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| PseudoExtendedSpendingKey::from_spending_key(x.into())
).or_else(|_parse_err| {
ExtendedViewingKey::from_str(raw).map(
|x| PseudoExtendedSpendingKey::from_viewing_key(x.into())
)
}).or_else(|_parse_err| {
// Or it is a stored alias of one
ctx.wallet
.find_spending_key(raw, None)
.map(|k| PseudoExtendedSpendingKey::from_spending_key(k.key.into()))
.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| PseudoExtendedSpendingKey::from_viewing_key(k.key.into()))
.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 @@ -663,7 +694,11 @@ impl ArgFromMutContext for TransferSource {
.map(Self::Address)
.or_else(|_| {
ExtendedSpendingKey::arg_from_mut_ctx(ctx, raw)
.map(Self::ExtendedSpendingKey)
.map(|x| Self::ExtendedSpendingKey(PseudoExtendedSpendingKey::from_spending_key(x.into())))
})
.or_else(|_| {
ExtendedViewingKey::arg_from_mut_ctx(ctx, raw)
.map(|x| Self::ExtendedSpendingKey(PseudoExtendedSpendingKey::from_viewing_key(x.into())))
})
}
}
Expand Down
82 changes: 79 additions & 3 deletions crates/apps_lib/src/client/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::io::Write;

use borsh::BorshDeserialize;
use borsh_ext::BorshSerializeExt;
use ledger_namada_rs::{BIP44Path, NamadaApp};
use ledger_namada_rs::{BIP44Path, NamadaApp, KeyResponse, NamadaKeys};
use namada_sdk::address::{Address, ImplicitAddress};
use namada_sdk::args::TxBecomeValidator;
use namada_sdk::collections::HashSet;
Expand All @@ -22,6 +22,9 @@ use namada_sdk::wallet::{Wallet, WalletIo};
use namada_sdk::{display_line, edisplay_line, error, signing, tx, Namada};
use rand::rngs::OsRng;
use tokio::sync::RwLock;
use namada_sdk::masp::ExtendedViewingKey;
use masp_primitives::zip32::ExtendedFullViewingKey;
use masp_primitives::sapling::ProofGenerationKey;

use masp_primitives::transaction::components::sapling::builder::{
BuildParams, ConvertBuildParams, OutputBuildParams, RngBuildParams,
Expand Down Expand Up @@ -791,11 +794,85 @@ pub async fn submit_transparent_transfer(

pub async fn submit_shielded_transfer(
namada: &impl Namada,
args: args::TxShieldedTransfer,
mut args: args::TxShieldedTransfer,
) -> Result<(), error::Error> {
let mut bparams: Box<dyn BuildParams> = if args.tx.use_device {
let transport = WalletTransport::from_arg(args.tx.device_transport);
let app = NamadaApp::new(transport);
let wallet = namada.wallet().await;
// Augment the pseudo spending key with a proof authorization key
for data in &mut args.data {
// Only attempt an augmentation if proof authorization is not there
if data.source.partial_spending_key().is_none() {
// First find the derivation path corresponding to this viewing
// key
let viewing_key =
ExtendedViewingKey::from(data.source.to_viewing_key());
let path = wallet
.find_path_by_viewing_key(&viewing_key)
.map_err(|err| error::Error::Other(format!(
"Unable to find derivation path from the wallet for \
viewing key {}. Error: {}",
viewing_key,
err,
)))?;
let path = BIP44Path { path: path.to_string() };
// Then confirm that the viewing key at this path in the
// hardware wallet matches the viewing key in this pseudo
// spending key
let response = app
.retrieve_keys(&path, NamadaKeys::ViewKey, true)
.await
.map_err(|err| error::Error::Other(format!(
"Unable to obtain viewing key from the hardware wallet \
at path {}. Error: {}",
path.path,
err,
)))?;
let KeyResponse::ViewKey(response_key) = response else {
return Err(error::Error::Other(
"Unexpected response from Ledger".to_string(),
))
};
let xfvk = ExtendedFullViewingKey::try_from_slice(&response_key.xfvk)
.expect("unable to decode extended full viewing key from the hardware wallet");
if ExtendedFullViewingKey::from(viewing_key) != xfvk {
return Err(error::Error::Other(format!(
"Unexpected viewing key response from Ledger: {}",
ExtendedViewingKey::from(xfvk),
)))
}
// Then obtain the proof authorization key at this path in the
// hardware wallet
let response = app
.retrieve_keys(&path, NamadaKeys::ProofGenerationKey, false)
.await
.map_err(|err| error::Error::Other(format!(
"Unable to obtain proof generation key from the \
hardware wallet for viewing key {}. Error: {}",
viewing_key,
err,
)))?;
let KeyResponse::ProofGenKey(response_key) = response else {
return Err(error::Error::Other(
"Unexpected response from Ledger".to_string(),
))
};
let pgk = ProofGenerationKey::try_from_slice(
&[response_key.ak, response_key.nsk].concat(),
).map_err(|err| error::Error::Other(format!(
"Unexpected proof generation key in response from the \
hardware wallet: {}.",
err,
)))?;
// Finally augment the pseudo spending key
data.source.augment(pgk).map_err(|_| error::Error::Other(format!(
"Proof generation key in response from the hardware wallet \
does not correspond to stored viewing key.",
)))?;
}
}
// Get randomness to aid in construction of various descriptors
let mut bparams = StoredBuildParams::default();
// Number of spend descriptions is the number of transfers
let spend_len = args.data.len();
Expand Down Expand Up @@ -833,7 +910,6 @@ pub async fn submit_shielded_transfer(
.get_output_randomness()
.await
.map_err(|err| error::Error::Other(err.to_string()))?;
println!("RCM: {:?}", output_randomness.rcm);
bparams.output_params.push(OutputBuildParams {
rcv: jubjub::Fr::from_bytes(&output_randomness.rcv).unwrap(),
rseed: output_randomness.rcm,
Expand Down
7 changes: 4 additions & 3 deletions crates/core/src/masp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use borsh_ext::BorshSerializeExt;
use masp_primitives::asset_type::AssetType;
use masp_primitives::sapling::ViewingKey;
use masp_primitives::transaction::TransparentAddress;
use masp_primitives::zip32::sapling::PseudoExtendedSpendingKey;
pub use masp_primitives::transaction::TxId as TxIdInner;
use namada_macros::BorshDeserializer;
#[cfg(feature = "migrations")]
Expand Down Expand Up @@ -517,7 +518,7 @@ pub enum TransferSource {
/// A transfer coming from a transparent address
Address(Address),
/// A transfer coming from a shielded address
ExtendedSpendingKey(ExtendedSpendingKey),
ExtendedSpendingKey(PseudoExtendedSpendingKey),
}

impl TransferSource {
Expand All @@ -532,7 +533,7 @@ impl TransferSource {
}

/// Get the contained ExtendedSpendingKey contained, if any
pub fn spending_key(&self) -> Option<ExtendedSpendingKey> {
pub fn spending_key(&self) -> Option<PseudoExtendedSpendingKey> {
match self {
Self::ExtendedSpendingKey(x) => Some(*x),
_ => None,
Expand Down Expand Up @@ -560,7 +561,7 @@ impl Display for TransferSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Address(x) => x.fmt(f),
Self::ExtendedSpendingKey(x) => x.fmt(f),
Self::ExtendedSpendingKey(x) => ExtendedViewingKey::from(x.to_viewing_key()).fmt(f),
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion crates/sdk/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::str::FromStr;
use std::time::Duration as StdDuration;

use masp_primitives::transaction::components::sapling::builder::BuildParams;
use masp_primitives::zip32::sapling::PseudoExtendedSpendingKey;

use namada_core::address::Address;
use namada_core::chain::{BlockHeight, ChainId, Epoch};
Expand Down Expand Up @@ -120,7 +121,7 @@ impl NamadaTypes for SdkTypes {
type MaspIndexerAddress = String;
type PaymentAddress = namada_core::masp::PaymentAddress;
type PublicKey = namada_core::key::common::PublicKey;
type SpendingKey = namada_core::masp::ExtendedSpendingKey;
type SpendingKey = PseudoExtendedSpendingKey;
type TendermintAddress = tendermint_rpc::Url;
type TransferSource = namada_core::masp::TransferSource;
type TransferTarget = namada_core::masp::TransferTarget;
Expand Down
7 changes: 4 additions & 3 deletions crates/sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ pub use std::marker::Sync as MaybeSync;
use std::path::PathBuf;
use std::str::FromStr;

use masp_primitives::zip32::sapling::PseudoExtendedSpendingKey;
use args::{DeviceTransport, InputAmount, SdkTypes};
use io::Io;
use masp::{ShieldedContext, ShieldedUtils};
Expand Down Expand Up @@ -189,7 +190,7 @@ pub trait Namada: Sized + MaybeSync + MaybeSend {
fn new_shielded_transfer(
&self,
data: Vec<args::TxShieldedTransferData>,
gas_spending_keys: Vec<ExtendedSpendingKey>,
gas_spending_keys: Vec<PseudoExtendedSpendingKey>,
disposable_signing_key: bool,
) -> args::TxShieldedTransfer {
args::TxShieldedTransfer {
Expand Down Expand Up @@ -220,9 +221,9 @@ pub trait Namada: Sized + MaybeSync + MaybeSend {
/// arguments
fn new_unshielding_transfer(
&self,
source: ExtendedSpendingKey,
source: PseudoExtendedSpendingKey,
data: Vec<args::TxUnshieldingTransferData>,
gas_spending_keys: Vec<ExtendedSpendingKey>,
gas_spending_keys: Vec<PseudoExtendedSpendingKey>,
disposable_signing_key: bool,
) -> args::TxUnshieldingTransfer {
args::TxUnshieldingTransfer {
Expand Down
25 changes: 17 additions & 8 deletions crates/sdk/src/masp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use masp_primitives::transaction::builder::{self, *};
use masp_primitives::transaction::components::sapling::builder::{
BuildParams, RngBuildParams, SaplingMetadata,
};
use masp_primitives::zip32::sapling::PseudoExtendedSpendingKey;
use masp_primitives::transaction::components::{
I128Sum, TxOut, U64Sum, ValueSum,
};
Expand Down Expand Up @@ -110,7 +111,7 @@ pub struct ShieldedTransfer {
#[allow(missing_docs)]
#[derive(Debug)]
pub struct MaspFeeData {
pub sources: Vec<namada_core::masp::ExtendedSpendingKey>,
pub sources: Vec<PseudoExtendedSpendingKey>,
pub target: Address,
pub token: Address,
pub amount: token::DenominatedAmount,
Expand Down Expand Up @@ -159,7 +160,7 @@ struct MaspTxReorderedData {
// Data about the unspent amounts for any given shielded source coming from the
// spent notes in their posses that have been added to the builder. Can be used
// to either pay fees or to return a change
type Changes = HashMap<namada_core::masp::ExtendedSpendingKey, I128Sum>;
type Changes = HashMap<PseudoExtendedSpendingKey, I128Sum>;

/// Shielded pool data for a token
#[allow(missing_docs)]
Expand Down Expand Up @@ -941,7 +942,7 @@ impl<U: ShieldedUtils + MaybeSend + MaybeSync> ShieldedContext<U> {
&mut self,
context: &impl Namada,
spent_notes: &mut SpentNotesTracker,
sk: namada_core::masp::ExtendedSpendingKey,
sk: PseudoExtendedSpendingKey,
is_native_token: bool,
target: I128Sum,
target_epoch: MaspEpoch,
Expand All @@ -954,7 +955,7 @@ impl<U: ShieldedUtils + MaybeSend + MaybeSync> ShieldedContext<U> {
),
Error,
> {
let vk = &to_viewing_key(&sk.into()).vk;
let vk = &sk.to_viewing_key().fvk.vk;
// TODO: we should try to use the smallest notes possible to fund the
// transaction to allow people to fetch less often
// Establish connection with which to do exchange rate queries
Expand Down Expand Up @@ -1496,7 +1497,11 @@ impl<U: ShieldedUtils + MaybeSend + MaybeSync> ShieldedContext<U> {
for (diversifier, note, merkle_path) in unspent_notes {
builder
.add_sapling_spend(
sk.into(),
sk.partial_spending_key().ok_or_else(|| {
Error::Other(format!(
"Unable to get proof authorization"
))
})?,
diversifier,
note,
merkle_path,
Expand Down Expand Up @@ -1615,7 +1620,7 @@ impl<U: ShieldedUtils + MaybeSend + MaybeSync> ShieldedContext<U> {
// viewing key in the following computations.
let ovk_opt = source
.spending_key()
.map(|x| MaspExtendedSpendingKey::from(x).expsk.ovk);
.map(|x| x.to_viewing_key().fvk.ovk);
// Make transaction output tied to the current token,
// denomination, and epoch.
if let Some(pa) = payment_address {
Expand Down Expand Up @@ -1708,7 +1713,7 @@ impl<U: ShieldedUtils + MaybeSend + MaybeSync> ShieldedContext<U> {
context: &impl Namada,
builder: &mut Builder<Network>,
source_data: &HashMap<MaspSourceTransferData, token::DenominatedAmount>,
sources: Vec<namada_core::masp::ExtendedSpendingKey>,
sources: Vec<PseudoExtendedSpendingKey>,
target: &Address,
token: &Address,
amount: &token::DenominatedAmount,
Expand Down Expand Up @@ -1950,7 +1955,11 @@ impl<U: ShieldedUtils + MaybeSend + MaybeSync> ShieldedContext<U> {
for (sp, changes) in changes.into_iter() {
for (asset_type, amt) in changes.components() {
if let Ordering::Greater = amt.cmp(&0) {
let sk = MaspExtendedSpendingKey::from(sp.to_owned());
let sk = sp.partial_spending_key().ok_or_else(|| {
Error::Other(format!(
"Unable to get proof authorization"
))
})?;
// Send the change in this asset type back to the sender
builder
.add_sapling_output(
Expand Down
Loading

0 comments on commit 5d3c4c6

Please sign in to comment.