Merge branch 'master' of github.com:AleoHQ/leo into fix/pest-address

This commit is contained in:
collin 2020-08-03 23:12:03 -07:00
commit 2c3c852ff4
12 changed files with 201 additions and 39 deletions

86
.github/workflows/leo.yml vendored Normal file
View File

@ -0,0 +1,86 @@
name: Leo Programs
on:
pull_request:
push:
branches:
- master
env:
RUST_BACKTRACE: 1
jobs:
new:
name: Hello Leo (from 'leo new')
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Load snarkOS
run: |
mkdir ~/.ssh
echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
eval $(ssh-agent -s)
ssh-add -k ~/.ssh/id_rsa
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
components: rustfmt
- name: Install Leo
uses: actions-rs/cargo@v1
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
with:
command: install
args: --path .
- name: 'leo new'
run: |
cd ..
leo new hello_world
ls -la
cd hello_world && ls -la
leo run
init:
name: Hello Leo (from 'leo init')
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Load snarkOS
run: |
mkdir ~/.ssh
echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
eval $(ssh-agent -s)
ssh-add -k ~/.ssh/id_rsa
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
override: true
components: rustfmt
- name: Install Leo
uses: actions-rs/cargo@v1
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
with:
command: install
args: --path .
- name: 'leo init'
run: |
cd .. && mkdir hello_world && cd hello_world
leo init
ls -la
leo run

22
Cargo.lock generated
View File

@ -1284,7 +1284,7 @@ checksum = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f"
[[package]] [[package]]
name = "snarkos-algorithms" name = "snarkos-algorithms"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#d80ce42f37c8dbdd8dcb0ab9574361aea3276dc3" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#c1bab103254631c892fade02662eaa66cc145d58"
dependencies = [ dependencies = [
"blake2", "blake2",
"derivative", "derivative",
@ -1304,7 +1304,7 @@ dependencies = [
[[package]] [[package]]
name = "snarkos-curves" name = "snarkos-curves"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#d80ce42f37c8dbdd8dcb0ab9574361aea3276dc3" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#c1bab103254631c892fade02662eaa66cc145d58"
dependencies = [ dependencies = [
"derivative", "derivative",
"rand", "rand",
@ -1319,7 +1319,7 @@ dependencies = [
[[package]] [[package]]
name = "snarkos-derives" name = "snarkos-derives"
version = "0.1.0" version = "0.1.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#d80ce42f37c8dbdd8dcb0ab9574361aea3276dc3" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#c1bab103254631c892fade02662eaa66cc145d58"
dependencies = [ dependencies = [
"proc-macro2 1.0.19", "proc-macro2 1.0.19",
"quote 1.0.7", "quote 1.0.7",
@ -1329,7 +1329,7 @@ dependencies = [
[[package]] [[package]]
name = "snarkos-dpc" name = "snarkos-dpc"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#d80ce42f37c8dbdd8dcb0ab9574361aea3276dc3" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#c1bab103254631c892fade02662eaa66cc145d58"
dependencies = [ dependencies = [
"blake2", "blake2",
"derivative", "derivative",
@ -1350,7 +1350,7 @@ dependencies = [
[[package]] [[package]]
name = "snarkos-errors" name = "snarkos-errors"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#d80ce42f37c8dbdd8dcb0ab9574361aea3276dc3" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#c1bab103254631c892fade02662eaa66cc145d58"
dependencies = [ dependencies = [
"base58", "base58",
"bech32", "bech32",
@ -1363,7 +1363,7 @@ dependencies = [
[[package]] [[package]]
name = "snarkos-gadgets" name = "snarkos-gadgets"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#d80ce42f37c8dbdd8dcb0ab9574361aea3276dc3" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#c1bab103254631c892fade02662eaa66cc145d58"
dependencies = [ dependencies = [
"derivative", "derivative",
"digest 0.8.1", "digest 0.8.1",
@ -1378,7 +1378,7 @@ dependencies = [
[[package]] [[package]]
name = "snarkos-models" name = "snarkos-models"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#d80ce42f37c8dbdd8dcb0ab9574361aea3276dc3" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#c1bab103254631c892fade02662eaa66cc145d58"
dependencies = [ dependencies = [
"bincode", "bincode",
"derivative", "derivative",
@ -1394,7 +1394,7 @@ dependencies = [
[[package]] [[package]]
name = "snarkos-objects" name = "snarkos-objects"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#d80ce42f37c8dbdd8dcb0ab9574361aea3276dc3" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#c1bab103254631c892fade02662eaa66cc145d58"
dependencies = [ dependencies = [
"base58", "base58",
"bech32", "bech32",
@ -1415,7 +1415,7 @@ dependencies = [
[[package]] [[package]]
name = "snarkos-parameters" name = "snarkos-parameters"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#d80ce42f37c8dbdd8dcb0ab9574361aea3276dc3" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#c1bab103254631c892fade02662eaa66cc145d58"
dependencies = [ dependencies = [
"hex", "hex",
"snarkos-algorithms", "snarkos-algorithms",
@ -1427,12 +1427,12 @@ dependencies = [
[[package]] [[package]]
name = "snarkos-profiler" name = "snarkos-profiler"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#d80ce42f37c8dbdd8dcb0ab9574361aea3276dc3" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#c1bab103254631c892fade02662eaa66cc145d58"
[[package]] [[package]]
name = "snarkos-utilities" name = "snarkos-utilities"
version = "0.8.0" version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#d80ce42f37c8dbdd8dcb0ab9574361aea3276dc3" source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#c1bab103254631c892fade02662eaa66cc145d58"
dependencies = [ dependencies = [
"bincode", "bincode",
"rand", "rand",

View File

@ -345,8 +345,8 @@ input_keyword = { "input" }
// Declared in functions/input/input.rs // Declared in functions/input/input.rs
input = { input = {
input_keyword function_input
| function_input | input_keyword
} }
input_list = _{ (input ~ ("," ~ NEWLINE* ~ input)*)? } input_list = _{ (input ~ ("," ~ NEWLINE* ~ input)*)? }

View File

@ -15,7 +15,7 @@ use leo_typed::{Input, LeoTypedAst, MainInput, Program};
use snarkos_errors::gadgets::SynthesisError; use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{ use snarkos_models::{
curves::{Field, PrimeField}, curves::{Field, PrimeField},
gadgets::r1cs::{ConstraintSynthesizer, ConstraintSystem, TestConstraintSystem}, gadgets::r1cs::{ConstraintSynthesizer, ConstraintSystem},
}; };
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
@ -150,8 +150,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
} }
/// Synthesizes the circuit for test functions with program input. /// Synthesizes the circuit for test functions with program input.
pub fn compile_test_constraints(self, cs: &mut TestConstraintSystem<F>) -> Result<(), CompilerError> { pub fn compile_test_constraints(self) -> Result<(), CompilerError> {
generate_test_constraints::<F, G>(cs, self.program, self.program_input, &self.imported_programs) generate_test_constraints::<F, G>(self.program, self.program_input, &self.imported_programs)
} }
/// Calls the internal generate_constraints method with arguments /// Calls the internal generate_constraints method with arguments

View File

@ -42,7 +42,6 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
} }
pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>( pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
cs: &mut TestConstraintSystem<F>,
program: Program, program: Program,
input: Input, input: Input,
imported_programs: &ImportParser, imported_programs: &ImportParser,
@ -57,6 +56,7 @@ pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
log::info!("Running {} tests", tests.len()); log::info!("Running {} tests", tests.len());
for (test_name, test_function) in tests.into_iter() { for (test_name, test_function) in tests.into_iter() {
let cs = &mut TestConstraintSystem::<F>::new();
let full_test_name = format!("{}::{}", program_name.clone(), test_name.to_string()); let full_test_name = format!("{}::{}", program_name.clone(), test_name.to_string());
let result = resolved_program.enforce_main_function( let result = resolved_program.enforce_main_function(
@ -68,7 +68,7 @@ pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
if result.is_ok() { if result.is_ok() {
log::info!( log::info!(
"test {} passed. Constraint system satisfied: {}", "test {} compiled successfully. Constraint system satisfied: {}",
full_test_name, full_test_name,
cs.is_satisfied() cs.is_satisfied()
); );

View File

@ -115,11 +115,18 @@ macro_rules! test_int {
let a: $type_ = rand::random(); let a: $type_ = rand::random();
let b: $type_ = rand::random(); let b: $type_ = rand::random();
// make sure that we can calculate the inverse of each number
// Leo signed integer division is non-wrapping. Thus attempting to calculate a
// division result that wraps should be ignored here.
if a.checked_neg().is_none() {
continue;
}
let bytes = include_bytes!("div.leo"); let bytes = include_bytes!("div.leo");
let mut program = parse_program(bytes).unwrap(); let mut program = parse_program(bytes).unwrap();
// expect an error when dividing by zero // expect an error when dividing by zero
if b == 0 || b == <$type_>::MIN { if b == 0 {
let main_input = generate_main_input(vec![ let main_input = generate_main_input(vec![
("a", Some(InputValue::Integer($integer_type, a.to_string()))), ("a", Some(InputValue::Integer($integer_type, a.to_string()))),
("b", Some(InputValue::Integer($integer_type, b.to_string()))), ("b", Some(InputValue::Integer($integer_type, b.to_string()))),

View File

@ -9,7 +9,6 @@ use crate::{
Int64, Int64,
Int8, Int8,
}; };
use snarkos_models::{ use snarkos_models::{
curves::PrimeField, curves::PrimeField,
gadgets::{ gadgets::{
@ -24,7 +23,7 @@ use snarkos_models::{
}; };
macro_rules! div_int_impl { macro_rules! div_int_impl {
($($gadget:ident)*) => ($( ($($gadget:ident),*) => ($(
impl<F: PrimeField> Div<F> for $gadget { impl<F: PrimeField> Div<F> for $gadget {
type ErrorType = SignedIntegerError; type ErrorType = SignedIntegerError;
@ -86,15 +85,52 @@ macro_rules! div_int_impl {
&allocated_zero, &allocated_zero,
)?; )?;
// if the numerator is 0, return 0
let self_is_zero = Boolean::Constant(self.eq(&Self::constant(0 as <$gadget as Int>::IntegerType))); let self_is_zero = Boolean::Constant(self.eq(&Self::constant(0 as <$gadget as Int>::IntegerType)));
// if other is the minimum number, the result will be zero or one
// -128 / -128 = 1
// x / -128 = 0 fractional result rounds to 0
let min = Self::constant(<$gadget as Int>::IntegerType::MIN);
let other_is_min = other.evaluate_equal(
&mut cs.ns(|| "other_min_check"),
&min
)?;
let self_is_min = self.evaluate_equal(
&mut cs.ns(|| "self_min_check"),
&min
)?;
let both_min = Boolean::and(
&mut cs.ns(|| "both_min"),
&other_is_min,
&self_is_min
)?;
// if other is the minimum, set other to -1 so the calculation will not fail
let negative_one = allocated_one.neg(&mut cs.ns(|| "allocated_one"))?;
let a_valid = min.add(&mut cs.ns(||"a_valid"), &allocated_one);
let a_set = Self::conditionally_select(
&mut cs.ns(|| "a_set"),
&self_is_min,
&a_valid?,
&self
)?;
let b_set = Self::conditionally_select(
&mut cs.ns(|| "b_set"),
&other_is_min,
&negative_one,
&other
)?;
// If the most significant bits of both numbers are equal, the quotient will be positive // If the most significant bits of both numbers are equal, the quotient will be positive
let a_msb = self.bits.last().unwrap();
let b_msb = other.bits.last().unwrap(); let b_msb = other.bits.last().unwrap();
let a_msb = self.bits.last().unwrap();
let positive = a_msb.evaluate_equal(cs.ns(|| "compare_msb"), &b_msb)?; let positive = a_msb.evaluate_equal(cs.ns(|| "compare_msb"), &b_msb)?;
// Get the absolute value of each number // Get the absolute value of each number
let a_comp = self.neg(&mut cs.ns(|| "a_neg"))?; let a_comp = a_set.neg(&mut cs.ns(|| "a_neg"))?;
let a = Self::conditionally_select( let a = Self::conditionally_select(
&mut cs.ns(|| "a_abs"), &mut cs.ns(|| "a_abs"),
&a_msb, &a_msb,
@ -102,12 +138,12 @@ macro_rules! div_int_impl {
&self &self
)?; )?;
let b_comp = other.neg(&mut cs.ns(|| "b_neg"))?; let b_comp = b_set.neg(&mut cs.ns(|| "b_neg"))?;
let b = Self::conditionally_select( let b = Self::conditionally_select(
&mut cs.ns(|| "b_abs"), &mut cs.ns(|| "b_abs"),
&b_msb, &b_msb,
&b_comp, &b_comp,
&other, &b_set,
)?; )?;
let mut q = zero.clone(); let mut q = zero.clone();
@ -142,13 +178,11 @@ macro_rules! div_int_impl {
&b &b
)?; )?;
let sub = r.sub( let sub = r.sub(
&mut cs.ns(|| format!("subtract_divisor_{}", i)), &mut cs.ns(|| format!("subtract_divisor_{}", i)),
&b &b
); );
r = Self::conditionally_select( r = Self::conditionally_select(
&mut cs.ns(|| format!("subtract_or_same_{}", i)), &mut cs.ns(|| format!("subtract_or_same_{}", i)),
&can_sub, &can_sub,
@ -182,6 +216,22 @@ macro_rules! div_int_impl {
&q_neg, &q_neg,
)?; )?;
// set to zero if we know result is fractional
q = Self::conditionally_select(
&mut cs.ns(|| "fraction"),
&other_is_min,
&allocated_zero,
&q,
)?;
// set to one if we know result is division of the minimum number by itself
q = Self::conditionally_select(
&mut cs.ns(|| "one_result"),
&both_min,
&allocated_one,
&q,
)?;
Ok(Self::conditionally_select( Ok(Self::conditionally_select(
&mut cs.ns(|| "self_or_quotient"), &mut cs.ns(|| "self_or_quotient"),
&self_is_zero, &self_is_zero,
@ -193,4 +243,4 @@ macro_rules! div_int_impl {
)*) )*)
} }
div_int_impl!(Int8 Int16 Int32 Int64 Int128); div_int_impl!(Int8, Int16, Int32, Int64, Int128);

View File

@ -282,12 +282,16 @@ fn test_int8_div_constants() {
for _ in 0..1000 { for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Fr>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let a: i8 = rng.gen_range(-127i8, i8::MAX); let a: i8 = rng.gen();
let b: i8 = rng.gen_range(-127i8, i8::MAX); let b: i8 = rng.gen();
if a.checked_neg().is_none() {
return;
}
let expected = match a.checked_div(b) { let expected = match a.checked_div(b) {
Some(valid) => valid, Some(valid) => valid,
None => continue, None => return,
}; };
let a_bit = Int8::constant(a); let a_bit = Int8::constant(a);
@ -308,12 +312,16 @@ fn test_int8_div() {
for _ in 0..100 { for _ in 0..100 {
let mut cs = TestConstraintSystem::<Fr>::new(); let mut cs = TestConstraintSystem::<Fr>::new();
let a: i8 = rng.gen_range(-127i8, i8::MAX); let a: i8 = rng.gen();
let b: i8 = rng.gen_range(-127i8, i8::MAX); let b: i8 = rng.gen();
if a.checked_neg().is_none() {
continue;
}
let expected = match a.checked_div(b) { let expected = match a.checked_div(b) {
Some(valid) => valid, Some(valid) => valid,
None => continue, None => return,
}; };
let a_bit = Int8::alloc(cs.ns(|| "a_bit"), || Ok(a)).unwrap(); let a_bit = Int8::alloc(cs.ns(|| "a_bit"), || Ok(a)).unwrap();

View File

@ -76,10 +76,17 @@ impl CLI for InitCommand {
// Verify the input file does not exist // Verify the input file does not exist
let input_file = InputFile::new(&package_name); let input_file = InputFile::new(&package_name);
if !input_file.exists_at(&path) { if !input_file.exists_at(&path) {
// Create the input file in the input directory // Create the input file in the inputs directory
input_file.write_to(&path)?; input_file.write_to(&path)?;
} }
// Verify the state file does not exist
let state_file = StateFile::new(&package_name);
if !state_file.exists_at(&path) {
// Create the state file in the inputs directory
state_file.write_to(&path)?;
}
// Verify the main file does not exist // Verify the main file does not exist
if !MainFile::exists_at(&path) { if !MainFile::exists_at(&path) {
// Create the main file in the source directory // Create the main file in the source directory

View File

@ -90,9 +90,12 @@ impl CLI for NewCommand {
// Create the input directory // Create the input directory
InputsDirectory::create(&path)?; InputsDirectory::create(&path)?;
// Create the input file in the input directory // Create the input file in the inputs directory
InputFile::new(&package_name).write_to(&path)?; InputFile::new(&package_name).write_to(&path)?;
// Create the state file in the inputs directory
StateFile::new(&package_name).write_to(&path)?;
// Create the main file in the source directory // Create the main file in the source directory
MainFile::new(&package_name).write_to(&path)?; MainFile::new(&package_name).write_to(&path)?;
} }

View File

@ -12,7 +12,6 @@ use leo_package::{
}; };
use snarkos_curves::edwards_bls12::Fq; use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::r1cs::TestConstraintSystem;
use clap::ArgMatches; use clap::ArgMatches;
use std::{convert::TryFrom, env::current_dir}; use std::{convert::TryFrom, env::current_dir};
@ -81,9 +80,8 @@ impl CLI for TestCommand {
// Generate the program on the constraint system and verify correctness // Generate the program on the constraint system and verify correctness
{ {
let mut cs = TestConstraintSystem::<Fq>::new();
let temporary_program = program.clone(); let temporary_program = program.clone();
let output = temporary_program.compile_test_constraints(&mut cs)?; let output = temporary_program.compile_test_constraints()?;
log::debug!("Compiled constraints - {:#?}", output); log::debug!("Compiled constraints - {:#?}", output);
} }

View File

@ -50,6 +50,9 @@ impl InputFile {
[main] [main]
a: u32 = 1; a: u32 = 1;
b: u32 = 2; b: u32 = 2;
[registers]
r0: u32 = 0;
"#, "#,
self.package_name self.package_name
) )