Introduction
Welcome! This book serves as the spot that the Worldcoin Project hosts its documentation for developing software for the orb.
It also provides an inside look at our development practices, which helps increase transparency of the project and provide foundations for other contributors to the project to build on top of.
Who is this for?
The target audience of this documentation is for contributors to the orb-software repo or any of the other open source repos that pertain to the orb. We plan to accept contributions at a later date, but do not have bandwidth to review PRs currently.
Likewise, we are providing source code and documentation for the benefit of the community, but cannot commit to any SemVer or API stability guarantees. Be warned: we may change things in a backwards-incompatible way at any time!
Where is the code?
See the orb-software repo for the code.
This is a living document. If you are a contributor and wish to improve the documentation, simply open a PR! The source code for the mdBook lives here.
However, spam/noise/typo PRs will be ignored. Especially those from bots. Do not farm green github squares from us.
Initial repo setup
To be able to build the code, there is some first-time setup required.
Set up nix + direnv (the developer environment)
We use nix to manage all of the dependencies during development. While most of the software can use convnetional rust tools like cargo, we do have a few additional dependencies. Instead of apt-installing them, we use nix as the package manager, and use direnv to handle automatically activating a developer shell. The process to install and configure these two tools is as follows:
- Install nix. This works for both mac and linux, if you are using a windows machine, you must first set up WSL2.
- Ensure that you have these lines in your
~/.config/nix/nix.conf
or/etc/nix/nix.conf
. This is done automatically by the above installer:
You can check that things work by runningexperimental-features = nix-command flakes max-jobs = auto
nix run nixpkgs#hello
- Install direnv:
nix profile install nixpkgs#direnv
- Hook direnv into your shell.
- Set up your personalized .envrc file by running
cp .envrc.example .envrc
. You can customize this file if you wish. We recommend filling in your cachix token if you have one. If prompted, dont rundirenv allow
yet, follow step 6 first. Otherwise you'll get a bunch of errors. - Follow the instructions on vendoring proprietary SDKs in the subsequent section.
- Run
direnv allow
in the repository's root directory. Direnv will then automatically use the .envrc file you set up any time youcd
into the directory. - If you are on macos, run the following:
brew install dbus brew services start dbus
- Install git lfs:
git lfs install git lfs pull
Vendoring proprietary SDKs
Although all of Worldcoin's code in the orb-software repo is open source, some of the sensors on the orb rely on proprietary SDKs provided by their hardware vendors. Luckily, these are accessible without any cost, they are just annoying to get and are not themselves open source.
To get started, you will need to download these SDKs. The process for this depends on if you are officially affiliated with Worldcoin.
If you have access to Worldcoin private repos
- Create a personal access token from github to allow you to use private git repos over HTTPS.
- Append the following to your
~/.config/nix/nix.conf
:access-tokens = github.com=github_pat_YOUR_ACCESS_TOKEN_HERE
- Test everything works so far by running
nix flake metadata github:worldcoin/priv-orb-core
. You should see a tree of info. If not, you probably don't have your personal access token set up right - post in slack for help.
If you don't have access to Worldcoin private repos
- Go to https://developer.thermal.com and create a developer account. Getting the SDK can take several days for Seek Thermal to approve access. In the meantime, you can skip steps 2 and 3.
- Download the 4.1.0.0 version of the SDK (its in the developer forums).
- Extract its contents, and note down the dir that contains the
Seek_Thermal_SDK_4.1.0.0
dir. - modify your
.envrc
like this:use flake --override-input seekSdk "PATH_FROM_STEP_3"
. If you don't yet have access to the SDK, just provide a path to an empty directory.
How to develop and build code
Make sure you followed the first time setup instructions.
Building
We use cargo zigbuild
for most things. The following cross-compiles a binary
in the foobar
crate to the orb. Replace foobar
with the crate that you wish
to build:
cargo zigbuild --target aarch64-unknown-linux-gnu --release -p foobar
You can also build code faster with cargo check
, since it skips the linking
step. Try running cargo check -p foobar
.
Testing the code
Unlike building the code, tests are expected to run on the same target as the host. But not all tests are possible on every target.
IF it is supported, you can run cargo test -p foobar
like normal. But
support varies from crate to crate.
Running the code
For binaries that are intended to run on the orb, you can take your
cross-compiled binary, and scp it onto the orb. You can either use teleport (if
you have access) via tsh scp
or you can get the orb's ip address and directly
scp it on, with the worldcoin
user.
If you choose the scp
route without teleport, you will need to know the
password for the worldcoin
user. Note that this password is only for dev
orbs, orbs used in prod are not accessible without teleport and logging in with
a password is disabled.
Debugging
Tokio Console
Some of the binaries have support for tokio console. This is
useful when debugging async code. Arguably the most useful thing to use it for
is to see things like histograms of poll()
latencies, which can reveal when
one is accidentally blocking in async code. Double check that the binary you
wish to debug actually supports tokio console - support has to be manually
added, it isn't magically available by default.
To use tokio console, you will need to scp a cross-compiled tokio-console
binary to the orb. To do this, just clone the repo and use
cargo zigbuild --target aarch64-unknown-linux-gnu --release --bin tokio-console
, then scp it over.
Note: tokio-console supports remote debugging via grpc, but I haven't figured out how to get the orb to allow that yet - I assume we have a firewall in place to prevent arbitrary tcp access, even in dev orbs.
Then, you must build the binary you want to debug unstable tokio features enabled. To do this, uncomment the line in .cargo/config.toml about tokio unstable.
Finally, make sure that the binary has the appropriate RUST_LOG level set up.
try using RUST_LOG="info,tokio=trace,runtime=trace"
.
Finally, run your compiled binary and the compiled tokio-console
binary on
the orb. You should see a nice TUI.
Note that it is recommended but not required to have symbols present to improve the readability of debugging.
How we do open source
Worldcoin is committed to building a fully open source, decentralized ecosystem. In service of this goal, the entirety of the orb-software repo is open source under an MIT/Apache 2.0 dual license. You can read more about the project's open sourcing efforts here.
All source code for the Worldcoin Project lives under the worldcoin github organizaton.
Overview of private repos
To the maximum extent possible, we put all public code in the orb-software and orb-firmware repos. But we also maintain private repos, which contain code that is responsible for fraud detection or uses third party SDKs that we do not have a license to open source.
The most notable private repos are:
- priv-orb-firmware. This repo contains the fraud sensitive parts of the firmware. It consumes the public orb-firmware repo as a dpenedency.
- orb-internal. This repo contains the fraud sensitive parts of the user-space software. It consumes the public orb-software repo as a dependency.
- priv-orb-core. This repo is the mainline branch of
orb-core
. Unlike the other repos, this is a fork of its public counterpart, orb-core. The public repo is therefore inherently less up to date and doesn't retain git history, as its code has all fraud-related codepaths manually deleted. One of the long-term goals is for these two repos to become un-forked, and most code consolidated intoorb-software
so that we can transition to developing orb-core directly in the open. - trustzone. This repo contains code related to the secure operating system OP-TEE that runs alongside linux inside ARM TrustZone. We plan to open source the OP-TEE CAs and TAs at some point in the future.-
- orb-os. This repo is where we build the operating system image that runs on the orb. It consumes artifacts from all the other repos to assemble one final image.
Hardware In Loop
Developing for the orb generally requires access to an orb. To make life easy,
as well as to enable automated tests, we use an x86 linux machine as a host, which
attaches to an orb via a number of hardware peripherals. We created the orb-hil
cli tool to leverage this known hardware setup to perform a number of common,
useful actions.
Getting an x86 Linux Machine
Technically, any x86 linux machine will do. However, we recommend using an ASUS/Intel NUC due to its compact form factor.
The Linux installation needs:
- Access to the various attached usb devices without sudo, i.e. udev rules configured
- Access to serial without sudo
- Various packages (awscli2, usbutils, etc)
- Teleport
- Github self-hosted runner (if using this in CI).
To make this setup easy, we have a nix config that sets all of this up. BUT you could use regular ubuntu, or some other linux distro instead.
For the NixOS approach, see the nixos setup. If you use NixOS, we can manage all the machines in one git repo, so this is the prefrred option, even though the initial setup is a bit more hassle (for now).
orb-hil cli
There is a CLI tool to facilitate hardware-in-loop operations. This tool lives in the orb-software repo and releases can be downloaded here.
It is a single, statically linked CLI tool with lots of features helpful for development:
- Rebooting orbs into either normal or recovery mode
- Flashing orbs (including downloading from S3, extraction, etc)
- Executing commands over serial
- Automating the login process over serial
Required peripherals
Different orb-hil
subcommands require different hardware peripherals. We
strongly recommend at least getting an x86 linux machine and a serial adapter.
See the hardware setup page for more detailed info.
Here are the different hardware peripherals necessary for the different
subcommands of orb-hil
:
orb-hil flash
: x86 linux machineorb-hil reboot
: Serial adapter.orb-hil login
: Serial adapter.orb-hil cmd
: Serial adapter.
Logging in to AWS
The flash
subcommand can download S3 urls. To set this up, we recommend putting
the following into ~/.aws/config
:
[default]
sso_session = hil
sso_account_id = 510867353226
sso_role_name = ViewOnlyAccess
[profile hil]
sso_session = hil
sso_account_id = 510867353226
sso_role_name = ViewOnlyAccess
[sso-session hil]
sso_start_url = https://d-90676ede48.awsapps.com/start/#
sso_region = us-east-1
sso_registration_scopes = sso:account:access
You can now chose the appropriate aws profile for the hil by passing the
AWS_PROFILE=hil
env var in any aws-related tasks. This works with both the
aws cli tool, and orb-hil.
To actually log in and get a fresh set of credentials:
AWS_PROFILE=hil aws sso login
HIL NixOS Setup
Eventually, we will support making installation media from the NixOS config directly, including setup scripts to fully automate this process. But for now, one first needs to do a lot of manual bootstrapping.
Installing NixOS to a liveusb
On the ASUS NUCs, they don't support MBR partitioned live usbs. But for some inexplicable reason the official NixOS installer only exists as a MBR partitioned disk. This means we need to build our own GPT/UEFI based NixOS live usb ;(
To work around this limitation of the official installer, we provide a liveusb image that has NixOS on it, and is built using the nixos-generators tool. To build the .img file yourself, run:
nix build .#liveusb # if you are natively on x86-64 linux
If you are not on x86-64 linux, you should either ssh into a x86 linux machine (such as one of the existing HILs) and SCP the image off, or you should use the remote builders feature of nix. Here is an example:
# ensure that sshing as root works, and that your ssh keys don't require any passwords, etc
sudo ssh -T user@hostname
# actually do the build
nix build .#packages.x86_64-linux.liveusb --builders 'ssh://user@hostname x86_64-linux - - - kvm'
Use the liveusb to install NixOS
Booting from the liveusb
This is the same as any other linux liveusb. Get into your boot menu using the function keys at boot, and select the USB from the boot options. If it doesn't show up, make sure you are using a GPT/UEFI based liveusb. You will likely need to disable UEFI secure boot as well.
Setting up Partitions
You need three partitions:
- EFI (512MB, format as FAT32)
- Swap (Make it 32GB or size of ram, whichever is bigger. Format as linux-swap)
- Rootfs (Rest of disk, format as ext4)
TODO: Describe how to do this from parted
. See also here and here
After you finish this step, the rootfs partition should be mounted to to /mnt and the EFI boot partition to /mnt/boot.
Install NixOS from the liveusb
-
Make sure that the new partitions are mounted under
/mnt
and/mnt/boot
. -
Run
sudo nixos-generate-config --root /mnt
. This will create a new nixos config for the NUC. -
Edit the NUC's NixOS config at
/mnt/etc/nixos/configuration.nix
to be the following: TODO: Make sure this is all that is needed, and just use this to generate an image instead of them typing it in./mnt/etc/nixos/configuration.nix
:{ config, pkgs, lib, ... }: let username = "worldcoin"; hostname = "my-hostname-here"; hashedPassword = ""; # paste output of mkpasswd here in { networking.hostName = "${hostname}"; environment.systemPackages = with pkgs; [ curl git neovim parted usbutils vim ]; # Enable the OpenSSH daemon. services.openssh = { enable = true; passwordAuthentication = false; }; # Enable the X11 windowing system. services.xserver.enable = true; # Enable the KDE Plasma Desktop Environment. services.xserver.displayManager.sddm.enable = true; services.xserver.desktopManager.plasma5.enable = true; # Enable networking networking.networkmanager.enable = true; users.users."${username}" = { isNormalUser = true; description = "${username}"; hashedPassword = hashedPassword; extraGroups = [ "networkmanager" "wheel" # Gives sudo "plugdev" "dialout" ]; }; # use the latest Linux kernel boot = { kernelPackages = pkgs.linuxPackages_latest; # Needed for https://github.com/NixOS/nixpkgs/issues/58959 supportedFilesystems = lib.mkForce [ "btrfs" "reiserfs" "vfat" "f2fs" "xfs" "ntfs" "cifs" ]; }; }
-
Make sure that your liveusb is connected to the internet. If its not, you can use
nmtui
to connect. -
cd /mnt && sudo nixos-install
-
sudo shutdown -h now
, and remove the liveusb. -
Boot the freshly installed NixOS (you may need to select it from the boot menu).
-
Make sure that all of the following is true:
- You can boot into it.
- You have internet access (you can connect to wifi with
nmtui
). - You have sudo rights
Switch to the full NixOS config.
Now that NixOS is installed on the NUC, we need to upgrade it to the full blown config that we use. Luckily nix makes this really easy.
- Clone the nix config.
- Customize the config to add an entry for your new machine. Be sure you set the hostname to be the same as what the current hostname is. You can ask @thebutlah to do this for you or look at the existing config to figure it out. Eventually we will make this really easy. Be sure that you add a ssh key for your account so that you can still access it in the case that teleport doesn't work.
- (only if creating a self-hosted runner) Create a
/etc/worldcoin/secrets/gh-runner-token
file and populate it with theorb-os-self-hosted-runner
token from 1Password. - Clone the nix config to ~/nix.
- Run
sudo nixos-rebuild --impure --flake ~/nix
- Install teleport. Ask in slack for how to do this, its a bit involved, since it requires manually editing the shell script, as well as requesting access.
Hardware Setup
The HIL leverages the use of several hardware peripherals to control the orb. Most important is the serial adapter and the x86 linux machine. While any x86 linux machine will do, we recommend purchasing an ASUS/Intel NUC due to the convenient form factor.
Required Parts
We break down the parts into common/shared items, and items per-hil.
Note: Not all of these parts are required. In the most minimal case, we recommend at least getting some electrical tape, an x86 linux machine, the Micro USB cable, and a serial adapter. This will cover 90% of the use cases. Note also, no soldering is required!
Shared
- Electrical Tape
- US Source: TODO
- DE Source
- Some Male-Male Jumper Wires (but Male-Female or Female-Female as needed).
- US Source: TODO
- DE Source
- Display for initial bringup
- A flash-drive
Per HIL Rig
The Essentials
- 1x Intel NUC 13 Pro Mini PC Core i7-1360P 16GB RAM
- 1x FT232(RL) Serial Adapter
- 1x USB Power Blocker for Flashing Cable
- USB A male to micro USB male cable
- US Source: TODO
- DE Source
- USB Dock (at least three usb-A ports)
Flashing the microcontrollers
Connecting the parts to the orb
Flashing support
- Connect the microusb cable to the microusb port of the orb.
- Use the USB Power blocker to ensure that this cable is data-only. This will ensure that the main mcu doesn't get power from the cable. This is an optional but highly recommended step.
- Connect the usb power blocker to the NUC directly. Do not use the usb dock.
Serial and Reboot support
- Ensure the serial adapter is configured for 3.3v. There is a jumper on the serial adapter that controls this setting.
- Add electrical tape behind the TX and RX pins, to prevent short circuiting the pins against the chassy.
- Connect the GND pin of the serial adapter to the GND pin on the orb (there is one at the top).
- Connect TX and RX pins to the orb. TX (blue) on bottom, RX (green) on top.
- Connect CTS pin to the BTN pin. Its located below the top GND pin. This allows controlling the power button of the orb.
- Connect the RTS pin to the bottom of the two pins on the recovery mode jumper on the right side of the orb. This allows controlling recovery mode of the orb.
- Double check that nothing is going to short circuit. It is ok for the GND pin to touch the chassy, but it is NOT ok for any of the other pins to touch anything else.
- Plug the serial adapter into the USB dock and connect the dock to the NUC.
(Optional) Recovery from a bricked microcontroller
For each microcontroller that you want to be able to recover without, you should attach the ST-Link. For setups where you don't want to physically have to access the orb, we recommend keeping both ST-Links always attached to their microcontrollers. You can do this by:
- Plug the tag-connect adapter into the port. There are two - one for the main mcu on the front center of the orb, and one for the security mcu on the back of the orb.
- Connect the other end of the tag-connect to the ST-Link.
- Plug the st-link into the NUC (via the dock or directly).
Software components of the orb
The orb consists of several software components. This section of the book provides a place to describe all of these different components.
See the individual sections in the table of contents to read more.
Orb Core
orb-core
contains the core rust application responsible for verifying users'
World IDs.
The binaries controlling the orb are found in src/bin/
:
- src/bin/orb-core.rs: the production binary, which runs verifications in the field.
- src/bin/orb-backend-connect.rs: a binary to ensure backend connectivity by scanning a WiFi QR code and establishing the WiFi connection as long as the backend is not reachable.
Code Overview
Overview of the do_signup
function:
flowchart TD A[Start Signup] --> B{Scan Operator QR Code} B -->|Success| C{Scan User QR Code} B -->|Failure| Z[End Signup] C -->|Success| D{Detect Face} C -->|Failure| Z D -->|Detected| E[Start Image Notary] D -->|Not Detected| Z E --> F[Biometric Capture] F --> G[Stop Image Notary] G --> H[Biometric Pipeline] H --> I{Detect Fraud} I -->|No Fraud| J[Enroll User] I -->|Fraud Detected| K[Mark as Fraud] J -->|Success| L[Mark Signup as Successful] J -->|Failure| M[Mark Signup as Failed] K --> N[Upload Debug Report and Opt-in Images] L --> N M --> N N --> Z
State of open sourcing
There are two orb-cores: the public one at worldcoin/orb-core and
the private one at worldcoin/priv-orb-core. Today, the public repo
is a manually stripped down version of the private one. This is done to remove
code paths that could reveal the types of fraud detection that we perform. Long
term, we plan to un-fork these two repos such that the public code lives in
worldcoin/orb-software and the private code is only minimal
additional code, which consumes the public code as a dependency. This will
ensure that most code we develop is done directly in the open, where main
lives in a public repo.
See how we do open source for more context.