Skip to content

Commit c9319c8

Browse files
committed
Add docs in language tour for for-each-join loop
1 parent 3621b76 commit c9319c8

File tree

1 file changed

+33
-0
lines changed

1 file changed

+33
-0
lines changed

language_tour.md

+33
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,39 @@ The patterns are not exhaustive. Missing cases:
366366
| }
367367
```
368368
369+
### For-Each-Join Loops
370+
371+
Garble has special support for joining together two sorted arrays of tuples, by comparing their first field for equality, which can be useful to combine two data sources coming from different parties similar to a JOIN in SQL. Syntactically for-each-join loops are a special case of for-each loops, using a `join` function instead of an array:
372+
373+
```rust
374+
let rows1 = [(0u8, 10u16), (1u8, 11u16), (2u8, 12u16)];
375+
let rows2 = [(0u8, 5u32, 5u32), (2u8, 6u32, 6u32)];
376+
// The arrays rows1 and rows2 will be joined based on their first field, which is of type u8.
377+
// The tuple (1u8, 11u16) from rows1 is discarded because it cannot be joined with rows2.
378+
for joined in join(rows1, rows2) {
379+
let ((id1, x), (id2, y, z)) = joined;
380+
// ...
381+
}
382+
```
383+
384+
Garble automatically joins the arrays in a for-each-join loop using a [bitonic sorting network](https://en.wikipedia.org/wiki/Bitonic_sorter), more concretely implementing the paper [Private Set Intersection:
385+
Are Garbled Circuits Better than Custom Protocols?](https://www.ndss-symposium.org/wp-content/uploads/2017/09/06_4.pdf), which has a circuit complexity of `(m + n) * log(m + n)` instead of `m * n` which would result from joining the arrays using nested loops. **The arrays that are joined in the loop must be sorted**, otherwise elements might be discarded or invalid data returned.
386+
387+
For-each-join loops always join two arrays based on the first field. If you would like to compare more than one field for equality, the easiest way is to transform the sorted array so that the relevant fields are grouped together in a tuple and thus form the first field. Such a transformation will be completely optimized away by the Garble compiler, such as in the following example, which groups together the first two fields, compiled to a circuit with 0 gates:
388+
389+
```rust
390+
pub fn main(arr1: [(u16, u16, u32); 8]) -> [((u16, u16), u32); 8] {
391+
let mut arr2 = [((0u16, 0u16), 0u32); 8];
392+
let mut i = 0usize;
393+
for elem in arr1 {
394+
let (a, b, c) = elem;
395+
arr2[i] = ((a, b), c);
396+
i = i + 1usize;
397+
}
398+
arr2
399+
}
400+
```
401+
369402
### Constants
370403
371404
Garble supports boolean and integer constants, which need to be declared at the top level and must be provided before compilation. This can be helpful for modelling "pseudo-dynamic" collections, i.e. collections whose size is not known during type-checking but will be known before compilation and execution:

0 commit comments

Comments
 (0)