pull master

This commit is contained in:
collin 2020-08-15 02:28:34 -07:00
commit e1f4fe1846
178 changed files with 4217 additions and 1382 deletions

149
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,149 @@
name: Leo Release
on:
push:
tags:
- 'v*.*.*'
env:
RUST_BACKTRACE: 1
jobs:
ubuntu:
name: Ubuntu
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: stable
override: true
components: rustfmt
- name: Build Leo
run: |
cargo build --all --release && strip target/release/leo
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
- id: get_version
uses: battila7/get-version-action@v2
- name: Zip
run: |
mkdir leo_${{ steps.get_version.outputs.version }}_ubuntu
mv target/release/leo leo_${{ steps.get_version.outputs.version }}_ubuntu
zip -r leo_${{ steps.get_version.outputs.version }}_ubuntu.zip leo_${{ steps.get_version.outputs.version }}_ubuntu
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
leo_${{ steps.get_version.outputs.version }}_ubuntu.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
macos:
name: macOS
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Load snarkOS
run: |
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: stable
override: true
components: rustfmt
- name: Build Leo
run: |
cargo build --all --release && strip target/release/leo
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
- id: get_version
uses: battila7/get-version-action@v2
- name: Zip
run: |
mkdir leo_${{ steps.get_version.outputs.version }}_mac
mv target/release/leo leo_${{ steps.get_version.outputs.version }}_mac
zip -r leo_${{ steps.get_version.outputs.version }}_mac.zip leo_${{ steps.get_version.outputs.version }}_mac
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
leo_${{ steps.get_version.outputs.version }}_mac.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
windows:
name: Windows
runs-on: windows-latest
continue-on-error: true
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Install SSH key
uses: shimataro/ssh-key-action@v1
with:
private-key: ${{ secrets.SNARKOS_DEPLOY_KEY_WINDOWS }}
public-key: ${{ secrets.SNARKOS_DEPLOY_KEY_WINDOWS_PUBLIC }}
name: id_rsa
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt
- name: Build Leo
run: |
cargo build --all --release
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
- id: get_version
uses: battila7/get-version-action@v2
- name: Zip
run: |
mkdir leo_${{ steps.get_version.outputs.version }}_windows
mv target/release/leo.exe leo_${{ steps.get_version.outputs.version }}_windows
Compress-Archive leo_${{ steps.get_version.outputs.version }}_windows leo_${{ steps.get_version.outputs.version }}_windows.zip
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
leo_${{ steps.get_version.outputs.version }}_windows.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

577
Cargo.lock generated
View File

@ -33,12 +33,6 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "arc-swap"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034"
[[package]]
name = "atty"
version = "0.2.14"
@ -158,7 +152,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"generic-array 0.14.3",
"generic-array 0.14.4",
]
[[package]]
@ -262,9 +256,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "chrono"
version = "0.4.13"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6"
checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b"
dependencies = [
"num-integer",
"num-traits",
@ -294,9 +288,9 @@ dependencies = [
[[package]]
name = "clap"
version = "2.33.1"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"ansi_term",
"atty",
@ -512,7 +506,7 @@ checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f"
dependencies = [
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
"syn 1.0.38",
]
[[package]]
@ -530,7 +524,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array 0.14.3",
"generic-array 0.14.4",
]
[[package]]
@ -541,9 +535,9 @@ checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
[[package]]
name = "either"
version = "1.5.3"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f"
[[package]]
name = "encoding_rs"
@ -595,7 +589,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
dependencies = [
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
"syn 1.0.38",
"synstructure",
]
@ -769,9 +763,9 @@ dependencies = [
[[package]]
name = "generic-array"
version = "0.14.3"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60fb4bb6bba52f78a471264d9a3b7d026cc0af47b22cd2cffbc0b787ca003e63"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
"version_check",
@ -836,9 +830,9 @@ checksum = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177"
[[package]]
name = "hashbrown"
version = "0.8.1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34f595585f103464d8d2f6e9864682d74c1601fed5e07d62b1c9058dba8246fb"
checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25"
dependencies = [
"autocfg",
]
@ -944,9 +938,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b88cd59ee5f71fea89a62248fc8f387d44400cefe05ef548466d61ced9029a7"
checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9"
dependencies = [
"autocfg",
"hashbrown",
@ -1066,9 +1060,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.2.1"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "leo"
@ -1086,18 +1080,19 @@ dependencies = [
"leo-state",
"log",
"notify",
"num-bigint",
"rand",
"rand_core",
"reqwest",
"rusty-hook",
"serde",
"serde_json",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-gadgets 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-algorithms",
"snarkos-curves",
"snarkos-errors",
"snarkos-gadgets",
"snarkos-models",
"snarkos-utilities",
"thiserror",
"toml",
]
@ -1135,13 +1130,13 @@ dependencies = [
"rand_xorshift",
"serde",
"sha2",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-dpc 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-gadgets 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-objects 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-curves",
"snarkos-dpc",
"snarkos-errors",
"snarkos-gadgets",
"snarkos-models",
"snarkos-objects",
"snarkos-utilities",
"thiserror",
]
@ -1151,9 +1146,9 @@ version = "0.1.0"
dependencies = [
"rand",
"rand_xorshift",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-errors",
"snarkos-models",
"snarkos-utilities",
"thiserror",
]
@ -1165,11 +1160,11 @@ dependencies = [
"pest",
"pest-ast",
"pest_derive",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-gadgets 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-algorithms",
"snarkos-curves",
"snarkos-errors",
"snarkos-gadgets",
"snarkos-models",
"thiserror",
]
@ -1198,14 +1193,14 @@ dependencies = [
"leo-typed",
"rand",
"rand_xorshift",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-dpc 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-objects 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-testing",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-algorithms",
"snarkos-curves",
"snarkos-dpc",
"snarkos-errors",
"snarkos-models",
"snarkos-objects",
"snarkos-storage",
"snarkos-utilities",
"thiserror",
]
@ -1219,8 +1214,8 @@ dependencies = [
"pest",
"serde",
"serde_json",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-errors",
"snarkos-models",
]
[[package]]
@ -1253,9 +1248,9 @@ dependencies = [
[[package]]
name = "libz-sys"
version = "1.0.25"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
checksum = "6ca8894883d250240341478bf987467332fbdd5da5c42426c69a8f93dbc302f2"
dependencies = [
"cc",
"libc",
@ -1352,7 +1347,7 @@ dependencies = [
"kernel32-sys",
"libc",
"log",
"miow 0.2.1",
"miow",
"net2",
"slab",
"winapi 0.2.8",
@ -1370,29 +1365,6 @@ dependencies = [
"slab",
]
[[package]]
name = "mio-named-pipes"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656"
dependencies = [
"log",
"mio",
"miow 0.3.5",
"winapi 0.3.9",
]
[[package]]
name = "mio-uds"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
dependencies = [
"iovec",
"libc",
"mio",
]
[[package]]
name = "miow"
version = "0.2.1"
@ -1405,16 +1377,6 @@ dependencies = [
"ws2_32-sys",
]
[[package]]
name = "miow"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e"
dependencies = [
"socket2",
"winapi 0.3.9",
]
[[package]]
name = "native-tls"
version = "0.2.4"
@ -1661,7 +1623,7 @@ dependencies = [
"pest_meta",
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
"syn 1.0.38",
]
[[package]]
@ -1692,7 +1654,7 @@ checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f"
dependencies = [
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
"syn 1.0.38",
]
[[package]]
@ -2046,9 +2008,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.114"
version = "1.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"
dependencies = [
"serde_derive",
]
@ -2065,13 +2027,13 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.114"
version = "1.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e"
checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48"
dependencies = [
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
"syn 1.0.38",
]
[[package]]
@ -2128,16 +2090,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
[[package]]
name = "signal-hook-registry"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035"
dependencies = [
"arc-swap",
"libc",
]
[[package]]
name = "single"
version = "1.0.0"
@ -2155,14 +2107,14 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]]
name = "smallvec"
version = "1.4.1"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3757cb9d89161a2f24e1cf78efa0c1fcff485d18e3f55e0aa3480824ddaa0f3f"
checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
[[package]]
name = "snarkos-algorithms"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [
"blake2",
"derivative",
@ -2173,161 +2125,62 @@ dependencies = [
"rayon",
"sha2",
"smallvec",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-profiler 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
]
[[package]]
name = "snarkos-algorithms"
version = "0.8.0"
dependencies = [
"blake2",
"derivative",
"digest 0.8.1",
"itertools 0.9.0",
"rand",
"rand_chacha",
"rayon",
"sha2",
"smallvec",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-profiler 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-consensus"
version = "0.8.0"
dependencies = [
"bincode",
"chrono",
"hex",
"log",
"rand",
"serde",
"snarkos-algorithms 0.8.0",
"snarkos-curves 0.8.0",
"snarkos-dpc 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-objects 0.8.0",
"snarkos-posw",
"snarkos-profiler 0.8.0",
"snarkos-storage",
"snarkos-utilities 0.8.0",
"tokio",
"snarkos-errors",
"snarkos-models",
"snarkos-profiler",
"snarkos-utilities",
]
[[package]]
name = "snarkos-curves"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [
"derivative",
"rand",
"rand_xorshift",
"rustc_version",
"serde",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
]
[[package]]
name = "snarkos-curves"
version = "0.8.0"
dependencies = [
"derivative",
"rand",
"rand_xorshift",
"rustc_version",
"serde",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-utilities 0.8.0",
"snarkos-errors",
"snarkos-models",
"snarkos-utilities",
]
[[package]]
name = "snarkos-derives"
version = "0.1.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
]
[[package]]
name = "snarkos-derives"
version = "0.1.0"
dependencies = [
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
"syn 1.0.38",
]
[[package]]
name = "snarkos-dpc"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [
"blake2",
"derivative",
"hex",
"itertools 0.9.0",
"rand",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-gadgets 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-objects 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-parameters 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-profiler 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
]
[[package]]
name = "snarkos-dpc"
version = "0.8.0"
dependencies = [
"blake2",
"derivative",
"hex",
"itertools 0.9.0",
"rand",
"snarkos-algorithms 0.8.0",
"snarkos-curves 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-gadgets 0.8.0",
"snarkos-models 0.8.0",
"snarkos-objects 0.8.0",
"snarkos-parameters 0.8.0",
"snarkos-profiler 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-errors"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807"
dependencies = [
"base58",
"bech32",
"bincode",
"curl",
"hex",
"jsonrpc-core",
"rocksdb",
"thiserror",
"snarkos-algorithms",
"snarkos-curves",
"snarkos-errors",
"snarkos-gadgets",
"snarkos-models",
"snarkos-objects",
"snarkos-parameters",
"snarkos-profiler",
"snarkos-utilities",
]
[[package]]
name = "snarkos-errors"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [
"base58",
"bech32",
@ -2337,60 +2190,28 @@ dependencies = [
"jsonrpc-core",
"rocksdb",
"thiserror",
"toml",
]
[[package]]
name = "snarkos-gadgets"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [
"derivative",
"digest 0.8.1",
"itertools 0.9.0",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
]
[[package]]
name = "snarkos-gadgets"
version = "0.8.0"
dependencies = [
"derivative",
"digest 0.8.1",
"itertools 0.9.0",
"snarkos-algorithms 0.8.0",
"snarkos-curves 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-marlin"
version = "0.1.0"
dependencies = [
"blake2",
"derivative",
"digest 0.8.1",
"rand_chacha",
"rand_core",
"rayon",
"snarkos-algorithms 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-gadgets 0.8.0",
"snarkos-models 0.8.0",
"snarkos-polycommit",
"snarkos-profiler 0.8.0",
"snarkos-utilities 0.8.0",
"snarkos-algorithms",
"snarkos-curves",
"snarkos-errors",
"snarkos-models",
"snarkos-utilities",
]
[[package]]
name = "snarkos-models"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [
"bincode",
"derivative",
@ -2399,51 +2220,14 @@ dependencies = [
"rand_xorshift",
"serde",
"smallvec",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
]
[[package]]
name = "snarkos-models"
version = "0.8.0"
dependencies = [
"bincode",
"derivative",
"itertools 0.9.0",
"rand",
"rand_xorshift",
"serde",
"smallvec",
"snarkos-errors 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-network"
version = "0.8.0"
dependencies = [
"bincode",
"byteorder",
"chrono",
"hex",
"log",
"rand",
"serde",
"snarkos-algorithms 0.8.0",
"snarkos-consensus",
"snarkos-dpc 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-objects 0.8.0",
"snarkos-storage",
"snarkos-utilities 0.8.0",
"tokio",
"snarkos-errors",
"snarkos-utilities",
]
[[package]]
name = "snarkos-objects"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [
"base58",
"bech32",
@ -2454,103 +2238,35 @@ dependencies = [
"rand",
"serde",
"sha2",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-curves 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
]
[[package]]
name = "snarkos-objects"
version = "0.8.0"
dependencies = [
"base58",
"bech32",
"chrono",
"derivative",
"hex",
"once_cell",
"rand",
"serde",
"sha2",
"snarkos-algorithms 0.8.0",
"snarkos-curves 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-parameters"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807"
dependencies = [
"hex",
"snarkos-algorithms 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-models 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-utilities 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-algorithms",
"snarkos-curves",
"snarkos-errors",
"snarkos-models",
"snarkos-utilities",
]
[[package]]
name = "snarkos-parameters"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [
"curl",
"hex",
"snarkos-algorithms 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-polycommit"
version = "0.1.0"
dependencies = [
"derivative",
"digest 0.8.1",
"rand_core",
"snarkos-algorithms 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-profiler 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-posw"
version = "0.8.0"
dependencies = [
"blake2",
"rand",
"snarkos-algorithms 0.8.0",
"snarkos-curves 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-gadgets 0.8.0",
"snarkos-marlin",
"snarkos-models 0.8.0",
"snarkos-objects 0.8.0",
"snarkos-parameters 0.8.0",
"snarkos-polycommit",
"snarkos-profiler 0.8.0",
"snarkos-utilities 0.8.0",
"thiserror",
"snarkos-algorithms",
"snarkos-errors",
"snarkos-models",
"snarkos-utilities",
]
[[package]]
name = "snarkos-profiler"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807"
[[package]]
name = "snarkos-profiler"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
[[package]]
name = "snarkos-storage"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [
"bincode",
"hex",
@ -2558,55 +2274,23 @@ dependencies = [
"rand",
"rocksdb",
"serde",
"snarkos-algorithms 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-objects 0.8.0",
"snarkos-parameters 0.8.0",
"snarkos-utilities 0.8.0",
]
[[package]]
name = "snarkos-testing"
version = "0.8.0"
dependencies = [
"once_cell",
"rand",
"rand_xorshift",
"snarkos-algorithms 0.8.0",
"snarkos-consensus",
"snarkos-curves 0.8.0",
"snarkos-dpc 0.8.0",
"snarkos-errors 0.8.0",
"snarkos-models 0.8.0",
"snarkos-network",
"snarkos-objects 0.8.0",
"snarkos-parameters 0.8.0",
"snarkos-posw",
"snarkos-storage",
"snarkos-utilities 0.8.0",
"tokio",
"snarkos-algorithms",
"snarkos-errors",
"snarkos-models",
"snarkos-objects",
"snarkos-parameters",
"snarkos-utilities",
]
[[package]]
name = "snarkos-utilities"
version = "0.8.0"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#8d84d89f6b6c3b4693d3c08758cce28139910807"
source = "git+ssh://git@github.com/AleoHQ/snarkOS.git#66243c33e7df47c7d5f5cb1b181c1f8140c660c1"
dependencies = [
"bincode",
"rand",
"snarkos-derives 0.1.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
"snarkos-errors 0.8.0 (git+ssh://git@github.com/AleoHQ/snarkOS.git)",
]
[[package]]
name = "snarkos-utilities"
version = "0.8.0"
dependencies = [
"bincode",
"rand",
"snarkos-derives 0.1.0",
"snarkos-errors 0.8.0",
"snarkos-derives",
"snarkos-errors",
]
[[package]]
@ -2646,9 +2330,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.36"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250"
checksum = "e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4"
dependencies = [
"proc-macro2 1.0.19",
"quote 1.0.7",
@ -2663,7 +2347,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
dependencies = [
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
"syn 1.0.38",
"unicode-xid 0.2.1",
]
@ -2716,7 +2400,7 @@ checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
dependencies = [
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
"syn 1.0.38",
]
[[package]]
@ -2765,28 +2449,11 @@ dependencies = [
"futures-core",
"iovec",
"lazy_static",
"libc",
"memchr",
"mio",
"mio-named-pipes",
"mio-uds",
"num_cpus",
"pin-project-lite",
"signal-hook-registry",
"slab",
"tokio-macros",
"winapi 0.3.9",
]
[[package]]
name = "tokio-macros"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389"
dependencies = [
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
]
[[package]]
@ -2996,7 +2663,7 @@ dependencies = [
"log",
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
"syn 1.0.38",
"wasm-bindgen-shared",
]
@ -3030,7 +2697,7 @@ checksum = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556"
dependencies = [
"proc-macro2 1.0.19",
"quote 1.0.7",
"syn 1.0.36",
"syn 1.0.38",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]

View File

@ -29,13 +29,14 @@ snarkos-gadgets = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", package = "
snarkos-models = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", package = "snarkos-models", default-features = false }
snarkos-utilities = { git = "ssh://git@github.com/AleoHQ/snarkOS.git", package = "snarkos-utilities" }
clap = { version = "2.33.0" }
clap = { version = "2.33.3" }
colored = { version = "2.0" }
env_logger = { version = "0.7" }
from-pest = { version = "0.3.1" }
lazy_static = { version = "1.4.0" }
log = { version = "0.4" }
notify= { version = "4.0.15" }
num-bigint = { version = "0.3" }
rand = { version = "0.7" }
rand_core = { version = "0.5.1" }
reqwest = { version = "0.10.7", features = ["blocking", "json"] }

26
FAQ.md Normal file
View File

@ -0,0 +1,26 @@
# FAQs
#### For some given code, changing the value in a constant variable changes the number of constraints in the generated circuit. Is this behavior correct?
**Yes**, take the integers as an example. In Leo, integers are represented as its binary decomposition,
with each bit occupying one field element (that takes on 0 or 1). Then, for an expression such as `a == 4u32`, the operation to evaluate equality
would comprise a linear pass of bitwise `AND` operations, comparing every bit in the **variable** value with each bit in the **constant** value.
As the constant value is already known to the compiler during circuit synthesis, the compiler is already able to complete part of the equality evaluation,
by assuming that any bit in the constant value that is `0` will clearly evaluate to `0`. As such, depending on the value of the constant integer in your code,
the total number of constraints in the generate circuit can vary.
To illustrate this, here are two examples to show the difference:
```
const = 00000001
variable = abcdefgh
---------------------------------
output = 0000000h (1 constraint)
```
```
const = 01110001
variable = abcdefgh
---------------------------------
output = 0bcd000h (4 constraints)
```

View File

@ -3,6 +3,8 @@
![CI](https://github.com/AleoHQ/leo/workflows/CI/badge.svg)
[![codecov](https://codecov.io/gh/AleoHQ/leo/branch/master/graph/badge.svg?token=S6MWO60SYL)](https://codecov.io/gh/AleoHQ/leo)
# Overview
## Compiler Architecture
<!-- generated by mermaid compile action - START -->

View File

@ -7,6 +7,7 @@ use serde::Serialize;
#[pest_ast(rule(Rule::access))]
pub enum Access<'ast> {
Array(ArrayAccess<'ast>),
Tuple(TupleAccess<'ast>),
Call(CallAccess<'ast>),
Object(MemberAccess<'ast>),
StaticObject(StaticMemberAccess<'ast>),

View File

@ -1,5 +1,5 @@
use crate::{
access::{ArrayAccess, MemberAccess},
access::{ArrayAccess, MemberAccess, TupleAccess},
ast::Rule,
};
@ -11,6 +11,7 @@ use std::fmt;
#[pest_ast(rule(Rule::access_assignee))]
pub enum AssigneeAccess<'ast> {
Array(ArrayAccess<'ast>),
Tuple(TupleAccess<'ast>),
Member(MemberAccess<'ast>),
}
@ -18,6 +19,7 @@ impl<'ast> fmt::Display for AssigneeAccess<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
AssigneeAccess::Array(ref array) => write!(f, "[{}]", array.expression),
AssigneeAccess::Tuple(ref tuple) => write!(f, ".{}", tuple.number),
AssigneeAccess::Member(ref member) => write!(f, ".{}", member.identifier),
}
}

View File

@ -1,4 +1,4 @@
use crate::{ast::Rule, expressions::Expression, SpanDef};
use crate::{ast::Rule, expressions::TupleExpression, SpanDef};
use pest::Span;
use pest_ast::FromPest;
@ -7,7 +7,7 @@ use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::access_call))]
pub struct CallAccess<'ast> {
pub expressions: Vec<Expression<'ast>>,
pub expressions: TupleExpression<'ast>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,

View File

@ -15,3 +15,6 @@ pub use member_access::*;
pub mod static_member_access;
pub use static_member_access::*;
pub mod tuple_access;
pub use tuple_access::*;

View File

@ -0,0 +1,14 @@
use crate::{ast::Rule, values::PositiveNumber, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::access_tuple))]
pub struct TupleAccess<'ast> {
pub number: PositiveNumber<'ast>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -14,6 +14,7 @@ use crate::{
values::Value,
};
use crate::expressions::TupleExpression;
use from_pest::{ConversionError, FromPest, Void};
use pest::{
error::Error,
@ -64,6 +65,9 @@ fn parse_term(pair: Pair<Rule>) -> Box<Expression> {
let next = clone.into_inner().next().unwrap();
match next.as_rule() {
Rule::expression => Expression::from_pest(&mut pair.into_inner()).unwrap(), // Parenthesis case
Rule::expression_tuple => {
Expression::Tuple(TupleExpression::from_pest(&mut pair.into_inner()).unwrap())
}
Rule::expression_array_inline => {
Expression::ArrayInline(ArrayInlineExpression::from_pest(&mut pair.into_inner()).unwrap())
}

View File

@ -22,12 +22,6 @@ pub use range::*;
pub mod range_or_expression;
pub use range_or_expression::*;
pub mod return_;
pub use return_::*;
pub mod return_tuple;
pub use return_tuple::*;
pub mod spread;
pub use spread::*;
@ -37,5 +31,8 @@ pub use spread_or_expression::*;
pub mod static_;
pub use static_::*;
pub mod variable;
pub use variable::*;
pub mod variables;
pub use variables::*;
pub mod variable_name;
pub use variable_name::*;

View File

@ -1,21 +0,0 @@
use crate::{ast::Rule, common::ReturnTuple, expressions::Expression};
use pest_ast::FromPest;
use serde::Serialize;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::return_))]
pub enum Return<'ast> {
Single(Expression<'ast>),
Tuple(ReturnTuple<'ast>),
}
impl<'ast> fmt::Display for Return<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Return::Single(ref expression) => write!(f, "{}", expression),
Return::Tuple(ref expressions) => write!(f, "{}", expressions),
}
}
}

View File

@ -1,27 +0,0 @@
use crate::{ast::Rule, expressions::Expression, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::return_tuple))]
pub struct ReturnTuple<'ast> {
pub expressions: Vec<Expression<'ast>>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for ReturnTuple<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, expression) in self.expressions.iter().enumerate() {
write!(f, "{}", expression)?;
if i < self.expressions.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "")
}
}

View File

@ -1,7 +1,6 @@
use crate::{
ast::Rule,
common::{Identifier, Mutable},
types::Type,
SpanDef,
};
@ -11,28 +10,21 @@ use serde::Serialize;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::variable))]
pub struct Variable<'ast> {
#[pest_ast(rule(Rule::variable_name))]
pub struct VariableName<'ast> {
pub mutable: Option<Mutable>,
pub identifier: Identifier<'ast>,
pub _type: Option<Type<'ast>>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Variable<'ast> {
impl<'ast> fmt::Display for VariableName<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref _mutable) = self.mutable {
write!(f, "mut ")?;
}
write!(f, "{}", self.identifier)?;
if let Some(ref _type) = self._type {
write!(f, ": {}", _type)?;
}
write!(f, "")
write!(f, "{}", self.identifier)
}
}

View File

@ -0,0 +1,41 @@
use crate::{ast::Rule, common::VariableName, types::Type, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::variables))]
pub struct Variables<'ast> {
pub names: Vec<VariableName<'ast>>,
pub type_: Option<Type<'ast>>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Variables<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.names.len() == 1 {
// mut a
write!(f, "{}", self.names[0])?;
} else {
// (a, mut b)
let names = self
.names
.iter()
.map(|x| format!("{}", x))
.collect::<Vec<_>>()
.join(",");
write!(f, "({})", names)?;
}
if self.type_.is_some() {
write!(f, ": {}", self.type_.as_ref().unwrap())?;
}
write!(f, "")
}
}

View File

@ -15,6 +15,7 @@ pub enum Expression<'ast> {
ArrayInitializer(ArrayInitializerExpression<'ast>),
CircuitInline(CircuitInlineExpression<'ast>),
Postfix(PostfixExpression<'ast>),
Tuple(TupleExpression<'ast>),
}
impl<'ast> Expression<'ast> {
@ -57,6 +58,7 @@ impl<'ast> Expression<'ast> {
Expression::ArrayInitializer(expression) => &expression.span,
Expression::CircuitInline(expression) => &expression.span,
Expression::Postfix(expression) => &expression.span,
Expression::Tuple(expression) => &expression.span,
}
}
}
@ -85,10 +87,9 @@ impl<'ast> fmt::Display for Expression<'ast> {
Expression::ArrayInitializer(ref expression) => {
write!(f, "[{} ; {}]", expression.expression, expression.count)
}
Expression::CircuitInline(ref expression) => {
write!(f, "inline circuit display not impl {}", expression.identifier)
}
Expression::Postfix(ref expression) => write!(f, "Postfix display not impl {}", expression.identifier),
Expression::CircuitInline(ref expression) => write!(f, "{}", expression.span.as_str()),
Expression::Postfix(ref expression) => write!(f, "{}", expression.span.as_str()),
Expression::Tuple(ref expression) => write!(f, "{}", expression.span.as_str()),
}
}
}

View File

@ -21,3 +21,6 @@ pub use postfix_expression::*;
pub mod ternary_expression;
pub use ternary_expression::*;
pub mod tuple_expression;
pub use tuple_expression::*;

View File

@ -0,0 +1,14 @@
use crate::{ast::Rule, expressions::Expression, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::expression_tuple))]
pub struct TupleExpression<'ast> {
pub expressions: Vec<Expression<'ast>>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -9,7 +9,7 @@ use serde::Serialize;
pub struct Function<'ast> {
pub identifier: Identifier<'ast>,
pub parameters: Vec<Input<'ast>>,
pub returns: Vec<Type<'ast>>,
pub returns: Option<Type<'ast>>,
pub statements: Vec<Statement<'ast>>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]

View File

@ -57,17 +57,16 @@ spread = { "..." ~ expression }
// Declared in common/spread_or_expression.rs
spread_or_expression = { spread | expression }
// Declared in common/return_.rs
return_ = { return_tuple | expression }
// Declared in common/return_tuple.rs
return_tuple = {"(" ~ expression ~ ("," ~ expression)+ ~ ")"}
// Declared in common/static_.rs
static_ = { "static " }
// Declared in common/variable.rs
variable = { mutable? ~ identifier ~ (":" ~ type_)? }
// Declared in common/variable_name.rs
variable_name = {mutable? ~ identifier}
variable_name_tuple = _{"(" ~ variable_name ~ ("," ~ variable_name)+ ~ ")"}
// Declared in common/variables.rs
variables = { ( variable_name_tuple | variable_name ) ~ (":" ~ type_ )? }
// Declared in common/declare.rs
declare = { let_ | const_ }
@ -124,7 +123,7 @@ operation_pow_assign = { "**=" }
/// Types
// Declared in types/type_.rs
type_ = { type_self | type_array | type_data | type_circuit }
type_ = { type_self | type_tuple | type_array | type_data | type_circuit }
// Declared in types/integer_type.rs
type_integer = {
@ -192,7 +191,7 @@ type_circuit = { identifier }
// Declared in types/array_type.rs
type_array = { type_data ~ ("[" ~ number_positive ~ "]")+ }
type_list = _{ (type_ ~ ("," ~ type_)*)? }
type_tuple = { "(" ~ NEWLINE* ~ type_ ~ ("," ~ NEWLINE* ~ type_)+ ~ ","? ~ NEWLINE* ~ ")" }
/// Values
@ -244,16 +243,19 @@ value_address = ${ type_address ~ "(" ~ address ~ ")" }
/// Access
// Declared in access/access.rs
access = { access_array | access_call | access_member | access_static_member}
access = { access_array | access_tuple | access_call | access_member | access_static_member}
// Declared in access/array_access.rs
access_array = !{ "[" ~ range_or_expression ~ "]" }
// Declared in access/tuple_access.rs
access_tuple = ${ "." ~ number_positive }
// Declared in access/assignee_access.rs
access_assignee = { access_array | access_member }
access_assignee = { access_array | access_tuple | access_member }
// Declared in access/call_access.rs
access_call = !{ "(" ~ expression_tuple ~ ")" }
access_call = !{ expression_tuple }
// Declared in access/member_access.rs
access_member = ${ "." ~ identifier }
@ -285,22 +287,25 @@ expression_conditional = { "if " ~ expression ~ "? " ~ expression ~ ": " ~ expre
/// Expressions
expression_term = {
("(" ~ expression ~ ")")
value
| ("(" ~ expression ~ ")")
| expression_tuple
| expression_conditional
| expression_array_initializer
| expression_array_inline
| expression_circuit_inline
| expression_conditional
| value
| expression_unary // must be defined below value to avoid conflicts with negative values
| expression_unary
| expression_postfix
| identifier
}
expression_tuple = _{ (expression ~ ("," ~ expression)*)? }
// Declared in expressions/expression.rs
expression = { expression_term ~ (operation_binary ~ expression_term)* }
// Declared in expressions/expression_tuple.rs
expression_tuple = { "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
// Declared in expressions/array_initializer_expression.rs
expression_array_initializer = { "[" ~ spread_or_expression ~ ";" ~ number_positive ~ "]" }
@ -325,7 +330,6 @@ statement = {
(statement_return
| statement_conditional
| statement_for
| statement_multiple_assignment
| statement_macro
| statement_definition
| statement_assign
@ -347,7 +351,7 @@ statement_conditional = {"if " ~ (expression | "(" ~ expression ~ ")") ~ "{" ~ N
conditional_nested_or_end_statement = { statement_conditional | "{" ~ NEWLINE* ~ statement+ ~ "}"}
// Declared in statements/definition_statement.rs
statement_definition = { declare ~ variable ~ "=" ~ expression ~ LINE_END}
statement_definition = { declare ~ variables ~ "=" ~ expression ~ LINE_END}
// Declared in statements/expression_statement.rs
statement_expression = { expression ~ LINE_END }
@ -355,12 +359,8 @@ statement_expression = { expression ~ LINE_END }
// Declared in statements/for_statement.rs
statement_for = { "for " ~ identifier ~ "in " ~ expression ~ ".." ~ expression ~ "{" ~ NEWLINE* ~ statement+ ~ "}"}
// Declared in statements/multiple_assignment_statement.rs
statement_multiple_assignment = { declare ~ "(" ~ variable_tuple ~ ")" ~ "=" ~ identifier ~ "(" ~ expression_tuple ~ ")" ~ LINE_END}
variable_tuple = _{ variable ~ ("," ~ variable)* }
// Declared in statements/return_statement.rs
statement_return = { "return " ~ return_}
statement_return = { "return " ~ expression}
/// Functions
@ -368,7 +368,7 @@ statement_return = { "return " ~ return_}
test_function = { "test " ~ function }
// Declared in functions/function.rs
function = { "function " ~ identifier ~ "(" ~ NEWLINE* ~ input_list ~ NEWLINE* ~ ")" ~ ("->" ~ (type_ | "(" ~ type_list ~ ")"))? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* }
function = { "function " ~ identifier ~ input_tuple ~ ("->" ~ type_)? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* }
// Declared in functions/input/function_input.rs
function_input = { mutable? ~ identifier ~ ":" ~ type_ }
@ -381,7 +381,7 @@ input = {
function_input
| input_keyword
}
input_list = _{ (input ~ ("," ~ NEWLINE* ~ input)*)? }
input_tuple = _{ "(" ~ NEWLINE* ~ (input ~ ("," ~ NEWLINE* ~ input)* ~ ","?)? ~ NEWLINE* ~ ")"}
/// Imports

View File

@ -1,6 +1,6 @@
use crate::{
ast::Rule,
common::{Declare, LineEnd, Variable},
common::{Declare, LineEnd, Variables},
expressions::Expression,
SpanDef,
};
@ -14,8 +14,8 @@ use std::fmt;
#[pest_ast(rule(Rule::statement_definition))]
pub struct DefinitionStatement<'ast> {
pub declare: Declare,
pub variable: Variable<'ast>,
pub expression: Expression<'ast>,
pub variables: Variables<'ast>,
pub expressions: Vec<Expression<'ast>>,
pub line_end: LineEnd,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
@ -24,6 +24,13 @@ pub struct DefinitionStatement<'ast> {
impl<'ast> fmt::Display for DefinitionStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "let {} = {};", self.variable, self.expression)
let expressions = self
.expressions
.iter()
.map(|x| format!("{}", x))
.collect::<Vec<_>>()
.join(",");
write!(f, "let {} = {};", self.variables, expressions)
}
}

View File

@ -19,9 +19,6 @@ pub use expression_statement::*;
pub mod for_statement;
pub use for_statement::*;
pub mod multiple_assignment_statement;
pub use multiple_assignment_statement::*;
pub mod return_statement;
pub use return_statement::*;

View File

@ -1,36 +0,0 @@
use crate::{
ast::Rule,
common::{Declare, Identifier, LineEnd, Variable},
expressions::Expression,
SpanDef,
};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::statement_multiple_assignment))]
pub struct MultipleAssignmentStatement<'ast> {
pub declare: Declare,
pub variables: Vec<Variable<'ast>>,
pub function_name: Identifier<'ast>,
pub arguments: Vec<Expression<'ast>>,
pub line_end: LineEnd,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for MultipleAssignmentStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, id) in self.variables.iter().enumerate() {
write!(f, "{}", id)?;
if i < self.variables.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, " = {}", self.function_name)
}
}

View File

@ -1,4 +1,4 @@
use crate::{ast::Rule, common::Return, SpanDef};
use crate::{ast::Rule, expressions::Expression, SpanDef};
use pest::Span;
use pest_ast::FromPest;
@ -8,7 +8,7 @@ use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::statement_return))]
pub struct ReturnStatement<'ast> {
pub return_: Return<'ast>,
pub expression: Expression<'ast>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
@ -16,6 +16,6 @@ pub struct ReturnStatement<'ast> {
impl<'ast> fmt::Display for ReturnStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.return_)
write!(f, "return {}", self.expression)
}
}

View File

@ -10,7 +10,6 @@ pub enum Statement<'ast> {
Return(ReturnStatement<'ast>),
Definition(DefinitionStatement<'ast>),
Assign(AssignStatement<'ast>),
MultipleAssignment(MultipleAssignmentStatement<'ast>),
Conditional(ConditionalStatement<'ast>),
Iteration(ForStatement<'ast>),
Assert(MacroStatement<'ast>),
@ -23,7 +22,6 @@ impl<'ast> fmt::Display for Statement<'ast> {
Statement::Return(ref statement) => write!(f, "{}", statement),
Statement::Definition(ref statement) => write!(f, "{}", statement),
Statement::Assign(ref statement) => write!(f, "{}", statement),
Statement::MultipleAssignment(ref statement) => write!(f, "{}", statement),
Statement::Conditional(ref statement) => write!(f, "{}", statement),
Statement::Iteration(ref statement) => write!(f, "{}", statement),
Statement::Assert(ref statement) => write!(f, "{}", statement),

View File

@ -28,6 +28,9 @@ pub use self_type::*;
pub mod signed_integer_type;
pub use signed_integer_type::*;
pub mod tuple_type;
pub use tuple_type::*;
pub mod type_;
pub use type_::*;

View File

@ -0,0 +1,14 @@
use crate::{ast::Rule, types::Type, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::type_tuple))]
pub struct TupleType<'ast> {
pub types: Vec<Type<'ast>>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -9,6 +9,7 @@ use std::fmt;
pub enum Type<'ast> {
Basic(DataType),
Array(ArrayType<'ast>),
Tuple(TupleType<'ast>),
Circuit(CircuitType<'ast>),
SelfType(SelfType),
}
@ -18,6 +19,7 @@ impl<'ast> fmt::Display for Type<'ast> {
match *self {
Type::Basic(ref _type) => write!(f, "basic"),
Type::Array(ref _type) => write!(f, "array"),
Type::Tuple(ref _type) => write!(f, "tuple"),
Type::Circuit(ref _type) => write!(f, "struct"),
Type::SelfType(ref _type) => write!(f, "Self"),
}

View File

@ -11,47 +11,45 @@
}
},
"parameters": [],
"returns": [],
"returns": null,
"statements": [
{
"Return": {
"return_": {
"Single": {
"Binary": {
"operation": "Add",
"left": {
"Value": {
"Implicit": {
"Positive": {
"value": "1",
"span": {
"input": "1",
"start": 29,
"end": 30
}
"expression": {
"Binary": {
"operation": "Add",
"left": {
"Value": {
"Implicit": {
"Positive": {
"value": "1",
"span": {
"input": "1",
"start": 29,
"end": 30
}
}
}
},
"right": {
"Value": {
"Implicit": {
"Positive": {
"value": "1",
"span": {
"input": "1",
"start": 33,
"end": 34
}
}
}
}
},
"span": {
"input": "1 + 1",
"start": 29,
"end": 34
}
},
"right": {
"Value": {
"Implicit": {
"Positive": {
"value": "1",
"span": {
"input": "1",
"start": 33,
"end": 34
}
}
}
}
},
"span": {
"input": "1 + 1",
"start": 29,
"end": 34
}
}
},

View File

@ -140,13 +140,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
/// Synthesizes the circuit without program input to verify correctness.
pub fn compile_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<OutputBytes, CompilerError> {
let path = self.main_file_path;
let input = self.program_input.empty();
generate_constraints::<F, G, CS>(cs, self.program, input, &self.imported_programs).map_err(|mut error| {
error.set_path(path);
generate_constraints::<F, G, CS>(cs, self.program, self.program_input, &self.imported_programs).map_err(
|mut error| {
error.set_path(path);
error
})
error
},
)
}
/// Synthesizes the circuit for test functions with program input.

View File

@ -5,7 +5,7 @@ use crate::{
value::ConstrainedValue,
GroupType,
};
use leo_typed::Variable;
use leo_typed::Identifier;
use snarkos_models::curves::{Field, PrimeField};
@ -13,15 +13,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn store_definition(
&mut self,
function_scope: String,
variable: Variable,
mutable: bool,
identifier: Identifier,
mut value: ConstrainedValue<F, G>,
) -> () {
// Store with given mutability
if variable.mutable {
if mutable {
value = ConstrainedValue::Mutable(Box::new(value));
}
let variable_program_identifier = new_scope(function_scope, variable.identifier.name);
let variable_program_identifier = new_scope(function_scope, identifier.name);
self.store(variable_program_identifier, value);
}

View File

@ -70,14 +70,14 @@ impl ExpressionError {
Self::new_from_span(message, span)
}
pub fn unexpected_array(expected: String, actual: String, span: Span) -> Self {
let message = format!("expected type `{}`, found array with elements `{}`", expected, actual);
pub fn incompatible_types(operation: String, span: Span) -> Self {
let message = format!("no implementation for `{}`", operation);
Self::new_from_span(message, span)
}
pub fn incompatible_types(operation: String, span: Span) -> Self {
let message = format!("no implementation for `{}`", operation);
pub fn index_out_of_bounds(index: usize, span: Span) -> Self {
let message = format!("cannot access index {} of tuple out of bounds", index);
Self::new_from_span(message, span)
}
@ -159,4 +159,16 @@ impl ExpressionError {
Self::new_from_span(message, span)
}
pub fn unexpected_array(expected: String, actual: String, span: Span) -> Self {
let message = format!("expected type `{}`, found array with elements `{}`", expected, actual);
Self::new_from_span(message, span)
}
pub fn unexpected_tuple(expected: String, actual: String, span: Span) -> Self {
let message = format!("expected type `{}`, found tuple with values `{}`", expected, actual);
Self::new_from_span(message, span)
}
}

View File

@ -78,6 +78,12 @@ impl FunctionError {
Self::new_from_span(message, span)
}
pub fn invalid_tuple(actual: String, span: Span) -> Self {
let message = format!("Expected function input tuple, found `{}`", actual);
Self::new_from_span(message, span)
}
pub fn return_arguments_length(expected: usize, actual: usize, span: Span) -> Self {
let message = format!("function expected {} returns, found {} returns", expected, actual);

View File

@ -19,12 +19,6 @@ impl OutputBytesError {
OutputBytesError::Error(FormattedError::new_from_span(message, span))
}
pub fn illegal_return(value: String, span: Span) -> Self {
let message = format!("program return must be a return value, found `{}`", value);
Self::new_from_span(message, span)
}
pub fn not_enough_registers(span: Span) -> Self {
let message = format!("number of input registers must be greater than or equal to output registers");

View File

@ -113,6 +113,12 @@ impl StatementError {
Self::new_from_span(message, span)
}
pub fn multiple_definition(value: String, span: Span) -> Self {
let message = format!("cannot assign multiple variables to a single value: {}", value,);
Self::new_from_span(message, span)
}
pub fn select_fail(first: String, second: String, span: Span) -> Self {
let message = format!(
"Conditional select gadget failed to select between `{}` or `{}`",
@ -122,6 +128,18 @@ impl StatementError {
Self::new_from_span(message, span)
}
pub fn tuple_assign_index(span: Span) -> Self {
let message = format!("Cannot assign single index to tuple of values");
Self::new_from_span(message, span)
}
pub fn tuple_type(type_: String, span: Span) -> Self {
let message = format!("Expected tuple type, found type `{}`", type_);
Self::new_from_span(message, span)
}
pub fn unassigned(name: String, span: Span) -> Self {
let message = format!("Expected assignment of return values for expression `{}`", name);

View File

@ -14,7 +14,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: &Vec<Type>,
expected_type: Option<Type>,
array: Box<Expression>,
index: RangeOrExpression,
span: Span,
@ -23,7 +23,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type,
*array,
span.clone(),
)? {

View File

@ -20,23 +20,22 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: &Vec<Type>,
mut expected_type: Option<Type>,
array: Vec<Box<SpreadOrExpression>>,
span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
// Check explicit array type dimension if given
let mut expected_types = expected_types.clone();
let expected_dimensions = vec![];
if !expected_types.is_empty() {
match expected_types[0] {
Type::Array(ref _type, ref dimensions) => {
expected_types = vec![expected_types[0].inner_dimension(dimensions)];
if expected_type.is_some() {
match expected_type.unwrap() {
Type::Array(ref type_, ref dimensions) => {
expected_type = Some(type_.inner_dimension(dimensions).clone());
}
ref _type => {
return Err(ExpressionError::unexpected_array(
expected_types[0].to_string(),
_type.to_string(),
format!("{:?}", array),
span,
));
}
@ -66,7 +65,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
&expected_types,
expected_type.clone(),
expression,
)?);
}

View File

@ -17,12 +17,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
index: Expression,
span: Span,
) -> Result<usize, ExpressionError> {
let expected_types = vec![Type::IntegerType(IntegerType::U32)];
let expected_type = Some(Type::IntegerType(IntegerType::U32));
match self.enforce_operand(
cs,
file_scope.clone(),
function_scope.clone(),
&expected_types,
expected_type,
index,
span.clone(),
)? {

View File

@ -14,7 +14,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: &Vec<Type>,
expected_type: Option<Type>,
left: Expression,
right: Expression,
span: Span,
@ -23,7 +23,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type.clone(),
left,
span.clone(),
)?;
@ -31,12 +31,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type.clone(),
right,
span.clone(),
)?;
resolved_left.resolve_types(&mut resolved_right, expected_types, span)?;
resolved_left.resolve_types(&mut resolved_right, expected_type, span)?;
Ok((resolved_left, resolved_right))
}

View File

@ -17,14 +17,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: &Vec<Type>,
expected_type: Option<Type>,
expression: Expression,
span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
let mut branch = self.enforce_expression(cs, file_scope, function_scope, expected_types, expression)?;
let mut branch = self.enforce_expression(cs, file_scope, function_scope, expected_type.clone(), expression)?;
branch.get_inner_mut();
branch.resolve_type(expected_types, span)?;
branch.resolve_type(expected_type, span)?;
Ok(branch)
}

View File

@ -21,7 +21,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: &Vec<Type>,
expected_type: Option<Type>,
circuit_identifier: Box<Expression>,
circuit_member: Identifier,
span: Span,
@ -33,7 +33,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
let self_function_scope = new_scope(self_file_scope.clone(), identifier.name.to_string());
let member_value =
self.evaluate_identifier(self_file_scope, self_function_scope, &vec![], circuit_member.clone())?;
self.evaluate_identifier(self_file_scope, self_function_scope, None, circuit_member.clone())?;
return Ok(member_value);
}
@ -43,7 +43,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type,
*circuit_identifier.clone(),
span.clone(),
)? {

View File

@ -51,7 +51,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
&vec![_type.clone()],
Some(_type.clone()),
field.expression,
)?;

View File

@ -14,7 +14,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: &Vec<Type>,
expected_type: Option<Type>,
circuit_identifier: Box<Expression>,
circuit_member: Identifier,
span: Span,
@ -24,7 +24,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type,
*circuit_identifier.clone(),
)? {
ConstrainedValue::CircuitDefinition(circuit_definition) => circuit_definition,

View File

@ -15,7 +15,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: &Vec<Type>,
expected_type: Option<Type>,
conditional: Expression,
first: Expression,
second: Expression,
@ -25,7 +25,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
&vec![Type::Boolean],
Some(Type::Boolean),
conditional,
)? {
ConstrainedValue::Boolean(resolved) => resolved,
@ -36,7 +36,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type.clone(),
first,
span.clone(),
)?;
@ -45,7 +45,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type,
second,
span.clone(),
)?;

View File

@ -25,13 +25,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: &Vec<Type>,
expected_type: Option<Type>,
expression: Expression,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
match expression {
// Variables
Expression::Identifier(unresolved_variable) => {
self.evaluate_identifier(file_scope, function_scope, expected_types, unresolved_variable)
self.evaluate_identifier(file_scope, function_scope, expected_type, unresolved_variable)
}
// Values
@ -39,7 +39,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Expression::Boolean(boolean, span) => Ok(ConstrainedValue::Boolean(new_bool_constant(boolean, span)?)),
Expression::Field(field, span) => Ok(ConstrainedValue::Field(FieldType::constant(field, span)?)),
Expression::Group(group_affine, span) => Ok(ConstrainedValue::Group(G::constant(group_affine, span)?)),
Expression::Implicit(value, span) => Ok(enforce_number_implicit(expected_types, value, span)?),
Expression::Implicit(value, span) => Ok(enforce_number_implicit(expected_type, value, span)?),
Expression::Integer(type_, integer, span) => {
Ok(ConstrainedValue::Integer(Integer::new_constant(&type_, integer, span)?))
}
@ -47,7 +47,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Binary operations
Expression::Negate(expression, span) => {
let resolved_value =
self.enforce_expression(cs, file_scope, function_scope, expected_types, *expression)?;
self.enforce_expression(cs, file_scope, function_scope, expected_type, *expression)?;
enforce_negate(cs, resolved_value, span)
}
@ -56,7 +56,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type,
*left,
*right,
span.clone(),
@ -69,7 +69,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type,
*left,
*right,
span.clone(),
@ -82,7 +82,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type,
*left,
*right,
span.clone(),
@ -95,7 +95,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type,
*left,
*right,
span.clone(),
@ -108,7 +108,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type,
*left,
*right,
span.clone(),
@ -119,7 +119,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Boolean operations
Expression::Not(expression, span) => Ok(evaluate_not(
self.enforce_expression(cs, file_scope, function_scope, expected_types, *expression)?,
self.enforce_expression(cs, file_scope, function_scope, expected_type, *expression)?,
span,
)?),
Expression::Or(left, right, span) => {
@ -127,7 +127,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type,
*left,
*right,
span.clone(),
@ -140,7 +140,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type,
*left,
*right,
span.clone(),
@ -153,7 +153,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
&vec![],
None,
*left,
*right,
span.clone(),
@ -166,7 +166,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
&vec![],
None,
*left,
*right,
span.clone(),
@ -179,7 +179,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
&vec![],
None,
*left,
*right,
span.clone(),
@ -192,7 +192,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
&vec![],
None,
*left,
*right,
span.clone(),
@ -205,7 +205,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
&vec![],
None,
*left,
*right,
span.clone(),
@ -219,7 +219,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope,
function_scope,
expected_types,
expected_type,
*conditional,
*first,
*second,
@ -228,10 +228,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Arrays
Expression::Array(array, span) => {
self.enforce_array(cs, file_scope, function_scope, expected_types, array, span)
self.enforce_array(cs, file_scope, function_scope, expected_type, array, span)
}
Expression::ArrayAccess(array, index, span) => {
self.enforce_array_access(cs, file_scope, function_scope, expected_types, array, *index, span)
self.enforce_array_access(cs, file_scope, function_scope, expected_type, array, *index, span)
}
// Tuples
Expression::Tuple(tuple, span) => {
self.enforce_tuple(cs, file_scope, function_scope, expected_type, tuple, span)
}
Expression::TupleAccess(tuple, index, span) => {
self.enforce_tuple_access(cs, file_scope, function_scope, expected_type, tuple, index, span)
}
// Circuits
@ -242,7 +250,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope,
function_scope,
expected_types,
expected_type,
circuit_variable,
circuit_member,
span,
@ -252,7 +260,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope,
function_scope,
expected_types,
expected_type,
circuit_identifier,
circuit_member,
span,
@ -263,7 +271,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope,
function_scope,
expected_types,
expected_type,
function,
arguments,
span,

View File

@ -14,7 +14,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: &Vec<Type>,
expected_type: Option<Type>,
function: Box<Expression>,
arguments: Vec<Expression>,
span: Span,
@ -23,7 +23,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
expected_types,
expected_type,
*function.clone(),
)?;
@ -36,22 +36,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
span.start,
);
match self.enforce_function(
self.enforce_function(
&mut cs.ns(|| name_unique),
outer_scope,
function_scope,
function_call,
arguments,
) {
Ok(ConstrainedValue::Return(return_values)) => {
if return_values.len() == 1 {
Ok(return_values[0].clone())
} else {
Ok(ConstrainedValue::Return(return_values))
}
}
Ok(_) => Err(ExpressionError::function_no_return(function.to_string(), span)),
Err(error) => Err(ExpressionError::from(Box::new(error))),
}
)
.map_err(|error| ExpressionError::from(Box::new(error)))
}
}

View File

@ -17,7 +17,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
&mut self,
file_scope: String,
function_scope: String,
expected_types: &Vec<Type>,
expected_type: Option<Type>,
unresolved_identifier: Identifier,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
// Evaluate the identifier name in the current function scope
@ -33,7 +33,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
} else if let Some(value) = self.get(&unresolved_identifier.name) {
// Check imported file scope
value.clone()
} else if expected_types.contains(&Type::Address) {
} else if expected_type.is_some() && expected_type.unwrap() == Type::Address {
// If we expect an address type, try to return an address
let address = Address::new(unresolved_identifier.name, unresolved_identifier.span)?;
@ -42,7 +42,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
return Err(ExpressionError::undefined_identifier(unresolved_identifier));
};
result_value.resolve_type(expected_types, unresolved_identifier.span.clone())?;
result_value.resolve_type(expected_type, unresolved_identifier.span.clone())?;
Ok(result_value)
}

View File

@ -29,3 +29,6 @@ pub use self::logical::*;
pub mod relational;
pub use self::relational::*;
pub mod tuple;
pub use self::tuple::*;

View File

@ -0,0 +1,40 @@
//! Enforces array access in a compiled Leo program.
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_typed::{Expression, Span, Type};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn enforce_tuple_access<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_type: Option<Type>,
tuple: Box<Expression>,
index: usize,
span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
let tuple = match self.enforce_operand(
cs,
file_scope.clone(),
function_scope.clone(),
expected_type,
*tuple,
span.clone(),
)? {
ConstrainedValue::Tuple(tuple) => tuple,
value => return Err(ExpressionError::undefined_array(value.to_string(), span.clone())),
};
if index > tuple.len() - 1 {
return Err(ExpressionError::index_out_of_bounds(index, span));
}
Ok(tuple[index].to_owned())
}
}

View File

@ -0,0 +1,7 @@
//! Methods to enforce tuple expressions in a compiled Leo program.
pub mod access;
pub use self::access::*;
pub mod tuple;
pub use self::tuple::*;

View File

@ -0,0 +1,53 @@
//! Enforces an tuple expression in a compiled Leo program.
use crate::{errors::ExpressionError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_typed::{Expression, Span, Type};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
/// Enforce tuple expressions
pub fn enforce_tuple<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_type: Option<Type>,
tuple: Vec<Expression>,
span: Span,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
// Check explicit tuple type dimension if given
let mut expected_types = vec![];
if expected_type.is_some() {
match expected_type.unwrap() {
Type::Tuple(ref types) => {
expected_types = types.clone();
}
ref type_ => {
return Err(ExpressionError::unexpected_tuple(
type_.to_string(),
format!("{:?}", tuple),
span,
));
}
}
}
let mut result = vec![];
for (i, expression) in tuple.into_iter().enumerate() {
let type_ = if expected_types.is_empty() {
None
} else {
Some(expected_types[i].clone())
};
result.push(self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), type_, expression)?);
}
Ok(ConstrainedValue::Tuple(result))
}
}

View File

@ -7,7 +7,7 @@ use crate::{
GroupType,
};
use leo_typed::{Expression, Function, InputVariable, Span};
use leo_typed::{Expression, Function, InputVariable, Span, Type};
use snarkos_models::{
curves::{Field, PrimeField},
@ -46,7 +46,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
scope.clone(),
caller_scope.clone(),
function_name.clone(),
vec![],
None,
input_expression,
)?;
@ -59,7 +59,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
scope.clone(),
caller_scope.clone(),
function_name.clone(),
vec![input_model.type_.clone()],
Some(input_model.type_.clone()),
input_expression,
)?;
@ -93,14 +93,20 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}
// Conditionally select a result based on returned indicators
let mut return_values = ConstrainedValue::Return(vec![]);
let mut return_values = ConstrainedValue::Tuple(vec![]);
Self::conditionally_select_result(cs, &mut return_values, results, function.span.clone())?;
if let ConstrainedValue::Return(ref returns) = return_values {
if function.returns.len() != returns.len() {
if let ConstrainedValue::Tuple(ref returns) = return_values {
let return_types = match function.returns {
Some(Type::Tuple(types)) => types.len(),
Some(_) => 1usize,
None => 0usize,
};
if return_types != returns.len() {
return Err(FunctionError::return_arguments_length(
function.returns.len(),
return_types,
returns.len(),
function.span.clone(),
));

View File

@ -16,16 +16,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
scope: String,
caller_scope: String,
function_name: String,
expected_types: Vec<Type>,
expected_type: Option<Type>,
input: Expression,
) -> Result<ConstrainedValue<F, G>, FunctionError> {
// Evaluate the function input value as pass by value from the caller or
// evaluate as an expression in the current function scope
match input {
Expression::Identifier(identifier) => {
Ok(self.evaluate_identifier(caller_scope, function_name, &expected_types, identifier)?)
Ok(self.evaluate_identifier(caller_scope, function_name, expected_type, identifier)?)
}
expression => Ok(self.enforce_expression(cs, scope, function_name, &expected_types, expression)?),
expression => Ok(self.enforce_expression(cs, scope, function_name, expected_type, expression)?),
}
}
}

View File

@ -42,7 +42,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
input_option,
span,
)?)),
Type::Array(_type, dimensions) => self.allocate_array(cs, name, *_type, dimensions, input_option, span),
Type::Array(type_, dimensions) => self.allocate_array(cs, name, *type_, dimensions, input_option, span),
Type::Tuple(types) => self.allocate_tuple(cs, name, types, input_option, span),
_ => unimplemented!("main function input not implemented for type"),
}
}

View File

@ -14,3 +14,6 @@ pub use self::input_keyword::*;
pub mod input_section;
pub use self::input_section::*;
pub mod tuple;
pub use self::tuple::*;

View File

@ -0,0 +1,56 @@
//! Allocates an array as a main function input parameter in a compiled Leo program.
use crate::{
errors::FunctionError,
program::{new_scope, ConstrainedProgram},
value::ConstrainedValue,
GroupType,
};
use leo_typed::{InputValue, Span, Type};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn allocate_tuple<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
name: String,
types: Vec<Type>,
input_value: Option<InputValue>,
span: Span,
) -> Result<ConstrainedValue<F, G>, FunctionError> {
let mut tuple_values = vec![];
match input_value {
Some(InputValue::Tuple(values)) => {
// Allocate each value in the tuple
for (i, (value, type_)) in values.into_iter().zip(types.into_iter()).enumerate() {
let value_name = new_scope(name.clone(), i.to_string());
tuple_values.push(self.allocate_main_function_input(
cs,
type_,
value_name,
Some(value),
span.clone(),
)?)
}
}
None => {
// Allocate all tuple values as none
for (i, type_) in types.into_iter().enumerate() {
let value_name = new_scope(name.clone(), i.to_string());
tuple_values.push(self.allocate_main_function_input(cs, type_, value_name, None, span.clone())?);
}
}
_ => return Err(FunctionError::invalid_tuple(input_value.unwrap().to_string(), span)),
}
Ok(ConstrainedValue::Tuple(tuple_values))
}
}

View File

@ -41,7 +41,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
&vec![],
None,
parameter.expression,
)?;

View File

@ -20,8 +20,8 @@ impl OutputBytes {
span: Span,
) -> Result<Self, OutputBytesError> {
let return_values = match value {
ConstrainedValue::Return(values) => values,
value => return Err(OutputBytesError::illegal_return(value.to_string(), span)),
ConstrainedValue::Tuple(values) => values,
value => vec![value],
};
let register_hashmap = registers.values();

View File

@ -33,7 +33,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Modify the single value of the array in place
match self.get_mutable_assignee(name, span.clone())? {
ConstrainedValue::Array(old) => {
new_value.resolve_type(&vec![old[index].to_type(span.clone())?], span.clone())?;
new_value.resolve_type(Some(old[index].to_type(span.clone())?), span.clone())?;
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
let selected_value = ConstrainedValue::conditionally_select(

View File

@ -33,7 +33,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Evaluate new value
let mut new_value =
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), &vec![], expression)?;
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), None, expression)?;
// Mutate the old value into the new value
match assignee {
@ -41,7 +41,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
let condition = indicator.unwrap_or(Boolean::Constant(true));
let old_value = self.get_mutable_assignee(variable_name.clone(), span.clone())?;
new_value.resolve_type(&vec![old_value.to_type(span.clone())?], span.clone())?;
new_value.resolve_type(Some(old_value.to_type(span.clone())?), span.clone())?;
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
let selected_value =
@ -62,6 +62,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
new_value,
span,
),
Assignee::Tuple(_tuple, index) => self.assign_tuple(cs, indicator, variable_name, index, new_value, span),
Assignee::CircuitField(_assignee, object_name) => {
self.mutute_circuit_field(cs, indicator, variable_name, object_name, new_value, span)
}

View File

@ -9,6 +9,7 @@ pub fn resolve_assignee(scope: String, assignee: Assignee) -> String {
match assignee {
Assignee::Identifier(name) => new_scope(scope, name.to_string()),
Assignee::Array(array, _index) => resolve_assignee(scope, *array),
Assignee::Tuple(tuple, _index) => resolve_assignee(scope, *tuple),
Assignee::CircuitField(circuit_name, _member) => resolve_assignee(scope, *circuit_name),
}
}

View File

@ -40,7 +40,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
return Err(StatementError::immutable_circuit_function("static".into(), span));
}
_ => {
new_value.resolve_type(&vec![object.1.to_type(span.clone())?], span.clone())?;
new_value.resolve_type(Some(object.1.to_type(span.clone())?), span.clone())?;
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
let selected_value = ConstrainedValue::conditionally_select(

View File

@ -11,3 +11,6 @@ pub use self::assignee::*;
pub mod circuit_field;
pub use self::circuit_field::*;
pub mod tuple;
pub use self::tuple::*;

View File

@ -0,0 +1,45 @@
//! Enforces a tuple assignment statement in a compiled Leo program.
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_typed::Span;
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::{
r1cs::ConstraintSystem,
utilities::{boolean::Boolean, select::CondSelectGadget},
},
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn assign_tuple<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
indicator: Option<Boolean>,
name: String,
index: usize,
mut new_value: ConstrainedValue<F, G>,
span: Span,
) -> Result<(), StatementError> {
let condition = indicator.unwrap_or(Boolean::Constant(true));
// Modify the single value of the tuple in place
match self.get_mutable_assignee(name, span.clone())? {
ConstrainedValue::Tuple(old) => {
new_value.resolve_type(Some(old[index].to_type(span.clone())?), span.clone())?;
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
let selected_value =
ConstrainedValue::conditionally_select(cs.ns(|| name_unique), &condition, &new_value, &old[index])
.map_err(|_| {
StatementError::select_fail(new_value.to_string(), old[index].to_string(), span)
})?;
old[index] = selected_value;
}
_ => return Err(StatementError::tuple_assign_index(span)),
}
Ok(())
}
}

View File

@ -16,7 +16,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope: String,
indicator: Option<Boolean>,
statements: Vec<Statement>,
return_types: Vec<Type>,
return_type: Option<Type>,
) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> {
let mut results = vec![];
// Evaluate statements. Only allow a single return argument to be returned.
@ -27,7 +27,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope.clone(),
indicator.clone(),
statement.clone(),
return_types.clone(),
return_type.clone(),
)?;
results.append(&mut value);

View File

@ -27,7 +27,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope: String,
indicator: Option<Boolean>,
statement: ConditionalStatement,
return_types: Vec<Type>,
return_type: Option<Type>,
span: Span,
) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> {
let statement_string = statement.to_string();
@ -40,7 +40,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs,
file_scope.clone(),
function_scope.clone(),
&vec![Type::Boolean],
Some(Type::Boolean),
statement.condition.clone(),
)? {
ConstrainedValue::Boolean(resolved) => resolved,
@ -70,7 +70,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope.clone(),
Some(branch_1_indicator),
statement.statements,
return_types.clone(),
return_type.clone(),
)?;
results.append(&mut branch_1_result);
@ -98,7 +98,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope,
Some(branch_2_indicator),
*nested,
return_types,
return_type,
span,
)?,
ConditionalNestedOrEndStatement::End(statements) => self.evaluate_branch(
@ -107,7 +107,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope,
Some(branch_2_indicator),
statements,
return_types,
return_type,
)?,
},
None => vec![],

View File

@ -1,7 +1,7 @@
//! Enforces a definition statement in a compiled Leo program.
use crate::{errors::StatementError, program::ConstrainedProgram, GroupType};
use leo_typed::{Declare, Expression, Span, Variable};
use crate::{errors::StatementError, program::ConstrainedProgram, ConstrainedValue, GroupType};
use leo_typed::{Declare, Expression, Span, Type, VariableName, Variables};
use snarkos_models::{
curves::{Field, PrimeField},
@ -9,39 +9,186 @@ use snarkos_models::{
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
fn enforce_single_definition<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
function_scope: String,
is_constant: bool,
variable_name: VariableName,
mut value: ConstrainedValue<F, G>,
span: Span,
) -> Result<(), StatementError> {
if is_constant && variable_name.mutable {
return Err(StatementError::immutable_assign(variable_name.to_string(), span));
} else {
value.allocate_value(cs, span)?
}
self.store_definition(function_scope, variable_name.mutable, variable_name.identifier, value);
Ok(())
}
fn enforce_expressions<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
type_: Option<Type>,
expressions: Vec<Expression>,
span: Span,
) -> Result<Vec<ConstrainedValue<F, G>>, StatementError> {
let types = match type_ {
Some(Type::Tuple(types)) => types,
Some(type_) => return Err(StatementError::tuple_type(type_.to_string(), span.clone())),
None => vec![],
};
let implicit_types = types.is_empty();
let mut expected_types = vec![];
for i in 0..expressions.len() {
let expected_type = if implicit_types { None } else { Some(types[i].clone()) };
expected_types.push(expected_type);
}
let mut values = vec![];
for (expression, expected_type) in expressions.into_iter().zip(expected_types.into_iter()) {
let value = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
expected_type,
expression,
)?;
values.push(value);
}
Ok(values)
}
fn enforce_tuple_definition<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
is_constant: bool,
variables: Variables,
expressions: Vec<Expression>,
span: Span,
) -> Result<(), StatementError> {
let values = self.enforce_expressions(
cs,
file_scope,
function_scope.clone(),
variables.type_.clone(),
expressions,
span.clone(),
)?;
let tuple = ConstrainedValue::Tuple(values);
let variable = variables.names[0].clone();
self.enforce_single_definition(cs, function_scope, is_constant, variable, tuple, span)
}
fn enforce_multiple_definition<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
function_scope: String,
is_constant: bool,
variables: Variables,
values: Vec<ConstrainedValue<F, G>>,
span: Span,
) -> Result<(), StatementError> {
if values.len() != variables.names.len() {
return Err(StatementError::invalid_number_of_definitions(
values.len(),
variables.names.len(),
span,
));
}
for (variable, value) in variables.names.into_iter().zip(values.into_iter()) {
self.enforce_single_definition(cs, function_scope.clone(), is_constant, variable, value, span.clone())?;
}
Ok(())
}
pub fn enforce_definition_statement<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
declare: Declare,
variable: Variable,
expression: Expression,
variables: Variables,
expressions: Vec<Expression>,
span: Span,
) -> Result<(), StatementError> {
let mut expected_types = vec![];
if let Some(ref _type) = variable._type {
expected_types.push(_type.clone());
let num_variables = variables.names.len();
let num_values = expressions.len();
let is_constant = match declare {
Declare::Let => false,
Declare::Const => true,
};
if num_variables == 1 && num_values == 1 {
// Define a single variable with a single value
let variable = variables.names[0].clone();
let expression = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
variables.type_,
expressions[0].clone(),
)?;
self.enforce_single_definition(cs, function_scope, is_constant, variable, expression, span)
} else if num_variables == 1 && num_values > 1 {
// Define a tuple (single variable with multiple values)
self.enforce_tuple_definition(
cs,
file_scope,
function_scope,
is_constant,
variables,
expressions,
span,
)
} else if num_variables > 1 && num_values == 1 {
// Define multiple variables for an expression that returns multiple results (multiple definition)
let values = match self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
variables.type_.clone(),
expressions[0].clone(),
)? {
// ConstrainedValue::Return(values) => values,
ConstrainedValue::Tuple(values) => values,
value => return Err(StatementError::multiple_definition(value.to_string(), span.clone())),
};
self.enforce_multiple_definition(cs, function_scope, is_constant, variables, values, span)
} else {
// Define multiple variables for multiple expressions
let values = self.enforce_expressions(
cs,
file_scope,
function_scope.clone(),
variables.type_.clone(),
expressions,
span.clone(),
)?;
self.enforce_multiple_definition(cs, function_scope, is_constant, variables, values, span)
}
let mut value = self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
&expected_types,
expression,
)?;
match declare {
Declare::Let => value.allocate_value(cs, span)?,
Declare::Const => {
if variable.mutable {
return Err(StatementError::immutable_assign(variable.to_string(), span));
}
}
}
self.store_definition(function_scope, variable, value);
Ok(())
}
}

View File

@ -2,6 +2,3 @@
pub mod definition;
pub use self::definition::*;
pub mod multiple;
pub use self::multiple::*;

View File

@ -1,54 +0,0 @@
//! Enforces a multiple definition statement in a compiled Leo program.
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_typed::{Expression, Span, Variable};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn enforce_multiple_definition_statement<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
variables: Vec<Variable>,
function: Expression,
span: Span,
) -> Result<(), StatementError> {
let mut expected_types = vec![];
for variable in variables.iter() {
if let Some(ref _type) = variable._type {
expected_types.push(_type.clone());
}
}
// Expect return values from function
let return_values = match self.enforce_expression(
cs,
file_scope.clone(),
function_scope.clone(),
&expected_types,
function,
)? {
ConstrainedValue::Return(values) => values,
value => unimplemented!("multiple assignment only implemented for functions, got {}", value),
};
if variables.len() != return_values.len() {
return Err(StatementError::invalid_number_of_definitions(
variables.len(),
return_values.len(),
span,
));
}
for (variable, value) in variables.into_iter().zip(return_values.into_iter()) {
self.store_definition(function_scope.clone(), variable, value);
}
Ok(())
}
}

View File

@ -29,7 +29,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
start: Expression,
stop: Expression,
statements: Vec<Statement>,
return_types: Vec<Type>,
return_type: Option<Type>,
span: Span,
) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> {
let mut results = vec![];
@ -40,6 +40,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
for i in from..to {
// Store index in current function scope.
// For loop scope is not implemented.
let index_name = new_scope(function_scope.clone(), index.to_string());
self.store(
@ -55,7 +56,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope.clone(),
indicator,
statements.clone(),
return_types.clone(),
return_type.clone(),
)?;
results.append(&mut result);

View File

@ -1,11 +1,6 @@
//! Enforces a return statement in a compiled Leo program.
use crate::{
errors::{StatementError, ValueError},
program::ConstrainedProgram,
value::ConstrainedValue,
GroupType,
};
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_typed::{Expression, Span, Type};
use snarkos_models::{
@ -13,25 +8,20 @@ use snarkos_models::{
gadgets::r1cs::ConstraintSystem,
};
fn check_return_types(expected: &Vec<Type>, actual: &Vec<Type>, span: Span) -> Result<(), StatementError> {
expected
.iter()
.zip(actual.iter())
.map(|(type_1, type_2)| {
if type_1.ne(type_2) {
// catch return Self type
if type_1.is_self() && type_2.is_circuit() {
Ok(())
fn check_return_type(expected: Option<Type>, actual: Type, span: Span) -> Result<(), StatementError> {
match expected {
Some(expected) => {
if expected.ne(&actual) {
if expected.is_self() && actual.is_circuit() {
return Ok(());
} else {
Err(StatementError::arguments_type(type_1, type_2, span.clone()))
return Err(StatementError::arguments_type(&expected, &actual, span));
}
} else {
Ok(())
}
})
.collect::<Result<Vec<()>, StatementError>>()?;
Ok(())
Ok(())
}
None => Ok(()),
}
}
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
@ -40,41 +30,23 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
cs: &mut CS,
file_scope: String,
function_scope: String,
expressions: Vec<Expression>,
return_types: Vec<Type>,
expression: Expression,
return_type: Option<Type>,
span: Span,
) -> Result<ConstrainedValue<F, G>, StatementError> {
// Make sure we return the correct number of values
if return_types.len() != expressions.len() {
return Err(StatementError::invalid_number_of_returns(
return_types.len(),
expressions.len(),
span,
));
}
let mut returns = vec![];
for (expression, ty) in expressions.into_iter().zip(return_types.clone().into_iter()) {
let expected_types = vec![ty.clone()];
let result = self.enforce_operand(
cs,
file_scope.clone(),
function_scope.clone(),
&expected_types,
expression,
span.clone(),
)?;
let result = self.enforce_operand(
cs,
file_scope.clone(),
function_scope.clone(),
return_type.clone(),
expression,
span.clone(),
)?;
returns.push(result);
}
check_return_type(return_type, result.to_type(span.clone())?, span)?;
let actual_types = returns
.iter()
.map(|value| value.to_type(span.clone()))
.collect::<Result<Vec<Type>, ValueError>>()?;
check_return_types(&return_types, &actual_types, span)?;
Ok(ConstrainedValue::Return(returns))
Ok(result)
}
}

View File

@ -12,8 +12,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
/// Enforce a program statement.
/// Returns a Vector of (indicator, value) tuples.
/// Each evaluated statement may execute of one or more statements that may return early.
/// To indicate which of these return values to take,
/// we conditionally select the value according the `indicator` bit that evaluates to true.
/// To indicate which of these return values to take we conditionally select the value according
/// to the `indicator` bit that evaluates to true.
pub fn enforce_statement<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
@ -21,24 +21,29 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope: String,
indicator: Option<Boolean>,
statement: Statement,
return_types: Vec<Type>,
return_type: Option<Type>,
) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> {
let mut results = vec![];
match statement {
Statement::Return(expressions, span) => {
Statement::Return(expression, span) => {
let return_value = (
indicator,
self.enforce_return_statement(cs, file_scope, function_scope, expressions, return_types, span)?,
self.enforce_return_statement(cs, file_scope, function_scope, expression, return_type, span)?,
);
results.push(return_value);
}
Statement::Definition(declare, variable, expression, span) => {
self.enforce_definition_statement(cs, file_scope, function_scope, declare, variable, expression, span)?;
}
Statement::MultipleDefinition(variables, function, span) => {
self.enforce_multiple_definition_statement(cs, file_scope, function_scope, variables, function, span)?;
Statement::Definition(declare, variables, expressions, span) => {
self.enforce_definition_statement(
cs,
file_scope,
function_scope,
declare,
variables,
expressions,
span,
)?;
}
Statement::Assign(variable, expression, span) => {
self.enforce_assign_statement(cs, file_scope, function_scope, indicator, variable, expression, span)?;
@ -50,7 +55,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope,
indicator,
statement,
return_types,
return_type,
span,
)?;
@ -66,7 +71,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
start,
stop,
statements,
return_types,
return_type,
span,
)?;
@ -74,7 +79,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}
Statement::AssertEq(left, right, span) => {
let (resolved_left, resolved_right) =
self.enforce_binary_expression(cs, file_scope, function_scope, &vec![], left, right, span.clone())?;
self.enforce_binary_expression(cs, file_scope, function_scope, None, left, right, span.clone())?;
self.enforce_assert_eq_statement(cs, indicator, &resolved_left, &resolved_right, span)?;
}
@ -83,11 +88,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}
Statement::Expression(expression, span) => {
let expression_string = expression.to_string();
let value = self.enforce_expression(cs, file_scope, function_scope, &vec![], expression)?;
let value = self.enforce_expression(cs, file_scope, function_scope, None, expression)?;
// handle empty return value cases
match &value {
ConstrainedValue::Return(values) => {
ConstrainedValue::Tuple(values) => {
if !values.is_empty() {
return Err(StatementError::unassigned(expression_string, span));
}

View File

@ -209,17 +209,10 @@ impl<F: Field + PrimeField> PartialOrd for FieldType<F> {
}
impl<F: Field + PrimeField> EvaluateEqGadget<F> for FieldType<F> {
fn evaluate_equal<CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
fn evaluate_equal<CS: ConstraintSystem<F>>(&self, _cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
match (self, other) {
(FieldType::Constant(first), FieldType::Constant(second)) => Ok(Boolean::constant(first.eq(second))),
(FieldType::Allocated(allocated), FieldType::Constant(constant))
| (FieldType::Constant(constant), FieldType::Allocated(allocated)) => {
let bool_option = allocated.value.map(|f| f.eq(constant));
Boolean::alloc(&mut cs.ns(|| "evaluate_equal"), || {
bool_option.ok_or(SynthesisError::AssignmentMissing)
})
}
(FieldType::Allocated(first), FieldType::Allocated(second)) => first.evaluate_equal(cs, second),
_ => unimplemented!(),
}
}
}

View File

@ -237,35 +237,12 @@ impl PartialEq for EdwardsGroupType {
impl Eq for EdwardsGroupType {}
impl EvaluateEqGadget<Fq> for EdwardsGroupType {
fn evaluate_equal<CS: ConstraintSystem<Fq>>(&self, mut cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
fn evaluate_equal<CS: ConstraintSystem<Fq>>(&self, _cs: CS, other: &Self) -> Result<Boolean, SynthesisError> {
match (self, other) {
(EdwardsGroupType::Constant(self_value), EdwardsGroupType::Constant(other_value)) => {
Ok(Boolean::Constant(self_value == other_value))
}
(EdwardsGroupType::Allocated(self_value), EdwardsGroupType::Allocated(other_value)) => {
let bool_option =
<EdwardsBlsGadget as GroupGadget<GroupAffine<EdwardsParameters>, Fq>>::get_value(self_value)
.and_then(|a| {
<EdwardsBlsGadget as GroupGadget<GroupAffine<EdwardsParameters>, Fq>>::get_value(
other_value,
)
.map(|b| a.eq(&b))
});
Boolean::alloc(&mut cs.ns(|| "evaluate_equal"), || {
bool_option.ok_or(SynthesisError::AssignmentMissing)
})
}
(EdwardsGroupType::Constant(constant_value), EdwardsGroupType::Allocated(allocated_value))
| (EdwardsGroupType::Allocated(allocated_value), EdwardsGroupType::Constant(constant_value)) => {
let bool_option =
<EdwardsBlsGadget as GroupGadget<GroupAffine<EdwardsParameters>, Fq>>::get_value(allocated_value)
.map(|a| a.eq(constant_value));
Boolean::alloc(&mut cs.ns(|| "evaluate_equal"), || {
bool_option.ok_or(SynthesisError::AssignmentMissing)
})
Ok(Boolean::constant(self_value.eq(other_value)))
}
_ => unimplemented!(),
}
}
}

View File

@ -6,13 +6,12 @@ use leo_typed::{Span, Type};
use snarkos_models::curves::{Field, PrimeField};
pub fn enforce_number_implicit<F: Field + PrimeField, G: GroupType<F>>(
expected_types: &Vec<Type>,
expected_type: Option<Type>,
value: String,
span: Span,
) -> Result<ConstrainedValue<F, G>, ValueError> {
if expected_types.len() == 1 {
return Ok(ConstrainedValue::from_type(value, &expected_types[0], span)?);
match expected_type {
Some(type_) => Ok(ConstrainedValue::from_type(value, &type_, span)?),
None => Ok(ConstrainedValue::Unresolved(value)),
}
Ok(ConstrainedValue::Unresolved(value))
}

View File

@ -1,5 +1,5 @@
//! Conversion of integer declarations to constraints in Leo.
use crate::{errors::IntegerError, integer::macros::IntegerTrait};
use crate::{errors::IntegerError, IntegerTrait};
use leo_gadgets::{
arithmetic::*,
bits::comparator::{ComparatorGadget, EvaluateLtGadget},
@ -17,7 +17,7 @@ use snarkos_models::{
boolean::Boolean,
eq::{ConditionalEqGadget, EqGadget, EvaluateEqGadget},
select::CondSelectGadget,
uint::{UInt, UInt128, UInt16, UInt32, UInt64, UInt8},
uint::*,
},
},
};
@ -489,7 +489,7 @@ impl<F: Field + PrimeField> ConditionalEqGadget<F> for Integer {
}
fn cost() -> usize {
<UInt128 as ConditionalEqGadget<F>>::cost() // upper bound. change trait to increase accuracy
unimplemented!() // cannot determine which integer we are enforcing
}
}
@ -517,6 +517,6 @@ impl<F: Field + PrimeField> CondSelectGadget<F> for Integer {
}
fn cost() -> usize {
<UInt128 as CondSelectGadget<F>>::cost() // upper bound. change trait to increase accuracy
unimplemented!() // cannot determine which integer we are enforcing
}
}

View File

@ -37,13 +37,15 @@ pub enum ConstrainedValue<F: Field + PrimeField, G: GroupType<F>> {
// Arrays
Array(Vec<ConstrainedValue<F, G>>),
// Tuples
Tuple(Vec<ConstrainedValue<F, G>>),
// Circuits
CircuitDefinition(Circuit),
CircuitExpression(Identifier, Vec<ConstrainedCircuitMember<F, G>>),
// Functions
Function(Option<Identifier>, Function), // (optional circuit identifier, function definition)
Return(Vec<ConstrainedValue<F, G>>),
// Modifiers
Mutable(Box<ConstrainedValue<F, G>>),
@ -61,8 +63,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
ConstrainedValue::from_type(value, &other_type, span)
}
pub(crate) fn from_type(value: String, _type: &Type, span: Span) -> Result<Self, ValueError> {
match _type {
pub(crate) fn from_type(value: String, type_: &Type, span: Span) -> Result<Self, ValueError> {
match type_ {
// Data types
Type::Address => Ok(ConstrainedValue::Address(Address::new(value, span)?)),
Type::Boolean => Ok(ConstrainedValue::Boolean(new_bool_constant(value, span)?)),
@ -103,15 +105,25 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
Type::Array(Box::new(array_type), vec![count])
}
ConstrainedValue::Tuple(tuple) => {
let mut types = vec![];
for value in tuple {
let type_ = value.to_type(span.clone())?;
types.push(type_)
}
Type::Tuple(types)
}
ConstrainedValue::CircuitExpression(id, _members) => Type::Circuit(id.clone()),
value => return Err(ValueError::implicit(value.to_string(), span)),
})
}
pub(crate) fn resolve_type(&mut self, types: &Vec<Type>, span: Span) -> Result<(), ValueError> {
pub(crate) fn resolve_type(&mut self, type_: Option<Type>, span: Span) -> Result<(), ValueError> {
if let ConstrainedValue::Unresolved(ref string) = self {
if !types.is_empty() {
*self = ConstrainedValue::from_type(string.clone(), &types[0], span)?
if type_.is_some() {
*self = ConstrainedValue::from_type(string.clone(), &type_.unwrap(), span)?
}
}
@ -119,16 +131,21 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
}
/// Expect both `self` and `other` to resolve to the same type
pub(crate) fn resolve_types(&mut self, other: &mut Self, types: &Vec<Type>, span: Span) -> Result<(), ValueError> {
if !types.is_empty() {
self.resolve_type(types, span.clone())?;
return other.resolve_type(types, span);
pub(crate) fn resolve_types(
&mut self,
other: &mut Self,
type_: Option<Type>,
span: Span,
) -> Result<(), ValueError> {
if type_.is_some() {
self.resolve_type(type_.clone(), span.clone())?;
return other.resolve_type(type_, span);
}
match (&self, &other) {
(ConstrainedValue::Unresolved(_), ConstrainedValue::Unresolved(_)) => Ok(()),
(ConstrainedValue::Unresolved(_), _) => self.resolve_type(&vec![other.to_type(span.clone())?], span),
(_, ConstrainedValue::Unresolved(_)) => other.resolve_type(&vec![self.to_type(span.clone())?], span),
(ConstrainedValue::Unresolved(_), _) => self.resolve_type(Some(other.to_type(span.clone())?), span),
(_, ConstrainedValue::Unresolved(_)) => other.resolve_type(Some(self.to_type(span.clone())?), span),
_ => Ok(()),
}
}
@ -208,6 +225,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
})
.collect::<Result<(), ValueError>>()?;
}
ConstrainedValue::Tuple(tuple) => {
tuple
.iter_mut()
.enumerate()
.map(|(i, value)| {
let unique_name = format!("allocate tuple member {} {}:{}", i, span.line, span.start);
value.allocate_value(cs.ns(|| unique_name), span.clone())
})
.collect::<Result<(), ValueError>>()?;
}
ConstrainedValue::CircuitExpression(_id, members) => {
members
.iter_mut()
@ -219,17 +247,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
})
.collect::<Result<(), ValueError>>()?;
}
ConstrainedValue::Return(array) => {
array
.iter_mut()
.enumerate()
.map(|(i, value)| {
let unique_name = format!("allocate return member {} {}:{}", i, span.line, span.start);
value.allocate_value(cs.ns(|| unique_name), span.clone())
})
.collect::<Result<(), ValueError>>()?;
}
ConstrainedValue::Mutable(value) => {
value.allocate_value(cs, span)?;
}
@ -280,6 +297,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F
}
write!(f, "]")
}
ConstrainedValue::Tuple(ref tuple) => {
let values = tuple.iter().map(|x| format!("{}", x)).collect::<Vec<_>>().join(", ");
write!(f, "({})", values)
}
ConstrainedValue::CircuitExpression(ref identifier, ref members) => {
write!(f, "{} {{", identifier)?;
for (i, member) in members.iter().enumerate() {
@ -290,16 +312,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F
}
write!(f, "}}")
}
ConstrainedValue::Return(ref values) => {
write!(f, "Program output: [")?;
for (i, value) in values.iter().enumerate() {
write!(f, "{}", value)?;
if i < values.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "]")
}
ConstrainedValue::CircuitDefinition(ref circuit) => write!(f, "circuit {{ {} }}", circuit.circuit_name),
ConstrainedValue::Function(ref _circuit_option, ref function) => {
write!(f, "function {{ {}() }}", function.identifier)
@ -347,6 +359,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConditionalEqGadget<F> for Constrai
}
Ok(())
}
(ConstrainedValue::Tuple(tuple_1), ConstrainedValue::Tuple(tuple_2)) => {
for (i, (left, right)) in tuple_1.into_iter().zip(tuple_2.into_iter()).enumerate() {
left.conditional_enforce_equal(cs.ns(|| format!("tuple index {}", i)), right, condition)?;
}
Ok(())
}
(_, _) => return Err(SynthesisError::Unsatisfiable),
}
}
@ -393,6 +411,20 @@ impl<F: Field + PrimeField, G: GroupType<F>> CondSelectGadget<F> for Constrained
ConstrainedValue::Array(array)
}
(ConstrainedValue::Tuple(tuple_1), ConstrainedValue::Array(tuple_2)) => {
let mut array = vec![];
for (i, (first, second)) in tuple_1.into_iter().zip(tuple_2.into_iter()).enumerate() {
array.push(Self::conditionally_select(
cs.ns(|| format!("tuple index {}", i)),
cond,
first,
second,
)?);
}
ConstrainedValue::Tuple(array)
}
(ConstrainedValue::Function(identifier_1, function_1), ConstrainedValue::Function(_, _)) => {
// This is a no-op. functions cannot hold circuit values
// However, we must return a result here
@ -415,20 +447,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> CondSelectGadget<F> for Constrained
ConstrainedValue::CircuitExpression(identifier.clone(), members)
}
(ConstrainedValue::Return(returns_1), ConstrainedValue::Return(returns_2)) => {
let mut returns = vec![];
for (i, (first, second)) in returns_1.into_iter().zip(returns_2.into_iter()).enumerate() {
returns.push(Self::conditionally_select(
cs.ns(|| format!("return[{}]", i)),
cond,
first,
second,
)?);
}
ConstrainedValue::Return(returns)
}
(ConstrainedValue::Static(first), ConstrainedValue::Static(second)) => {
let value = Self::conditionally_select(cs, cond, first, second)?;

View File

@ -169,6 +169,7 @@ fn test_mul() {
}
#[test]
#[ignore]
fn test_eq() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);

View File

@ -0,0 +1,7 @@
[main]
a: u32 = 0;
b: u32 = 0;
[registers]
a: u32 = 0;
b: u32 = 0;

View File

@ -41,6 +41,20 @@ fn test_iteration_repeated() {
assert_satisfied(program);
}
#[test]
fn test_newlines() {
let input_bytes = include_bytes!("input/newlines.in");
let program_bytes = include_bytes!("newlines.leo");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
let expected_bytes = include_bytes!("output_/newlines.out");
let expected = std::str::from_utf8(expected_bytes).unwrap();
let actual_bytes = get_output(program);
let actual = std::str::from_utf8(actual_bytes.bytes().as_slice()).unwrap();
assert_eq!(expected, actual);
}
#[test]
fn test_multiple_returns() {
let bytes = include_bytes!("multiple.leo");

View File

@ -0,0 +1,9 @@
function main(
a: u32,
b: u32,
) -> (
u32,
u32,
) {
return (a, b)
}

View File

@ -0,0 +1,3 @@
[registers]
a: u32 = 0u32;
b: u32 = 0u32;

View File

@ -0,0 +1,2 @@
[main]
a: group = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group;

View File

@ -44,6 +44,16 @@ fn test_point() {
assert_satisfied(program);
}
#[test]
fn test_point_input() {
let program_bytes = include_bytes!("point_input.leo");
let input_bytes = include_bytes!("input/point.in");
let program = parse_program_with_input(program_bytes, input_bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_input() {
let program_bytes = include_bytes!("input.leo");
@ -196,6 +206,7 @@ fn test_assert_eq_fail() {
}
#[test]
#[ignore]
fn test_eq() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);

View File

@ -0,0 +1,3 @@
function main(a: group) {
let b = a;
}

View File

@ -81,6 +81,11 @@ fn test_i128_eq() {
TestI128::test_eq();
}
#[test]
fn test_i128_ne() {
TestI128::test_ne();
}
#[test]
fn test_i128_ge() {
TestI128::test_ge();

View File

@ -0,0 +1,3 @@
function main(a: i128, b: i128, c: bool) {
assert_eq!(a != b, c);
}

View File

@ -80,6 +80,11 @@ fn test_i16_eq() {
TestI16::test_eq();
}
#[test]
fn test_i16_ne() {
TestI16::test_ne();
}
#[test]
fn test_i16_ge() {
TestI16::test_ge();

View File

@ -0,0 +1,3 @@
function main(a: i16, b: i16, c: bool) {
assert_eq!(a != b, c);
}

View File

@ -80,6 +80,11 @@ fn test_i32_eq() {
TestI32::test_eq();
}
#[test]
fn test_i32_ne() {
TestI32::test_ne();
}
#[test]
fn test_i32_ge() {
TestI32::test_ge();

View File

@ -0,0 +1,3 @@
function main(a: i32, b: i32, c: bool) {
assert_eq!(a != b, c);
}

View File

@ -81,6 +81,11 @@ fn test_i64_eq() {
TestI64::test_eq();
}
#[test]
fn test_i64_ne() {
TestI64::test_ne();
}
#[test]
fn test_i64_ge() {
TestI64::test_ge();

View File

@ -0,0 +1,3 @@
function main(a: i64, b: i64, c: bool) {
assert_eq!(a != b, c);
}

View File

@ -80,6 +80,11 @@ fn test_i8_eq() {
TestI8::test_eq();
}
#[test]
fn test_i8_ne() {
TestI8::test_ne();
}
#[test]
fn test_i8_ge() {
TestI8::test_ge();

View File

@ -0,0 +1,3 @@
function main(a: i8, b: i8, c: bool) {
assert_eq!(a != b, c);
}

View File

@ -257,6 +257,44 @@ macro_rules! test_int {
}
}
fn test_ne() {
for _ in 0..10 {
let a: $type_ = rand::random();
let b: $type_ = rand::random();
// test a != a == false
let bytes = include_bytes!("ne.leo");
let mut program = parse_program(bytes).unwrap();
let main_input = generate_main_input(vec![
("a", Some(InputValue::Integer($integer_type, a.to_string()))),
("b", Some(InputValue::Integer($integer_type, a.to_string()))),
("c", Some(InputValue::Boolean(false))),
]);
program.set_main_input(main_input);
assert_satisfied(program);
// test not equal
let c = a.ne(&b);
let mut program = parse_program(bytes).unwrap();
let main_input = generate_main_input(vec![
("a", Some(InputValue::Integer($integer_type, a.to_string()))),
("b", Some(InputValue::Integer($integer_type, b.to_string()))),
("c", Some(InputValue::Boolean(c))),
]);
program.set_main_input(main_input);
assert_satisfied(program);
}
}
fn test_ge() {
for _ in 0..10 {
let a: $type_ = rand::random();

View File

@ -32,6 +32,9 @@ pub trait IntegerTester {
/// Tests == evaluation
fn test_eq();
/// Tests != evaluation
fn test_ne();
/// Tests >= evaluation
fn test_ge();

View File

@ -8,7 +8,7 @@ pub mod integer_tester;
pub use self::integer_tester::*;
// must be below macro definitions!
pub mod u128;
// pub mod u128;
pub mod u16;
pub mod u32;
pub mod u64;

View File

@ -65,6 +65,11 @@ fn test_u128_eq() {
TestU128::test_eq();
}
#[test]
fn test_u128_ne() {
TestU128::test_ne();
}
#[test]
fn test_u128_ge() {
TestU128::test_ge();

Some files were not shown because too many files have changed in this diff Show More