leo/README.md

386 lines
7.4 KiB
Markdown
Raw Normal View History

2020-04-24 03:43:58 +03:00
# The Leo Language
2020-05-05 02:52:32 +03:00
* All code examples can be copied and pasted into `main.leo` directly and executed with cargo run
2020-04-24 03:43:58 +03:00
* Programs should be formatted:
1. Import definitions
2020-05-05 02:52:32 +03:00
2. Struct definitions
2020-04-24 03:43:58 +03:00
3. Function definitions
### Integers:
Currently, all integers are parsed as u32.
You can choose to explicitly add the type or let the compiler interpret implicitly.
```rust
2020-05-05 02:52:32 +03:00
function main() -> u32 {
2020-05-09 02:39:14 +03:00
let a: u32 = 1u32 + 1u32; // explicit type
2020-05-05 02:52:32 +03:00
let b = 1 - 1; // implicit type
let c = 2 * 2;
let d = 4 / 2;
let e = 2 ** 3;
2020-04-24 03:43:58 +03:00
return a
}
```
### Field Elements:
Field elements must have the type added explicitly.
```rust
2020-05-05 02:52:32 +03:00
function main() -> fe {
2020-05-09 02:39:14 +03:00
let f: fe = 21888242871839275222246405745257275088548364400416034343698204186575808495617fe;
2020-05-05 02:52:32 +03:00
let a = 1fe + 1fe;
let b = 1fe - 1fe;
let c = 2fe * 2fe;
let d = 4fe / 2fe;
2020-04-24 03:43:58 +03:00
return a
}
```
2020-05-05 02:52:32 +03:00
### Operator Assignment Statements:
```rust
function main() -> u32 {
let a = 10;
a += 5;
a -= 10;
a *= 5;
a /= 5;
a **= 2;
return a
}
```
2020-04-24 03:43:58 +03:00
### Booleans:
```rust
2020-05-05 02:52:32 +03:00
function main() -> bool {
2020-05-09 02:39:14 +03:00
let a: bool = true || false;
2020-05-05 02:52:32 +03:00
let b = false && false;
let c = 1 == 1;
2020-04-24 03:43:58 +03:00
return a
}
```
### Arrays:
Leo supports static arrays with fixed length.
Array type must be explicitly stated
```rust
2020-05-05 02:52:32 +03:00
function main() -> u32[2] {
2020-04-24 03:43:58 +03:00
// initialize an integer array with integer values
2020-05-09 02:39:14 +03:00
let a: u32[3] = [1, 2, 3];
2020-04-24 03:43:58 +03:00
// set a member to a value
2020-05-05 02:52:32 +03:00
a[2] = 4;
2020-04-24 03:43:58 +03:00
// initialize an array of 4 values all equal to 42
2020-05-05 02:52:32 +03:00
let b = [42; 4];
2020-04-24 03:43:58 +03:00
// initialize an array of 5 values copying all elements of b using a spread
2020-05-05 02:52:32 +03:00
let c = [1, ...b];
2020-04-24 03:43:58 +03:00
// initialize an array copying a slice from `c`
2020-05-05 02:52:32 +03:00
let d = c[1..3];
2020-04-24 03:43:58 +03:00
// initialize a field array
2020-05-05 02:52:32 +03:00
let e = [5fe; 2];
2020-04-24 03:43:58 +03:00
// initialize a boolean array
2020-05-05 02:52:32 +03:00
let f = [true, false || true, true];
2020-04-24 03:43:58 +03:00
// return an array
return d
}
```
### Structs:
```rust
struct Point {
2020-05-09 02:39:14 +03:00
x: u32
y: u32
2020-04-24 03:43:58 +03:00
}
2020-05-05 02:52:32 +03:00
function main() -> u32 {
2020-04-24 03:43:58 +03:00
Point p = Point {x: 1, y: 0}
return p.x
}
```
```rust
struct Foo {
2020-05-09 02:39:14 +03:00
x: bool
2020-04-24 03:43:58 +03:00
}
2020-05-05 02:52:32 +03:00
function main() -> Foo {
let f = Foo {x: true};
f.x = false;
2020-04-24 03:43:58 +03:00
return f
}
```
2020-05-05 02:52:32 +03:00
### Assert Equals:
This will enforce that the two values are equal in the constraint system.
```rust
function main() {
assert_eq(45, 45);
assert_eq(2fe, 2fe);
assert_eq(true, true);
}
```
2020-04-24 03:43:58 +03:00
### Conditionals:
2020-05-05 02:52:32 +03:00
#### If Else Ternary Expression
2020-04-24 03:43:58 +03:00
```rust
2020-05-05 02:52:32 +03:00
function main() -> u32 {
let y = if 3==3 ? 1 : 5;
2020-04-24 03:43:58 +03:00
return y
}
```
2020-05-05 02:52:32 +03:00
#### If Else Conditional Statement
2020-04-24 03:43:58 +03:00
```rust
2020-05-05 02:52:32 +03:00
function main(a: private bool, b: private bool) -> u32 {
let res = 0;
if (a) {
res = 1;
} else if (b) {
res = 2;
} else {
res = 3;
}
return res
}
```
#### For loop
```rust
function main() -> fe {
let a = 1fe;
for i in 0..4 {
a = a + 1fe;
}
2020-04-24 03:43:58 +03:00
return a
}
```
### Functions:
```rust
2020-05-05 02:52:32 +03:00
function test1(a : u32) -> u32 {
return a + 1
2020-04-24 03:43:58 +03:00
}
2020-05-05 02:52:32 +03:00
function test2(b: fe) -> fe {
return b * 2fe
2020-04-24 03:43:58 +03:00
}
2020-05-05 02:52:32 +03:00
function test3(c: bool) -> bool {
2020-04-24 03:43:58 +03:00
return c && true
}
2020-05-05 02:52:32 +03:00
function main() -> u32 {
2020-04-24 03:43:58 +03:00
return test1(5)
}
```
#### Function Scope:
```rust
2020-05-05 02:52:32 +03:00
function foo() -> field {
// return myGlobal <- not allowed
return 42fe
}
function main() -> field {
let myGlobal = 42fe;
return foo()
}
```
#### Multiple returns:
Functions can return tuples whose types are specified in the function signature.
```rust
function test() -> (u32, u32[2]) {
return 1, [2, 3]
2020-04-24 03:43:58 +03:00
}
2020-05-05 02:52:32 +03:00
function main() -> u32[3] {
let (a, b) = test();
2020-05-09 02:39:14 +03:00
// (a, u32[2] b) = test() <- explicit type also works
2020-05-05 02:52:32 +03:00
return [a, ...b]
2020-04-24 03:43:58 +03:00
}
```
2020-05-09 02:39:14 +03:00
#### Main function inputs:
Main function inputs are allocated as public or private variables in the program's constaint system.
2020-04-24 03:43:58 +03:00
```rust
2020-05-05 02:52:32 +03:00
function main(a: private fe) -> fe {
2020-04-24 03:43:58 +03:00
return a
}
```
```rust
2020-05-05 02:52:32 +03:00
function main(a: public fe) -> fe {
2020-04-24 03:43:58 +03:00
return a
}
```
2020-05-09 02:39:14 +03:00
Function inputs are passed by value.
2020-05-05 02:52:32 +03:00
```rust
function test(a: u32) {
a = 0;
}
function main() -> u32 {
let a = 1;
test(a);
return a // <- returns 1
}
```
2020-04-24 03:43:58 +03:00
### Imports:
2020-05-05 02:52:32 +03:00
Both struct and function imports are supported.
import all: `*`
import alias: `symbol as alias`
2020-04-24 03:43:58 +03:00
/simple_import.leo
```rust
struct Point {
2020-05-09 02:39:14 +03:00
x: u32
y: u32
2020-04-24 03:43:58 +03:00
}
2020-05-05 02:52:32 +03:00
function test() -> (u32, u32[2]) {
return 1, [2, 3]
}
2020-04-24 03:43:58 +03:00
```
/simple.leo
```rust
2020-05-05 02:52:32 +03:00
from "./simple_import" import {
Point as Foo,
test
};
// from "./simple_import" import *
2020-04-24 03:43:58 +03:00
2020-05-05 02:52:32 +03:00
function main() -> (u32[3]) {
let p = Foo { x: 1, y: 2};
2020-05-09 02:39:14 +03:00
let (a, b) = test();
2020-05-05 02:52:32 +03:00
return [a, ...b]
2020-04-24 03:43:58 +03:00
}
```
2020-05-05 02:52:32 +03:00
2020-04-24 03:43:58 +03:00
# Leo CLI
## Develop
2020-05-05 02:52:32 +03:00
### `leo new`
To setup a new package, run:
```
leo new {$NAME}
```
This will create a new directory with a given package name. The new package will have a directory structure as follows:
```
- inputs # Your program inputs
- outputs # Your program outputs
- src
- lib.leo # Your program library
- main.leo # Your program
- tests
- tests.leo # Your program tests
- Leo.toml # Your program manifest
```
### `leo init`
To initialize an existing directory, run:
```
leo init
```
This will initialize the current directory with the same package directory setup.
### `leo build`
2020-04-24 03:43:58 +03:00
To compile your program and verify that it builds properly, run:
```
leo build
```
2020-05-05 02:52:32 +03:00
### `leo test`
2020-04-24 03:43:58 +03:00
To execute unit tests on your program, run:
```
leo test
```
## Run
2020-05-05 02:52:32 +03:00
### `leo setup`
2020-04-24 03:43:58 +03:00
To perform the program setup, producing a proving key and verification key, run:
```
leo setup
```
Leo uses cryptographic randomness from your machine to perform the setup. The proving key and verification key are stored in the `target` directory as `.leo.pk` and `.leo.vk`:
```
{$LIBRARY}/target/{$PROGRAM}.leo.pk
{$LIBRARY}/target/{$PROGRAM}.leo.vk
```
2020-05-05 02:52:32 +03:00
### `leo prove`
2020-04-24 03:43:58 +03:00
To execute the program and produce an execution proof, run:
```
leo prove
```
Leo starts by checking the `target` directory for an existing `.leo.pk` file. If it doesn't exist, it will proceed to run `leo setup` and then continue.
Once again, Leo uses cryptographic randomness from your machine to produce the proof. The proof is stored in the `target` directory as `.leo.proof`:
```
{$LIBRARY}/target/{$PROGRAM}.leo.proof
```
2020-05-05 02:52:32 +03:00
### `leo verify`
2020-04-24 03:43:58 +03:00
To verify the program proof, run:
```
leo verify
```
Leo starts by checking the `target` directory for an existing `.leo.proof` file. If it doesn't exist, it will proceed to run `leo prove` and then continue.
After the verifier is run, Leo will output either `true` or `false` based on the verification.
## Remote
To use remote compilation features, start by authentication with:
```
leo login
```
You will proceed to authenticate using your username and password. Next, Leo will parse your `Leo.toml` file for `remote = True` to confirm whether remote compilation is enabled.
If remote compilation is enabled, Leo syncs your workspace so when you run `leo build`, `leo test`, `leo setup` and `leo prove`, your program will run the program setup and execution performantly on remote machines.
This speeds up the testing cycle and helps the developer to iterate significantly faster.
## Publish
To package your program as a gadget and publish it online, run:
```
leo publish
```
Leo will proceed to snapshot your directory and upload your directory to the circuit manager. Leo will verify that `leo build` succeeds and that `leo test` passes without error.
If your gadget name has already been taken, `leo publish` will fail.
## Deploy
2020-05-05 02:52:32 +03:00
To deploy your program to Aleo, run:
2020-04-24 03:43:58 +03:00
```
leo deploy
```
## TODO
- Change `target` directory to some other directory to avoid collision.
- Figure out how `leo prove` should take in assignments.
- Come up with a serialization format for `.leo.pk`, `.leo.vk`, and `.leo.proof`.