Giter VIP home page Giter VIP logo

leo's Introduction

The Leo Programming Language

Leo is a functional, statically-typed programming language built for writing private applications.

Table of Contents

๐ŸŽ Overview

Welcome to the Leo programming language.

Leo provides a high-level language that abstracts low-level cryptographic concepts and makes it easy to integrate private applications into your stack. Leo compiles to circuits making zero-knowledge proofs practical.

The syntax of Leo is influenced by traditional programming languages like JavaScript, Scala, and Rust, with a strong emphasis on readability and ease-of-use. Leo offers developers with tools to sanity check circuits including unit tests, integration tests, and console functions.

Leo is one part of a greater ecosystem for building private applications on Aleo. The language is currently in an alpha stage and is subject to breaking changes.

โš™๏ธ๏ธ Build Guide

๐Ÿฆ€ Install Rust

We recommend installing Rust using rustup. You can install rustup as follows:

  • macOS or Linux:

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  • Windows (64-bit):

    Download the Windows 64-bit executable and follow the on-screen instructions.

  • Windows (32-bit):

    Download the Windows 32-bit executable and follow the on-screen instructions.

๐Ÿ™ Build from Source Code

We recommend installing Leo by building from the source code as follows:

# Download the source code
git clone https://github.com/AleoHQ/leo
cd leo

# Install 'leo'
$ cargo install --path .

Now to use leo, in your terminal, run:

leo

๐Ÿฆ Update from Leo

You can update Leo to the latest version using the following command:

leo update

Now to check the version of leo, in your terminal, run:

leo --version

๐Ÿ“ฆ Download using Cargo

You can also install Leo directly from crates.io using cargo:

cargo install leo-lang

Now to use leo, in your terminal, run:

leo

๐Ÿš€ Quick Start

Use the Leo CLI to create a new project

# create a new `hello-world` Leo project
leo new helloworld
cd helloworld

# build & setup & prove & verify
leo run main 0u32 1u32

The leo new command creates a new Leo project with a given name.

The leo run command will compile the program into Aleo instructions and run it.

Congratulations! You've just run your first Leo program.

๐Ÿงฐ Troubleshooting

If you are having trouble installing and using Leo, please check out our guide.

If the issue still persists, please open an issue.

๐Ÿ“– Documentation

๐Ÿค Contributing

Please see our guidelines in the developer documentation

โค๏ธ Contributors

View all Leo contributors here.

๐Ÿ›ก๏ธ License

License: GPL v3

๐Ÿ”ผ Back to top

leo's People

Contributors

0rphon avatar acoglio avatar actions-user avatar aharshbe avatar bendyarm avatar bors[bot] avatar centril avatar christianwwwwwwww avatar collinc97 avatar d0cd avatar damirka avatar davidcardenasus avatar dependabot-preview[bot] avatar dependabot[bot] avatar evan-schott avatar franfiuba avatar gluax avatar hackmd-deploy avatar halimao avatar howardwu avatar huitseeker avatar isvforall avatar ljedrz avatar protryon avatar raychu86 avatar tom-originstorage avatar tudorpintea999 avatar vuittont60 avatar weikengchen avatar yuliyu123 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

leo's Issues

Update file extension name formats

To simplify file types, I propose the following file formats to transition to.

{package_name}.leo.pk -> {package_name}.lpk
{package_name}.leo.vk -> {package_name}.lvk
{package_name}.leo.proof -> {package_name}.proof
{package_name}.leo.checksum -> {package_name}.sum

In addition, inputs will be changed as follows:

inputs.leo -> {package_name}.in

[Bug] 1 != 1 and 0 != 0

๐Ÿ› Describe the Bug

Integer variable != integer value

Steps to Reproduce

Code snippet to reproduce

function mean(inputs: u32[10]) -> u32 {
    let mut output = 0u32;
    for i in 0..10 {
        output += inputs[i];
    }
    return output/10
}

function calculate_coefficients(y_array: u32[10], x_array: u32[10]) -> (u32, u32) {
    let x_mean = mean(x_array);
    let y_mean = mean(y_array);

    let mut numerator = 0u32;
    let mut denominator = 0u32;

    for i in 0..10 {
        numerator += (x_array[i] - x_mean) * (y_array[i] - y_mean);
        denominator += (x_array[i] - x_mean) ** 2;
    }

    let b1 = numerator / denominator;
    let b0 = y_mean - (b1 * x_mean);

    return (b1, b0)
}

// 1 != 1, and 0 != 0
test function test_calculate_coefficients() {
    let x_array: u32[10] = [0,1,2,3,4,5,6,7,8,9];
    let y_array: u32[10] = [0,1,2,3,4,5,6,7,8,9];

    print!("{}", x_array);
    print!("{}", y_array);

    let (b1, b0) = calculate_coefficients(y_array, x_array);

    assert_eq!(b1, 1);
    assert_eq!(b0, 0);
}

Clear Error Syntax

Refactor all errors to follow the following example:

leo error: expected `;` found `EOF`
--> src/main.leo:3:19
   |
 3 |     let a: u32 = 1โŠ
   |                   ^---
   |
 = expected `;`
leo error: could not compile src/main.leo

Field element to decimal conversion

The field tests for leo in compiler/tests/field do not test the full length of field elements.

Leo will parse a number in decimal format into a field element. However, there is currently no way to convert a field element into decimal format.

This makes it difficult to test because we can generate random field elements but cannot pass them into the Leo compiler.

A conversion between the field element's BigInteger format into decimal is needed to resolve this issue.

Refactor compiler modules

Issue Overview:

The leo-compiler directory structure is a mess after adding several individual features. It should be simplified to improve readability and further development.

Current directory structure

leo
|- compiler/
    |- src/
        |- address/
        |- constraints/
            |- definitions/
            |- mod.rs
            |- boolean.rs
            |- comparator.rs
            |- expression.rs
            |- field.rs
            |- function.rs
            |- generate_constraints.rs
            |- group.rs
            |- integer.rs
            |- program.rs
            |- statement.rs
            |- value.rs
        |- errors/
        |- field/
        |- group/
        |- imports/
        |- compiler.rs
        |- lib.rs
    |- tests/
    |- Cargo.toml
    |- README.md

New directory structure

leo
|- compiler/
    |- src/
        |- constraints/
            |- generate_constraints.rs
        |- definition/
        |- errors/
        |- expression/
        |- function/
        |- import/
        |- program/
        |- statement/
        |- value/
            |- address/
            |- boolean/
            |- field/
            |- group/
            |- integer/
            |- comparator.rs
            |- value.rs
        |- compiler.rs
        |- lib.rs
    |- tests/
    |- Cargo.toml
    |- README.md

All files in the previous structure will be moved into a module folder with the same name where appropriate.
Files with conflicting names will be renamed according to their function within the new module.

explicit tuple types

Currently assigning multiple returns from a function:

let (a, b) = double();

With explicit types:

let (u32 a, u32 b) = double();

The explicit type assignment should be changed to:

let (a, b): (u32, u32) = double();

Refactor FieldElement enum -> FieldType module

Issue Scope

Currently the FieldElement enum does not take advantage of FpGadget and directly holds the value and variable for an allocated field.

https://github.com/AleoHQ/leo/blob/dfcf2d3dbded4695c786039c819c2a106b394b73/compiler/src/types.rs#L61

As a result, the following gadgets need to be manually implemented: AllocGadget, EqGadget, ConditionalEqGadget, CondSelectGadget, ToBitsGadget, ToBytesGadget
In addition, relying on Field as a trait parameter in types.rs bloats the code significantly. We can optimize by passing the string down to a FieldType module. Similar to the changes from #37

Proposed Changes

FieldElement will be refactored to Field which will contain a string in /compiler/src/types.rs.
A new FieldType module will be defined at /compiler/src/field.

pub enum FieldType<F: Field + PrimeField> {
  Constant(F),
  Allocated(FpGadget<F>),
}

The FieldType module will implement the following methods: constant(), add(), sub(), mul(), div(), pow().

and traits: AllocGadget, EqGadget, ConditionalEqGadget, CondSelectGadget, ToBitsGadget, ToBytesGadget.

Refactor GroupElement enum -> GroupType module

Issue Scope

Currently the GroupElement enum holds only constant values that implement the Group trait.
https://github.com/AleoHQ/leo/blob/dfcf2d3dbded4695c786039c819c2a106b394b73/compiler/src/constraints/value.rs#L27
Relying on the Group trait in SnarkOS does not add enough generality for multiple curves in leo. The trait also does not provide enough functionality to create, allocate, and operate on affine points in the leo compiler.

Proposed Changes

First, the GroupElement will be renamed to GroupAffine to make it more clear that this data type should generically represent an affine point (x, y) on the given elliptic curve.

Second, a new data type will be created to hold both constant and allocated representations of an affine point.
This data type will be implemented similar to https://github.com/AleoHQ/snarkOS/tree/master/models/src/gadgets/utilities

The following gadget trait implementations will be required: ToBytesGadget, EqGadget, ConditionalEqGadget, CondSelectGadget, AllocGadget.
There should also be methods constant(), add(), add_constant(), sub(), sub_constant() where a constraint system over a given field can be passed into the method signature.
As a result, the final GroupAffine type will not have any additional trait arguments. This will help to keep the overall compiler clean and free of additional trait dependencies.

Implement const variables in Leo inputs

This introduces const in the Leo input file.

[main]
const a: bool = true;
b: u8 = 2;
c: field = 0;
d: group = (0, 1)group;

Note that in main.leo this is unchanged.

function main(a: bool, b: u8, c: field, d: group) {
}

Remove visibility

Currently private and public keywords represent allocated public and private inputs that are passed to the constraint system when a leo program is executed.
We will be removing these visibility keywords altogether and restricting all program variables to private. This will remove visual confusion and code conflict when integrating Leo with snarkOS down the line.

Remove constraint system trait from constrained program type

Overview

Currently ConstraintSystem is a parameter for ConstrainedProgram. ConstraintSystem is used in some but not all methods and is not used by ConstrainedProgram directly. This should be changed so that ConstraintSystem is only passed into methods that need it.

The current ConstrainedProgram struct:

pub struct ConstrainedProgram<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> {
    pub identifiers: HashMap<String, ConstrainedValue<F, G>>,
    pub _cs: PhantomData<CS>,
}

The new struct:

pub struct ConstrainedProgram<F: Field + PrimeField, G: GroupType<F>> {
    pub identifiers: HashMap<String, ConstrainedValue<F, G>>,
}

The current enforce_add_expression() method:

fn enforce_add_expression(
        &mut self,
        cs: &mut CS,
        left: ConstrainedValue<F, G>,
        right: ConstrainedValue<F, G>,
    ) -> Result<ConstrainedValue<F, G>, ExpressionError>

The new method:

fn enforce_add_expression<CS: ConstraintSystem<F>>(
        &mut self,
        cs: &mut CS,
        left: ConstrainedValue<F, G>,
        right: ConstrainedValue<F, G>,
    ) -> Result<ConstrainedValue<F, G>, ExpressionError>

Span impl in `leo-typed/common/span.rs` could be simpler

I don't believe we are using these two methods in leo-typed/common/span.rs:
https://github.com/AleoHQ/leo/blob/master/types/src/common/span.rs#L33
https://github.com/AleoHQ/leo/blob/master/types/src/common/span.rs#L51

In addition, I believe the conversion from AstSpan<'ast> can be done much cleaner, as Pest already has this logic built-in. e.g. span.as_str() should be able to replace our logic of span.start_pos().line_of().trim_end() and would be a more reliable impl then as semantically, we just want the affected string.

@collinc97 if you can confirm, I can impl these changes in PR #120

[Bug] Test environment is not isolated

๐Ÿ› Describe the Bug

Tests are not run in isolation. Running two tests on the same method produces error if expected outputs differ.

Steps to Reproduce

Code snippet to reproduce

function mean(inputs: u32[10]) -> u32 {
    let mut output = 0u32;
    for i in 0..10 {
        output += inputs[i];
    }
    return output/10
}

test function test_mean() {
    let inputs = [1u32; 10];
    assert_eq!(1, mean(inputs));
}

// Should equal 2, mean(inputs) outputs 1.
test function test_mean2() {
    let inputs = [2u32; 10];
    assert_eq!(2, mean(inputs));
}

Add support for the address type

function main(owner: address) {
    let sender = address(aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8);
    let receiver: address = aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8sta57j8;
    assert_eq!(owner, sender);
    assert_eq!(sender, receiver);
}

Implement let and const variable keywords

let will indicate an allocated program variable.
const will indicate a constant program variable.

Allocated program variables must be passed in as private inputs to the constraint system upon program execution.

Constant program variables are static values which do not need to passed in as inputs to the constraint system.

Implement bitwise >=, >, <=, < gadgets

Currently integer >=, >, <=, < is only supported at the evaluation level for leo primitives.
This means that these operators are not enforced in the constraint system.

Dependabot couldn't fetch all your path-based dependencies

Dependabot couldn't fetch one or more of your project's path-based Rust dependencies. The affected dependencies were ../snarkOS/algorithms/Cargo.toml, ../snarkOS/curves/Cargo.toml, ../snarkOS/errors/Cargo.toml, ../snarkOS/gadgets/Cargo.toml, ../snarkOS/models/Cargo.toml and ../snarkOS/utilities/Cargo.toml.

To use path-based dependencies with Dependabot the paths must be relative and resolve to a directory in this project's source code.

View the update logs.

Add runtime state to Leo inputs

Inputs

token_withdraw.in

[main]
data: u8[32] = [0u8; 32];

[registers]
token_id: u8[32] = [0u8; 32];
value_balance: u64 = 0;

token_withdraw.state

[[public]]

[state]
leaf_index: u32 = 0;
root: u8[32] = [0u8; 32];

[[private]]

[record]
serial_number: u8[32] = [0u8; 32];
commitment: u8[32] = [0u8; 32];
owner: address = aleo1...;
value: u64 = 5;
payload: u8[32] = [0u8; 32]; // TBD
birth_program_id: u8[32] = [0u8; 32];
death_program_id: u8[32] = [0u8; 32];
serial_number_nonce: u8[32] = [0u8; 32];
commitment_randomness: u8[32] = [0u8; 32];

[state_leaf]
path: u8[32][2] = [ [0u8; 32], [0u8; 32] ];
memo: u8[32] = [0u8; 32];
network_id: u8 = 0;
leaf_randomness: u8[32] = [0u8; 32];

Outputs

token_withdraw.out

[registers]
token_id: u8[32] = [0u8; 32];
value_balance: u64 = 5;

For integration tests, one can invoke these files to load the correct input and state as follows:

#[({USER_DEFINED_1}.in, {USER_DEFINED_2}.state, {USER_DEFINED_3}.out)]
test function token_withdraw() {
    ...
}

For example, one could invoke it as any of the following examples:

#[(token_withdraw.in, token_withdraw.state, token_withdraw.out)]
test function token_withdraw() {
    ...
}

#[(test_input.in, test_state.state, test_output.out)]
test function token_withdraw() {
    ...
}

#[
    mainnet.in,
    mainnet.state,
    mainnet.out
]
test function token_withdraw() {
    ...
}

Output warnings to console.

Overview

For syntax errors that do not match the style guide we should output warnings to console.

Changes

Use the warn! macro from the log crate.
Try to catch candidates as early as possible in compiler.

refactor import file compilation

Currently import files are compiled when their functions are called. Not when the main file is compiled.
This should be changed so that all files care compiled at the same time.

Enforce multiple return statements

Overview

Currently a function containing multiple return statements will short circuit upon evaluating the first one.
This is incorrect behavior because we need to evaluate the entirety of each function to satisfy R1CS constraints.

Changes

function main(cond: bool) -> u32 {
    if cond {
        return 1u32
    } else {
        return 0u32
    }
}

In the above function there are two return statements whose results depend on a cond input boolean.
We can conditionally select the desired result from the conditional by passing this cond as an indicator to the function main when it is ready to return.
As expected, return arguments will no longer terminate a function early. Instead, they will pass their result along with their indicator to the function main when it is ready to return.

[Bug] Signed int pow edge cases

๐Ÿ› Describe the Bug

The pow exponentiation function for signed integers fails on negative bases, large powers, and some large bases.

Steps to Reproduce

// src/main.leo
function main() {
    let a = 11i8 ** 2i8;
}

Stack trace & error message

Result::unwrap()` on an `Err` value: Overflow

Expected Behavior

The function should compile and run without error.

Conflicting namespaces

Issue Scope

Currently, unique name spaces are not created for statements or expressions in a program.

function main() {
  let mut a = 0;
  a += 1;
  a += 1; // <- gives conflicting namespace error
}

This makes iterative code like for loops fail as well.

Proposed Changes

refactor the Types module to include Span details such as line number which can be used to create a unique namespace.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.