Security through Simplicity & Compartmentalization

RAILGUN Project
3 min readAug 22, 2022

The more simplistic your code, the more inherently secure it tends to be. This is further improved when code is properly compartmentalized. Let’s look at an example of this in the RAILGUN Privacy Project code. OpenZepplin’s governance system (which is what RAILGUN Privacy Project’s governance system is inspired by) has been subject to two critical vulnerabilities:

Timelock controller had a reentrancy bug that allowed executors to act as admin:

Changing quorum requirements could lead to old, failed proposals becoming executable

However, these bugs could have been avoided by using the principles of compartmentalization and simplicity for critical code. The more things your code does, the larger the attack surface. It also doesn’t help that vulnerabilities in on-chain code are difficult to patch as deploying patches will alert all malicious actors to vulnerabilities. If your code isn’t properly compartmentalized it is very difficult to deploy an upgrade in a way that the bug is not exploitable by said bad actors.

So, how does one mitigate this?

First and foremost, identify the critical components of the code. This can be things like storage of funds or the upgrade process associated with the system. A great best practice to implement when writing these critical components is to ensure they’re segregated from the non-critical parts of your code and are distilled as much as possible.

This will keep potential bugs at arms length from your critical components and the simplicity and disciplined distillation of critical component code will equate to a smaller attack surface area. It also means it is easier to defend and upgrade in a way that doesn’t lead to exploits.

How does RAILGUN’s code implement these principles?

First let’s have a look at the governance system for the RAILGUN Privacy Project.

Governance system (all critical code): https://github.com/Railgun-Privacy/contract/tree/master/contracts/governance

We see multiple independent contracts here:

- Voting: Only handles the process of passing proposals, no other logic is present.

- Staking: Only handles staking and exposes interfaces for other contracts to get staking information.

- Delegator: Manages governance permissions for contracts by proxy, owned by voting contract.

So, even within this already segregated governance system there is 3 distinct, compartmentalized contracts, each implementing the minimum amount of logic to fulfill its function.

We can see the same thing in the privacy system logic as well; Privacy system (some critical code, some not):

- Critical code is here: https://github.com/Railgun-Privacy/contract/tree/master/contracts/logic

- Non critical code is here: https://github.com/Railgun-Privacy/contract/tree/master/contracts/adapt/relay

The critical core contract code only handles storage and movement of funds within private balances. DeFi interactions are segmented in their own adapt contracts. These adapt contracts have very limited access to user funds. At any given moment, an adapt contract only has funds in it for the duration of a single transaction before yielding control back to the core contract on completion. This means the only “at risk” funds are what’s being transacted by the adapt contract at any given time and the exposure length can even be shorter than an individual block.

This has two key effects: The core contract code is simplified for minimal attack surface, which is important as user funds are stored here. Less critical code is in a separate adapt contract so more complex logic can be implemented here and exploits in this code will not have access to user funds.

So what’s the tl;dr here?

Developers should strive to build systems that are both simplistic and compartmentalized to minimize attack surfaces across their code. This improves overall security and minimizes attack vectors not only to live code but also enhances upgradeability if/when fixes need to be implemented.

--

--

RAILGUN Project

Framework for ZK Privacy on EVM blockchains. Send transactions and interact with DeFi on Ethereum, Polygon, Arbitrum, and BSC privately. https://railgun.org