Generating Keys for the Burrow Blockchain using Swift

At Katalysis, we use the Burrow blockchain built by Monax (also known as Eris in the days of old) using the Zewo Swift server side stack.

We have been using the Monax blockchain for over a year now, and one thing we found missing from the tools is a means to create your own keys without having to rely on the trusted eris services start keys.

Our rational here is that we want to avoid sharing our private keys as much as possible (i.e. generate them and use them for signing purposes locally on the same trusted box/device).

In this post we will show how to use our open source native Swift library ErisKeys, which wraps the necessary crypto primitives to generate valid Eris keys and accounts, sign messages (or transactions), and also verify them.

This post assumes only minimal knowledge of the Swift programming language.

Setup

So let’s get started — Swift code can run on all Apple platforms, as well as on Linux (on x86 architectures — ARM still requires more involvement). First, let’s set up a working Swift development environment.

Linux

Here, we use the excellent swiftenv on an Ubuntu Digital Ocean or AWS cloud instance. Regarding IDE, Atom has some optional Swift packages which can make development more streamlined.

MacOs

On MacOS, Xcode is king. If you don’t have it installed, you can get it from the Mac App Store. Additionally, we also recommend to install swiftenv since programming server side with Swift requires going to the command line quite a bit. You can of course also stick to Atom, however, you miss out on more advanced debugging capabilities.

Swift Package Manager

The Swift Package Manager (SPM) is part of the standard Swift install. It is not yet fully integrated with Xcode, however it is invaluable when working with Swift from the command line. Here are the main commands used (from the current project directory):

swift package init --type=executable Initializes the current directory for a CLI app project.

swift package initInitializes the current directory for a library project.

swift build Builds the local project.

swift package clean Cleans the current directory of build artifacts.

swift package generate-xcodeproj Generates an Xcode project that can be used to work from Xcode. It will contain all the dependencies from Package.swift.

Additionally, if you are not familliar with the SPM we recommend you spend some time reading up on the various files in an SPM compliant project directory structure.

Side track: CocoaPods

If you want to target iOS, you should use CocoaPods. In that case, you will need to add the following to your pod file:

pod 'ErisKeys', '~> 0.3.8'

Since the pod is privately hosted by Katalysis, you also need to add the pod location to your local repo and provide the location to look for Katalysis Pods in your Podfile.

source 'https://gitlab.com/katalysis/Pods.git'

Testing the setup

Coming back to Linux or MacOS, you should now be able to run swift on the command line:

$ swift
Welcome to Apple Swift version 3.1 (swift-3.1-RELEASE). Type :help for assistance.
1> print ("hello")
hello
2>

Using the ErisKeys library

Now that we have a working environment, let’s take a look at the library itself.

The library is meant to be very simple. It provides a way to create an instance of a key from a private seed, and that instance will make the public key and the account available. The key instance is also able to sign a message and verify it. The private key is not retrievable from the instance, however, when one knows the seed, it can be deduced.

Side track: Monax keys

The Burrow blockchain uses Tendermint as its consensus engine. The Tendermint engine uses Ed25519 curve and RIPEMD160 for its keys and accounts. The ErisKeys are in fact Tendermint keys.

In very short, the private key of an Eris Key is 64 bytes long. It is composed of a 32 bytes seed, and a 32 bytes public key, derived from the Ed25519 curve. The account (20 bytes) used by the blockchain to identify the user is the RIPEMD160 hash of the public key augmented with some type information.

public class ErisKey {}

The ErisKey class is initialised using a 32 bytes array seed. It is pretty straight forward:

import Ed25519
import RipeMD
public class ErisKey {
public init(_ seed: [UInt8]) throws
public convenience init?(seed: [UInt8])
  public var pubKey: [UInt8]
public var account: String
  public func sign(_ message: [UInt8]) -> [UInt8]

public static func verify(_ publicKey: [UInt8], _ message: [UInt8], _ sig: [UInt8]) -> Bool
  public static func account( _ publicKey: [UInt8]) -> String
public static func account( _ publicKey: String) -> String
}
extension ErisKey {
public var pubKeyStr: String
public func signAsStr(_ message: [UInt8]) -> String
}

Interesting to note are the two static account functions, which allow to generate an account from a public key without requiring the private key seed.

Similarly, a message verification does not require a full blown key and thus is static.

Example app

Let’s now put all of this together and build a working CLI app generating keys that we will be able to use on a Burrow Blockchain. You can find the full source code for the project here.

First let’s create the Swift project:

> mkdir KeyGenerator
> cd KeyGenerator
> swift package init --type=executable
Creating executable package: KeyGenerator
Creating Package.swift
Creating .gitignore
Creating Sources/
Creating Sources/main.swift
Creating Tests/
>

Change your Package.swift to this:

// swift-tools-version:3.1
import PackageDescription
let package = Package(
name: "KeyGenerator",
dependencies: [
.Package(url: "https://github.com/Zewo/OpenSSL.git", majorVersion: 0, minor: 14),
.Package(url: "https://gitlab.com/katalysis/ErisKeys.git", majorVersion: 0, minor: 3),
]
)

We use Zewo/OpenSSL to generate random numbers. If you want to use Xcode at that stage, you can run:

> swift package generate-xcodeproj
...
> open -a xcode ./KeyGenerator.xcodeproj/

Then, open up your ./Sources/main.swift file and change it to this:

import ErisKeys
import OpenSSL
var seed = [UInt8]()
for i in 0..<32 {
seed.append(UInt8(Random.number(max: Int(UInt8.max))))
}
if let key = ErisKey(seed: seed) {
let seedStr: String = seed.reduce("") {(s,u) in return s + String(format: "%02X",u)}
  let pubKey = key.pubKey
  print("Seed      : \(seedStr)")
print("Public key: \(key.pubKeyStr)")
print("Account : \(key.account)")
  let messageStr = "Hello Marmots!"
  print("Message to sign: \(messageStr)")
  let message = [UInt8](messageStr.utf8)
let signature = key.sign(message)
let sigStr: String = signature.reduce("") {(s,u) in return s + String(format: "%02X",u)}
  print("Signature      : \(sigStr)")
  if (ErisKey.verify(pubKey, message, signature)) {
print("Message has been verified!")
} else {
print("Message has been tampered with!")
}
} else {
print("Seed is not 32 bytes.")
}

And we’re done!

Now run:

> swift build
...
> .build/debug/KeyGenerator
Seed : AA5F6846072570B270F2C1F0BDA63C55DDDAE2567D33202523DECFA75FC6C39C
Public key: 3D19628DF37B8F4479248909BC6570B266B067B765307631B7EF39EC076FAF44
Account : 91E409621FCA8432758B1D80C4CD4C6C996C97BD
Message to sign: Hello Marmots!
Signature : 47AF2A262B059BC3F683492CE9E3072F3F730A8628707665F5B905367F5F08DA92262A1E4AAA7249F0E69A67B89FE0006F76892FE70397874CAC7B133A950C0F
Message has been verified!
>

Recap

So let’s recap what we’ve just seen. The ErisKeys library allows you to do the following:

  • instantiate keys which you can use to connect to a Burrow blockchain,
  • sign messages to send to the Burrow blockchain,
  • verify messages sent from a public address on the Burrow blockchain,
  • all of this in native Swift!

In a following post, we will discuss how we can create new users on a running Burrow blockchain using Swift, a seed from a private key with the required privileges, and our Swift BurrowBlockchain library.

Happy Swifting!

Feel free to reach out if you have any comments and/or questions.