I’m fortunate to be spending this week at Recurse Center, a fantastic “coder retreat” in Manhattan. Highly recommended!

My goals for this short stay are: (a) dust off some coding skills that started to grow rusty, and (b) become more fluent in my favorite software language.

To those ends, I’ve put together a set of tools that construct, sign and submit Ripple Consensus Ledger (RCL) transactions. There’s a reason I explicitly list construct, sign, and submit. In these tools, each of those responsibilities is handled by separate process.

For example, constuct a payment with the rcl-tx tool, but don’t sign or submit it:

# Send 20 XRP to rRC5GVM3i2wdPmsC3Jga3w5qz1rxvdGzG...
rcl-tx send rRC5GVM3i2wdPmsC3Jga3w5qz1rxvdGzG 20/XRP > /tmp/rcl-transaction

Another example, sign that transaction with the rcl-key tool, but still don’t submit it:

rcl-key sign < /tmp/rcl-transaction

The processes encode and decode transactions through input and output. Here’s an example that shows construct, sign, and submit in one shot (using pipes):

rcl-tx send rRC5GVM3i2wdPmsC3Jga3w5qz1rxvdGzG 20/XRP | rcl-key sign | rcl-tx submit

(The tools and more examples can be found at https://github.com/dncohen/rcl.)

Why three process to submit a single transaction? I’m glad you asked…

One reason is to maintain a bare minimum of signing code. This is the code that will work with secret keys. As such, it needs to be held to a high standard: never leak a secret. A larger codebase with more dependencies means more to audit and test for security.

Code that constructs or submits transactions must communicate with network servers. But signing code doesn’t need to. It can and should be isolated. The highest standard is to keep the signing process, and the secrets it needs, on an air gapped and tamper-proof machine. Merely using a another process, shown above, doesn’t meet that standard, but it does separate the concern of signing from the concerns of preparing and submitting. This means, in principal, the signing task could be moved to a more secure environment.

Poor Man’s Air Gap

I’m a fan of Qubes, a desktop environment that keeps thing reasonably secure through isolation. Qubes comes with split-gpg, which isolates gpg keys into a separate virtual machine from the processes that rely on encrypted or signed documents. The rcl-key process, example above, can be set up the same way.

Here, briefly, is how that is done. (Full details: here)

Vault VM with Secrets

Use qvm-copy to install rcl-key in the vault VM.

On that VM, create /etc/qubes-rpc/rcl.Sign script to execute rcl-key sign

#!/bin/sh
/usr/local/bin/rcl-key sign

I can create my RCL signing key here on the vault VM (the secret key never leaves the vault)…

rcl-key generate

(Either fund the address created, or configure an account to use that as a regular key. Topics beyond the scope of this post.)

AppVM with RCL Tools

On the appvm where you’ve installed the tools, create ~/bin/rcl-sign-split

#!/bin/sh
signvm=vault
qrexec-client-vm $signvm rcl.Sign

Dom0

On dom0, set up the privileges. This works for me in /etc/qubes-rpc/policy/rcl.Sign, for an appvm named rcl

rcl vault allow
$anyvm vault ask
$anyvm $anyvm deny

With this setup, I can replace rcl-key sign with rcl-sign-split in my earlier example…

rcl-tx send rRC5GVM3i2wdPmsC3Jga3w5qz1rxvdGzG 20/XRP | rcl-sign-split | rcl-tx submit