IOTΛlias, a wallet protocol for implementing public and private aliases
In my previous two articles I explored possible solutions to the IOTA donation address problem and the IOTA address alias problem . Since both solutions were written up as kind of spur-of-the-moment articles there were still a few weaknesses in the approaches, especially with respect to the alias solution. The latter needed the assistance of the IRI to be able to function properly. Now that I have had the time to think things through more thoroughly I think I have come up with a solution that builds entirely on the existing IOTA protocol and can function with full backward compatibility.
Please read the previous two articles first, because I will be building upon the ideas discussed in there to avoid having to explain the concepts in detail again. Even though a few details have changed the basic ideas are still valid and the background will help you understand this article better.
Furthermore the concepts introduced have now merged together to form a powerful solution that is fully decentralized and finds a nice balance between usability and security. I decided to split up this (way too long) article into three separate but related articles based on the concepts used:
- The IOTA deep linking scheme, which is essential in being able to hide most of the implementation details to the user, yet provides enormous flexibility and utility.
- The IOTA cheque protocol, which is the key to solving the donation address problem, but is only one of the possible applications of the IOTΛlias protocol.
- The IOTΛlias protocol itself, which allows anyone to define their own simple human-readable public aliases relatively easily, and also allows the wallets to create private aliases that are much more (psuedo-)anonymous.
I will focus on the IOTΛlias protocol in this article, and use bits and pieces from the other 2 articles.
A short recap
Since my original solution in part 1 of this series could not use aliases yet, the proposed use cases are still a bit cumbersome. Now that we do have aliases solved, we will see a lot of the interface become much cleaner.
Part 2 of this series came up with a few interesting ideas but still needed the cooperation of the node software (the IRI) to completely solve the aliasing problem.
The final puzzle piece involved solving the alias uniqueness problem: how can we prevent other people from creating the exact same alias, or make sure that our alias is the one that is being used, without enlisting the help of the IRI.
A second worry was what would happen at the moment of a snapshot. In the original solution, the first person to register an alias would be the one recognized as the owner, which allowed for hijacking aliases after a snapshot unless there would be some data that survived the snapshot, which again required enlisting the help of the IRI.
With my new solution to the uniqueness problem, the snapshot survival problem becomes a non-issue. If the alias is truly unique then it becomes a matter of reattaching the alias definition transaction bundle after a snapshot so that people can find it again. No one will be able to hijack it because it is unforgeable. And anyone that has used the alias already before the snapshot will be able to keep on using it, simply by having the wallet remember the alias information locally in their address book. The alias definition doesn’t even have to be present any more for them.
Solving the alias uniqueness problem
So how do we verify the uniqueness of an alias? Well in cryptography we often do this by verifying a hash value. So my proposal is to add a little hash value to the alias. Not too large to be too bothersome for users, like the full 81 trytes of an address, but still sufficient to make it unique and unforgeable.
Let’s say I run www.mywebsite.com and I want to be able to receive iota donations. Of course I would love to be able to use an alias that contains www.mywebsite.com. Well, that is very possible. We can use the IOTA deep linking scheme and have our wallet generate a donation link with that alias string in it:
The xdv9tlqa part is the first 8 trytes of an 81-tryte hash value that was calculated by my wallet when creating the alias. We only need a few trytes to make it unique enough so that it becomes impossible to duplicate our alias in such a way that other wallets cannot tell which one is the valid one. That’s because we will use IOTA’s trick to combat Sybil attacks to make it very difficult to generate one: Proof of Work. As part of creating the hash value we will do PoW by incrementing a nonce until we end up with a hash value that ends in a specific amount of zeroes.
Now let’s examine the implications of this. We will calculate the hash value over the immutable parts of all the data that we need (we will discuss the exact data we need later), making sure we end up with a hash value that ends in (for example) 15 zero trits. We can easily verify this by checking if the hash value ends with 5 trytes that are 9. A simple string comparison. We take the first 8 trytes of the hash value in lowercase as our suffix to our alias, like we did above.
All this means that even when people decide to use the same alias, the hash suffix will make it unique. So there is no need for complex systems to guard against people using the same alias, and we also remove the possibility for easy ‘alias grabbing’, like we saw happening with domain names, because we cannot predict the hash that someone will be using.
Note that if we can thus guarantee the uniqueness of the alias, then we can even survive a snapshot, by simply re-attaching an alias definition transaction bundle after the snapshot. We are the only ones that can do that for our alias. The alias hash is completely independent from the bundle or transaction hash to allow for easy reattaching and the transaction doesn’t even need to be confirmed. All it needs is to be present in the Tangle.
It would even be feasible for other wallets, when they cannot find the alias definition transaction bundle due to a snapshot, to then query a perma-node or a central server for the alias. Since the transaction bundle is unforgeable that kind of temporary centralized access is now perfectly acceptable.
Consequences for a hacker
Now for a hacker to create a similar hash (starting with those same 8 trytes) means that he needs to generate (on average) 27⁸/ 2 or about 141 billion hashes. Multiply that by the amount of time it takes to do the PoW to additionally make the hash end with 5 trytes that are 9. Let’s for simplicity’s sake assume that PoW takes on average about 1 second. That would mean that it takes on average slightly over 4477 years to generate a forged hash.
And that is without taking the nature of the hashed data into account. We could define that data in such a way that it naturally resists the above brute forcing method by prohibiting any field from being usable as a nonce. That way it would become impossible to brute force a spoof alias. I decided against this in the end as it would make the alias verification process too involved and cumbersome. The current measures should be sufficient for now.
Anyway, even if the hacker would manage to succeed in creating a spoof version of our alias, by throwing ridiculous amounts of power and computational resources at the problem, our wallet will regularly be checking to see if our hash is still the only one that matches these criteria. Once the wallet detects that someone else has created a spoof alias, it would be very simple to signal the user to add 1 or 2 more trytes of the hash value to the alias hash suffix to make it unique again. In which case it just became 27 or 729 times more difficult to break it. The amount of trytes in the hash suffix can be seen as the security level of the alias. It can be changed without any ill effect on creating the hash, but the impact on brute forcing is exponential.
Any wallet that wants to use the alias for the first time will of course also double check first if it is truly unique. If it’s not unique, it will simply refuse to do business with that alias.
Meanwhile, any wallet that already made use of the alias in the past would have copied the entire hash and associated data after finding it in the Tangle and added that to its local address book. Those wallets would not even be fooled by the spoofed alias since it simply does not match up with their stored 81 tryte hash value. But the one that was updated by the original owner to use a longer hash suffix will still match the start of their stored hash value. So old users of the alias will simply keep on using it, and new users will use the new, slightly longer one in that case. Nice, how it all comes together, eh?
Assembling all the pieces
So, going over the previous articles and the above, the components we need are:
- A searchable alias string. We will be storing the upper case alias (without the hash suffix) in the tag field, which allows us to use aliases up to 27 characters long. Any non-letter in the alias will be replaced by a 9, and the alias will be padded with 9’s until it is 27 trytes long. Note that for now we only allow periods in the alias name to make it easy to parse them.
- A public key byte string encoded as trytes. I propose to use an encoding scheme for the type of asymmetric encryption scheme that is used, so that we can use different schemes when necessary. Simple schemes can use RSA or DH, which are usually already present on devices. And in the spirit of keeping it quantum-proof we could even use NTRU, although that will probably require extra coding on the wallet side. Parameters to the encryption will be encoded in ASCII by using slashes to separate them, and the actual base64 encoded public key bytes will follow after a colon. This entire byte string will then be encoded as trytes.
Example: RSA/2048:<base64 encoded public key bytes>
Example: NTRU/251/128/3:<base64 encoded public key bytes>
- The encrypted alias string. We first encrypt the alias tryte string exactly as stored in the tag field, then encode the resulting base64 encoded byte string as trytes.
- A hash value created by hashing the above components. I propose to combine both parts into a single data payload. The first 4 trytes wil specify the length of the encoded public key payload, followed by the pubkey payload itself. Then another 4 trytes encode the length of the encrypted alias payload, followed by the alias payload itself. And finally we add 4 trytes that encode a zero length. This enables future expansion of this scheme. 4 trytes will allow lengths to be up to 531440, which should be sufficient for our purpose.
We are going to put this data on the Tangle as part of an IOTA zero-value message transaction bundle. The hash value needs to be part of the bundle which makes it immutable. If we use standard hashing into 81 trytes then we can actually store the hash in the address field of the transaction, which then also gives us the address where anyone can post messages to communicate with the alias owner.
Note that we don’t care about who ‘owns’ the address, and that the address does not have to be generated by our seed at all. Using a seed to generate addresses is only one way of doing it anyway. And the address will not be holding any funds for our purpose. Even in the unlikely event we would use an address with balance on it that does not matter because the usages do not interfere with each other.
The hashing algorithm, using Curl sponge function, is very simple:
- Absorb a nonce value, which starts out with all nines. This one will be incremented just like a seed, when necessary.
- Absorb the entire payload data, padded with nines until a multiple of 81 trytes, in 81 tryte chunks.
- Squeeze out an 81 tryte hash value. If it does not end in 15 zero trits, increment the nonce and restart.
- Use the found hash as the address in the transaction(s) that make(s) up the bundle (depending on the length of the payload, it may have to be split over several transactions).
- Set the tag of the first transaction in the bundle to the tryte-encoded alias.
- Store the payload as usual in the signature/message field.
Public and private aliases
An interesting aspect of these aliases is that they can be either public or private:
- Public aliases, like the one specified above, use an easy to remember human readable alias, that can be used in public places, like a website for example. These aliases are very suitable to be used as a fixed donation or payment address that anyone can send iotas to at any time without the need for the receiver to generate any receive addresses. The wallet will automatically gather the donations into a receive address in a safe way, and switch to a different receive address in case of a spend.
The public alias can also be used to initiate a private communication with the alias owner.
- Private aliases just use a random 27-tryte tag. They can even be the same as someone else’s (unlikely anyway) because the hash suffix will make them unique. Of course we will double-check the uniqueness of a private alias upon creation. These aliases will be used primarily between parties that want to be able to send to each other. They will be part of the address book in the wallet, where a more easily readable name can be assigned to them. For example, you can set up a private alias for yourself and one for each of your kids, which allows you to send them their allowance at their alias every week. And they can use your alias to pay you back some money that they borrowed from you. You can also communicate with them over this connection.
Note that because of the general nature of asymmetric encryption in combination with IOTA messages these aliases can be used for much more than just sending iotas. The exact nature of the data that will be sent to an alias will be detailed further below. Suffice to say for now that this data will always be encrypted with the public key of the alias, so that only the owner of the alias can decrypt it. First let’s sketch some use cases for these aliases and how to work with them.
Use case 1: Fixed direct donation/payment address
Of course the use case that comes to mind first is the fixed direct donation or payment address we discussed above. We can immediately use such an address. Since it is essentially an IOTA deep link, you can simply click on the http://iotalias.link/donate/… link on the website and it will automatically open the wallet and ask you if you want to send funds to that alias. All you need to do then is fill in the amount, and maybe a message, click send, and then enter your PIN. The wallet will automatically create an IOTA cheque and post it at the alias address, where the recipient’s wallet can redeem the cheque.
The wallet will automatically verify the alias link that was clicked, and load the alias and the associated data into your address book, so that next time you can directly donate from your wallet without even having to go to the site and click the link. The wallet will automatically use the name without the hash suffix as the name of the recipient, unless there are multiple with the same name, in which case it uses the hash to show the difference. Of course you can always manually overrule the name to something that makes more sense to you.
An interesting aspect of deep links is that they can have parameters, just like with ordinary web links. That means that it is possible to add more information to them. Examples:
- A suggested donation amount:
- An alternative name for the alias:
- Or how about an order id that the merchant can specify and the wallet can automatically incorporate in the payment:
Just defining the parameters for the IOTA deep link protocol will take a separate article. So many exciting possibilities, all allowing for single-click solutions.
Use case 2: Initiating a money transfer through email
Let’s say we need to send someone money but they are not in our address book yet. Wouldn’t it be nice to be able to just send them an IOTA cheque through email or any other messaging system? That way they don’t have to generate a receive address, then send that to us, which we then have to copy/paste into our wallet and can only use a single time to send them iotas. Instead we could send money unsolicited, and as many times as we want.
We can achieve this by emailing an IOTA deep link that will automatically start their wallet when clicked, which can then initiate a sequence of events that ends up in the redeeming of an IOTA cheque by using private aliases between both parties.
The link could look something like this:
It is essentially an invitation link specifying a private alias of the sender. When the receiver clicks this shared link the wallet of the receiver will respond by creating a private alias of its own (or maybe re-use an existing one, depending on what the wallet owner wants). It can load the sender’s alias data in its address book under ‘John Doe’, and post its own private alias encrypted at the sender’s private alias address, along with the cheque id so that the sender wallet knows what cheque invite resulted in this post.
This response will be structured as an IOTA deep link again:
Note that this link will not be visible to the sender. It will be posted at the sender’s alias address and automatically be handled by his wallet. The only thing the sender notices is that an extra entry appears for Jane Doa in his address book, so that next time he can contact her directly.
Now that we have a 2-way communication possibility it becomes a matter of further communication between wallets through the Tangle. Since the sender wallet now has the private alias of the receiver, it can easily post the actual IOTA cheque there, exactly like in the case of a public alias. The receiver wallet will then automatically redeem the cheque.
Note that all of this can happen pretty fast, since none of the transactions involved needs to be confirmed on the Tangle. The only delay involved is the (possible) generation of an alias for the receiver and the PoW needed for posting the transactions. The moment a transaction appears to the other party it can immediately be processed.
Also note that this invitation procedure only needs to be done once. After the exchange of private aliases any cheques can be sent straight to either private alias, just as if we are using a public alias.
For now we deem email as sufficiently secure to set up the initial connection.
Use case 3: encrypted communication between aliases
Once a connection between two aliases is established, in whatever way, the parties can use this connection to send messages between them. Because of the encryption and the private nature of the aliases it would be completely anonymous and private communication. With everything set up already it would be trivial to implement a messaging system between the parties.
The only small delaying factor is the PoW needed for each message. There is no need to wait for confirmation. Just the presence of the message in the Tangle is enough.
A special protocol could use public aliases as ‘channels’ similar to Discord or Slack channels. Wouldn’t it be fun to move everyone on IOTA Discord over to the Tangle instead? Well maybe not. Moderation would be a nightmare unless properly built in to the communication protocol. But using a channel for smaller groups of people communicating with each other would definitely work. I could see people communicating using symmetric encryption, where they can only be added by invite. Banning someone could be done by changing the encryption secret and simply not telling the banned user. But I digress into MAM territory now.
Any known alias could be used to initiate a private communication between private aliases. I won’t go into too much detail right now, but suffice to say that the ability to use the same alias for sending money and for messaging allows for very interesting use cases. It also means you would have only a single unified address book, instead of a separate one for banking and one for messaging.
Using the IOTA deep links
How does the wallet use the deep links? It parses the alias name part and strips off the hash suffix. Then transforms it into a tag as specified above. It then uses the findTransactions() API to search for transactions with this tag. If it finds none: too bad, we cannot use this alias right now. It could be that a snapshot has occurred and we need to wait for the alias owner’s wallet to restore a transaction for the alias in the Tangle. Or maybe we could fall back to a perma-node and check its history if we want to be more sophisticated.
If it finds one or more transactions, then the wallet will start a verification phase, doing successively more complex verifications that reject the ones that are definitely not candidates for being the alias we are looking for as fast as possible. The verification phase has the following steps:
- Verify that the transaction address starts with the alias hash suffix.
- Verify that the transaction address ends with 5 nines (PoW done).
- Verify that the transaction is the first one in its bundle (check if the currentIndex field is zero)
- Verify that the transaction is a zero transaction (check if the value field is zero)
- Now we get to the payload verification, which means that in case the transaction bundle contains more transactions (lastIndex field is non-zero) we need to retrieve the entire transaction bundle. Verify the bundle hash and transaction hashes. Verify that each extra transaction has the same address field as the first, a value field that is zero, and a tag that is all nines. Calculate the maxLength of the payload (2187 times number of transactions in bundle). The following steps will verify that the payload can be decoded.
- Verify that each 4-tryte length field makes sense w.r.t. maxLength and split the payload into its sub-components. Verify there are at least 2 sub-components. Also verify that unused payload space is all nines.
- Convert the public key and encrypted alias payloads to bytes and verify that the public key can decode the encrypted alias successfully and the result matches the tag field of the first transaction in the bundle.
- Verify that the payload hash is equal to the address of the first transaction in the bundle. This means doing the same PoW cycle on the payload that the alias creator had to do, to see if it is really the first valid hash that generated this address. This is crucial in verifying the uniqueness of the alias, but luckily we only have to do this once.
- Verify that after all this we only have a single matching result left. If none are left report that we cannot find the alias at the moment. If multiple are left report that we cannot uniquely identify the alias and refuse to continue.
If the verification process results in a single match, then the alias data will be loaded into the address book for future reference. Now we have an address to post message transactions to and a public key to encode them with so that only the intended recipient can read the messages. This address is key, because the recipient will only watch for new message transactions arriving at that address.
Note that even in the unlikely event of another valid alias ending up at the same alias address it is still easy to distinguish between messages for either recipient. The messages that can be decoded by a recipient are clearly meant for him.
So far we have been avoiding the exact implementation details of IOTA cheques. But since those cheques are an important reason for the existence of our alias system no protocol specification would be complete without specifying the IOTA cheque implementation.
First a little rehash. An IOTA cheque is nothing more than an address generated by the sender, pre-filled with the amount of iotas to send, of which we hand over the private key to the receiver so that he can redeem the cheque by transferring the funds to his own wallet.
An interesting artifact of this method is that it is possible for a sender to cancel a cheque as long as it has not been redeemed. Because of course the sender also has the private key to the cheque address. This becomes extra interesting in the case where a cheque is never redeemed. It means the funds won’t be lost but can simply be sent back to the sender wallet if the sender decides to. The sender wallet will of course keep track of all cheques ever created and their status.
Anyway, the private key of an address is generated from an 81-tryte sub-seed. So all that we need to pass on to the recipient is this sub-seed. Then the recipient can derive the public key and address and redeem the cheque.
Since the whole alias system already creates an encrypted environment for the messages that are posted all we need is to define the payload of such a message that holds a cheque. The payload is then encrypted and sent in the signature/message field of one or more transactions in a single bundle that is posted at the alias address.
Now all we need, after decrypting the payload is determine what kind of payload this is. Since we are already doing a similar thing when decoding IOTA deep links we may as well use an IOTA deep link to specify what the payload type is because we already have a way to parse those. For example:
http://iotalias.link/cheque/<81 trytes of subseed>?from=John%20Doe&reason=Birthday%20gift
Or in the case of paying a merchant (the amazon example above):
http://iotalias.link/cheque/<81 trytes of subseed>?order=3432.8995.67
Similar to IOTA cheques we can define how the alias system knows we have posted a message for the user. This can be kept pretty simple. We again reuse the IOTA deep link encoding. Example:
The app receiving this message transaction (note that it does not have to be the wallet app) will display the message like any messaging app would do. In turn it can create these messages and post them at the other party’s alias. It is pretty simple to keep track of them and use the timestamps in the messages to order them. Any messenger app does the same thing.
Other interesting things that can be done:
- The messenger app could run a service in the background that periodically checks for messages and post a notification to the user when one pops up.
- The handshake that sets up the communication channel could specify the user name or his handle, and even an url to an avatar picture.
I will not go into too much detail because the article has ballooned quite a bit already. Expect some more articles in the future.
This article describes a workable complete solution for an alias protocol for wallets that runs on top of the IOTA protocol, is 100% backward compatible and does not interfere with any other applications.
Feel free to comment on this article or contact me on Discord (@Eric Hop) or my IOTA Facebook group (https://www.facebook.com/groups/iotatangle) to discuss this protocol more.