Nomadic Labs
Nomadic Labs
Cortez security by using the Spending Limit contract

In this most recent blog post we discuss how to benefit from the secure enclave using the Daily Spending Limit smart contract.

My wallet, my crypto

When holding a cryptocurrency, one needs a safe and secure wallet to store it. Wallets are used to store, receive, or spend cryptocurrencies. They work by keeping private keys to themselves and using them to sign transaction from the corresponding public keys.

A public key is used to send assets to the corresponding destination, whereas a private key is used to send assets from your corresponding wallet. Addresses are uniquely defined as a public function of the public key.

The most important component of a cryptocurrency wallet is a private key, if one loses it then its tokens are not accessible. Cryptocurrency holders must take really good care of where and how they store their private keys. To make things easier, one can use a seed phrase, which is a randomly generated list of words used to deterministicaly generate a secret key. Therefore the seed phrase gives the ability to recover an account and the corresponding funds.

This is typically what cryptocurrency wallet software tends to do - they randomly generate seed phrases and ask users to write them down on a piece of paper. In the unfortunate event that something were to happen, like losing a phone or breaking a computer, a user can download the wallet software on a different device and use a seed phrase to recover the associated account.

Keep it safe, stupid*

If one would rather not leave its private key on a mobile wallet, a hardware wallet is a good alternative. This little gadget has no network capabilities, for obvious security reasons, and therefore must be used in conjunction with a computer/phone in order to transact.

Even so, some phones use the same level of security one can expect from a hardware wallet like a Ledger Nano S. Apple and its secure enclave and Samsung, which relies on ARM TrustZone technology, both provide hardware isolation (“hardware security modules”) to prevent malicious software from extracting private keys.

Peg-Leg Pete got me

You might feel safe using a private key, but what if someone like Peg-Leg Pete asks you for your cryptocurrency wallet in a way that you can’t refuse? What if he commands you to transfer all your cryptocurrencies to him, or else… How unfortunate it would be to lose everything despite taking so much care of keeping your private key safe!

pete

Peg-Leg Pete threatens Mickey © Disney

A similar situation with a credit card would not have been as critical. At most you would have lost what your daily limit allows for before calling your bank to file a report/chargeback.

Cortez proposal

The Secure enclave

A few words about the secure enclave on mobile devices.

Some smartphones (iOS/Android) possess special security chips (HSM) which are basically tiny computers themselves. One of these HSMs has its own operating system running on top of its own processor and memory. With this, an attacker will likely never be able to access the contents of this secure area even if he/she is able to compromise the main operating system of the phone.

When using Apple Pay, Google Pay and/or Samsung Pay, payment details are stored securely in an HSM to prevent access by malicious software.

Enclave

Secure enclave inside a mobile phone

Something really interesting about the Trusted World (referenced above) on mobile is that it allows users to generate cryptographic keys and encrypt/decrypt/sign/verify and so on, without private keys being exposed. Private keys stay in the secure enclave, the Trusted World.

Signing Tezos transactions with a key generated in a secure enclave would be perfect to avoid the threat of malicious actors. It’s actually already possible to do that.

Mobile operating systems like iOS and Android allow us to generate a NIST P-256 (aka secp256r1) key pair for ECDSA and store the private key in the Trusted World. This elliptic curve is the one used to generate tz3 addresses for Tezos accounts.

We could then have a tz3 public key hash and sign transactions using the corresponding secure enclave, that would be perfect.

The problem with secure enclave key generations is that you cannot extract a private key and use it later on via another device. You can sign, verify, encrypt, and decrypt data, but exports are not allowed.

This is the whole point of a secure enclave - Nobody ever has access to a private key itself. If you lose your phone with this configuration, the wallet on your phone (and all its contents) is lost forever inside the phone’s secure enclave.

Secure enclave using a smart contract

Our goal is to use a phone’s secure enclave to generate a tz3 address to be able to sign tezos transactions with it, while at the same time facilitating a great user experience to enable actions such as account recovery. For this, we can use a smart contract.

The contract is created from a main account (tz1…) simply by originating a KT1 account with the Spending Limit Contract code, preferably with some ꜩ in it.

The visual below summarizes the contract:

Schema

The contract keeps two pieces of information in its storage:

  • a public key hash (tz3…), aka the “signatory.”
  • a spending limit (explained in the next paragraph).

The contract will send transactions from the KT1 account to another address if, and only if, the transaction is signed using the secure enclave private key used to generate the tz3 in its storage.

The Spending Limit Contract storage is amendable using a 24-word mnemonic (seed phrase). Thus, it is possible to change a contract’s public key hash and spending limit.

Once again, keep your mnemonic/seed phrase safe.

Limit from traditional bank system

This contract also has another benefit, a spending limit. The first version of the contract we developed at Nomadic Labs is called the Daily Spending Limit.

This feature is inspired from traditional banking systems. Daily limits are placed for security reasons so that a bank account can’t be drained of an amount of funds in excess of a limit if theft or fraud occurs.

Many banks set ATM withdrawal limits around $500

The Daily Spending Limit contract works on a rolling 24h basis. In the same way as a traditional bank, using the Daily Spending Limit contract, a transaction will be declined if one tries to transfer more than the contract specifies for a 24h window.

Example: your spending limit is set to 2,000ꜩ per 24 rolling hours. If you transfer 1,500ꜩ at 10.07 am, you can only transfer 500ꜩ until the next day at 10.07 am, at which point the 2,000ꜩ limit is reset.

Unless you amend the contract storage using the corresponding 24-word mnemonic, there is no way to transfer more than the specified spending limit from the contract. You can also set the daily spending limit to 0.00ꜩ to be sure that no tez will be sent from the KT1 contract.

In practice

You can test this way of using tez via the Cortez wallet for Alphanet*

  1. Create a new wallet and send it some ꜩ (remember this is the alphanet test network).
  2. Create a Daily Spending Limit Contract and add a few ꜩ from your main account to it.
  3. Go to “Key Management” then remove the master key.

You cannot spend tez from your main account (tz1…) anymore because the master key was removed from your phone. However, you can still spend ꜩ from the newly created Daily Spending Limit contract (KT1…).

If you want to amend the contract’s storage, go to “Key Management” and restore the master key by entering the associated 24-word mnemonic. This way, you will also be able to transfer from your main account (your tz1). Don’t forget to remove the master key to maximise security.

I need to make a big transfer

You can always change your Spending Limit as long as you have the master key. In the first alphanet version, users can set their daily spending limits up to 10,000ꜩ per 24h.

This also means that if you do not have the master key encrypted in your phone, or if you do not have access to the 24-word mnemonic, then you cannot update the contract’s storage to spend more than what is indicated in it.

What if I lose my phone?

All you need is a 24-word mnemonic and a new phone. Download the last version of Cortez, then restore your wallet with the mnemonic.

Once restored, you will be able to amend the storage of your Spending Limit Contract and assign your new secure enclave key to it (the tz3 generated by your new phone).

Once the contract is assigned to your new phone/tz3 address, you can make transfers from it. Do not forget to remove the master key from your phone in the key management section to maximize security.

Peg-Leg Pete stole my phone with my password.

There are two possible situations:

  • You previously removed the masterkey from your phone in Key Management section of the app.

Peg-Leg Pete can then only make transfers from your Spending Limit Contract, not your main account (your tz1). He will probably spend up to the specified limit. Without the 24-word mnemonic, and no matter how much he wants to, Pete cannot steal more than the spending limit in a 24h window, and not more than the balance of the contract.

Pete_attack

Peg-Leg Pete attacks Mickey © Disney

Assuming the contract is a Daily Spending Limit contract, you now have 24h to obtain the 24-word mnemonic, restore the wallet, and assign the Daily Spending Limit contract to the new secure enclave key (tz3…) before Peg-Leg Pete can once again spend the daily spending limit amount.

  • You didn’t remove the masterkey from your phone.

If you can find another phone and the 24-word mnemonic very quickly, you can restore your wallet and amend the contract storage to assign a new tz3. This must be done before Peg-Leg Pete transfers the whole balance to his own wallet.

Status of the implementation

The first version of the Daily Spending Limit (“DSL”) smart contract is available on Cortez for Alphanet. Even if it already works, the feature is still experimental and there are some flaws.

The DSL version won’t be deployed on mainnet until it is well-tested, fully functional, and formally verified. You can find the current version of the DSL code below, however the code will evolve.

For free Tezzies follow these instructions. If you have any issues or if you want us to send you Tezzies feel free to ask for help at cortez@nomadic-labs.com.

Formal verification

You can find a link below to the very first version of the DSL, currently implemented in the Android version of Cortez for alphanet.

The contract has been partially verified using Mi-Cho-Coq, a specification of Michelson in Coq to prove properties about smart contracts in Tezos. There is more work to be done.

As stated above, the contract is meant to evolve and improve with subsequent versions until it is sufficiently flawless before it will be deployed on mainnet.

Michelson code

This is the current version of the Daily Spending Limit (DSL) contract code. Note that this version will change over time.

storage (pair
           (pair
              (pair
                 (nat %salt)
                 (key_hash %daily_key_hash))
              (pair
                 (pair
                    (mutez %remaining_funds)
                    (int %blocking_period))
                 (pair %file
                    (list (pair timestamp mutez))
                    (list (pair timestamp mutez)))))
           (pair
              (key_hash %master_key_hash)
              (nat %salt)));
parameter (option
             (or
                (pair %contract_renewal
                   (pair
                      (key %public_key)
                      signature)
                   (pair
                      (pair
                         (pair
                            (nat %salt)
                            (key_hash %daily_key_hash))
                         (pair
                            (pair
                               (mutez %remaining_funds)
                               (int %blocking_period))
                            (pair %file
                               (list (pair timestamp mutez))
                               (list (pair timestamp mutez)))))
                      (key_hash %new_master_key_hash)))
                (pair %transfer
                   (pair
                      (list %beneficiaries
                         (pair
                            (mutez %amount)
                            (contract %beneficiary unit)))
                      (key_hash %new_daily_key_hash))
                   (pair
                      (key %public_key)
                      signature))));
code { UNPAPAIR;
       IF_SOME{ IF_LEFT{ DIP{DROP}; # call by master key
                         SWAP;
                         UNPAIR;
                         DIP{ SWAP;
                              UNPAIR;
                              DIP{ DUP;
                                   PACK;
                                   DIP{ DIP{ DUP;
                                             PUSH nat 1;
                                             ADD;
                                             SWAP;
                                             PACK};
                                        SWAP
                                      };
                                   CONCAT;
                                   DUP};
                              UNPAIR;
                              DUP;
                              HASH_KEY;
                            };
                         ASSERT_CMPEQ;
                         CHECK_SIGNATURE;
                         IF{DROP}{FAILWITH};
                         UNPAIR;
                         DIP{PAIR};
                         NIL operation
                       }
                       { DIP {UNPAPAIR}; # transaction call
                         UNPAIR;
                         DUP;
                         PACK;
                         DIP{ UNPAIR;
                              DIP{SWAP}};
                         SWAP;
                         DIP{ DIP{ DIP{SWAP};
                                   SWAP;
                                   DIP{ UNPAIR;
                                        DUP;
                                        HASH_KEY};
                                   UNPAIR;
                                   DIP{ ASSERT_CMPEQ}; # keys compatibility verification
                                   DUP;
                                   PUSH nat 1;
                                   ADD;
                                   SWAP;
                                   PACK;
                                 };
                              CONCAT;
                              SWAP;
                              DIP{ SWAP;
                                   DIP{ SWAP;
                                        DIP{DUP}};
                                   CHECK_SIGNATURE; # signature verification
                                   IF{DROP}{FAILWITH}};
                              PAIR;
                              DIP{ UNPAIR;
                                   SWAP;
                                   DIP{ SWAP;
                                        UNPAIR;
                                        PUSH bool True;
                                        LOOP{ # search for funds to unlock
                                              IF_CONS{ DUP;
                                                       CAR;
                                                       NOW;
                                                       IFCMPGE{ CDR;
                                                                SWAP;
                                                                DIP{ SWAP;
                                                                     DIP{ ADD}};
                                                                PUSH bool True
                                                              }
                                                              { CONS;
                                                                PUSH bool False
                                                              };
                                                     }
                                                     { IF_CONS{ NIL (pair timestamp mutez);
                                                                SWAP;
                                                                CONS;
                                                                SWAP;
                                                                ITER{ CONS};
                                                                NIL (pair timestamp mutez);
                                                                SWAP;
                                                                PUSH bool True}
                                                              { NIL (pair timestamp mutez);
                                                                DUP;
                                                                PUSH bool False}
                                                     };
                                            };
                                        DIP{ SWAP};
                                        SWAP;
                                      };
                                 };
                              PUSH mutez 0;
                              NIL operation;
                            };
                         ITER{ UNPAIR; # transactions production
                               DUP;
                               DIP{
                                    UNIT;
                                    TRANSFER_TOKENS;
                                    CONS;
                                  };
                               SWAP;
                               DIP{ SWAP;
                                    ADD} # blocking period computation
                             };
                         DIP{ SWAP; # spent funds lock
                              DIP{ SWAP;
                                   DUP;
                                   NOW;
                                   ADD;
                                   SWAP;
                                   DIP{ DIP{SWAP};
                                        SWAP;
                                        DIP{ SWAP;
                                             DUP;
                                             DIP{ SWAP;
                                                  PAIR;
                                                  SWAP;
                                                  DIP{ CONS}; # add to the queue
                                                  PAIR}};
                                        SUB}; # unlocked remaining funds computation
                                   SWAP;
                                   PAIR;
                                   PAIR;
                                 };
                              PAIR};
                       }
              }
              { NIL  operation; # simple fund addition (parameter: None)
                };
       PAPAIR;
     }

*KISS Principle: https://en.wikipedia.org/wiki/KISS_principle

*Google Play: https://play.google.com/store/apps/details?id=com.tezcore.cortez.alphanet.

*Source code: https://gitlab.com/nomadic-labs/cortez-android


Babylon update instructions for delegation wallet developers

How to update the delegation feature of your wallet for 005 (aka. Babylon)

Introduction Tezos wallets usually feature management of scriptless originated (aka KT1) accounts used to delegate tokens. This document details the steps needed for wallet developers to update their applications in anticipation to the breaking changes in the Babylon protocol update. See also cryptium’s migration guidelines and Babylon’s documentation for more technical details on the Babylon update. The Babylon protocol update brings two big changes to the way delegation can be implemented. First, implicit (aka tz) accounts can now directly delegate their tokens (see relevant...

Read More
Babylon: Proposal Injected!

EDIT (August 2, 2019): The updated Babylon proposal has been injected by Cryptium Labs. Its hash is PsBABY5HQTSkA4297zNHfsZNKtxULfL18y95qb3m53QJiXGmrbU. The instructions contained in this post have been updated accordingly. Cryptium Labs just injected the hash of our new joint proposal: Babylon. This triggers the beginning of the third on-chain vote to amend Tezos. This process could end in the successful migration from current protocol Athens in about three months, if the participants decide so. This update is joint work with Cryptium Labs, with contributions from...

Read More
Michelson updates in 005

Changes in Michelson As hinted at in a previous blog post, we’ve been working on improving different parts of the protocol, including our favourite smart contract language: Michelson. The changes made to Michelson in this proposal intend to simplify smart contract development by making the code of complex contracts simpler and cleaner. In particular: smart contracts now support entrypoints contracts can now create, store and transmit as many big_maps as they want comparable types are now closed under products (i.e. the pair constructor) a new instruction, CHAIN_ID, allows...

Read More
Analysis of Emmy+

Note: This analysis was done with the help of Arthur Breitman and Bruno Blanchet (Inria). The code used for the analysis can be found at this url. We have recently announced Emmy+ an improvement of Emmy, the current consensus algorithm used by Tezos. In this blog post, we perform a brief analysis of Emmy+. Disclaimer: We emphasize that this is not a complete analysis; in particular, we do not present any security proofs. Also, the...

Read More
An indexer for Tezos

We are happy to announce that the indexer for Tezos we have been working on is ready for beta-testing and available here. But first… What is an indexer, and what is it useful for? Mainly, indexers fill a void by providing information that’s not directly available from the node’s RPC interface. But then why don’t nodes provide these RPCs in the first place? That’s simply because when you design and implement your node, you want to provide just what is necessary, focus...

Read More
Meanwhile at Nomadic Labs #3

Another update on the many projects we have been busy working on. Most of the following topics will be subject of more in-depth posts of their own. Protocol The consensus team is finishing their analysis of selfish baking on Emmy+ and tweaking the constants of the protocol accordingly. At the same time work on our version of Tendermint is progressing to the point of having a proof of concept protocol to play with. The protocol team has been steadily reviewing and testing...

Read More
How to write a Tezos protocol

A Tezos node is parameterized by a software component called an economic protocol (or protocol for short). Different protocol implementations can be used to implement different types of blockchains. This is the first post of a tutorial series on how to implement such a protocol. We will see how to write, compile, register, activate and use an extremely simple protocol. By doing so, we will also start to explore the interface between the protocol and the node (more specifically the shell component of...

Read More
Emmy+: an improved consensus algorithm

Underlying the Tezos network is a consensus algorithm, which, for the ease of reference, we will call Emmy. Consensus ensures that participants agree on the same blockchain and on its state. The ideas behind Emmy are described in the white paper and the specifics to its implementation can be found in the documentation. We recall that Emmy is a PoS based consensus with a use of endorsements to speed-up confirmation times and reduce...

Read More
Release of Mainnet May

Today we are proud to announce a new release of the Tezos node and client. The main features present in this release are: node support for snapshots (boot and synchronize a node in minutes), node support for new history modes (not everyone needs to be an archive), client integration for a multi-signature contract. Remember that besides major features there are always a myriad of smaller improvements, have a look at the changelog. We encourage bakers to switch to history mode “full” using a snapshot before the activation of...

Read More
  • 1
  • 2

Receive Updates

ATOM

Contacts