Storing & Retrieving Secrets on a Tezos Smart Contract
With a grant from the Tezos Foundation, we are set out to develop a set of smart contracts that would make usability much easier for the average user of cryptocurrencies.
One of the difficulties of use stems from the need to remember private keys or some mnemonics (random words). As a non-custodial wallet, Ejara users have to handle/remember different mnemonics for different cryptocurrencies (bitcoin, tezos, etc.) which proves challenging to mainstream users. We are proposing a set of smart contracts which we believe will make this hurdle much easier for the user of our Ejara platform and which we hope could be widely adopted by others or at least span a discussion around the subject of usability.
In this post, we discuss the challenge of storing secrets in a smart contract and how we are going about it. We use the word secret in a generic sense but it could be anything from a mnemonic to private keys or anything else you’d like to hide from others.
This problem can be compared to storing secrets in a traditional database except with one big difference, that data stored on a blockchain is public. The obvious way to go is to encrypt the data with a private key.
There are two approaches that we discuss here, the first one requires that the user have a tezos account and that they can access that account. The second approach does not require that the user have a tezos account but rather use a strong memorable password of their choosing.
1. Smart Contract Requiring Tezos Account.
In this approach, the smart contract has two endpoints as follows.
- addSecret — This endpoint must be invoked by the tezos account that wants to add the secret. It takes as parameters:
- The encrypted_secret. The client invoking this endpoint must encrypt the secret with the private keys of the tezos account.
The parameters are stored as a key-value pair attached to the user’s public key hash or userAddress of the invoking tezos account. To give a clear picture, let me describe the data structure used to store user secrets.
blake2b(encrypted_secret): encrypted_secret, ...
This smart contract requires that the client has the private key of the tezos account. The use cases here are that one could store several secrets on the smart contract and would only need to ensure that they do not lose their tezos private key or the mnemonic used to generate the private key.
2. Smart Contract Requiring a Standard Username and Password.
This smart contract is much more general and does not require users to have a tezos account or remember some mnemonic or private keys. Rather, it takes the approach of allowing the user to provide a username and a strong memorable password.
The password provided by the user will be used by the client to generate a private key using the Argon2id hashing algorithm, i.e Argon2id(password). This would ensure that we get the correct bit-length required for the AES-256 encryption algorithm.
Since this smart contract must not necessarily be invoked by a tezos account as opposed to the one above, we need a mechanism to restrict access to who can add data to a username. In the smart contract proposed above, additional data is automatically added to the public key hash or userAddress of the invoking tezos account. This restricts access as to who can add data to the user’s space since only the user could have the private key to invoke the contract on their address.
To achieve a similar effect in this current username, password approach we use a simple but effective zero-knowledge scheme to prove to the smart contract that the invoking user has the password related to the username.
Let us define a term we would use that might not be common. The term is nonce value. A nonce value is just a number (integer) that is either randomly generated or sequentially generated. In this particular writing, we use sequentially generated nonce values with increments of +1. For instance, given that the initial nonce value is N, then the sequence of all possible nonce values is (N, N+1, N+2, …).
Using the private key derived from the user’s password, i.e Argorn2id(password), we encrypt a nonce value and store the blake2b(encrypted(nonce) ) as well as the nonce value itself in the smart contract. To prove to the smart contract that a user has the password, they get the current nonce from the smart contract, encrypt it using the procedure above to get the encrypted(nonce). Any request requiring proof of password is made with the following extra parameters, encrypted(nonce) and blake2b(encrypted(nonce+1)) . Upon receipt, the smart contract compares blake2b(encrypted(nonce) ) to what it already has, and if they match, it updates what it already has with blake2b(encrypted(nonce+1)) and increments the nonce value to nonce+1.
- addSecret — This endpoint adds a new secret on to username. It takes the following parameters.
As we can see, this smart contract requires a standard username and password approach as is already common with traditional web applications. This is much easier for users and can be used to store any secret including private keys. It has the same use cases as the initial contract described but allows people to use the standard username and password approach they are already comfortable with.
Here is how this smart contract can benefit normal users.
- Contrary to the way users have been asked to store private keys and long mnemonics, this smart contract allows users to use the familiar username and password combination just as in normal applications. Note that this does not in any way reduce the security of the system so long as users use strong but memorable passwords or passphrases.
- The second strong point is that it ensures that the data is not lost with a very high probability since a copy of it will be stored on computers that power the Tezos blockchain. This level of data protection is not something that even well-known cloud providers can boast of.
In another post, we are going to release and discuss a demo application implementing the second contract as discussed above. This demo application makes use of Conseiljs and Smartpy, and would be a great example application for development using those tools. We will discuss all the challenges we faced and how it was solved hopefully it will be of help to other developers.
Our Next Steps
As of now, we have chosen to go with the second contract as described above. We believe it is much more flexible and the use of username and password is also an attractive proposition for a great user experience. We are currently finalizing the smart contract test on carthagenet and planning the integration into Ejara for the benefits of our customers.