2021.01.22

Nakamoto: a new privacy-preserving bitcoin light-client

With Bitcoin Core 0.21 out the door offering full support for Client Side Filtering,1 it seems like a good time to talk about the project I’ve been spending my weekends on for the last six months.

Nakamoto is a Bitcoin light-client2 implementation in Rust, with a focus on low resource utilization, modularity and privacy.

The vision for the project is to build a set of high quality and easily embeddable libraries targeting light client wallet functionality, that can run on any platform – be it mobile or desktop – while preserving user privacy.

When we take a look at the greater ecosystem, we see that it isn’t uncommon for users to end up trusting third parties when transacting. In the majority of cases - Ethereum being a good example - it is due to poor light-client support. This poses a considerable security and privacy risk that is counter to the nature and raison d’être of blockchains, which are designed as peer-to-peer systems. Light-clients are necessary for the average user to securely interface with the network in a peer-to-peer manner, and hence the availability of high quality implementations is paramount.

Requirements

One of the key long-term plans for Nakamoto is to offer a C FFI, enabling interoperation with other languages and opening up the possibility to run on mobile devices. This could have been satisfied by writing Nakamoto in C, though one of the project’s primary goals is to offer the most secure implementation possible. Rust was chosen over C.

Another important consideration for mobile is power and resource efficiency. This rules out implementations in managed languages with heavy runtimes such as bitcoinJ and nudges us towards simpler designs.

Finally, user privacy is becoming increasingly important. Privacy influences the choice of client protocols and forces us to think about how the client interacts with the nodes on the network, and what information it reveals.

Landscape

There are very few options out there that are satisfactory. It’s fairly common for mobile Bitcoin wallets to have a custom light-client implementation, most of which are still based on BIP 37. Another common avenue is to use something like Electrum, which relies on non-standard Bitcoin nodes. Unfortunately neither of those are privacy-preserving.

Nakamoto talks directly to the Bitcoin P2P network, and thus doesn’t require special servers to connect to. For simple payment verification (SPV), the new BIP 157 client-side block filtering protocol offers improved privacy.

Additionally, Nakamoto’s client architecture enables it to run on a single thread, minimizing CPU and memory footprint. This allows the library to be easily embedded in any environment.

Modularity

A lot of work has been put into building an I/O-free protocol core. This is the key to Nakamoto’s modularity and also enables some very powerful testing strategies that only work when the code being tested is deterministic, i.e. all inputs can be controlled for.

Having a clean separation between the networking code and protocol state-machine reduces the possible failure states, and allows the networking code to be swapped based on the user’s needs. If performance is more important than efficiency or code complexity, the included poll-based network reactor, which uses popol under the hood can be swapped for one based on a thread-pool or a thread-per-connection model.

On Dependencies

When developing software that handles money, the security of the software is critical. Targetted attacks on dependencies are perhaps one of the most obvious attack vectors. One of the most important steps to prevent that is writing software that is easy to audit. Nakamoto follows two simple principles:

  1. Less code equals less bugs and less to audit
  2. Less dependencies equals less moving parts and potential security risks

The second point is particularly important because dependencies are much harder to track than code that is internal to the library. Third-party code often ends up changing hands, and though one may trust the original maintainer, one may not trust whoever comes next.

These have been guiding principles from the start, and thus I’ve been very economical with Nakamoto’s dependency budget. Compared to other projects with a similar scope, Nakamoto does away with a fraction of the (transitive) dependencies.

Closing thoughts

The project is still in its early days, though the core functionality has been implemented and the client is able to securely synchronize the blockchain and use compact block filters for wallet functionality and payment verification.

There is a lot of work left to do before Nakamoto is ready to power the next generation of client software on the Bitcoin and Lightning network, so if you’re interested in peer-to-peer protocols, Rust or Bitcoin, contributions are very welcome. If you are developing wallet software and are interested in using Nakamoto, get in touch, I’d love to help.

//! A trivial example of a client that connects to the Bitcoin
//! testnet and syncs the chain.
use std::{net, thread};

use nakamoto::client::{Client, Config, Network};
use nakamoto::client::error::Error;
use nakamoto::client::handle::Handle as _;

/// The network reactor we're going to use. This one ships with Nakamoto,
/// as part of the `nakamoto-net-poll` crate. It's a single-threaded
/// reactor using non-blocking sockets and `poll(2)`.
type Reactor = nakamoto::net::poll::Reactor<net::TcpStream>;

/// Run the light-client.
fn main() -> Result<(), Error> {
    let cfg = Config {
        network: Network::Testnet,
        ..Config::default()
    };
    // Create a client using the above network reactor.
    let client = Client::<Reactor>::new(cfg)?;
    let handle = client.handle();

    // Run the client on a different thread, to not block the main thread.
    thread::spawn(|| client.run().unwrap());

    // Wait for the client to be in sync with the blockchain.
    handle.wait_for_ready()?;

    // The client is in sync. Ask it to shutdown.
    handle.shutdown()?;

    Ok(())
}

Nakamoto is available as a 📦 crate.


If Nakamoto’s vision is appealing, please consider 💚 funding the project or contributing to the code.

  1. Client Side Block Filtering, or BIP 157 is the new light-client protocol: https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki 

  2. A light-client, or SPV node is a client able to operate securely without access to the full blockchain. Typically, light-clients use only block headers to verify the chain, and thus offer a different security guarantee to full nodes.