Choosing a blockchain platform for Finprint
Note: Finprint isn’t under active development, but we think the lessons we learned are still valuable for other developers evaluating blockchain platforms.
We recently open-sourced Finprint, a data sharing protocol that aims to empower consumers with the ability to own and securely share their financial data. Finprint’s goal of bringing control and transparency to consumers was a natural fit for the decentralized nature of blockchain platforms. We built our first implementation of the protocol on Ethereum in the Solidity smart contract language. However, we soon encountered limitations in Ethereum that made it difficult to build our protocol without sacrificing scale or security.
Some of the key needs of the protocol are:
- Payments: Data providers must be paid for providing valid data.
- Staking: Certain parties to the protocol must hold a stake of a network-specific Finprint token before they can participate in the protocol and collect fees.
- On-chain decryption: Finprint provides a “challenge” mechanism designed to ensure readers receive the data they pay for. Our design requires asymmetric-key decryption to be performed on the blockchain in order to verify the challenge claim in a decentralized manner.
- Low cost, low latency, high throughput: The protocol needs to be able to process a high volume of read operations quickly in order to support consumer applications.
Payments and token staking were straightforward to implement on Ethereum, but the latter two needs were not well-supported. We were able to implement a proof-of-concept version of RSA decryption in Solidity, but we quickly ran into gas limits when increasing the key size past 1024 bits. While Solidity could support this unsophisticated RSA decryption, we felt that an elliptic curve encryption scheme such as X25519 should be used in a production application for better security with smaller key sizes. As an added benefit, the operations with smaller key sizes would also reduce gas costs. We did not believe it was viable to safely implement this on Ethereum in the short term.
Many developers and researchers have examined Ethereum’s current scalability problem, leading to projects working on a wide range of possible solutions. However, the timeframe for a production-ready “Ethereum 2.0” is still up in the air, and given that our aim was to support useful consumer applications in the short term, we decided to explore the viability of other platforms.
We explored many of the nascent next-gen blockchain platforms aiming to compete against Ethereum. Kadena stood out as the most viable option given our project’s needs, while offering a scalable mainnet in 2019. In addition to scalability, other priorities included smart contract security and developer productivity, two areas in which we found Kadena’s platform to excel.
Key features of Kadena
Kadena offers a hybrid (public and permissioned) blockchain that is designed to address the scale, security, and speed needs of industrial infrastructure. These features provided a natural rollout strategy that allowed our partners to assess our protocol with minimal security risk. We could launch our protocol on a permissioned blockchain, then transition to a fully public chain as the financial industry’s appetite for the public blockchain grew. Furthermore, the hybrid blockchain offered us an avenue to transition a centralized entry check for members into a decentralized one by guarding access to the chain via a smart contract.
Pact, their unique smart contract language built on Haskell, addressed the shortcomings we ran into with Solidity and the EVM. Pact had more native support for cryptographic functions, built entirely using widely vetted open-source Haskell libraries. While it didn’t support X25519 at the time, the Kadena team assured us that it could be added to the language quickly and would directly call the cryptonite library with a low gas cost. We co-designed the decryption primitive with their team, and they were able to release a new version of the interpreter that included it in just a couple of days.
Pact’s concept of guards and capabilities also helped us simplify permissioning. Guards provided a primitive to gate access to functions based on the caller’s keyset, while capabilities let us define reusable custom permissions for our contracts. The built-in unit testing via the Pact interpreter made it easy to set up different users to test our more complex permission checks easily, leaving less room for developer error.
Rewriting our smart contracts
Pact was a young language without the large community and usage of Ethereum, so we naturally ran into some unintuitive behavior and tooling gaps in the language. As we rewrote our contracts, we noted areas of improvement for Pact, and reported our suggestions to the Kadena team.
They were very quick to respond to our requests and eager to collaborate. In particular, we worked with them on adding a
try function and designing a decrypt function. The
try function allowed developers to run a function that could cause a transaction revert, and act upon knowledge of the function’s failure. The decrypt function leveraged Curve25519, Salsa20, and Poly1305, since NaCl box encryption was not supported by Haskell’s
cryptonite library at the time. As part of this, the Kadena team also encouraged
cryptonite to add NaCl box encryption. They were able to add all requested functionality to Pact on the order of days to weeks, enabled by Pact being an interpreted language.
web3.js for Ethereum, albeit with much less functionality. We hope that this tooling serves as a starting point for other developers to contribute to the Pact ecosystem.
While we won’t see the full implications of our choice of blockchain, there were some valuable signals we learned to look for while evaluating nascent technologies.
- Long-term vision of the platform. The Kadena team had already planned native support for cryptographic commitments. This meant our unusual on-chain decryption needs aligned with what they had planned for the future, and they were able to help us out quickly. Shifting the priority of items already in a roadmap is much easier than adding to that roadmap.
- Understand requirements for transitions. Ethereum supported our end goal of a public chain, and provided an option to start on a private institutional chain, but didn’t provide an easy transition between the two.
- Build bottleneck-seeking prototypes. Our Ethereum implementation of Finprint wasn’t usable, but included the pieces we thought would be most difficult to build performantly — on-chain decryption and keypair validation. We identified the implementation-level problems we faced with these early on (lack of arbitrary-precision arithmetic support, gas costs for more than 1024-bit RSA, weak debugging tools) and used them as criteria when looking for a new system.