Hello Dash Community,
While I have been active in Dash development since 2015, this will be my first blog post. As we get closer to launching Dash Platform and upgrading our wallets to support the DashPay contract and specification, I will do my best to write more blog posts summarizing the work we’re doing in a less technical manner than in our DIPs.
So today I am extremely pleased to announce that we are publishing 4 new Dash Improvement Proposals (DIPs) surrounding DashPay, and I would like to thank all the people who made this possible. Before I get into DashPay, let me first give introductory explanations about Dash Platform, identities, data contracts and DPNS. There will most likely be more blog posts that go in depth on these components, so I will stay quite light.
Dash Platform is a byzantine fault tolerant system that provides state replication. A byzantine fault tolerant system is a network where nodes can go offline or even lie and yet the system will still work. Platform uses something called practical byzantine fault tolerance (pBFT) to achieve this, while Core uses Nakamoto consensus. The interplay of Nakamoto Consensus and Byzantine Fault Tolerance is a nice medium article that you can read to help familiarize yourself with these concepts. Nevertheless, I will give a small explanation on how these apply in Dash.
In Dash Core, the validity of information is based on transactions being included in blocks and the fact that these blocks were mined. For example, in Dash Core if you have a coinbase transaction “A” that comes from mining a block and then a mined transaction “B” that uses “A” as an input, the validity of “B” comes from the fact that “A” was valid and there is a proof that the “owner” of “A” is spending the amount with the transaction “B”.
In Dash Platform, however, the current state of information can be proved with a merkleized binary state tree. The validity of any information is based on what a majority of greater than 2/3rds of the masternode network think it is. This means we no longer have to rely on transactional proofs and instead can rely on what we will call threshold state proofs. And this, in turn, allows us to do some pretty cool and awesome things. DashPay being one of them.
I’ll take a moment to preemptively answer some questions that might arise. Some people have heard that Dash Platform uses its own blockchain and probably don’t understand what this means. Let me be clear, this does not mean it has its own coin. The platform chain is used to help synchronize state data efficiently. Blocks in the platform chain are short-lived, so a certain time after they correctly synchronize state data they can and should be pruned. We might keep some archive nodes that store all blocks, however, this will not be a requirement for masternodes. Ivan Shumkov published a blog post last year explaining the rationale and motivations behind the platform chain. That can be found here.
A second question that might arise is why we have forked Tendermint to use as our pBFT consensus engine and what exactly this means. Up until early 2019 the plan was to use the Core chain for DashPay, however, this approach did not provide all necessary features and basically just did not work. Our choices at that point were to build something from scratch or take an existing open source project that best fit our requirements and modify it. To get DashPay out the door as fast as possible, we decided that option B would be faster, a relatively small sacrifice which allows for iterative improvements in the future.
So you might be wondering how our fork is different from Tendermint? Well, I think the most significant difference is that it uses threshold signatures to produce efficient proofs for the current data state.
An example might best explain this. Imagine that on a mobile device I query Dash Platform and ask for all people who sent me a DashPay contact request. This information is stored in a key-value database and proofs for this information reside in the Platform state tree. One should always remember that in a distributed system proofs are foundational, meaning that the system can not be secure without them. But knowing that the information is stored in a state tree won’t do a mobile client much good, will it? What is important is that the state tree’s root is signed by a masternode quorum that the mobile client has previously retrieved and trusts. For technical details of how mobile clients get and trust quorums, please refer to DIP 4. The crucial point is that mobile clients have a mechanism for trusting a masternode quorum and have a threshold public key for this quorum. If over 2/3rds of masternodes in a quorum sign a message, a threshold signature can be produced that mobile clients can verify as authentic.
To summarize all of this, if a client retrieves data, that data can be proved to be in a tree with a certain tree root. That tree root in turn is signed by a quorum and the client can verify the authenticity of that signature. Without threshold signatures a client would need to verify 2/3rds of all signatures. Since this would be quite slow and lead to very large proofs, we implemented threshold signatures.
Now you might be asking, why didn’t the Tendermint team implement threshold signatures? Well it might be on their roadmap but I would like to put in a disclaimer that I am merely guessing here. I think one of the biggest challenges for them would be the fact that members in their quorums do not all have to be equal. Based on an amount of staked cryptocurrency one validator might have twice the voting power as another. What is important in Tendermint is having over 2/3rds of all voting power in a quorum, not over 2/3rds of nodes. This would present a challenge for threshold signing for them. In Dash however all of our masternodes all hold 1000 Dash so we do not have a problem.
Our fork of Tendermint is called Tenderdash and can be viewed here. While I normally work on the mobile team, a decent chunk of my work for the last few months has been incorporating threshold signatures into Tenderdash — one of the remaining components we still need for our testnet release.
I talked mainly about the Dash Platform consensus as it is most pertinent for the following explanations about DashPay. Dash Platform also provides access to state data with a decentralized HTTP API (DAPI) that is hosted on all masternodes. This important component of platform deserves its own blog post, but for now I will move on to identities.
Identities are defined in DIP 11. In a very simple way an identity is like an account. They hold a balance of credits, which are Dash (the currency) converted to pay for state transitions on the Platform chain.
In theory, identities should be able to identify any subject such as a person, an organization, an electronic device or even more abstract entities. For example, a refrigerator could have an identity that might publish requests to buy milk when you are low. The refrigerator would not actually purchase the milk but would notify a user identity that the milk is low. The user identity could then buy milk from a supermarket identity potentially using DashPay. In the context of our first version of DashPay, identities will be users or merchants using our DashPay enabled wallet.
Identities are also a part of the state of Dash Platform. This means that proofs of an identity’s existence and balance are present in the platform state tree. Therefore mobile clients can receive proofs for the existence of these identities as I described above. These proofs are critical for DashPay.
One important thing I would like to mention is that the identifier of an identity is derived from a funding transaction that can trace back part of its entropy generation to mining proof of work. I mention this because it’s nice to know that all parts of our system are somewhat layers upon layers that originate in proof of work.
Identities are registered with attached keys and more can later be added or changed. These keys allow for message authentication, encryption and decryption based on the key type. DIP 13 that is being released alongside this blog post deals with identities in HD wallets and how keys are deterministically derived from a recovery phrase (also known as a mnemonic or seed phrase). Dash Core Group’s DashWallet for iOS and Android are both HD wallets as described here. We will assume though for the rest of this post that you are familiar with them.
The big takeaway from DIP13 is that identities can be recovered from a recovery phrase. If you paid for the creation of an identity but didn’t yet register it on Dash Platform, that can also be recovered.
The identifier of an identity is a 256 bit number. This is not great when trying to find or interact with someone. Enter name resolvers! We use name resolvers on a day to day basis. You are using one right now when you are reading this blog post. The fact that you see blog.dash.org is just because blog.dash.org resolves to an IP address which in IPv4 is a 128 bit number. If you entered that number into your browser you would be able to see this same blog post.
I won’t talk so much about DPNS right now, as I want to focus on DashPay, but the takeaway is that DPNS is used to associate a name like “quantumexplorer” to an identity. DPNS is technically explained in DIP12.
If you have ever worked with databases, the following explanation should be easier. For data to be stored in a database it needs to conform to a table structure. For example, a car table has certain properties like color, brand, and license plate. In Dash Platform the same is true, except we call our tables “document types”. Registering data contracts entails sending a state transition to Platform that defines one or more document types.
Let’s say a developer wants to store flight schedules on Dash Platform. They could create a document type “plane” and a document type “flight”. The flight would have a scheduled departing and arrival time that would both be set as timestamps with a rule that the departure time be before the arrival time. If transitions come in trying to create a new flight, platform would verify the structure of the data. For example, that the departure time is a timestamp and that it is not before the arrival time.
There are 2 main contracts that are important for DashPay to function properly, the DPNS contract and the DashPay one. I’ll cover aspects of the DashPay one later in this post.
At its core DashPay is a data contract that enables a decentralized application that creates bidirectional direct settlement payment channels between identities. Let’s decompose what this means. Well, we already explained that a contract is a set of properties on a document type that are validated. Dashpay has three document types : profiles, contact requests and contact info.
In the case of DashPay the most important document type is the contact request. A contact request is a document that says identity A wants to be “contacts” with identity B. It also indicates that any payments identity B sends to identity A should be sent to a range of addresses that are defined by an extended public key.
All relationships between contacts are public in this initial version of DashPay. However, payments between these contacts are not public. You can basically understand this as a channel being created between two identities that can send transactions without the transactions being able to be linked to the channel. We call these channels direct settlement payment channels — in contrast to the payment channels used in Bitcoin’s lightning network that often don’t settle immediately. It is possible that in future iterations we allow for non direct settlement to save blockchain space, but this is not currently planned.
Contact Address Derivation
To create these payment channels we needed to create a deterministic and derivable unique set of addresses for bidirectional payments between identities. This enables a seed phrase to recover all payment information between identities. I personally find this a very nice feature. Currently when viewing transaction history it is difficult to associate transactions with the individual(s) involved. After DashPay is enabled in our wallets, if you send from identity A to identity B, this information will always be obtainable but only by identity A and identity B. This is because the extended public key — which is made to provide addresses for payments — is encrypted between identities. Even though I talk about addresses, these addresses are not shown to end users, which is part of the beauty of the system. An end user such as Bob will only see that he made a payment to Alice, unless he decides to look at the underlying transaction information in a block explorer.
The creation of this payment extended public key is quite interesting. BIP32 that defines derivation paths used in HD wallets only allows for up to 31 bits of derivation path which is around 2 billion addresses. The authors, I am sure, did not see the advantage of deriving with more than that. We already talked about the fact that an identity is referenced internally as a 256 bit number. To create a unique derivation path for payments to identity A from identity B we must start with a root extended public key (this is done based entirely on BIP32) then derive with identity A’s number, and then derive with identity B’s number. The issue here is that the identities are 256 bits and BIP32 only supports 31 bits. So we had to allow for 256-bit derivation while maintaining compatibility with BIP32. DIP14 explains the technical implementation of this change. The section `DashPay Incoming Funds Derivation Path` in DIP 15 explains how this is applicable to DashPay.
You might think, well why not truncate the 256-bit numbers to 31 bits and just use them to make things more simple? Well actually if you were to do so the system would be open to a pretty big attack. Any set of 31 bits is easy brute-forced and does not provide enough security. A Dash identity’s identifier is provably unique, however the last or first or any 31 sequential bits is not, and one could even match such an amount of hashes on a personal computer. Having two identities have the same bits would leave them to have the same set of incoming addresses which would allow users to snoop on private transaction information. Using 256 bits protects us unconditionally from this.
Now that we have an extended public key to receive payments, we need to encrypt it so third parties cannot see transactions between identities. An encryption key is created using a Diffie Hellman Key Exchange based on referenced encryption and decryption keys of the identities. The encryption of the extended public key is done using CBC-AES-256 with a 16 byte initialization vector that we prepend to the field.
The contact request also allows for multi-account wallets. For example, if your wallet were to support two accounts, one being a professional account and one a personal account, you could create a personal contact relationship with a coworker and a professional one as well. This feature is supported at the data contract level but will not be present in DashWallet for iOS or Android yet, as they do not currently support multiple accounts.
Automatically Accepting Contact Requests
In certain situations an identity may want to accept contact requests (i.e. responding with a contact request in the opposite direction) automatically. This could be the case when providing a QR code for someone in close proximity to scan or for a merchant that provides a QR code for customer payments. Imagine you are next to a friend and would like to become contacts in DashPay. By providing them your QR code and having them scan it, you can automatically become contacts. Your action of giving them your QR code is enough to signify your future acceptance of the contact request. I would say this feature is more important for merchants and exchanges though. Merchants want to receive payments without having to accept a contact request. By providing an auto accept proof that is public, they will basically allow all contact requests to be accepted. This auto accept proof however should not be made public on the internet but should be used more like a physical QR code to scan at a shop. There are most likely better ways to accept payments from merchants with a more unidirectional payment approach. We will continue to investigate approaches and make new proposals as resources allow.
In addition to payments between identities, we also endeavored to provide a certain level of user friendliness. Profiles are another document type in the DashPay contract. They store some information about the identity that one would come to expect from a payment application; a user will be able to set a profile image, a display name and a public message. The storage of profile images are outside the scope of DashPay. In our DashWallet apps we allow users to upload images to a variety of 3rd party image hosting services such as Imgur, Gravatar or their own Google drive, among others. Images will have a perceptual hash attached to them so that even image thumbnails can be recognized as authentic. We will also be using an image thumbnail server to distribute these thumbnails efficiently. The mechanism to do this in a decentralized environment is quite involved and warrants its own blog post due to the interesting challenges it poses.
The DashPay contract allows for more features that I will also not discuss exhaustively in this blog post, mostly because they are not all that interesting or can be quite complicated to explain. I will mention though that once a contact relationship is created it can not be deleted, as doing so would remove from a user the ability to know how to retrieve previous payments. On a UI level, however, we allow users in DashWallet to hide contacts that they had previously accepted.
Proof of Payment
There is a cool feature I would like to highlight that is made possible by DashPay. Let’s say you are paid 50 Dash by a company for some work you did. Then you wish to sell these Dash for Fiat on an exchange. Everything is going great until the exchange asks you for proof of origin of funds. Now you are at the mercy of the company you did work for to provide you with the proof of payment requested by the exchange.
With DashPay this situation can be resolved much easier. If the exchange were to ask for proof of origin of funds, you could simply submit the transaction where you were paid and a DashPay proof that this address is a derivation coming from a specific identity. We have not made a DIP explaining the exact construction and verification of the proof needed, but I hope to in the future as this feature is in my opinion quite nice to have.
Block Order Synchronization
Up until now we have covered DIP13, 14, and 15, so what does DIP 16 deal with you might be wondering? A traditional Bitcoin SPV wallet syncs merkle blocks in order to recover historical transactions of interest. This is done by adding addresses to a bloom filter and sending that bloom filter to a download peer. For each transaction in each block, transaction information such as payment addresses will be verified against the filter. Any matches will be sent to the requesting wallet. This is a grossly oversimplified explanation for conciseness. Now this works fine when addresses are all derived in order from the recovery phrase. However in DashPay, addresses are derived from an extended public key in a contact request.
This means that one must know all contact requests before syncing merkle blocks. To know verified contact requests, a device must have the masternode list. Furthermore, to know the masternode list, a wallet must have headers from the end of the chain. While it would seem we are in a chicken and egg situation, we can easily solve it by just getting the headers of the chain first, then the masternode list and quorums through DIP4. After that is known, a client can query DAPI to get its contact requests, construct a bloom filter and then sync merkle blocks.
DIP16 explains this on a more technical level and can be found here.
The Road to Come
As I mentioned earlier, in this initial version of DashPay all relationships between contacts are public. This is not completely ideal. Someone might not want the world to know they are in contact with a certain individual. I certainly think that there will always be value in public contacts, but I also believe that we should follow up this work by figuring out how to allow for private contacts as well. We haven’t spent much time researching these private contacts yet, though I do think that a solution would be non-trivial. Our current goal is to release a version of our software that provides a good step up over the current state of crypto payments and then to continue iteratively adding improvements going forward.
The content described in this post has been in the works for years. The fact that it is getting closer and closer to being production-ready is quite exciting. There is still quite a lot of work to come, I know how patient so many members of our community have been, and I ask that you all continue to be so. We all have great aspirations and are doing our best to make them into a reality.