diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b05f228e..4e568546 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -487,7 +487,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: doc - args: --no-deps + args: --no-deps --workspace - name: Deploy to GitHub Pages uses: crazy-max/ghaction-github-pages@v3 diff --git a/Cargo.lock b/Cargo.lock index fea00cfa..54cae4eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1968,7 +1968,7 @@ dependencies = [ [[package]] name = "ledger-mob" -version = "0.15.0" +version = "0.16.0" dependencies = [ "anyhow", "async-trait", @@ -2015,7 +2015,7 @@ dependencies = [ [[package]] name = "ledger-mob-apdu" -version = "0.15.0" +version = "0.16.0" dependencies = [ "bitflags 1.3.2", "byteorder", @@ -2041,7 +2041,7 @@ dependencies = [ [[package]] name = "ledger-mob-core" -version = "0.15.0" +version = "0.16.0" dependencies = [ "aes 0.7.5", "anyhow", @@ -2099,7 +2099,7 @@ dependencies = [ [[package]] name = "ledger-mob-tests" -version = "0.15.0" +version = "0.16.0" dependencies = [ "anyhow", "base64 0.21.0", diff --git a/Makefile b/Makefile index d4ef9832..f9297767 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ nanox-test: nanox # Build docs docs: - cargo doc --no-deps + cargo doc --no-deps --workspace # Build nanosplus firmware nanosplus: @@ -129,4 +129,4 @@ miri: clean: rm -rf target fw/target -.PHONY: fw lib core nanosplus nanox fmt clippy clean +.PHONY: fw lib core nanosplus nanox fmt clippy clean docs diff --git a/README.md b/README.md index 69677363..6f2d1348 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A [MobileCoin][1] NanoApp for [Ledger][2] `nanosplus` and `nanox` devices. You can grab the latest (unsigned) firmware and tooling [here](https://github.com/mobilecoinofficial/ledger-mob/releases), or follow the [Getting Started](#Getting-Started) instructions to build your own. -For application interaction or integration see the [library](https://mobilecoinofficial.github.io/ledger-mob/ledger_mob/index.html) and [APDU](https://mobilecoinofficial.github.io/ledger-mob/ledger_mob_apdu/index.html) documentation. +For application interaction or integration see the [library](https://mobilecoinofficial.github.io/ledger-mob/ledger_mob/index.html), [Engine](https://mobilecoinofficial.github.io/ledger-mob/ledger_mob_core/index.html) and [APDU](https://mobilecoinofficial.github.io/ledger-mob/ledger_mob_apdu/index.html) documentation. ## Status diff --git a/apdu/Cargo.toml b/apdu/Cargo.toml index 3e5f1695..ab895f85 100644 --- a/apdu/Cargo.toml +++ b/apdu/Cargo.toml @@ -4,7 +4,7 @@ cargo-features = ["per-package-target"] name = "ledger-mob-apdu" description = "MobileCoin hardware wallet protocol / APDU definitions" repository = "https://github.com/mobilecoinofficial/ledger-mob.git" -version = "0.15.0" +version = "0.16.0" edition = "2021" license = "Apache-2.0" publish = false diff --git a/apdu/src/digest.rs b/apdu/src/digest.rs index 046ad3dc..c27f0c36 100644 --- a/apdu/src/digest.rs +++ b/apdu/src/digest.rs @@ -1,6 +1,6 @@ //! Helpers for computing APDU / event digests //! -//! This is used instead of [Digestible] as the same digest must be computed over [ledger_mob_core::engine::Event]s and APDUs. +//! This is used in place of `Digestible` as the same digest must be computed over engine events and APDUs. use sha2::{Digest as _, Sha512_256}; diff --git a/apdu/src/ident.rs b/apdu/src/ident.rs index 65db4bfe..09a634d8 100644 --- a/apdu/src/ident.rs +++ b/apdu/src/ident.rs @@ -62,7 +62,7 @@ impl<'a> ApduStatic for IdentSignReq<'a> { impl<'a> Encode for IdentSignReq<'a> { type Error = ApduError; - /// Encode an [`IdentReq`] APDU into the provided buffer + /// Encode an [`IdentSignReq`] APDU into the provided buffer #[inline] fn encode(&self, buff: &mut [u8]) -> Result { let mut index = 0; @@ -108,7 +108,7 @@ impl<'a> Decode<'a> for IdentSignReq<'a> { type Output = Self; type Error = ApduError; - /// Decode a [`IdentReq`] APDU from the provided buffer + /// Decode a [`IdentSignReq`] APDU from the provided buffer #[inline] fn decode(buff: &'a [u8]) -> Result<(Self, usize), ApduError> { let mut index = 0; @@ -198,7 +198,7 @@ pub struct IdentResp { } impl IdentResp { - /// Create a new [`KeyImage`] APDU + /// Create a new [`IdentResp`] APDU pub fn new(public_key: [u8; 32], signature: [u8; 64]) -> Self { Self { public_key, diff --git a/apdu/src/lib.rs b/apdu/src/lib.rs index 2a1e8da2..2fc93d21 100644 --- a/apdu/src/lib.rs +++ b/apdu/src/lib.rs @@ -13,6 +13,7 @@ //! 32-bit field alignment to reduce the need for unaligned access on constrained platforms. //! All field encodings are little-endian, because most of the world is these days. //! +//! See [Instruction] for APDU instruction codes. //! #![no_std] diff --git a/apdu/src/state.rs b/apdu/src/state.rs index 4f1b132d..185b2da5 100644 --- a/apdu/src/state.rs +++ b/apdu/src/state.rs @@ -11,7 +11,7 @@ use sha2::{Digest as _, Sha512_256}; use strum::{Display, EnumIter, EnumString, EnumVariantNames}; /// Engine state enumeration -/// used in [`TxInfo`] to communicate transaction progress +/// used in [crate::tx::TxInfo] to communicate transaction progress #[derive( Copy, Clone, PartialEq, Debug, EnumString, Display, EnumVariantNames, EnumIter, TryFromPrimitive, )] diff --git a/apdu/src/tx/mod.rs b/apdu/src/tx/mod.rs index 6d400325..118e4b96 100644 --- a/apdu/src/tx/mod.rs +++ b/apdu/src/tx/mod.rs @@ -2,7 +2,7 @@ //! Transaction related APDUs, used to execute a transaction via the hardware wallet. //! -//! See [crate::engine] for interaction and state machines +//! See [ledger_mob_core::engine] for interaction and state machines use encdec::{Decode, Encode}; use ledger_proto::ApduStatic; diff --git a/apdu/src/tx/summary.rs b/apdu/src/tx/summary.rs index 7339eb29..f2c19c7b 100644 --- a/apdu/src/tx/summary.rs +++ b/apdu/src/tx/summary.rs @@ -67,7 +67,37 @@ impl TxSummaryInit { /// Add TxOutSummary to the summary /// -/// See [mc_transaction_core::tx_summary::TxOutSummary] for equivalence +/// See [mc_transaction_core::tx_summary::TxOutSummary] for an equivalent MobileCoin core object. +/// +/// ## Encoding: +/// ```text +/// 0 1 2 3 +/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | FLAGS | INDEX | RESERVED | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | MASKED_VALUE | +/// | (u64, 8-byte) | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | MASKED_TOKEN_ID | +/// | (u64, 8-byte) | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | | +/// / COMMITMENT / +/// / (32-byte Compressed Ristretto Point) / +/// | | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | | +/// / TXOUT_TARGET_KEY / +/// / (32-byte Compressed Ristretto Public Key) / +/// | | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | | +/// / PUBLIC_KEY / +/// / (32-byte Compressed Ristretto Public Key) / +/// | | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// ``` #[derive(Clone, PartialEq, Debug, Encode, Decode)] #[encdec(error = "ApduError")] pub struct TxSummaryAddTxOut { @@ -192,7 +222,50 @@ impl TxSummaryAddTxOut { /// Add TxOutSummaryUnblinding to the summary /// -/// +/// ## Encoding: +/// ```text +/// 0 1 2 3 +/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | FLAGS | INDEX | FOG_ID | RESERVED | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | UNMASKED_VALUE | +/// | (u64, 8-byte) | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | TOKEN_ID | +/// | (u64, 8-byte) | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | | +/// / BLINDING / +/// / (32-byte Ristretto Scalar) / +/// | | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | | +/// / TARGET_SPEND_PUBLIC_KEY (Optional, see HAS_ADDRESS) / +/// / (32-byte Ristretto Public Key) / +/// | | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | | +/// / TARGET_VIEW_PUBLIC_KEY (Optional, see HAS_ADDRESS) / +/// / (32-byte Ristretto Public Key) / +/// | | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | | +/// / TXOUT_TARGET_KEY / +/// / (32-byte Compressed Ristretto Public Key) / +/// | | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | | +/// / TXOUT_PRIVATE_KEY (optional, see HAS_PRIVATE_KEY) / +/// / (32-byte Compressed Ristretto Private Key) / +/// | | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | | +/// / FOG_AUTHORITY_SIG (optional, see HAS_FOG_AUTHORITY_SIG) / +/// / (64-byte Fog Authority Signature) / +/// | | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// ``` #[derive(Clone, PartialEq, Debug, Encode, Decode)] #[encdec(error = "ApduError")] pub struct TxSummaryAddTxOutUnblinding { @@ -488,7 +561,35 @@ impl TxSummaryAddTxOutUnblinding { /// Add TxInSummary for a transaction /// -/// +/// ## Encoding: +/// ```text +/// 0 1 2 3 +/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | FLAGS | INDEX | RESERVED | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | | +/// / PSEUDO_OUTPUT_COMMITMENT / +/// / (32-byte Compressed Ristretto Point) / +/// | | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | UNMASKED_VALUE | +/// | (u64, 8-byte) | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | TOKEN_ID | +/// | (u64, 8-byte) | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | | +/// / BLINDING / +/// / (32-byte Ristretto Scalar) / +/// | | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | | +/// / INPUT_RULES_DIGEST (optional, see HAS_INPUT_RULES) / +/// / (32-byte Input Rules Digest) / +/// | | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// ``` #[derive(Clone, PartialEq, Debug, Encode, Decode)] #[encdec(error = "ApduError")] pub struct TxSummaryAddTxIn { @@ -582,7 +683,21 @@ impl TxSummaryAddTxIn { /// Complete TxSummary building /// -/// +/// ## Encoding: +/// ```text +/// 0 1 2 3 +/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | FEE_VALUE | +/// | (u64, 8-byte) | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | FEE_TOKEN_ID | +/// | (u64, 8-byte) | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// | TOMBSTONE_BLOCK | +/// | (u64, 8-byte) | +/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/// ``` #[derive(Clone, PartialEq, Debug, Encode, Decode)] #[encdec(error = "ApduError")] pub struct TxSummaryBuild { diff --git a/core/Cargo.toml b/core/Cargo.toml index e006134c..517fbd65 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -4,7 +4,7 @@ cargo-features = ["per-package-target"] name = "ledger-mob-core" description = "MobileCoin hardware wallet engine" repository = "https://github.com/mobilecoinofficial/ledger-mob.git" -version = "0.15.0" +version = "0.16.0" edition = "2021" license = "GPL-3.0" publish = false diff --git a/core/src/engine/error.rs b/core/src/engine/error.rs index 6a42fefa..68349e52 100644 --- a/core/src/engine/error.rs +++ b/core/src/engine/error.rs @@ -1,6 +1,6 @@ // Copyright (c) 2022-2023 The MobileCoin Foundation -/// [Engine] errors +/// [super::Engine] errors #[derive(Clone, PartialEq, Debug)] #[cfg_attr(feature = "thiserror", derive(thiserror::Error))] #[repr(u8)] diff --git a/core/src/engine/function.rs b/core/src/engine/function.rs index be6d15aa..f41505f8 100644 --- a/core/src/engine/function.rs +++ b/core/src/engine/function.rs @@ -66,7 +66,7 @@ impl Function { /// Setup ring-signer context /// /// this uses out-pointer based init to avoid stack allocation - /// see: https://doc.rust-lang.org/core/mem/union.MaybeUninit.html#out-pointers + /// see: #[cfg(feature = "mlsag")] #[allow(clippy::too_many_arguments)] #[cfg_attr(feature = "noinline", inline(never))] @@ -138,7 +138,7 @@ impl Function { /// Setup summarizer context /// /// this uses out-pointer based init to avoid stack allocation - /// see: https://doc.rust-lang.org/core/mem/union.MaybeUninit.html#out-pointers + /// see: #[cfg(feature = "summary")] #[cfg_attr(feature = "noinline", inline(never))] pub fn summarizer_init( diff --git a/core/src/engine/output.rs b/core/src/engine/output.rs index c20f6709..82da37fa 100644 --- a/core/src/engine/output.rs +++ b/core/src/engine/output.rs @@ -18,7 +18,7 @@ use super::summary::SummaryState; #[cfg(feature = "ident")] use super::ident::IdentState; -/// [`Engine`][super::Engine] outputs (in response to events), typically encoded to response [APDUs][crate::apdu] +/// [`Engine`][super::Engine] outputs (in response to events), typically encoded to response [APDUs][ledger_mob_apdu] #[derive(Clone, PartialEq, Debug)] pub enum Output { None, @@ -93,7 +93,7 @@ impl Output { ptr.write(Output::None); } - /// Encode an [`Output`] object to a response [APDU] + /// Encode an [`Output`] object to a response [APDU][ledger_mob_apdu] #[cfg_attr(feature = "noinline", inline(never))] pub fn encode(&self, buff: &mut [u8]) -> Result { match self.clone() { @@ -204,7 +204,7 @@ impl From<(crate::engine::State, TxDigest)> for apdu::tx::TxInfo { } impl crate::engine::State { - /// Map [engine](crate::engine) states to [apdu][apdu::state::TxState] states for transmission + /// Map [engine](crate::engine) states to [apdu][ledger_mob_apdu::state::TxState] states for transmission pub fn state(&self) -> apdu::state::TxState { use crate::{apdu::state::TxState, engine::State}; diff --git a/core/src/engine/summary.rs b/core/src/engine/summary.rs index 1926ac30..ecc61527 100644 --- a/core/src/engine/summary.rs +++ b/core/src/engine/summary.rs @@ -37,7 +37,7 @@ pub struct Summarizer { num_inputs: usize, } -/// [Summarizer] state enumeration +/// Summarizer state enumeration #[derive( Copy, Clone, PartialEq, Debug, Default, EnumString, Display, EnumVariantNames, EnumIter, )] diff --git a/core/src/lib.rs b/core/src/lib.rs index b5dd4f1a..4a54eb1d 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -5,29 +5,30 @@ //! This provides a common [Engine][engine] supporting transaction signing and verification //! for execution on hardware wallets. //! -//! Interactions with the [Engine][engine] are performed via [Event][engine::Event]s and [Output][engine::Output]s, translated into [APDUs][ledger_mob_apdu] over the wire. +//! Interactions with the [Engine][engine] are performed via [Event][engine::Event]s and [Output][engine::Output]s, +//! see [ledger_mob_apdu] for APDU objects and wire encodings. //! //! ## Operations //! //! Prior to interacting with a hardware wallet the client should issue an -//! [`AppInfoReq`][apdu::app_info::AppInfoReq] to fetch an -//! [`AppInfoResp`][apdu::app_info::AppInfoResp] containing application information +//! [`AppInfoReq`][ledger_mob_apdu::app_info::AppInfoReq] to fetch an +//! [`AppInfoResp`][ledger_mob_apdu::app_info::AppInfoResp] containing application information //! including the applet version, protocol version, and flags for available features. //! //! ### Requesting wallet / subaddress keys //! -//! Wallet keys can be requested via [`WalletKeyReq`][apdu::wallet_keys::WalletKeyReq] -//! APDU, returning a [`WalletKeyResp`][apdu::wallet_keys::WalletKeyResp] containing +//! Wallet keys can be requested via [`WalletKeyReq`][ledger_mob_apdu::wallet_keys::WalletKeyReq] +//! APDU, returning a [`WalletKeyResp`][ledger_mob_apdu::wallet_keys::WalletKeyResp] containing //! the root spend public key and view private key for a given account index. //! -//! SubAddress keys can be requested via [`WalletKeyReq`][apdu::subaddress_keys::SubaddressKeyReq] -//! APDU, returning a [`WalletKeyResp`][apdu::subaddress_keys::SubaddressKeyResp] containing +//! SubAddress keys can be requested via [`WalletKeyReq`][ledger_mob_apdu::subaddress_keys::SubaddressKeyReq] +//! APDU, returning a [`WalletKeyResp`][ledger_mob_apdu::subaddress_keys::SubaddressKeyResp] containing //! the subaddress spend public key and view private key for a given account index. //! //! ### Key Image Scanning //! -//! Key images can be recovered via [`KeyImageReq`][apdu::key_image::KeyImageReq] request, -//! returning a [`KeyImageResp`][apdu::key_image::KeyImageResp] APDU containing the computed +//! Key images can be recovered via [`KeyImageReq`][ledger_mob_apdu::key_image::KeyImageReq] request, +//! returning a [`KeyImageResp`][ledger_mob_apdu::key_image::KeyImageResp] APDU containing the computed //! key image. //! //! @@ -37,41 +38,40 @@ //! transaction, sign memos for the transaction, then to sign the set of //! rings included in the transaction. //! +//! See [`lib/src/handle.rs`](https://github.com/mobilecoinofficial/ledger-mob/blob/main/lib/src/handle.rs#L219) +//! for a complete / reference implementation. +//! //! Unless otherwise documented each transaction operation returns a -//! [`TxInfo`][apdu::tx::TxInfo] response containing the current -//! [transaction state][apdu::tx::TxState] as well as a +//! [`TxInfo`][ledger_mob_apdu::tx::TxInfo] response containing the current +//! [transaction state][ledger_mob_apdu::state::TxState] as well as a //! [`TxDigest`][engine::TxDigest] computed from the inputs to the transaction. //! This digest ensures the executed transaction matches the callers expectations, -//! and _MUST_ be cached on [`TxInit`][apdu::tx::TxInit] and updated and +//! and _MUST_ be cached on [`TxInit`][ledger_mob_apdu::tx::TxInit] and updated and //! compared for each operation during a transaction, with the transaction //! discarded if a mismatch is detected. //! //! -//! 1. Issue [`TxInit`][apdu::tx::TxInit] with transaction options to start a transaction operation +//! 1. Issue [`TxInit`][ledger_mob_apdu::tx::TxInit] with transaction options to start a transaction operation //! 2. Generate and sign memos -//! 1. Issue [`TxMemoSign`][apdu::tx::TxMemoSign] to fetch a [`TxMemoSig`][apdu::tx::TxMemoSig] +//! 1. Issue [`TxMemoSign`][ledger_mob_apdu::tx::TxMemoSign] to fetch a [`TxMemoSig`][ledger_mob_apdu::tx::TxMemoSig] //! APDU containing a signature for the provided memo -//! 3. Set transaction message via [`TxSetMessage`][apdu::tx::TxSetMessage] APDU (see notes) +//! 3. Build transaction summary to generate message for signing (see: [MCIP#52](https://github.com/mobilecoinfoundation/mcips/pull/52)) +//! 1. Issue [`TxSummaryInit`][ledger_mob_apdu::tx::TxSummaryInit] to start summary generation +//! 2. Add N outputs and unblinding information using [`TxSummaryAddTxOut`][ledger_mob_apdu::tx::TxSummaryAddTxOut] followed by [`TxSummaryAddTxOutUnblinding`][ledger_mob_apdu::tx::TxSummaryAddTxOutUnblinding] +//! 3. Add M inputs via [`TxSummaryAddTxIn`][ledger_mob_apdu::tx::TxSummaryAddTxIn] +//! 4. Issue [`TxSummaryBuild`][ledger_mob_apdu::tx::TxSummaryBuild] to build summary message //! 4. Sign N rings -//! 1. Issue [`TxRingInit`][apdu::tx::TxRingInit] to start a ring signing operation -//! 2. Issue [`TxSetBlinding`][apdu::tx::TxSetBlinding] to set the blinding values for the ring -//! 3. Issue [`TxAddTxOut`][apdu::tx::TxAddTxOut] for each ring entry +//! 1. Issue [`TxRingInit`][ledger_mob_apdu::tx::TxRingInit] to start a ring signing operation +//! 2. Issue [`TxSetBlinding`][ledger_mob_apdu::tx::TxSetBlinding] to set the blinding values for the ring +//! 3. Issue [`TxAddTxOut`][ledger_mob_apdu::tx::TxAddTxOut] for each ring entry //! (in order of `real_index` to `(real_index - 1) % ring_size)` -//! 4. Issue [`TxRingSign`][apdu::tx::TxRingSign] to complete signing -//! 5. Issue [`TxGetKeyImage`][apdu::tx::TxGetKeyImage] to fetch a [`TxKeyImage`][apdu::tx::TxKeyImage] +//! 4. Issue [`TxRingSign`][ledger_mob_apdu::tx::TxRingSign] to complete signing +//! 5. Issue [`TxGetKeyImage`][ledger_mob_apdu::tx::TxGetKeyImage] to fetch a [`TxKeyImage`][ledger_mob_apdu::tx::TxKeyImage] //! APDU containing the key image and zeroth challenge for the signed ring -//! 6. Issue [`TxGetResponse`][apdu::tx::TxGetResponse] to fetch [`TxResponse`][apdu::tx::TxResponse] -//! APDU the response scalar for each ring entry -//! 5. Issue [`TxComplete`][apdu::tx::TxComplete] to complete transaction -//! -//! -//! -//! ### Notes +//! 6. Issue [`TxGetResponse`][ledger_mob_apdu::tx::TxGetResponse] to fetch [`TxResponse`][ledger_mob_apdu::tx::TxResponse] +//! APDU containing the response scalar for each ring entry +//! 5. Issue [`TxComplete`][ledger_mob_apdu::tx::TxComplete] to complete transaction //! -//! - `TxSetMessage` to be replaced with streaming of tx summaries to support computation -//! of the tx prefix on device and allow the device to verify transaction values once -//! [MCIP#52](https://github.com/mobilecoinfoundation/mcips/pull/52) -//! ([mobilecoin#2683](https://github.com/mobilecoinfoundation/mobilecoin/pull/2683)) is available. //! #![cfg_attr(not(feature = "std"), no_std)] diff --git a/docs/apdu.md b/docs/apdu.md new file mode 100644 index 00000000..f90447b3 --- /dev/null +++ b/docs/apdu.md @@ -0,0 +1,5 @@ +# Mobilecoin application: Technical Specifications + +See [ledger_mob_apdu](https://mobilecoinofficial.github.io/ledger-mob/ledger_mob_apdu/index.html) documentation for APDU instructions and encodings, [ledger_mob_core](https://mobilecoinofficial.github.io/ledger-mob/ledger_mob_core/index.html) for device/APDU interactions, and [ledger_mob](https://mobilecoinofficial.github.io/ledger-mob/ledger_mob/index.html) for a reference implementation. + + diff --git a/fw/Cargo.lock b/fw/Cargo.lock index 5b40fcf7..5f23a87d 100644 --- a/fw/Cargo.lock +++ b/fw/Cargo.lock @@ -901,7 +901,7 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "ledger-mob-apdu" -version = "0.15.0" +version = "0.16.0" dependencies = [ "bitflags 1.3.2", "byteorder", @@ -924,7 +924,7 @@ dependencies = [ [[package]] name = "ledger-mob-core" -version = "0.15.0" +version = "0.16.0" dependencies = [ "aes", "anyhow", @@ -968,7 +968,7 @@ dependencies = [ [[package]] name = "ledger-mob-fw" -version = "0.15.0" +version = "0.16.0" dependencies = [ "anyhow", "chrono", @@ -1319,7 +1319,7 @@ dependencies = [ [[package]] name = "nanos_ui" version = "0.2.0" -source = "git+https://github.com/LedgerHQ/ledger-nanos-ui?branch=master#730fed32ffead4b5236940a549841e020b749a3a" +source = "git+https://github.com/LedgerHQ/ledger-nanos-ui?branch=master#6a7c4a3eb41ee0b09c8fd4dcc5be4f3a1f5d7b45" dependencies = [ "include_gif", "nanos_sdk", diff --git a/fw/Cargo.toml b/fw/Cargo.toml index e8958e6f..e4219ed4 100644 --- a/fw/Cargo.toml +++ b/fw/Cargo.toml @@ -5,7 +5,7 @@ cargo-features = ["per-package-target"] name = "ledger-mob-fw" description = "MobileCoin Ledger NanoApp" repository = "https://github.com/mobilecoinofficial/ledger-mob.git" -version = "0.15.0" +version = "0.16.0" edition = "2021" license = "GPL-3.0" publish = false diff --git a/fw/docs/apdu.md b/fw/docs/apdu.md deleted file mode 100644 index a8285e39..00000000 --- a/fw/docs/apdu.md +++ /dev/null @@ -1,4 +0,0 @@ -# Mobilecoin application: Technical Specifications - -See [APDU](https://developers.ledger.com/docs/nano-app/application-structure/#apdu-interpretation-loop) spec - diff --git a/fw/src/consts.rs b/fw/src/consts.rs index 503f793a..7a2e7ffa 100644 --- a/fw/src/consts.rs +++ b/fw/src/consts.rs @@ -11,7 +11,8 @@ use ledger_mob_core::apdu::app_info::AppFlags; /// App Information pub const APP_NAME: &str = "MobileCoin"; -pub const APP_VERSION: &str = env!("GIT_TAG"); +pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION"); +pub const GIT_VERSION: &str = env!("GIT_TAG"); pub const BUILD_TIME: &str = env!("BUILD_TIME"); pub fn app_flags() -> AppFlags { diff --git a/fw/src/main.rs b/fw/src/main.rs index 16646fbf..60736680 100644 --- a/fw/src/main.rs +++ b/fw/src/main.rs @@ -186,8 +186,9 @@ extern "C" fn sample_main() { // Execute lock syscall (blocks on pin entry) request_pin_validation(); - // Reset timeout on re-entry + // Reset timeout and redraw on re-entry lock_timeout = ticks.wrapping_add(LOCK_TIMEOUT_S * TICKS_PER_S); + redraw = true; } } }; diff --git a/fw/src/ui/app_info.rs b/fw/src/ui/app_info.rs index 5bbf1f7b..f09d4276 100644 --- a/fw/src/ui/app_info.rs +++ b/fw/src/ui/app_info.rs @@ -1,6 +1,5 @@ // Copyright (c) 2022-2023 The MobileCoin Foundation -use emstr::{helpers::Hex, EncodeStr}; use rand_core::{CryptoRng, RngCore}; use nanos_sdk::buttons::ButtonEvent; @@ -9,13 +8,10 @@ use nanos_ui::{ screen_util, }; -use ledger_mob_core::{ - apdu::app_info::AppFlags, - engine::{Driver, Engine}, -}; +use ledger_mob_core::engine::{Driver, Engine}; use super::{clear_screen, UiResult}; -use crate::consts::{app_flags, APP_VERSION, BUILD_TIME}; +use crate::consts::{BUILD_TIME, GIT_VERSION}; #[derive(Copy, Clone, Debug, PartialEq)] pub struct AppInfo {} @@ -34,36 +30,12 @@ impl AppInfo { } } - pub fn render(&self, engine: &Engine) { - let mut buff = [0u8; 32]; - + pub fn render(&self, _engine: &Engine) { // Clear screen clear_screen(); - let state = engine.state(); - let s = u16::from_be_bytes([state.state() as u8, state.value() as u8]); - - let mut flags = app_flags(); - - if engine.is_unlocked() { - flags |= AppFlags::UNLOCKED; - } - - let state_str = emstr::write!( - &mut buff[..], - "S: 0x", - Hex(&s.to_be_bytes()), - " F: 0x", - Hex(&flags.bits().to_be_bytes()) - ) - .map(|n| core::str::from_utf8(&buff[..n])); - - let state_str = match state_str { - Ok(Ok(v)) => v, - _ => "INVALID_UTF8", - }; - - [APP_VERSION, BUILD_TIME, state_str].place(Location::Middle, Layout::Centered, false); + // Show git version and build time + [GIT_VERSION, BUILD_TIME].place(Location::Middle, Layout::Centered, false); // Update screen screen_util::screen_update(); diff --git a/fw/src/ui/menu.rs b/fw/src/ui/menu.rs index 34656ac7..a5d667b1 100644 --- a/fw/src/ui/menu.rs +++ b/fw/src/ui/menu.rs @@ -13,7 +13,7 @@ use nanos_ui::{ use ledger_mob_core::engine::{Driver, Engine}; use super::{clear_screen, UiResult}; -use crate::consts::MOB32X32; +use crate::consts::{APP_VERSION, MOB32X32}; #[derive(Copy, Clone, Debug, PartialEq, EnumCount)] pub enum MenuState { @@ -38,6 +38,9 @@ pub const MENU_STATES: &[MenuState] = &[ MenuState::Exit, ]; +const ICON_OFFSET: i16 = -8; +const TEXT_OFFSET: usize = 34; + impl UiMenu { pub const fn new() -> Self { Self { i: 0 } @@ -84,19 +87,35 @@ impl UiMenu { // Render pages match state { MenuState::Hello => { - "M O B I L E C O I N".place(Location::Custom(8), Layout::Centered, false); - MOB32X32.draw((128 - 32) / 2, 24); + MOB32X32.draw((128 - 32) / 2, 2); + "MobileCoin".place(Location::Custom(38), Layout::Centered, true); + "is ready".place(Location::Custom(50), Layout::Centered, false); } MenuState::Address => { - "Address".place(Location::Middle, Layout::Centered, false); + CERTIFICATE_ICON + .shift_v(ICON_OFFSET) + .shift_h((128 - 16) / 2) + .display(); + "Address".place(Location::Custom(TEXT_OFFSET), Layout::Centered, true); } MenuState::Version => { - "App Info".place(Location::Middle, Layout::Centered, false); + "Version".place(Location::Custom(20), Layout::Centered, true); + APP_VERSION.place(Location::Custom(36), Layout::Centered, false); } MenuState::Settings => { - "Settings".place(Location::Middle, Layout::Centered, false); + COGGLE_ICON + .shift_v(ICON_OFFSET) + .shift_h((128 - 16) / 2) + .display(); + "Settings".place(Location::Custom(TEXT_OFFSET), Layout::Centered, true); + } + MenuState::Exit => { + DASHBOARD_X_ICON + .shift_v(ICON_OFFSET) + .shift_h((128 - 16) / 2) + .display(); + "Exit".place(Location::Custom(TEXT_OFFSET), Layout::Centered, true) } - MenuState::Exit => "Exit".place(Location::Middle, Layout::Centered, false), } // Update screen diff --git a/fw/src/ui/settings.rs b/fw/src/ui/settings.rs index 7e628209..69c27ecc 100644 --- a/fw/src/ui/settings.rs +++ b/fw/src/ui/settings.rs @@ -66,7 +66,7 @@ impl Settings { let name = fog_name(fog); // Display current selection - "Fog ID".place(Location::Custom(8), Layout::Centered, false); + "Fog ID".place(Location::Custom(8), Layout::Centered, true); name.place(Location::Custom(26), Layout::Centered, false); // Update screen diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 0663fa73..4eb6d9a1 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -2,7 +2,7 @@ name = "ledger-mob" description = "MobileCoin Ledger Interface Library" repository = "https://github.com/mobilecoinofficial/ledger-mob.git" -version = "0.15.0" +version = "0.16.0" edition = "2021" license = "Apache-2.0" publish = false diff --git a/lib/src/handle.rs b/lib/src/handle.rs index 87057a2e..7ca74668 100644 --- a/lib/src/handle.rs +++ b/lib/src/handle.rs @@ -3,7 +3,7 @@ //! Handle for connected ledger devices //! //! This provides methods for interacting with the device -//! and is generic over [Exchange] +//! and is generic over [ledger_lib::Device] use std::{sync::Arc, time::Duration}; diff --git a/tests/Cargo.toml b/tests/Cargo.toml index b5f89b17..6eb53562 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -2,7 +2,7 @@ name = "ledger-mob-tests" description = "Common tests for MobileCoin hardware wallets" repository = "https://github.com/mobilecoinofficial/ledger-mob.git" -version = "0.15.0" +version = "0.16.0" edition = "2021" license = "Apache-2.0" publish = false diff --git a/tests/src/lib.rs b/tests/src/lib.rs index c527d54b..625a23d9 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -2,7 +2,7 @@ //! Tests for mobilecoin wallet integration. //! -//! Generic over [ledger_transport::Exchange] for reuse. +//! Generic over [ledger_lib::Exchange] for reuse. //! pub mod wallet;