Skip to content

Latest commit

 

History

History
391 lines (295 loc) · 12.9 KB

README.md

File metadata and controls

391 lines (295 loc) · 12.9 KB

Lexe Public Monorepo

Lexe is a managed, non-custodial Lightning node and wallet based on Intel SGX.

  • LDK-based Lightning node written in Rust
  • Flutter/Dart iOS and Android apps
  • BDK wallet for on-chain payments
  • Fortanix EDP for integration with SGX

This repository contains all public code including the user Lightning node, iOS / Android apps, and shared libraries.

More information is available on our website: lexe.app

Guide to this repository

  • node: Lightning node (usually referred to as the "user node").
  • app: Flutter/Dart apps.
  • app-rs: Rust logic used in the Lexe mobile app along with an FFI interface for the Flutter apps.
  • lexe-ln: Shared Bitcoin and Lightning logic.
  • common: A general shared library which contains:
    • APIs: definitions, errors, clients (with TLS and quote verification), models
    • SGX: remote attestation, sealing, SGX types
    • Cryptography: ed25519, ring, secp256k1, AES-256-GCM, SHA-256, root seeds, key derivation, rng, E2EE "vfs" for untrusted storage
    • Utils: hex, byte strings, test-utils, tasks, channels, exponential backoff, iterator extensions
    • and other miscellaneous things.
  • flake.nix: Reproducible node build
  • SECURITY.md contains information about Lexe's security model and responsible disclosure.

Reproducibly building the user node

Follow these instructions if you are interested in verifying the reproducible build for a Lexe user node release.

Overview

Lexe's user node builds are bit-for-bit reproducible, meaning that given the source code in this repository, anyone can independently derive the exact same ~250 million bits of the enclave binary that Lexe has released in this repo.

This is an important part of the remote attestation process because it allows you to verify that the node that your app is talking to inside of SGX is running the exact code that has been published in this repository, without any backdoors or other modifications that could give Lexe the ability to steal your funds.

Enclave binaries are identified by their measurement (known in SGX lingo as the MRENCLAVE), which is a SHA256 hash of the initial SGX memory contents, including the loaded binary. The enclave binary is a .sgxs file. The SHA256 hash of the .sgxs file is the measurement.

For convenience, Lexe has included the metadata of all currently supported user node builds in a releases.json file at the root of the directory. The releases.json represents the current list of acceptable node measurements, and is hard-coded into node clients, and must therefore be independently verifiable.

Clone the repo and take a look at releases.json:

$ git clone https://github.com/lexe-app/lexe-public.git
$ cd lexe-public
$ cat releases.json
{
  "node": {
    "0.4.0": {
      "measurement": "ac018bb70a5901dedb0a7da01820f16b04044755809203783b9e4d43477269cd",
      "revision": "f53221b4a4c6c180b6d9845f2da07746f95f2828",
      "release-date": "2024-10-15",
      "release-url": "https://github.com/lexe-app/lexe-public/releases/tag/node-v0.4.0"
    }
  }
}

Requirements

If you want to reproducibly build the user node SGX enclave, you'll need a x86_64-linux machine or VM. We recommend at least 16gb disk and 4gb memory. You can check your machine architecture with a simple command:

$ uname -sm
Linux x86_64

If you don't have one readily available, and you use macOS, we recommend using OrbStack to run local, near-native x86_64 linux pseudo-VMS. Follow the OrbStack linux-builder setup instructions in the next section to get going quickly.

Another good option is to use a cloud VM (make sure it's running on an x86_64 CPU). If you're on Windows, then WSL2 might work, though we haven't tried it.

OrbStack linux-builder setup

Follow these instructions if you're running on macOS and want to reproduce the user node with a local Linux VM.

Download OrbStack. Either follow https://orbstack.dev/download or just install with homebrew:

$ brew install orbstack

Create a new NixOS VM @ v24.05 called linux-builder:

NOTE: when orbstack runs, you don't need to install the privileged docker socket helper, since we don't require it.

$ orb create nixos linux-builder

In order to get a usable builder VM, we have to tweak the base NixOS config. This will install some extra required packages in the VM (git), enable some nix features, and tell the VM to sign its store packages:

$ orb push -m linux-builder ./nix/linux-builder/configuration.nix /tmp/configuration.nix
$ orb run -m linux-builder --user root --shell <<EOF
sed "s/{{ username }}/$USER/" /tmp/configuration.nix > /etc/nixos/configuration.nix
chown root:root /etc/nixos/configuration.nix
nixos-rebuild switch
EOF

Shell into the VM:

$ orb shell -m linux-builder

Check that Nix is available:

$ nix --version
nix (Nix) 2.18.1

Now you're ready to run a reproduce a node build!

Nix setup

If you're in a x86_64-linux environment that isn't the linux-builder VM, you'll need to install Nix.

Install nix with the DeterminateSystems/nix-installer. We suggest the multi-user installation.

$ curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix \
    | sh -s -- install

Reproduce the user node

Now that you're in a x86_64-linux environment with Nix, you can reproduce any node version that you want.

Clone and cd into the repo if you haven't already:

$ git clone https://github.com/lexe-app/lexe-public.git
$ cd lexe-public

Take a look at releases.json and set VERSION to the one you want to reproduce. If you're not sure, we recommend reproducing the latest node release.

$ VERSION=0.4.0 # Change this 

# Save the measurement that we'll compare our build against later.
$ MEASUREMENT=$(jq -r ".node.\"$VERSION\".measurement" releases.json)
$ echo $MEASUREMENT
ac018bb70a5901dedb0a7da01820f16b04044755809203783b9e4d43477269cd

Check out the code for this version:

$ git fetch --all --tags
$ git checkout node-v$VERSION
$ git show --no-patch
─────────────────────────────────────────────────────────────────────────┐
commit f53221b4a4c6c180b6d9845f2da07746f95f2828 (HEAD, tag: node-v0.4.0) │
─────────────────────────────────────────────────────────────────────────┘
Author: Max Fang <hello.github@maxfa.ng>
Date:   Mon Oct 14 19:44:42 2024 -0700

    release (1/2): `node-v0.4.0` (Reproducible commit)

Reproducibly build the node.sgxs enclave binary:

$ nix build .#packages.x86_64-linux.node-release-sgx

Check that the locally-built .sgxs produces the intended measurement:

$ sha256sum result/bin/node.sgxs
ac018bb70a5901dedb0a7da01820f16b04044755809203783b9e4d43477269cd  result/bin/node.sgxs
$ cat result/bin/node.measurement
ac018bb70a5901dedb0a7da01820f16b04044755809203783b9e4d43477269cd
$ echo $MEASUREMENT
ac018bb70a5901dedb0a7da01820f16b04044755809203783b9e4d43477269cd

Congrats, you have verified a reproducible node build! We invite you to share your results in the node build attestations issue.

If you need help setting up the reproducible build, or if reproducibility seems broken in your environment, please open a separate issue or ping us on Discord.

(Optional) Verify the contents of a node GitHub Release

Follow these instructions if you would like to further verify the contents of a Lexe node release package against the associated measurement in releases.json.

# Ensure $VERSION is set to the version you want to verify
$ echo $VERSION
0.4.0

# Set up a package dir to contain the release package contents
$ mkdir node-v$VERSION

# Fetch and extract the node release into our package directory.
$ wget https://github.com/lexe-app/lexe-public/releases/download/node-v$VERSION/node-v$VERSION.tar.gz
$ tar -xzf node-v$VERSION.tar.gz -C node-v$VERSION && rm node-v$VERSION.tar.gz

# Directory contents:
$ ls node-v$VERSION
node*
node.measurement
node.sgxs
node.sigstruct

Let's check that the SHA256 hash of Lexe's node.sgxs matches that contained in the node.measurement file, as well as in the releases.json file:

$ sha256sum node-v$VERSION/node.sgxs
ac018bb70a5901dedb0a7da01820f16b04044755809203783b9e4d43477269cd  node.sgxs
$ cat node-v$VERSION/node.measurement
ac018bb70a5901dedb0a7da01820f16b04044755809203783b9e4d43477269cd
$ cat releases.json | jq -r ".node.\"$VERSION\".measurement"
ac018bb70a5901dedb0a7da01820f16b04044755809203783b9e4d43477269cd

Dev Setup (nix)

Follow these steps if you want to quickly set up a basic Lexe dev environment.

First follow the Nix setup steps above.

From the root of the repo, enter an ephemeral dev shell for working on the project. This shell is set up with all the tools needed to build, lint, run tests, etc...

$ nix develop

And you're done! You can try out your setup by running the Rust tests:

$ cargo test

Dev Setup (manual)

Follow these instructions if you need to do extensive work on this repo.

Install rustup

$ curl --proto '=https' --tlsv1.3 -sSf https://sh.rustup.rs | bash

#  default host triple: default
#    default toolchain: stable
#              profile: default
# modify PATH variable: yes

Install Protocol Buffers

# (Ubuntu/Debian/Pop!_OS)
$ sudo apt install protobuf-compiler
# (macOS)
$ brew install protobuf

For devs without x86_64 linux hosts, you'll need to set up a x86_64-unknown-linux-gnu cross-compilation toolchain in order to build for the enclave target x86_64-fortanix-unknown-sgx.

# (macOS)
$ brew tap MaterializeInc/homebrew-crosstools https://github.com/MaterializeInc/homebrew-crosstools
$ brew install materializeinc/crosstools/x86_64-unknown-linux-gnu

Install the enclave toolchain (does not appear to work on M1 Macs)

$ cd ~
$ git clone --branch lexe-2023_09_27 https://github.com/lexe-app/rust-sgx.git
$ cd rust-sgx
$ cargo install --path intel-sgx/fortanix-sgx-tools
$ cargo install --path intel-sgx/sgxs-tools

Non-x86_64 linux hosts should also add the following to their ~/.cargo/config.toml:

[target.x86_64-fortanix-unknown-sgx]
linker = "x86_64-unknown-linux-gnu-ld"

[env]
CC_x86_64-fortanix-unknown-sgx = "x86_64-unknown-linux-gnu-gcc"
AR_x86_64-fortanix-unknown-sgx = "x86_64-unknown-linux-gnu-ar"

If running the node or running tests in SGX, install our runners:

# Clone the repo if not already cloned
$ git clone https://github.com/lexe-app/lexe-public
$ cd lexe-public # or $ cd lexe/public
$ cargo install --path run-sgx

Usage

After setting up your dev environment, you can work with the repo like so.

Run lints and tests

$ cargo clippy --all
$ cargo fmt -- --check
$ cargo test

Build the node

# Build for the local environment (non-SGX)
$ cargo build -p node
# Build for SGX
$ cargo build -p node --target=x86_64-fortanix-unknown-sgx
$ cargo build -p node --release --target=x86_64-fortanix-unknown-sgx

Check that the node runs by printing the current version

$ cargo run -p node -- --version
$ cargo run -p node --target=x86_64-fortanix-unknown-sgx -- --version
$ cargo run -p node --release --target=x86_64-fortanix-unknown-sgx -- --version

See node help

$ cargo run -p node -- run --help
$ cargo run -p node --target=x86_64-fortanix-unknown-sgx -- run --help
$ cargo run -p node --release --target=x86_64-fortanix-unknown-sgx -- run --help
  • If running in SGX, make sure that you are running on real Intel hardware with SGX enabled.
  • If running the node independently of Lexe services, you will need to use mock API clients instead of the real ones, which simulate the APIs exposed by these services. To do this, pass -m and simply don't specify a --backend-url, --runner-url, or LSP url. Note that mocking functionality is provided on a best-effort basis and is not tested (or used) regularly by Lexe devs.

See RunArgs/ProvisionArgs contained in common::cli::node for full options.

License

All files in this repository are licensed under the PolyForm Noncommercial License 1.0.0, unless otherwise indicated.

Lexe recognizes the value of open-source. To give back to the open-source community, Lexe commits to switching to the MIT license or other permissive open-source license once Lexe is in a financially stable position.

© 2022-2024 Lexe Corporation