Skip to content

Commit

Permalink
Merge pull request #448 from Zokrates/structs
Browse files Browse the repository at this point in the history
Implement structures
  • Loading branch information
Schaeff authored Oct 7, 2019
2 parents 595866e + 6517702 commit 8abf996
Show file tree
Hide file tree
Showing 38 changed files with 4,734 additions and 1,272 deletions.
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ jobs:
- restore_cache:
keys:
- v4-cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }}
- run:
name: Check format
command: rustup component add rustfmt-preview; cargo fmt --all -- --check
# - run:
# name: Check format
# command: rustup component add rustfmt; cargo fmt --all -- --check
- run:
name: Install libsnark prerequisites
command: ./scripts/install_libsnark_prerequisites.sh
Expand Down
57 changes: 48 additions & 9 deletions zokrates_book/src/concepts/imports.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,66 @@
## Imports

You can separate your code into multiple ZoKrates files using `import` statements, ignoring the `.zok` extension of the imported file:
You can separate your code into multiple ZoKrates files using `import` statements to import symbols, ignoring the `.zok` extension of the imported file.

### Import syntax

#### Symbol selection

The preferred way to import a symbol is by module and name:
```zokrates
from "./path/to/my/module" import MySymbol
// `MySymbol` is now in scope.
```

#### Aliasing

The `as` keyword enables renaming symbols:

```zokrates
from "./path/to/my/module" import MySymbol as MyAlias
// `MySymbol` is now in scope under the alias MyAlias.
```
#### Legacy

The legacy way to import a symbol is by only specifying a module:
```
import "./path/to/my/module"
```
In this case, the name of the symbol is assumed to be `main` and the alias is assumed to be the module's filename so that the above is equivalent to
```zokrates
from "./path/to/my/module" import main as module
// `main` is now in scope under the alias `module`.
```

Note that this legacy method is likely to be become deprecated, so it is recommended to use the preferred way instead.
### Symbols

Two type of symbols can be imported

#### Functions
Functions are imported by name. If many functions have the same name but different signatures, all of them get imported, and which one to use in a particular call is infered.

#### User-defined types
User-defined types declared with the `struct` keyword are imported by name.

### Relative Imports

You can import a resource in the same folder directly, like this:
```zokrates
import "./mycode"
from "./mycode" import foo
```

There also is a handy syntax to import from the parent directory:
```zokrates
import "../mycode"
from "../mycode" import foo
```

Also imports further up the file-system are supported:
```zokrates
import "../../../mycode"
```

You can also choose to rename the imported resource, like so:
```zokrates
import "./mycode" as abc
from "../../../mycode" import foo
```

### Absolute Imports
Expand Down
68 changes: 54 additions & 14 deletions zokrates_book/src/concepts/types.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
## Types
# Types

ZoKrates currently exposes two primitive types and a complex array type:
ZoKrates currently exposes two primitive types and two complex types:

### Primitive Types
## Primitive Types

#### `field`
### `field`

This is the most basic type in ZoKrates, and it represents a positive integer in `[0, p - 1]` where `p` is a (large) prime number.

Expand All @@ -16,17 +16,19 @@ While `field` values mostly behave like unsigned integers, one should keep in mi
{{#include ../../../zokrates_cli/examples/book/field_overflow.zok}}
```

#### `bool`
### `bool`

ZoKrates has limited support for booleans, to the extent that they can only be used as the condition in `if ... else ... endif` expressions.

You can use them for equality checks, inequality checks and inequality checks between `field` values.

Note that while equality checks are cheap, inequality checks should be use wisely as they are orders of magnitude more expensive.

### Complex Types
## Complex Types

#### Arrays
ZoKrates provides two complex types, Arrays and Structs.

### Arrays

ZoKrates supports static arrays, i.e., their length needs to be known at compile time.
Arrays can contain elements of any type and have arbitrary dimensions.
Expand All @@ -37,10 +39,10 @@ The following examples code shows examples of how to use arrays:
{{#include ../../../zokrates_cli/examples/book/array.zok}}
```

##### Declaration and Initialization
#### Declaration and Initialization
An array is defined by appending `[]` to a type literal representing the type of the array's elements.

Initialization always needs to happen in the same statement than declaration, unless the array is declared within a function's signature.
Initialization always needs to happen in the same statement as declaration, unless the array is declared within a function's signature.

For initialization, a list of comma-separated values is provided within brackets `[]`.

Expand All @@ -54,7 +56,7 @@ The following code provides examples for declaration and initialization:
bool[13] b = [false; 13] // initialize a bool array with value false
```

##### Multidimensional Arrays
#### Multidimensional Arrays

As an array can contain any type of elements, it can contain arrays again.
There is a special syntax to declare such multi-dimensional arrays, i.e., arrays of arrays.
Expand All @@ -67,21 +69,59 @@ Consider the following example:
{{#include ../../../zokrates_cli/examples/book/multidim_array.zok}}
```

##### Spreads and Slices
#### Spreads and Slices
ZoKrates provides some syntactic sugar to retrieve subsets of arrays.

###### Spreads
The spread operator `...` applied to an copies the elements of an existing array.
##### Spreads
The spread operator `...` applied to an array copies the elements of the existing array.
This can be used to conveniently compose new arrays, as shown in the following example:
```
field[3] = [1, 2, 3]
field[4] c = [...a, 4] // initialize an array copying values from `a`, followed by 4
```

###### Slices
##### Slices
An array can also be assigned to by creating a copy of a subset of an existing array.
This operation is called slicing, and the following example shows how to slice in ZoKrates:
```
field[3] a = [1, 2, 3]
field[2] b = a[1..3] // initialize an array copying a slice from `a`
```

### Structs
A struct is a composite datatype representing a named collection of variables.
The contained variables can be of any type.

The following code shows an example of how to use structs.

```zokrates
{{#include ../../../zokrates_cli/examples/book/structs.code}}
```

#### Definition
Before a struct data type can be used, it needs to be defined.
A struct definition starts with the `struct` keyword followed by a name. Afterwards, a new-line separated list of variables is declared in curly braces `{}`. For example:

```zokrates
struct Point {
field x
field y
}
```

#### Declaration and Initialization

Initialization of a variable of a struct type always needs to happen in the same statement as declaration, unless the struct-typed variable is declared within a function's signature.

The following example shows declaration and initialization of a variable of the `Point` struct type:

```zokrates
{{#include ../../../zokrates_cli/examples/book/struct_init.code}}
```

#### Assignment
The variables within a struct instance, the so called members, can be accessed through the `.` operator as shown in the following extended example:

```zokrates
{{#include ../../../zokrates_cli/examples/book/struct_assign.code}}
```
10 changes: 10 additions & 0 deletions zokrates_cli/examples/book/struct_assign.code
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
struct Point {
field x
field y
}

def main(field a) -> (Point):
Point p = Point {x: 1, y: 0}
p.x = a
p.y = p.x
return p
8 changes: 8 additions & 0 deletions zokrates_cli/examples/book/struct_init.code
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
struct Point {
field x
field y
}

def main() -> (Point):
Point p = Point {x: 1, y: 0}
return p
14 changes: 14 additions & 0 deletions zokrates_cli/examples/book/structs.code
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
struct Bar {
field[2] c
bool d
}

struct Foo {
Bar a
bool b
}

def main() -> (Foo):
Foo[2] f = [Foo { a: Bar { c: [0, 0], d: false }, b: true}, Foo { a: Bar {c: [0, 0], d: false}, b: true}]
f[0].a.c = [42, 43]
return f[0]
16 changes: 16 additions & 0 deletions zokrates_cli/examples/structs/add.code
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
struct Point {
field x
field y
}

def main(Point p, Point q) -> (Point):

field a = 42
field d = 21

field dpxpyqxqy = d * p.x * p.y * q.x * q.y

return Point {
x: (p.x * q.y + q.x * p.y) / (1 + dpxpyqxqy),
y: (q.x * q.y - a * p.x * p.y) / (1 - dpxpyqxqy)
}
29 changes: 29 additions & 0 deletions zokrates_cli/examples/structs/set_member.code
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
struct Bar {
field[2] c
bool d
}

struct Foo {
Bar a
bool b
}

def main() -> (Foo):
Foo[2] f = [
Foo {
a: Bar {
c: [0, 0],
d: false
},
b: true
},
Foo {
a: Bar {
c: [0, 0],
d: false
},
b: true
}
]
f[0].a.c = [42, 43]
return f[0]
Loading

0 comments on commit 8abf996

Please sign in to comment.