Simplicity: Jets Release

A new developer preview of Simplicity introducing jets to streamline contract development

By Andrew Poelstra & Russell O’Connor

This week we are excited to announce a milestone in Simplicity development: a major new developer preview release with jets. Jets can be thought of as pre-made building blocks that can be combined together to construct complex Simplicity programs without having to build everything from scratch, simultaneously speeding up the process of developing Simplicity-based smart contracts while reducing their resource costs. We go into detail on this development below.

This release also introduces Simplicity support for test branches of Bitcoin and Elements, making it easier for developers to start thinking about how Simplicity as a script language upgrade could work for Bitcoin in the future. To demonstrate the new functionality in this release we give details of some test transactions written using pure Simplicity validation logic. These transactions are signed with BIP-Schnorr signatures, implemented in Simplicity itself, on modified Bitcoin and Elements regtest networks.

The test transactions demonstrate that Simplicity core is functionally complete, and is closer to being production-ready. While there is not yet any tooling available for developers, the code is available to download for anyone wanting to start experimenting with the new scripting language.

An Intro to Simplicity

Simplicity is a blockchain programming language expressly designed for formal verification of correctness and for efficiency. It was built to overcome the limitations of Bitcoin scripting on Bitcoin and “Bitcoin-like” chains (e.g. Elements and Liquid), introducing:

Introspection: allowing contracts to observe and control the amounts and destinations of transactions based on spend criteria.

allowing contracts to observe and control the amounts and destinations of transactions based on spend criteria. Generality: supports any program a developer can think of, while still guaranteeing the verifiability of resource costs.

supports any program a developer can think of, while still guaranteeing the verifiability of resource costs. Extensibility: even new library-level functionality can be implemented in Simplicity itself—for example, Schnorr signatures.

With these tools, developers can produce a wide variety of new Bitcoin and sidechain-based applications, including:

Vaults: users can secure their coins by requiring a devaulting withdrawal notice period before moving to their final destination. During the devaulting stage they can approve or cancel the withdrawal. This means that even if keys are stolen, an attacker cannot abscond with coins without giving the user sufficient time to detect and block the theft.

users can secure their coins by requiring a devaulting withdrawal notice period before moving to their final destination. During the devaulting stage they can approve or cancel the withdrawal. This means that even if keys are stolen, an attacker cannot abscond with coins without giving the user sufficient time to detect and block the theft. Limit order swaps: a limitation of swaps made using the Liquid Swap Tool is the atomic swap contract only supports the execution of a trade of a fixed amount of an asset. A partial order match requires a new contract to be created. With Simplicity, traders can set up far more flexible swap contracts that support partially-filled orders. This enables the generation of “limit orders” with reduced settlement risk — useful for building P2P and non-custodial asset exchanges. Even more advanced uses are possible, including algorithmic trading or even smart contract-based derivatives.

The language’s reference implementation is in the Coq proof assistant language, which allows users to create mathematical proofs of their programs’ semantics. As such, Simplicity is a very low-level language, consisting of nine primitive operators called combinators, which can be composed in various ways to create complete programs. While Simplicity is not Turing complete, it can verify the execution of a Turing-complete set of programs, which is the property we need for blockchain applications.

These combinators are pure functions, meaning that every time they are executed they have the same result. This allows Simplicity programs to be represented as trees (or DAGs) of combinators, where unused branches can be removed and known branches can be safely computed by optimized machine code rather than executing the full Simplicity code.

Simplicity combinators are very low-level, so Simplicity lacks native facilities for expressing even such basic concepts as bitwise arithmetic or comparison of values. These operations and functions must instead be built up from Simplicity combinators, which in turn can be used to build a series of higher-level constructs until we can implement elliptic curve arithmetic and digital signature verification. Writing such a program is akin to building a signature verifier starting from a big bag of transistors — and this is exactly what Blockstream’s Russell O’Connor did to implement Schnorr signature verification.

History

The last technical blog update on Simplicity was in November 2018, when we announced the first source code release of the interpreter in multiple languages, along with a technical report detailing the language. This announcement marked a shift from Simplicity as a research project, to Simplicity as a production-targeted blockchain language intended for real use cases on real blockchains.

In September 2019, we released the first Simplicity developer release along with the first Simplicity transaction being created on an Elements regtest network. While this was an exciting milestone, it was not complete enough to demonstrate the full power of Simplicity. In particular, the entirety of the signature verification was provided on-chain in Simplicity code. Execution of this program took many minutes, even on fast hardware, because pure Simplicity is a low-level language lacking hardware support for even simple operations such as bitwise addition.

Over the last year, we have also implemented Simplicity interpreters in C and Rust, extended the language with Bitcoin and Elements primitives, and are pleased to have started receiving external contributions.

The Advent of Jets

To deploy Simplicity in real life, we need a feature called jets. Jets are fragments of Simplicity programs that have efficient machine-code implementations and are implemented in a language such as C designed for raw performance. When validators recognize a Simplicity fragment for which a jet exists, they can substitute the high-performance C version of the code for the raw Simplicity. On a network with a standard set of jets, the original Simplicity code does not even need to be provided on the blockchain.

Earlier this year, by extending the C implementation to support jets, and implementing key functionality with a modified version of the high-performance libsecp256k1 library, we were able to recreate the previous release’s test transaction, but now with a greatly reduced program size of 448 bytes, down from 14,635 bytes! For reference, a standard Bitcoin script of similar functionality is 107 bytes. There are still plenty more jets to implement, which will further reduce script sizes, but these numbers and the surprising compactness of Simplicity script object code, shows that Simplicity is practical and usable in a blockchain context.

Simplicity on Bitcoin

Like Segregated Witnesses, which was originally developed by Blockstream researchers for Elements Alpha before being overhauled by the Bitcoin community, we hope that one day Simplicity will make its way into Bitcoin. To demonstrate what this might look like, we have made a branch of Bitcoin Core to allow the creation of Simplicity-enabled Bitcoin regtest networks.

If Bitcoin had Simplicity scripting today, the recent BIP proposal for Taproot & Schnorr signatures could instead have been implemented as a smart contract, without needing a soft-fork, as could the new Lightning network design eltoo.

In fact, we implement Schnorr signatures fully in Simplicity using jets as a Simplicity “Hello, World!” program — a programming benchmark to demonstrate the power and compactness of using scripting to build new signature schemes.

In our previous release, Schnorr signatures were implemented in pure, manual, inline Simplicity script. For this release, Schnorr signatures were implemented using jets, yielding further efficiency benefits as shown in the results below.

Simplicity-based Schnorr signatures: jets vs no jets

Simplicity on Elements & Liquid

Unlocking the full power of Simplicity is a long-term project, and we expect it to take some years for the technical community to get to grips with the potential of the new language. Uptake should be aided by being able to try Simplicity within the Bitcoin-like context of Elements, and later, Liquid.

As a step towards Simplicity in Liquid, we have also created a Simplicity-enabled branch of Elements. This branch will be the basis of implementing Simplicity on Liquid later this year.

Future Work

Before Simplicity is ready for deployment on Liquid, some of the steps we’ll be working on include:

Implementing Taproot on Liquid.

Cleaning up our Elements branch and updating Simplicity to build on Taproot, which provides a more flexible script-updating mechanism than raw SegWit.

Determining an accurate cost model for Simplicity programs, starting from the formal Bit Machine (as in Section 3.5.2 of the Simplicity Tech Report) but modified to take account of jets. Similarly, designing an update mechanism to allow these costs to change as new jets are implemented.

Completing the implementation of Simplicity, including all resource estimation features, anti-denial-of-service mitigations, and finalizing the canonical program representation.

In addition to this work on the consensus layer, to make Simplicity more usable we need to write high-level tools to enable programmers to work with the language. As a first step toward this, we intend to implement a Simplicity target for the rust-miniscript library, allowing users to compile Miniscript policies to Simplicity. By decompiling the resulting programs back to the policy language (called lifting), users can easily verify that the resulting programs have identical semantics to the corresponding Miniscript, allowing them to explore the additional powers of Simplicity starting from a rich but formally-verifiable baseline.

Building a new blockchain programming language is no easy task. We’re extremely proud of how much we’ve achieved since embarking on developing Simplicity in 2017, and are excited about building real things for real users in 2020.