GithubHelp home page GithubHelp logo

zondax / ledger-stacks Goto Github PK

View Code? Open in Web Editor NEW
16.0 11.0 7.0 1.95 MB

License: Apache License 2.0

GDB 0.09% CMake 0.67% Makefile 1.29% C 15.90% Rust 59.98% C++ 3.29% JavaScript 0.75% HTML 0.14% Vue 1.81% TypeScript 16.08%
ledger blockstack

ledger-stacks's Issues

Multisig PreSigHash Calculation

Currently, the app just signs the prior PreSigHash directly, but the protocol does roughly this calculation instead:

What it should be:
  sign(sha512/256(concat(prior_post_sig_hash, tx_auth_flag, tx_fee, tx_nonce)))
What it does now:
  sign(prior_post_sig_hash)

A hack-y version of implementing this is:

diff --git a/app/src/common/actions.h b/app/src/common/actions.h
index 1c874bd..98f6933 100644
--- a/app/src/common/actions.h
+++ b/app/src/common/actions.h
@@ -67,6 +67,7 @@ __Z_INLINE zxerr_t get_presig_hash(uint8_t* hash, uint16_t hashLen);
 
 // Heper function to verify the previous signer post_sig_hash in a multisig transaction
 __Z_INLINE zxerr_t validate_post_sig_hash(uint8_t *current_pre_sig_hash, uint16_t hash_len, uint8_t *signer_data, uint16_t signer_data_len);
+__Z_INLINE zxerr_t get_presig_hash_from_postsig(uint8_t* hash, uint16_t hashLen, uint8_t* data);
 
 __Z_INLINE void app_sign() {
     uint8_t presig_hash[CX_SHA256_SIZE];
@@ -89,7 +90,9 @@ __Z_INLINE void app_sign() {
         if (data != NULL && len >= PREVIOUS_SIGNER_DATA_LEN) {
             if (validate_post_sig_hash(presig_hash, CX_SHA256_SIZE, data, len) == zxerr_ok) {
                 // the previous signer post_sig_hash becomes our presig_hash
-                memcpy(presig_hash, data, CX_SHA256_SIZE);
+                if (get_presig_hash_from_postsig(presig_hash, CX_SHA256_SIZE, data) != zxerr_ok) {
+                    err = zxerr_no_data;
+                }
             } else {
                 // An invalid post_sig_hash from a full signer data should be considered an error
                 err = zxerr_no_data;
@@ -208,6 +211,45 @@ __Z_INLINE zxerr_t validate_post_sig_hash(uint8_t *current_pre_sig_hash, uint16_
     return zxerr_ok;
 }
 
+__Z_INLINE zxerr_t get_presig_hash_from_postsig(uint8_t* hash, uint16_t hashLen, uint8_t* data) {
+    uint8_t hash_temp[SHA512_DIGEST_LENGTH];
+    uint8_t presig_data[PRESIG_DATA_LEN];
+    memcpy(presig_data, data, CX_SHA256_SIZE);
+    {
+        zemu_log("tx_hash: ***");
+        char buffer[65];
+        array_to_hexstr(buffer, 65, presig_data, CX_SHA256_SIZE);
+        zemu_log(buffer);
+        zemu_log("\n");
+    }
+
+    // now append the auth-flag, fee and nonce
+    uint8_t idx = CX_SHA256_SIZE;
+
+    // append the tx auth type
+    if (tx_auth_flag(&presig_data[idx++]) != zxerr_ok)
+        return zxerr_no_data;
+
+    // append the 8-byte transaction fee
+    idx += tx_fee(&presig_data[idx], 8);
+
+    // append the 8-byte transaction nonce
+    idx += tx_nonce(&presig_data[idx], 8);
+
+    if (hashLen < CX_SHA256_SIZE || idx != PRESIG_DATA_LEN)
+        return zxerr_no_data;
+
+    // Now get the presig_hash
+    sha512_256_ctx ctx;
+    SHA512_256_init(&ctx);
+    SHA512_256_starts(&ctx);
+    SHA512_256_update(&ctx, presig_data, PRESIG_DATA_LEN);
+    SHA512_256_finish(&ctx, hash_temp);
+    memcpy(hash, hash_temp, CX_SHA256_SIZE);
+
+    return zxerr_ok;
+}
+
 __Z_INLINE zxerr_t get_presig_hash(uint8_t* hash, uint16_t hashLen) {
     uint8_t tx_auth[INITIAL_SIGHASH_AUTH_LEN];
     MEMZERO(tx_auth, INITIAL_SIGHASH_AUTH_LEN);

Update sdks

update to recent versions of the nanos and nanox SDKs

Message signing

Hiro wants to support message signing and verification in its wallets, similar to the user flow described the MyCrypto wallet. Ledger device support is needed to offer parity between our software and hardware wallets.

The feature has been discussed in context of Hiro's wallet leather-wallet/extension#1051, and the Stacks blockchain stacks-network/stacks-core#2693

Ultimately, we'd like support for structured data signing, like Ethereum's EIP-721, though this task is scoped to prefixed bytestring message signing.

Spec

  • The device should support prefixed bytestring message signing
    • Errors should be thrown for invalid content, or messages that would exceed the device's memory limits
  • An ascii-encoded preview of the message should be printed on the device
    • Users can be warned or prohibited from passing too length content by wallet clients
  • The readable prefix should be "Stacks Signed Message", with a similar formatting specification to EIP-712
  • A new method, sign, should be added to the @zondax/ledger-blockstack package

These are relatively high-level requirements. If more details needed, let us know. We'll follow up with input from the blockchain team.

Limitation (max elements in list)

Due to memory constraints, we have limited the number of:

  • list elements
  • tuple elements

#1 (comment)

Can you confirm that this limit is acceptable? or please suggest a number that would be adequate.

Incorrectly truncated address when split on two pages

A Stacks community member shared this issue where their address is displayed on their device missing a character.

It seems like this could well be related to the logic of how addresses are split to be shown on two pages, as the missing char is missing between the break. This likely only happens for addresses with particularly wide characters, such as W.

Displayed on Ledger:
SP11KGACP5Q3DMHA3ER4QDWY6WPVT4ZGWTWRVYR1 <-- missing H
Correct address:
SP11KGACP5Q3DMHA3ER4QDWY6WPVT4ZGWHTWRVYR1 

image

Likely solution would be to divide the chars more evenly between the two pages.

Adjust `Stacks Signed Message` length prefix

In implementing message signing for the Hiro Wallet, I've noticed a discrepancy between our software implementation.

Software implementation:

// 'Stacks Message Signing:\n'.length //  = 24
// 'Stacks Message Signing:\n'.length.toString(16) //  = 18
const chainPrefix = '\x18Stacks Message Signing:\n';

https://github.com/blockstack/stacks.js/blob/5ac9385069ce48bde452520d5168c84e31b5b961/packages/encryption/src/messageSignature.ts#L5-L8

(This uses the wrong phrasing and needs to be updated to Stacks Signed Message)

Zondax implementation:
https://github.com/Zondax/ledger-blockstack/blob/32d8f12fe93bfc9e4c4a65605a88f0a9048695ec/js/src/index.ts#L251-L254

Hiro Wallet is currently using \x18 and Zondax uses \x19. There was some discussion about the prefix in the issue @MarvinJanssen created.

Stacks Signed Message:\n is 24 chars, so wouldn't that make the prefix \x18 in little-endian encoding

I believe we should be using \x18, unless I misunderstand how the prefix length works.

@neithanmo did say here that it should indeed by 19, though I don't understand why.

Edit: actually both wrong:

"Ethereum Signed Message:\n".length.toString(16) // = 19, same used in Eth prefix `\x19`
"Stacks Signed Message:\n".length.toString(16) // = 17

In previous calculations I was counting \n manually as two chars, so believe that value should instead be:

\x17Stacks Signed Message:\n

πŸ”— zboto Link

Verify the structure of STX token transfer payload

According to the documentation for Transaction payloads:

A STX token-transfer payload is encoded as follows:

  • A recipient address, comprised of a 1-byte address version number and a 20-byte public key hash that identifies a (possibly unmaterialized) standard account to receive the tokens,
  • An 8-byte number denominating the number of microSTX to send to the recipient address's account.

We realized that there is a third field called MEMO, according to this issue. this rises the next questions:

  1. Is this field optional? if so, there is a byte that indicates whether this value is present or not?
  2. Looking at the test in here, seems that the MEMO field is always present, but the final encoding does not follow the one stated in the documentation, for example, following the same test in the link above, we see:
        let tt_stx = TransactionPayload::TokenTransfer(addr.clone(), 123, TokenTransferMemo([1u8; 34]));

        // wire encodings of the same
        let mut tt_stx_bytes = vec![];
        tt_stx_bytes.push(TransactionPayloadID::TokenTransfer as u8);
        addr.consensus_serialize(&mut tt_stx_bytes).unwrap();
        tt_stx_bytes.append(&mut vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 123]);
        tt_stx_bytes.append(&mut vec![1u8; 34]);

the tt_stx_bytes is the encoded token-transfer payload, which content is:
[0, 5, (1-byte addrs version, Hash160), 8-bytes-amount, [u8; 34(MEMO)]]
lets focus on the first 2 bytes, If we follow the documentation, those 2 bytes should be:

  • 0x00 => Indicating it is a token transfer payload
  • 0x00 or 0x01? => Indicating it is an STX token-transfer payload

so that the question is, what does the 0x05 byte identifier mean??

Update name in Ledger Live to "Stacks (STX)"

It's unclear just what needs to be done to make this happen, but we'd like the Stacks app for Ledger Live to have the name "Stacks (STX)" instead of just "Stacks" so that users can search by "stx" and see it in the results for installation.

This is similar to how other tokens show the currency ticker in their listings.

@jleni has read that it's something in the configuration file for Ledger Live.

Screen Shot 2021-01-22 at 14 28 28

Screen Shot 2021-01-22 at 14 28 39

Support mainnet or testnet addresses on any derivation path

I don't believe there's an immediate rush for this feature, however inline with the expected behaviour of our addressing conventions, we do need to be able to specify network in addition to derivation path.

This could be in the form of an additional flag passed to the device.

Potentially dangerous sign_msg function should be removed

The potentially dangerous sign_msg function introduced in #82 should be removed. It is based on Ethereum's personal_sign, the use of which is discouraged since the introduction of the much superior EIP712 standard. EIP712 addresses the many issues and shortcomings of personal_sign. If the function is adopted in Stacks wallets, it will put the entire ecosystem on a perilous path. We should learn from the Ethereum space and skip this function completely.

personal_sign had two main use cases:

  1. Signing messages to authenticate with some app/dapp.
  2. Signing messages that authorise some on-chain action.

When it comes to the first, we already have an authentication scheme. Right now it does not allow us to prove address ownership, but that can be achieved in different ways. (I will come back to this at the end.)

The second one is more important, so I will focus on that. Signed messages have been used for many different things in the Ethereum space. I will take on one such example for brevity: off-chain order signing. 0xProtocol allows users to sign an order, which can later be submitted to a smart contract to make a token trade happen. Early versions of the protocol would hash an order structure and request users to sign the order hash via personal_sign to authorise the trade.

It first looked like this:

image

And then this:

image

Does the user have any idea what he or she is actually signing? Obviously not. The user will just have to trust that the dapp fed the right message to the wallet. The messages are also not domain specific, which means that a malicious app could trick a user into signing something meant for another platform. And since the messages that are passed to the wallet are hashes, there is no way to reconstruct the original message in the wallet. It is just all-round terrible UX and highly dangerous. In hindsight it is obvious that the function should never have existed, but back then it is all we had and such signed messages were cutting edge. They allowed for many new an exciting things. Although personal_sign was largely left behind, it is still causing longer-lasting damage because it normalised the concept of signing byte strings. Many people are now so used to signing on-chain actions in this way, that they just hit Confirm when that wallet screen pops up. The sign_msg function opens us up to all of it.

Signing byte strings should not be normalised in the Stacks ecosystem.

I cannot stress that enough. We have so many tools at our disposal to make the UX a lot better and safer. Ethereum did not have the benefit of a human-readable interpreted language like Clarity. There is no good reason to introduce a personal_sign equivalent for Stacks.

Besides, it seems to be carelessly implemented and actually commits the same mistake as the original personal_sign implementation.

https://github.com/Zondax/ledger-blockstack/blob/abaf1d01a0bef27b2a603ec3d15bb6a20ddbcc96/js/src/index.ts#L245

  • The \x19 is a (Bitcoin) varint representing the byte length of the prefix, which is correct for Ethereum Signed Message:\n as it's 25, but not for Stacks Signed Message:\n. It seems like it was copy and pasted thoughtlessly. It should have been \x18.
  • The message length is appended as an ASCII string, so you have no idea where the actual message starts. They made the same mistake in geth. ethereum/go-ethereum#14794

The language in #76 almost makes it sound like sign_msg is a stopgap solution until we have something better. I really do not think that is the right approach. I rather have nothing, over this function, until a good message signing standard arrives. Hiro, as a shepherd of the Stacks ecosystem, should consider very carefully whether adding such a function is worth it.

There is a draft SIP that describes a structured data signing method much like EIP712. It describes a general structured message signing standard that leverages Stacks wire format, while still allowing safe human-readable text message signing. (If people insist.) I would welcome such a standard or one like it. And to go back to proving address ownership, the linked SIP would make that effortless as well.

I hope that all this is convincing enough to remove sign_msg. For reference, we are building a hardware wallet at Ryder and will not implement an unstructured message signing function such as this one for the reasons laid out above.

Show amount while confirming Stacking delegation transaction

The Stacks Wallet should cause the user's Ledger device to show the amount of STX they will be delegating for Stacking when confirming the transaction on their device.

See example of delegate-stx transaction with amount-ustx

Ledger is reporting that they need this enhancement in order to approve the Stacks app for removal of "developer mode".

From @tjulien-ledger at Ledger:

the actual amount staked when staking in a pool is not displayed on the device when signing the tx while users should be able to verify the amount they are staking.
we will require this feature for a public release.

From @jleni:

I think issue is that staking is a contract call and the amount is a kind of hidden argument of the call. Unless we know the destination hash is for staking.. we cannot guess the meaning of the arguments
we think it is relatively complex issue in the way Stacks work and it is not a bug or a small fix. Stacks contract calls contain this information and parsing depends on destination hashes. On a hardware wallet can be very hard to determine the semantics of a contract call parameters

Publish js app `v0.22.3`

Hey all,

I saw you made PRs to add a CI job to publish the version, but it hasn't updated yet.

Maybe the job didn't run, or the action failed?

image

(Opening issue now but no rush, as it tis a Friday afternoon)

Implement formatting for contract-call payloads

The required info to be shown :

  • Origin
  • Nonce
  • Fee
  • Contract-publisher address
  • Contract-name
  • Function-name

There are some memory limitations, so that, function arguments are not included as part of the visualization.

Unable to retrieve keys for `m/888'` derivations paths

Related #102

Stacks authentication uses a the derivation path m/888'/0'/0'/<account> to generate "identify" keys.

The Stacks Ledger app doesn't work when passing a m/888' leading derivation path, returning the error Data is invalid. This is preventing us getting the public keys for this path, and may also impact our ability to use #102

Display Domain name when signing JWT messages

Sharing a commend from the ledger team:

JWT tokens are signed on a dedicated path (888'/0').
Header for JWW tokens must be exactly {"typ":"JWT","alg":"ES256K"}. I find it a bit restrictive (some wallets may add spaces).
Displaying the hash of the data to sign is not good from a security point of view.
I suggest, if possible, displaying the domain name contained in the JWT token on the device screen. This could be added in a future version.

This could be a bit problematic as it would probably require a full JSON parser in a device whose memory is very limited.

πŸ”— zboto Link

Implement PostConditions formatting

Currently, the number of PostConditions is limited to 16 due to memory restrictions. We need to format each post-conditions before presenting the relevant info through the UI. This formatting would be on-demand to reduce the memory consumption during the parsing stage.

Prevent freezing issue reported by Ledger

Per @nndiaye-ledger in Slack: "I have a freezing issue as I can't navigate through the menus or quit the app"

Requested for diagnosis:

  • some description of the steps you follow that lead to the problem?
  • ideally the actual transaction blob that results in the freeze (so we can avoid going through the webapp, etc.)

Support JWT signing for Stacks authentication

As mentioned in Slack, in order for the Stacks Ledger integration to be compatible with the Stack authentication flow, a JWT payload needs to be signed by a key on the "identities keychain", the m/888'/0' derivation path.

This feature would need to accept a JWT payload and return a signature.

The implementation would need to function the same as our TypeScript implementation found here.

  • Is the device capable of handing and signing a JWT?
  • How large of an effort would this be to implement?

Update data key derivation path

In #103 I stated that the data derivation path we need to support is m/888'/0'/0'/<account>

This is not the case. The scheme used is m/888'/0'/<account>, with one fewer 0'.

Would it be possible to update the Ledger app so that this new path is supported by the getIdentityPubKey method? Here's an example of where the path is being used in the @stacks/wallet-sdk package.

πŸ”— zboto Link

CI errors

There are two errors in CI not related to the code but:

  • Conan certificate is outdated
  • The master -> main branch rename in google test.

Fix Ledger Nano X support for sending transactions

We've gotten reports in Discord that users can authenticate to the Stacks Wallet v4.0.2 with Ledger Nano X but cannot subsequently send transactions successfully.

Ledger's redeployment of the Stacks app for provider 1 instead of 4 doesn't appear to have resolved this issue.

Support additional path prefix `5757'`

The 5757' prefix was used in multisig wallet setups in Stacks 1.0, where the derivation path was similar to the derivation path used for bitpay multisig and electrum multisig:

m/5757'/<account-index>'/<co-signer-index>/<change>/<address-index>

Where instead of the 45' purpose, 5757' is used.

e.g.,

m/5757'/0'/0/0/0
m/5757'/0'/0/0/1

It would be helpful for those old setups to have support for those paths as well.

For mainnet vs. testnet address encodings, this should behave similar to the current interface, where the address version can be passed in by the caller library.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.