Ardor Contracts Require Secure and Simple to Use Secrets
In the movie Sneakers (1992), there is a mysterious corporation the protagonists are investigating called “Setec Astronomy”. There is a pivotal scene where Robert Redford puts down Scrabble tiles and spells out the name “Setec Astronomy”, and then starts rearranging the letters to discover that the name is an anagram of “Too Many Secrets”, and the company is in the business of cracking codes. Fast-forward 26 years and code cracking is no longer reserved for Hollywood blockbusters - many people make a decent living from cracking private keys and hijacking crypto currency accounts by revealing their secrets.
In my previous lightweight contract article, I explained how we can use a hash of a secret to make sure a transaction which triggers a contract, and a transaction submitted by a contract in response, can be either approved at the same time or ignored at the same time. This raises the question: how do you generate a good secret?
The secrets we generate must be:
- Difficult to crack — ideally it should be as strong as an account passphrase.
- Unique — secrets must be unique since once a secret is revealed its hash can never be safely reused.
- Simple to remember — in some cases, we need to reveal a secret long after its hash was submitted. Ideally, it should be simple to remember a secret and even possible for the secret generator to recover a secret in case it was lost.
A naive attempt would be to concatenate my dog’s name with my cat’s name and add my wedding date as a postfix for extra security. This secret is indeed simple to remember but it is not unique, once I reveal it to the blockchain I can never reuse it. Furthermore, it is certainly insecure in case Jihan Wu decides to dedicate his hashing power into cracking it. Adding a counter at the end will guarantee uniqueness but would offer little help against an attacker equipped with a rainbow table.
But wait a minute, as an Ardor user I already possess one piece of information which is impossible to brute force: my account passphrase. Can we do something with it?
Can we use the passphrase itself as a secret? Surely not since we don’t want to reveal it to the blockchain. Can we use a hash of the passphrase as a secret? Not unique. Damn! What if we append a counter to the end of the passphrase and then hash it? Now we are getting somewhere, this is secure and unique.
A hash of the concatenation of a passphrase and a one-time unique number (which we call “nonce”) will generate a unique secret which is simple to remember as long as you remember the nonce. We assume that you remember the passphrase since if you don’t all is lost anyway.
This is quite a good secret generation process: every time we need a secret we increase the nonce by one, concatenate it with the passphrase, hash it using SHA256 and use this as the secret. When submitting the hashed secret we hash it again of course.
But there are still problems, if we need to generate a massive number of secrets, like millions, the nonce becomes difficult to remember. If we generate the secrets on multiple workstations it is difficult to ensure the nonce uniqueness so there is a risk that we repeat the secret from time to time.
Solution — generate secrets which are impossible to crack, unique and simple to remember and even can be reproduced by the generator if lost
To solve this we need to add another twist, we concatenate to the end of the secret, already composed of passphrase + nonce, the block id of a block which is “nonce” blocks in the past and we limit the nonce range between 1 and 9999. We then hash the resulting string and use it as a secret. We hash this secret again when submitting our transaction with the hashed secret and reveal it to approve our transaction once we verify the contract operations.
Our new secret is secure since it is based on the account passphrase that only we know. It is unique since it is based on an increasing counter and a block id which changes every minute. Last, it is simple to remember since all we need to remember is the block height at the time the secret was generated and the four-digit nonce.
Even if we forget our secret, we can easily recover it, all we need to do is check 10000 combinations for each block height, a simple calculation that can be performed by any modern workstation.