Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deploy Garble Guide using Mdbook to GH Pages #158

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Mdbook Pages
on:
push:
branches:
- mdbook

jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: write # To push a branch
pages: write # To push to a GitHub Pages site
id-token: write # To update the deployment status
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install latest mdbook
run: |
tag=$(curl 'https://api.github.com/repos/rust-lang/mdbook/releases/latest' | jq -r '.tag_name')
url="https://github.com/rust-lang/mdbook/releases/download/${tag}/mdbook-${tag}-x86_64-unknown-linux-gnu.tar.gz"
mkdir mdbook
curl -sSL $url | tar -xz --directory=./mdbook
echo `pwd`/mdbook >> $GITHUB_PATH
- name: Build Book
run: |
cd garble_docs && mdbook build
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: "garble_docs/book"
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
42 changes: 4 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
# Garble Language
# The Garble Programming Language

Garble is a simple programming language for [Secure Multi-Party Computation](https://en.wikipedia.org/wiki/Secure_multi-party_computation) with [Garbled Circuits](https://en.wikipedia.org/wiki/Garbled_circuit). The circuits generated by Garble specify a _function_, with each input coming from a different party and the output computed collaboratively by all parties in a way that no party learns another party's input. Garble is statically typed, low-level, purely functional and uses a syntax heavily inspired by Rust.

All programs written in Garble are deliberately Turing-incomplete (only supporting bounded recursion), guaranteeing that they can be compiled to circuits using only `AND`, `XOR` and `NOT` gates (without any kind of stateful latches or registers). Here's an example of solving the [Millionaire's Problem](https://en.wikipedia.org/wiki/Yao%27s_Millionaires%27_problem) in Garble:
Garble is a simple programming language for [**Multi-Party Computation**](https://en.wikipedia.org/wiki/Secure_multi-party_computation). Garble programs are **compiled to Boolean circuits** and always terminate, making them ideal for [**Garbled Circuits**](https://en.wikipedia.org/wiki/Garbled_circuit). Garble is **statically typed, low-level, purely functional** and uses a **Rust-like syntax**. Garble is much simpler than Rust though, making it easy to learn and simple to [integrate](https://sine-fdn.github.io/garble-lang/integration.html) into MPC engines.

```rust
// A function for solving Yao's Millionaires' problem:
// A program for solving Yao's Millionaires' problem in Garble:

enum Richest {
IsA,
Expand All @@ -24,36 +22,4 @@ pub fn main(a: u64, b: u64) -> Richest {
}
```

For more examples, see the [Language Tour](language_tour.md).

## How to Use Garble

The circuits generated by Garble are meant to be executed using a cryptographically secure MPC engine, which is not provided by this crate. Garble is agnostic about the details of the MPC engine and assumes only that the engine executes Garbled Circuits with support for `AND`, `XOR` and `NOT` gates. For local development and testing, Garble supports a direct and unencrypted evaluation of a generated circuit, with all inputs supplied by the local user.

To execute the Millionaire's problem example, first install the `garble` utility, checkout the repository to get the example programs, then run the function inside the repository directory:

```sh
$ cargo install garble_lang --features="bin"
$ git clone [email protected]:sine-fdn/garble-lang.git
$ cd garble-lang
$ garble run garble_examples/millionaires.garble.rs --function=main 10000000 10000
Richest::IsA
$ garble run garble_examples/millionaires.garble.rs --function=main 100 5000000
Richest::IsB
$ garble run garble_examples/millionaires.garble.rs --function=main 1000 1000
Richest::Tie
```

You can also type-check a program without running it by using `garble check` followed by the file name.

You might need to wrap input or metadata in single quotes if they contain whitespace.

## Architecture of this Repository

The Garble compiler is relatively straightforward and turns a program `&str` into a `circuit::Circuit` (or aborts with a scan/parse/type error). The different steps and their modules are as follows (with steps 1-4 happening during compile time, step 5 during run time):

1. [`scan.rs`](src/scan.rs) splits a program `&str` into a `token::Token` sequence.
2. [`parse.rs`](src/parse.rs) parses a `token::Token` sequence into an untyped `ast::Program`.
3. [`check.rs`](src/check.rs) type-checks an untyped `ast::Program`, returning a typed `ast::Program`.
4. [`compile.rs`](src/compile.rs) converts a well-typed `ast::Program` into a `circuit::Circuit`.
5. [`eval.rs`](src/eval.rs) executes a `circuit::Circuit` with locally supplied inputs.
To learn more about Garble, check out the [website](https://sine-fdn.github.io/garble-lang).
29 changes: 29 additions & 0 deletions docs/pages/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
title: "Garble Language"
---

# Garble — A Language for Multi-Party Computation

Garble is a Turing-incomplete Programming Language for Multi-Party Computation (MPC) with Garbled Circuits. Garble can be compiled to Boolean (AND, XOR and NOT) gates and always terminates. Garble's syntax is a subset of Rust and all of its concepts will be familiar to Rust programmers. Garble is much simpler though, making it easy to learn and integrate into MPC engines.

Here's a taste of Garble:

```rust
// A function for solving Yao's Millionaires' problem:

enum Richest {
IsA,
IsB,
Tie,
}

pub fn main(a: u64, b: u64) -> Richest {
if a > b {
Richest::IsA
} else if b > a {
Richest::IsB
} else {
Richest::Tie
}
}
```
1 change: 1 addition & 0 deletions garble_docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
book
10 changes: 10 additions & 0 deletions garble_docs/book.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[book]
authors = ["Frederic Kettelhoit"]
language = "en"
multilingual = false
src = "src"
title = "The Garble Programming Language"
[output.html]
no-section-label = true
[output.html.playground]
runnable = false
14 changes: 14 additions & 0 deletions garble_docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Summary

- [What is Garble?](./landing.md)
- [A Guide to Garble](./guide/intro.md)
- [Installation](./guide/installation.md)
- [Functions](./guide/basics.md)
- [Variables and Mutability](./guide/variables.md)
- [Data Types](./guide/data_types.md)
- [If/Else and Pattern Matching](./guide/control_flow.md)
- [For Loops and For-Join Loops](./guide/loops.md)
- [Const Parameters](./guide/const.md)
- [Circuits and Termination](./guide/computational_model.md)
- [MPC Engine Integration](./integration.md)
- [Contributing](./contributing.md)
15 changes: 15 additions & 0 deletions garble_docs/src/contributing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Contributing

While Garble was developed by us at the [SINE Foundation](https://sine.foundation/) for the use in our MPC engine, we would love to see how you end up using Garble and are happy to accept pull requests. Garble is distributed under the MIT license and hosted on GitHub:

[![Github](github-mark.png "Contribute on Github")](https://github.com/sine-fdn/garble-lang)

The Garble compiler is relatively straightforward and turns a program `&str` into a `circuit::Circuit` (or aborts with a scan/parse/type error). The different steps and their modules are as follows (with steps 1-4 happening during compile time, step 5 is optional and happens during run time):

1. [`scan.rs`](https://github.com/sine-fdn/garble-lang/blob/main/src/scan.rs) splits a program `&str` into a [`token::Token`](https://github.com/sine-fdn/garble-lang/blob/main/src/token.rs) sequence.
2. [`parse.rs`](https://github.com/sine-fdn/garble-lang/blob/main/src/parse.rs) parses a [`token::Token`](https://github.com/sine-fdn/garble-lang/blob/main/src/token.rs) sequence into an untyped [`ast::Program`](https://github.com/sine-fdn/garble-lang/blob/main/src/ast.rs).
3. [`check.rs`](https://github.com/sine-fdn/garble-lang/blob/main/src/check.rs) type-checks an untyped [`ast::Program`](https://github.com/sine-fdn/garble-lang/blob/main/src/ast.rs), returning a typed [`ast::Program`](https://github.com/sine-fdn/garble-lang/blob/main/src/ast.rs).
4. [`compile.rs`](https://github.com/sine-fdn/garble-lang/blob/main/src/compile.rs) converts a well-typed [`ast::Program`](https://github.com/sine-fdn/garble-lang/blob/main/src/ast.rs) into a [`circuit::Circuit`](https://github.com/sine-fdn/garble-lang/blob/main/src/circuit.rs).
5. [`eval.rs`](https://github.com/sine-fdn/garble-lang/blob/main/src/eval.rs) executes a [`circuit::Circuit`](https://github.com/sine-fdn/garble-lang/blob/main/src/circuit.rs) with locally supplied inputs, not using any MPC or other privacy-preserving techniques.

You can also reach us at [[email protected]](mailto:[email protected]).
Binary file added garble_docs/src/github-mark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
71 changes: 71 additions & 0 deletions garble_docs/src/guide/basics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Functions

Garble programs are a collection of pure functions. There are no side effects such as printing output or doing any other form of IO. Functions that are meant to be invoked as the entry points of multi-party computations must be marked public by using the `pub` modifier. Non-`pub` top-level function definitions can be used to split the program into smaller chunks:

```rust
pub fn main(x: u16) -> u16 {
inc(x)
}

fn inc(x: u16) -> u16 {
add(x, 1)
}

fn add(x: u16, y: u16) -> u16 {
x + y
}
```

Garble will abort with an error if any of the non-`pub` defined functions are unused:

```
$ garble run garble_examples/error_examples/unused_fn.garble.rs --function=main 0
Type error on line 3:2.
Function 'inc' is declared but never used:

| pub fn main(x: u16) -> u16 {
| x + 1
3 > | }
> |
4 > |
> |
5 > | fn inc(x: u16) -> u16 {
> | ^^^^^^^^^^^^^^^^^^^^^^^
6 > | add(x, 1)
> | ^^^^^^^^^^^^^
7 > | }
> | ^
|
```

Garble panics if an error occurs, for example if an integer overflows during an addition:

```
$ garble run garble_examples/calculator.garble.rs --function=main '(200, 200)' Op::Add
Panic due to Overflow on line 17:43.

| pub fn main(values: (u8, u8), op: Op) -> OpResult {
| match (op, values) {
17 > | (Op::Add, (x, y)) => OpResult::Ok(x + y),
> | ^^^^^
| (Op::Sub, (x, y)) => OpResult::Ok(x - y),
```

Garble will also panic on integer overflows caused by other arithmetic operations (such as subtraction and multiplication), divisions by zero, and out-of-bounds array indexing.

> Circuit logic for panics is always compiled into the final circuit (and includes the line and column number of the code that caused the panic), **it is your responsibility to ensure that no sensitive information can be leaked by causing a panic**.

Just like Rust, Garble supports both `//` and (nested) `/* */` comments:

```rust
/*
fn unused_fn(x: ...) -> ... {
/* nested block comment */
// normal comment within block comment
}
*/
pub fn main(x: u16) -> u16 {
// comment including '/*'
x + /* ... */ 1
}
```
58 changes: 58 additions & 0 deletions garble_docs/src/guide/computational_model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Circuits and Termination

Garble programs are Boolean _circuits_ consisting of a graph of logic gates, not a sequentially executed program of instructions on a von Neumann architecture with main memory and CPU. This has deep consequences for the programming style that leads to efficient Garble programs, with programs that would be efficient in "normal" programming languages resulting in highly inefficient circuits and vice versa.

## Copying is Free

One example has already been mentioned: Copying whole arrays in Garble is essentially free, because arrays (and their elements) are just a collection of output wires from a bunch of Boolean logic gates. Duplicating these wires does not increase the complexity of the circuit, because no additional logic gates are required.

Replacing the element at a _constant_ index in an array with a new value is equally cheap, because the Garble compiler can just duplicate the output wires of all the other elements and only has to use the wires of the replacement element where previously the old element was being used. In contrast, replacing the element at a _non-constant_ index (i.e. an index that depends on a runtime value) is a much more expensive operation in a Boolean circuit than it would be on a normal computer, because the Garble compiler has to generate a nested multiplexer circuit.

The following program seems to do a lot of work, but is actually just re-arranging the bits in an array, turning each element from a tuple of three values into a nested tuple. Garble optimizes the actual loop away, resulting in a program with 0 AND gates:

```rust
pub fn main(arr1: [(u16, u16, u32); 8]) -> [((u16, u16), u32); 8] {
let mut arr2 = [((0u16, 0u16), 0u32); 8];
let mut i = 0usize;
for elem in arr1 {
let (a, b, c) = elem;
arr2[i] = ((a, b), c);
i = i + 1usize;
}
arr2
}
```

## Branching is Expensive

Here's an additional example: Let's assume that you want to implement an MPC function that on each invocation adds a value into a (fixed-size) collection of values, overwriting previous values if the buffer is full. In most languages, this could be easily done using a ring buffer and the same is possible in Garble:

```rust
pub fn main(mut arr: [u16; 500], i: usize, x: u16) -> [u16; 500] {
arr[i % 500] = x;
arr
}
```

However, Garble has no way of knowing that the above function is meant to implement a ring buffer and that the value of `i` will only be incremented in steps of 1 between each invocation. From the perspective of the compiler, the above code requires an array access at an arbitrary location, which requires the Garble compiler to generate a nested multiplexer circuit.

Instead of passing the parameter `i` as an input, we could also "shift" the whole array by 1 element, constructing a new array in the process. This would require a lot of copying in other languages, but is much more performant in Garble:

```rust
pub fn main(arr: [u16; 500], x: u16) -> [u16; 500] {
let mut arr2 = [0u16; 500];
arr2[0] = x;
for i in 1usize..500usize {
arr2[i] = arr[i - 1usize]
}
arr2
}
```

The difference in circuit size is extreme: While the first version (with `i` as an input parameter) is compiled to a circuit with more than 700,000 non-input gates, the second version (which shifts the entire array by one element) uses only 2 non-input gates (because the program is effectively a static transformation from input to output).

Such an example might be a bit contrived, since it is possible to infer the inputs of both parties (except for the element that is dropped from the array) from the output of the above function, defeating the purpose of MPC, which is to keep each party's input private. But it does highlight how unintuitive the computational model of pure Boolean circuits can be from the perspective of a load-and-store architecture with main memory and CPU.

## Garble's Computational Model

It can be helpful to think of Garble programs as being executed on a computer with infinite memory, free copying and no garbage collection: Nothing ever goes out of scope, it is therefore trivial to reuse old values. But any form of branching or looping needs to be compiled into a circuit where each possible branch or loop invocation is "unrolled" and requires its own dedicated logic gates. In normal programming languages, looping a few additional times does not increase the program size, but in Garble programs additional gates are necessary. The size of Garble programs therefore reflects the _worst case_ algorithm performance: While normal programming languages can return early and will often require much less time in the best or average case than in the worst case, the evaluation of Garble programs will always take constant time, because the full circuit must always be evaluated.
40 changes: 40 additions & 0 deletions garble_docs/src/guide/const.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Const Parameters

To be able to generate Boolean circuits, Garble programs cannot contain any data structures with a dynamic size, such as a list whose size is only known at run time. Instead, the size of all data structures needs to be known at compile time, which can be quite limiting in practice. For example, two parties might want to compare their data sets without knowing ahead of time how many records each data set contains.

To make this easier, Garble supports `const` parameters, whose size is not yet known while type-checking but will only later be supplied when the program is actually compiled. This makes it possible to develop and check Garble programs without knowing the size of these values in advance. Calling these parameters "constants" might be slightly confusing, because their value is left unspecified before compilation and allows Garble to simulate a restricted form of dynamism, but since Garble is syntactically a subset of Rust and the values are indeed constants during compilation, they are declared using the `const` keyword.

Garble supports Boolean and integer constants, which need to be declared at the top level:

```rust
const MY_CONST: usize = PARTY_0::MY_CONST;

pub fn main(x: u16) -> u16 {
let array = [2u16; MY_CONST];
x + array[1]
}
```

Garble also supports taking the `min()` / `max()` of several constants as part of the declaration of a constant, which, for instance, can be useful to set the size of a collection to the size of the biggest collection provided by different parties:

```rust
const MY_CONST: usize = min(PARTY_0::MY_CONST, PARTY_1::MY_CONST);

pub fn main(x: u16) -> u16 {
let array = [2; MY_CONST];
x + array[1]
}
```

```rust
const MY_CONST: usize = max(PARTY_0::MY_CONST, PARTY_1::MY_CONST);

pub fn main(x: u16) -> u16 {
let array = [2; MY_CONST];
x + array[1]
}
```

> Garble currently does not support type inference in const declarations, which is why you always have to use type suffixes even for simple number literals, e.g. use `2u16` instead of `2`.

Garble programs can be type checked without providing concrete values for the declared constants, but all const values must be provided during compilation, using [`garble_lang::compile_with_constants`](https://docs.rs/garble_lang/latest/garble_lang/fn.compile_with_constants.html). See [MPC Engine Integration](../integration.md) for more details.
Loading
Loading