merge dev, fix conflicts, remove base64 crate
This commit is contained in:
commit
edd7b5bbd1
38 changed files with 2182 additions and 699 deletions
|
@ -57,6 +57,14 @@ jobs:
|
|||
# - run:
|
||||
# name: Generate code coverage report
|
||||
# command: ./scripts/cov.sh
|
||||
cpp_format:
|
||||
docker:
|
||||
- image: dark64/clang-format-checker:env
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Check cpp format (clang-format)
|
||||
command: run-clang-format.py -r $(pwd)/zokrates_core/lib
|
||||
wasm_test:
|
||||
docker:
|
||||
- image: rustlang/rust:nightly-slim
|
||||
|
@ -133,6 +141,7 @@ workflows:
|
|||
jobs:
|
||||
- build
|
||||
- test
|
||||
- cpp_format
|
||||
- wasm_test
|
||||
- integration_test
|
||||
- zokrates_js_build
|
||||
|
@ -145,6 +154,7 @@ workflows:
|
|||
requires:
|
||||
- build
|
||||
- test
|
||||
- cpp_format
|
||||
- wasm_test
|
||||
- integration_test
|
||||
- zokrates_js_build
|
||||
|
|
287
Cargo.lock
generated
287
Cargo.lock
generated
|
@ -60,9 +60,9 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
|||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.45"
|
||||
version = "0.3.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8"
|
||||
checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
|
||||
dependencies = [
|
||||
"backtrace-sys",
|
||||
"cfg-if",
|
||||
|
@ -72,49 +72,25 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "backtrace-sys"
|
||||
version = "0.1.34"
|
||||
version = "0.1.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69"
|
||||
checksum = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d5ca2cd0adc3f48f9e9ea5a6bbdf9ccc0bfade884847e484d452414c7ccffb3"
|
||||
|
||||
[[package]]
|
||||
name = "bellman_ce"
|
||||
version = "0.3.1"
|
||||
source = "git+https://github.com/matter-labs/bellman?rev=9e35737#9e35737209d4afc2e69af1e0d7cbe6d02e32aecf"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0300152b8d0c0220c70a39d6da08adff84352f5dd28d91944bc60e9dc8cbebb9"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
"byteorder",
|
||||
"cfg-if",
|
||||
"crossbeam",
|
||||
"futures",
|
||||
"futures-cpupool",
|
||||
"num_cpus",
|
||||
"pairing_ce",
|
||||
"rand 0.4.6",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bellman_ce"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "938ec0feff00f9dfda0e7cbfe8db8b717966a84f6a12e63ed0943c4a90d6a5de"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
"byteorder",
|
||||
"cfg-if",
|
||||
"crossbeam",
|
||||
"futures",
|
||||
"futures-cpupool",
|
||||
"num_cpus",
|
||||
"pairing_ce",
|
||||
"rand 0.4.6",
|
||||
|
@ -134,9 +110,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.4.4"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f"
|
||||
checksum = "a4523a10839ffae575fb08aa3423026c8cb4687eef43952afb956229d4f246f7"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
|
@ -190,9 +166,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.2.0"
|
||||
version = "3.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f359dc14ff8911330a51ef78022d376f25ed00248912803b58f00cb1c27f742"
|
||||
checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187"
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
|
@ -452,9 +428,9 @@ version = "0.1.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.9",
|
||||
"proc-macro2 1.0.10",
|
||||
"quote 1.0.3",
|
||||
"syn 1.0.16",
|
||||
"syn 1.0.17",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
@ -466,28 +442,28 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
|||
|
||||
[[package]]
|
||||
name = "ff_ce"
|
||||
version = "0.7.1"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18af1ea1b80a4b474fae13af4c58cf0a5a2bc33832d5fa70f68a4b286178fdb5"
|
||||
checksum = "83c0a6a2c53b0bd6d8cae976816dc8a171e0554c03f304e3dac110473e0219fd"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"ff_derive_ce",
|
||||
"hex 0.3.2",
|
||||
"hex",
|
||||
"rand 0.4.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ff_derive_ce"
|
||||
version = "0.5.1"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d245b4e76c5b36bb7721ea15b7fbc61bebf0c5d2890eaf49fe1e2a3eed36db9"
|
||||
checksum = "7543567f0c51910363eb5706ee2f5368a64e79a8ae607d0332aa60bae03a1bb1"
|
||||
dependencies = [
|
||||
"num-bigint 0.2.6",
|
||||
"num-integer",
|
||||
"num-traits 0.2.11",
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.13",
|
||||
"syn 0.14.9",
|
||||
"proc-macro2 1.0.10",
|
||||
"quote 1.0.3",
|
||||
"syn 1.0.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -514,20 +490,81 @@ checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
|||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.1.29"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef"
|
||||
checksum = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-cpupool"
|
||||
version = "0.1.8"
|
||||
name = "futures-channel"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
|
||||
checksum = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.12.3"
|
||||
|
@ -550,9 +587,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.13.1"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef222034f2069cfc5af01ce423574d3d9a3925bd4052912a14e5bcfd7ca9e47a"
|
||||
checksum = "2cfb93ca10f2934069c3aaafb753fbe0663f08ee009a01b6d62e062391447b15"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
|
@ -577,19 +614,13 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.8"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
|
||||
checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.2"
|
||||
|
@ -633,9 +664,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.36"
|
||||
version = "0.3.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cb931d43e71f560c81badb0191596562bafad2be06a3f9025b845c847c60df5"
|
||||
checksum = "6a27d435371a2fa5b6d2b028a74bbdb1234f308da363226a2854ca3ff8ba7055"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
@ -654,9 +685,9 @@ checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
|
|||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.12.2+1.0.0"
|
||||
version = "0.12.3+1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a12c878ccc1a49ff71e264233a66d2114cdcc7fdc44c0ebe2b54075240831238"
|
||||
checksum = "7637dc15e7f05a16011723e0448655081fc01a374bcd368e2c9b9c7f5c5ab3ea"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
@ -849,9 +880,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pairing_ce"
|
||||
version = "0.18.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f075a9c570e2026111cb6dddf6a320e5163c42aa32500b315ec34acbcf7c9b36"
|
||||
checksum = "6c7b23aa7f0489d9a5e8e15cc5b7cb4f3e9b9d64812b8875fb91d25b640b0939"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"ff_ce",
|
||||
|
@ -904,9 +935,9 @@ checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
|
|||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2 1.0.9",
|
||||
"proc-macro2 1.0.10",
|
||||
"quote 1.0.3",
|
||||
"syn 1.0.16",
|
||||
"syn 1.0.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -920,6 +951,12 @@ dependencies = [
|
|||
"sha-1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0-alpha.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.17"
|
||||
|
@ -943,9 +980,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
|
||||
checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
@ -974,7 +1011,7 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.9",
|
||||
"proc-macro2 1.0.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1134,7 +1171,7 @@ version = "0.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec318b68765114e578fe42446b6861565b302bc93089aa01669d19417a6de993"
|
||||
dependencies = [
|
||||
"bellman_ce 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bellman_ce",
|
||||
"blake2-rfc_bellman_edition",
|
||||
"byteorder",
|
||||
"digest",
|
||||
|
@ -1175,9 +1212,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.105"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff"
|
||||
checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399"
|
||||
|
||||
[[package]]
|
||||
name = "serde_bytes"
|
||||
|
@ -1190,20 +1227,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.105"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8"
|
||||
checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.9",
|
||||
"proc-macro2 1.0.10",
|
||||
"quote 1.0.3",
|
||||
"syn 1.0.16",
|
||||
"syn 1.0.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.48"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25"
|
||||
checksum = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -1259,6 +1296,12 @@ dependencies = [
|
|||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.2.0"
|
||||
|
@ -1271,17 +1314,6 @@ version = "0.8.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.14.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.13",
|
||||
"unicode-xid 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.44"
|
||||
|
@ -1295,11 +1327,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.16"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859"
|
||||
checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.9",
|
||||
"proc-macro2 1.0.10",
|
||||
"quote 1.0.3",
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
@ -1310,9 +1342,9 @@ version = "0.12.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.9",
|
||||
"proc-macro2 1.0.10",
|
||||
"quote 1.0.3",
|
||||
"syn 1.0.16",
|
||||
"syn 1.0.17",
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
||||
|
@ -1360,9 +1392,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tiny-keccak"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2953ca5148619bc99695c1274cb54c5275bbb913c6adad87e72eaf8db9787f69"
|
||||
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
|
||||
dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
@ -1487,9 +1519,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.59"
|
||||
version = "0.2.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3557c397ab5a8e347d434782bcd31fc1483d927a6826804cec05cc792ee2519d"
|
||||
checksum = "2cc57ce05287f8376e998cbddfb4c8cb43b84a7ec55cf4551d7c00eef317a47f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
|
@ -1497,24 +1529,24 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.59"
|
||||
version = "0.2.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0da9c9a19850d3af6df1cb9574970b566d617ecfaf36eb0b706b6f3ef9bd2f8"
|
||||
checksum = "d967d37bf6c16cca2973ca3af071d0a2523392e4a594548155d89a678f4237cd"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"proc-macro2 1.0.9",
|
||||
"proc-macro2 1.0.10",
|
||||
"quote 1.0.3",
|
||||
"syn 1.0.16",
|
||||
"syn 1.0.17",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.9"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "457414a91863c0ec00090dba537f88ab955d93ca6555862c29b6d860990b8a8a"
|
||||
checksum = "7add542ea1ac7fdaa9dc25e031a6af33b7d63376292bd24140c637d00d1c312a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
|
@ -1524,9 +1556,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.59"
|
||||
version = "0.2.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f6fde1d36e75a714b5fe0cffbb78978f222ea6baebb726af13c78869fdb4205"
|
||||
checksum = "8bd151b63e1ea881bb742cd20e1d6127cef28399558f3b5d415289bc41eee3a4"
|
||||
dependencies = [
|
||||
"quote 1.0.3",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -1534,28 +1566,28 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.59"
|
||||
version = "0.2.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25bda4168030a6412ea8a047e27238cadf56f0e53516e1e83fec0a8b7c786f6d"
|
||||
checksum = "d68a5b36eef1be7868f668632863292e37739656a80fc4b9acec7b0bd35a4931"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.9",
|
||||
"proc-macro2 1.0.10",
|
||||
"quote 1.0.3",
|
||||
"syn 1.0.16",
|
||||
"syn 1.0.17",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.59"
|
||||
version = "0.2.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc9f36ad51f25b0219a3d4d13b90eb44cd075dff8b6280cca015775d7acaddd8"
|
||||
checksum = "daf76fe7d25ac79748a37538b7daeed1c7a6867c92d3245c12c6222e4a20d639"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-test"
|
||||
version = "0.3.9"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "449aeba7035e4a4710cd263bbac33519fa3828bff1c6f642fa8896601e7016ad"
|
||||
checksum = "648da3460c6d2aa04b715a936329e2e311180efe650b2127d6267f4193ccac14"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"js-sys",
|
||||
|
@ -1567,19 +1599,19 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-test-macro"
|
||||
version = "0.3.9"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49449f8dcedc192bd0cf11b5711982decdd4dbad1029f92370e2b1215031dd59"
|
||||
checksum = "cf2f86cd78a2aa7b1fb4bb6ed854eccb7f9263089c79542dca1576a1518a8467"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.9",
|
||||
"proc-macro2 1.0.10",
|
||||
"quote 1.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.36"
|
||||
version = "0.3.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "721c6263e2c66fd44501cc5efbfa2b7dfa775d13e4ea38c46299646ed1f9c70a"
|
||||
checksum = "2d6f51648d8c56c366144378a33290049eafdd784071077f6fe37dae64c1c4cb"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
@ -1603,9 +1635,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80"
|
||||
checksum = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
@ -1654,8 +1686,7 @@ name = "zokrates_core"
|
|||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"assert_cli",
|
||||
"base64",
|
||||
"bellman_ce 0.3.1 (git+https://github.com/matter-labs/bellman?rev=9e35737)",
|
||||
"bellman_ce",
|
||||
"bincode",
|
||||
"cc",
|
||||
"cmake",
|
||||
|
@ -1663,7 +1694,7 @@ dependencies = [
|
|||
"ff_ce",
|
||||
"git2",
|
||||
"glob 0.2.11",
|
||||
"hex 0.4.2",
|
||||
"hex",
|
||||
"lazy_static",
|
||||
"num",
|
||||
"num-bigint 0.1.44",
|
||||
|
@ -1695,7 +1726,7 @@ dependencies = [
|
|||
name = "zokrates_embed"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"bellman_ce 0.3.1 (git+https://github.com/matter-labs/bellman?rev=9e35737)",
|
||||
"bellman_ce",
|
||||
"sapling-crypto_ce",
|
||||
]
|
||||
|
||||
|
|
8
scripts/clang-format.sh
Executable file
8
scripts/clang-format.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
# Usage: ./clang-format.sh zokrates_core/lib
|
||||
|
||||
dir=$1
|
||||
|
||||
for file in $dir/*.cpp $dir/*.hpp; do
|
||||
clang-format -i -style=WebKit -verbose $file
|
||||
done
|
|
@ -4,7 +4,7 @@ def lt(field a,field b) -> (field):
|
|||
def cutoff() -> (field):
|
||||
return 31337
|
||||
|
||||
def getThing(index) -> (field):
|
||||
def getThing(field index) -> (field):
|
||||
field result = 3
|
||||
result = if index == 0 then 13 else result fi
|
||||
result = if index == 1 then 23 else result fi
|
|
@ -719,12 +719,18 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn examples() {
|
||||
for p in glob("./examples/**/*.zok").expect("Failed to read glob pattern") {
|
||||
for p in glob("./examples/**/*").expect("Failed to read glob pattern") {
|
||||
let path = match p {
|
||||
Ok(x) => x,
|
||||
Err(why) => panic!("Error: {:?}", why),
|
||||
};
|
||||
|
||||
if !path.is_file() {
|
||||
continue;
|
||||
}
|
||||
|
||||
assert!(path.extension().expect("extension expected") == "zok");
|
||||
|
||||
if path.to_str().unwrap().contains("error") {
|
||||
continue;
|
||||
}
|
||||
|
@ -747,7 +753,7 @@ mod tests {
|
|||
#[test]
|
||||
fn examples_with_input_success() {
|
||||
//these examples should compile and run
|
||||
for p in glob("./examples/test*.zok").expect("Failed to read glob pattern") {
|
||||
for p in glob("./examples/test*").expect("Failed to read glob pattern") {
|
||||
let path = match p {
|
||||
Ok(x) => x,
|
||||
Err(why) => panic!("Error: {:?}", why),
|
||||
|
@ -775,7 +781,7 @@ mod tests {
|
|||
#[should_panic]
|
||||
fn examples_with_input_failure() {
|
||||
//these examples should compile but not run
|
||||
for p in glob("./examples/runtime_errors/*.zok").expect("Failed to read glob pattern") {
|
||||
for p in glob("./examples/runtime_errors/*").expect("Failed to read glob pattern") {
|
||||
let path = match p {
|
||||
Ok(x) => x,
|
||||
Err(why) => panic!("Error: {:?}", why),
|
||||
|
|
|
@ -25,17 +25,16 @@ serde_json = "1.0"
|
|||
serde_bytes = "0.10"
|
||||
bincode = "0.8.0"
|
||||
hex = "0.4.2"
|
||||
base64 = "0.12.0"
|
||||
regex = "0.2"
|
||||
pairing_ce = "0.18"
|
||||
ff_ce = "0.7"
|
||||
pairing_ce = "0.20"
|
||||
ff_ce = "0.9"
|
||||
zokrates_field = { version = "0.3.0", path = "../zokrates_field" }
|
||||
zokrates_pest_ast = { version = "0.1.0", path = "../zokrates_pest_ast" }
|
||||
zokrates_embed = { path = "../zokrates_embed" }
|
||||
zokrates_common = { path = "../zokrates_common" }
|
||||
rand = "0.4"
|
||||
csv = "1"
|
||||
bellman_ce = { git = "https://github.com/matter-labs/bellman", rev = "9e35737", default-features = false }
|
||||
bellman_ce = { version = "0.3.3", default-features = false}
|
||||
|
||||
[dev-dependencies]
|
||||
glob = "0.2.11"
|
||||
|
|
|
@ -156,76 +156,83 @@ fn statements_from_statement<'ast, T: Field>(
|
|||
pest::Statement::Definition(s) => statements_from_definition(s),
|
||||
pest::Statement::Iteration(s) => vec![absy::StatementNode::from(s)],
|
||||
pest::Statement::Assertion(s) => vec![absy::StatementNode::from(s)],
|
||||
pest::Statement::Assignment(s) => vec![absy::StatementNode::from(s)],
|
||||
pest::Statement::Return(s) => vec![absy::StatementNode::from(s)],
|
||||
pest::Statement::MultiAssignment(s) => statements_from_multi_assignment(s),
|
||||
}
|
||||
}
|
||||
|
||||
fn statements_from_multi_assignment<'ast, T: Field>(
|
||||
assignment: pest::MultiAssignmentStatement<'ast>,
|
||||
) -> Vec<absy::StatementNode<T>> {
|
||||
use absy::NodeValue;
|
||||
|
||||
let declarations = assignment
|
||||
.lhs
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter(|i| i.ty.is_some())
|
||||
.map(|i| {
|
||||
absy::Statement::Declaration(
|
||||
absy::Variable::new(
|
||||
i.id.span.as_str(),
|
||||
absy::UnresolvedTypeNode::from(i.ty.unwrap()),
|
||||
)
|
||||
.span(i.id.span),
|
||||
)
|
||||
.span(i.span)
|
||||
});
|
||||
|
||||
let lhs = assignment
|
||||
.lhs
|
||||
.into_iter()
|
||||
.map(|i| absy::Assignee::Identifier(i.id.span.as_str()).span(i.id.span))
|
||||
.collect();
|
||||
|
||||
let multi_def = absy::Statement::MultipleDefinition(
|
||||
lhs,
|
||||
absy::Expression::FunctionCall(
|
||||
&assignment.function_id.span.as_str(),
|
||||
assignment
|
||||
.arguments
|
||||
.into_iter()
|
||||
.map(|e| absy::ExpressionNode::from(e))
|
||||
.collect(),
|
||||
)
|
||||
.span(assignment.function_id.span),
|
||||
)
|
||||
.span(assignment.span);
|
||||
|
||||
declarations.chain(std::iter::once(multi_def)).collect()
|
||||
}
|
||||
|
||||
fn statements_from_definition<'ast, T: Field>(
|
||||
definition: pest::DefinitionStatement<'ast>,
|
||||
) -> Vec<absy::StatementNode<T>> {
|
||||
use absy::NodeValue;
|
||||
|
||||
vec![
|
||||
absy::Statement::Declaration(
|
||||
absy::Variable::new(
|
||||
definition.id.span.as_str(),
|
||||
absy::UnresolvedTypeNode::from(definition.ty),
|
||||
let lhs = definition.lhs;
|
||||
|
||||
match lhs.len() {
|
||||
1 => {
|
||||
// Definition or assignment
|
||||
let a = lhs[0].clone();
|
||||
|
||||
let e: absy::ExpressionNode<T> = absy::ExpressionNode::from(definition.expression);
|
||||
|
||||
let s = match e.value {
|
||||
absy::Expression::FunctionCall(..) => absy::Statement::MultipleDefinition(
|
||||
vec![absy::AssigneeNode::from(a.a.clone())],
|
||||
e,
|
||||
),
|
||||
_ => absy::Statement::Definition(absy::AssigneeNode::from(a.a.clone()), e),
|
||||
};
|
||||
|
||||
match a.ty {
|
||||
Some(ty) => {
|
||||
assert_eq!(a.a.accesses.len(), 0);
|
||||
|
||||
let declaration = absy::Statement::Declaration(
|
||||
absy::Variable::new(
|
||||
a.a.id.span.as_str(),
|
||||
absy::UnresolvedTypeNode::from(ty),
|
||||
)
|
||||
.span(a.a.id.span.clone()),
|
||||
)
|
||||
.span(definition.span.clone());
|
||||
|
||||
vec![declaration, s.span(definition.span)]
|
||||
}
|
||||
None => {
|
||||
// Assignment
|
||||
vec![s.span(definition.span)]
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Multidefinition
|
||||
let declarations = lhs.clone().into_iter().filter(|i| i.ty.is_some()).map(|a| {
|
||||
let ty = a.ty;
|
||||
let a = a.a;
|
||||
|
||||
assert_eq!(a.accesses.len(), 0);
|
||||
absy::Statement::Declaration(
|
||||
absy::Variable::new(
|
||||
a.id.span.as_str(),
|
||||
absy::UnresolvedTypeNode::from(ty.unwrap()),
|
||||
)
|
||||
.span(a.id.span),
|
||||
)
|
||||
.span(a.span)
|
||||
});
|
||||
let lhs = lhs
|
||||
.into_iter()
|
||||
.map(|i| absy::Assignee::Identifier(i.a.id.span.as_str()).span(i.a.id.span))
|
||||
.collect();
|
||||
|
||||
let multi_def = absy::Statement::MultipleDefinition(
|
||||
lhs,
|
||||
absy::ExpressionNode::from(definition.expression),
|
||||
)
|
||||
.span(definition.id.span.clone()),
|
||||
)
|
||||
.span(definition.span.clone()),
|
||||
absy::Statement::Definition(
|
||||
absy::AssigneeNode::from(definition.id),
|
||||
absy::ExpressionNode::from(definition.expression),
|
||||
)
|
||||
.span(definition.span),
|
||||
]
|
||||
.span(definition.span);
|
||||
|
||||
declarations.chain(std::iter::once(multi_def)).collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> From<pest::ReturnStatement<'ast>> for absy::StatementNode<'ast, T> {
|
||||
|
@ -289,18 +296,6 @@ impl<'ast, T: Field> From<pest::IterationStatement<'ast>> for absy::StatementNod
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> From<pest::AssignmentStatement<'ast>> for absy::StatementNode<'ast, T> {
|
||||
fn from(statement: pest::AssignmentStatement<'ast>) -> absy::StatementNode<T> {
|
||||
use absy::NodeValue;
|
||||
|
||||
absy::Statement::Definition(
|
||||
absy::AssigneeNode::from(statement.assignee),
|
||||
absy::ExpressionNode::from(statement.expression),
|
||||
)
|
||||
.span(statement.span)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> From<pest::Expression<'ast>> for absy::ExpressionNode<'ast, T> {
|
||||
fn from(expression: pest::Expression<'ast>) -> absy::ExpressionNode<'ast, T> {
|
||||
match expression {
|
||||
|
@ -971,4 +966,147 @@ mod tests {
|
|||
absy::Module::<FieldPrime>::from(ast);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn declarations() {
|
||||
use self::pest::Span;
|
||||
|
||||
let span = Span::new(&"", 0, 0).unwrap();
|
||||
|
||||
// For different definitions, we generate declarations
|
||||
// Case 1: `id = expr` where `expr` is not a function call
|
||||
// This is a simple assignment, doesn't implicitely declare a variable
|
||||
// A `Definition` is generatedm and no `Declaration`s
|
||||
|
||||
let definition = pest::DefinitionStatement {
|
||||
lhs: vec![pest::OptionallyTypedAssignee {
|
||||
ty: None,
|
||||
a: pest::Assignee {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("a"),
|
||||
span: span.clone(),
|
||||
},
|
||||
accesses: vec![],
|
||||
span: span.clone(),
|
||||
},
|
||||
span: span.clone(),
|
||||
}],
|
||||
expression: pest::Expression::Constant(pest::ConstantExpression::DecimalNumber(
|
||||
pest::DecimalNumberExpression {
|
||||
value: String::from("42"),
|
||||
span: span.clone(),
|
||||
},
|
||||
)),
|
||||
span: span.clone(),
|
||||
};
|
||||
|
||||
let statements: Vec<absy::StatementNode<FieldPrime>> =
|
||||
statements_from_definition(definition);
|
||||
|
||||
assert_eq!(statements.len(), 1);
|
||||
match &statements[0].value {
|
||||
absy::Statement::Definition(..) => {}
|
||||
s => {
|
||||
panic!("should be a Definition, found {}", s);
|
||||
}
|
||||
};
|
||||
|
||||
// Case 2: `id = expr` where `expr` is a function call
|
||||
// A MultiDef is generated
|
||||
|
||||
let definition = pest::DefinitionStatement {
|
||||
lhs: vec![pest::OptionallyTypedAssignee {
|
||||
ty: None,
|
||||
a: pest::Assignee {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("a"),
|
||||
span: span.clone(),
|
||||
},
|
||||
accesses: vec![],
|
||||
span: span.clone(),
|
||||
},
|
||||
span: span.clone(),
|
||||
}],
|
||||
expression: pest::Expression::Postfix(pest::PostfixExpression {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("foo"),
|
||||
span: span.clone(),
|
||||
},
|
||||
accesses: vec![pest::Access::Call(pest::CallAccess {
|
||||
expressions: vec![],
|
||||
span: span.clone(),
|
||||
})],
|
||||
span: span.clone(),
|
||||
}),
|
||||
span: span.clone(),
|
||||
};
|
||||
|
||||
let statements: Vec<absy::StatementNode<FieldPrime>> =
|
||||
statements_from_definition(definition);
|
||||
|
||||
assert_eq!(statements.len(), 1);
|
||||
match &statements[0].value {
|
||||
absy::Statement::MultipleDefinition(..) => {}
|
||||
s => {
|
||||
panic!("should be a Definition, found {}", s);
|
||||
}
|
||||
};
|
||||
// Case 3: `ids = expr` where `expr` is a function call
|
||||
// This implicitely declares all variables which are type annotated
|
||||
|
||||
// `field a, b = foo()`
|
||||
|
||||
let definition = pest::DefinitionStatement {
|
||||
lhs: vec![
|
||||
pest::OptionallyTypedAssignee {
|
||||
ty: Some(pest::Type::Basic(pest::BasicType::Field(pest::FieldType {
|
||||
span: span.clone(),
|
||||
}))),
|
||||
a: pest::Assignee {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("a"),
|
||||
span: span.clone(),
|
||||
},
|
||||
accesses: vec![],
|
||||
span: span.clone(),
|
||||
},
|
||||
span: span.clone(),
|
||||
},
|
||||
pest::OptionallyTypedAssignee {
|
||||
ty: None,
|
||||
a: pest::Assignee {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("b"),
|
||||
span: span.clone(),
|
||||
},
|
||||
accesses: vec![],
|
||||
span: span.clone(),
|
||||
},
|
||||
span: span.clone(),
|
||||
},
|
||||
],
|
||||
expression: pest::Expression::Postfix(pest::PostfixExpression {
|
||||
id: pest::IdentifierExpression {
|
||||
value: String::from("foo"),
|
||||
span: span.clone(),
|
||||
},
|
||||
accesses: vec![pest::Access::Call(pest::CallAccess {
|
||||
expressions: vec![],
|
||||
span: span.clone(),
|
||||
})],
|
||||
span: span.clone(),
|
||||
}),
|
||||
span: span.clone(),
|
||||
};
|
||||
|
||||
let statements: Vec<absy::StatementNode<FieldPrime>> =
|
||||
statements_from_definition(definition);
|
||||
|
||||
assert_eq!(statements.len(), 2);
|
||||
match &statements[1].value {
|
||||
absy::Statement::MultipleDefinition(..) => {}
|
||||
s => {
|
||||
panic!("should be a Definition, found {}", s);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,6 +164,9 @@ pub fn compile<T: Field, E: Into<imports::Error>>(
|
|||
// optimize
|
||||
let optimized_ir_prog = ir_prog.optimize();
|
||||
|
||||
// analyse (check for unused constraints)
|
||||
let optimized_ir_prog = optimized_ir_prog.analyse();
|
||||
|
||||
Ok(CompilationArtifacts {
|
||||
prog: optimized_ir_prog,
|
||||
abi,
|
||||
|
|
|
@ -203,7 +203,7 @@ fn use_variable(
|
|||
/// * the return value of the `FlatFunction` is not deterministic: as we decompose over log_2(p) + 1 bits, some
|
||||
/// elements can have multiple representations: For example, `unpack(0)` is `[0, ..., 0]` but also `unpack(p)`
|
||||
pub fn unpack<T: Field>() -> FlatFunction<T> {
|
||||
let nbits = T::get_required_bits();
|
||||
let bit_width = T::get_required_bits();
|
||||
|
||||
let mut counter = 0;
|
||||
|
||||
|
@ -221,23 +221,23 @@ pub fn unpack<T: Field>() -> FlatFunction<T> {
|
|||
format!("i0"),
|
||||
&mut counter,
|
||||
))];
|
||||
let directive_outputs: Vec<FlatVariable> = (0..T::get_required_bits())
|
||||
let directive_outputs: Vec<FlatVariable> = (0..bit_width)
|
||||
.map(|index| use_variable(&mut layout, format!("o{}", index), &mut counter))
|
||||
.collect();
|
||||
|
||||
let solver = Solver::bits();
|
||||
let solver = Solver::bits(bit_width);
|
||||
|
||||
let outputs = directive_outputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(index, _)| *index >= T::get_required_bits() - nbits)
|
||||
.filter(|(index, _)| *index >= T::get_required_bits() - bit_width)
|
||||
.map(|(_, o)| FlatExpression::Identifier(o.clone()))
|
||||
.collect();
|
||||
|
||||
// o253, o252, ... o{253 - (nbits - 1)} are bits
|
||||
let mut statements: Vec<FlatStatement<T>> = (0..nbits)
|
||||
// o253, o252, ... o{253 - (bit_width - 1)} are bits
|
||||
let mut statements: Vec<FlatStatement<T>> = (0..bit_width)
|
||||
.map(|index| {
|
||||
let bit = FlatExpression::Identifier(FlatVariable::new(T::get_required_bits() - index));
|
||||
let bit = FlatExpression::Identifier(FlatVariable::new(bit_width - index));
|
||||
FlatStatement::Condition(
|
||||
bit.clone(),
|
||||
FlatExpression::Mult(box bit.clone(), box bit.clone()),
|
||||
|
@ -245,14 +245,14 @@ pub fn unpack<T: Field>() -> FlatFunction<T> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
// sum check: o253 + o252 * 2 + ... + o{253 - (nbits - 1)} * 2**(nbits - 1)
|
||||
// sum check: o253 + o252 * 2 + ... + o{253 - (bit_width - 1)} * 2**(bit_width - 1)
|
||||
let mut lhs_sum = FlatExpression::Number(T::from(0));
|
||||
|
||||
for i in 0..nbits {
|
||||
for i in 0..bit_width {
|
||||
lhs_sum = FlatExpression::Add(
|
||||
box lhs_sum,
|
||||
box FlatExpression::Mult(
|
||||
box FlatExpression::Identifier(FlatVariable::new(T::get_required_bits() - i)),
|
||||
box FlatExpression::Identifier(FlatVariable::new(bit_width - i)),
|
||||
box FlatExpression::Number(T::from(2).pow(i)),
|
||||
),
|
||||
);
|
||||
|
@ -312,7 +312,7 @@ mod tests {
|
|||
(0..FieldPrime::get_required_bits())
|
||||
.map(|i| FlatVariable::new(i + 1))
|
||||
.collect(),
|
||||
Solver::bits(),
|
||||
Solver::bits(FieldPrime::get_required_bits()),
|
||||
vec![FlatVariable::new(0)]
|
||||
))
|
||||
);
|
||||
|
|
|
@ -566,8 +566,9 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
|||
FlatExpression::Identifier(self.layout.get(&x).unwrap().clone()[0])
|
||||
}
|
||||
BooleanExpression::Lt(box lhs, box rhs) => {
|
||||
// Get the bitwidth to know the size of the binary decompsitions for this Field
|
||||
let bitwidth = T::get_required_bits();
|
||||
// Get the bit width to know the size of the binary decompositions for this Field
|
||||
let bit_width = T::get_required_bits();
|
||||
let safe_width = bit_width - 2; // making sure we don't overflow, assert here?
|
||||
|
||||
// We know from semantic checking that lhs and rhs have the same type
|
||||
// What the expression will flatten to depends on that type
|
||||
|
@ -587,22 +588,22 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
|||
{
|
||||
// define variables for the bits
|
||||
let lhs_bits_be: Vec<FlatVariable> =
|
||||
(0..bitwidth).map(|_| self.use_sym()).collect();
|
||||
(0..safe_width).map(|_| self.use_sym()).collect();
|
||||
|
||||
// add a directive to get the bits
|
||||
statements_flattened.push(FlatStatement::Directive(FlatDirective::new(
|
||||
lhs_bits_be.clone(),
|
||||
Solver::bits(),
|
||||
Solver::bits(safe_width),
|
||||
vec![lhs_id],
|
||||
)));
|
||||
|
||||
// bitness checks
|
||||
for i in 0..bitwidth - 2 {
|
||||
for i in 0..safe_width {
|
||||
statements_flattened.push(FlatStatement::Condition(
|
||||
FlatExpression::Identifier(lhs_bits_be[i + 2]),
|
||||
FlatExpression::Identifier(lhs_bits_be[i]),
|
||||
FlatExpression::Mult(
|
||||
box FlatExpression::Identifier(lhs_bits_be[i + 2]),
|
||||
box FlatExpression::Identifier(lhs_bits_be[i + 2]),
|
||||
box FlatExpression::Identifier(lhs_bits_be[i]),
|
||||
box FlatExpression::Identifier(lhs_bits_be[i]),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
@ -610,12 +611,12 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
|||
// bit decomposition check
|
||||
let mut lhs_sum = FlatExpression::Number(T::from(0));
|
||||
|
||||
for i in 0..bitwidth - 2 {
|
||||
for i in 0..safe_width {
|
||||
lhs_sum = FlatExpression::Add(
|
||||
box lhs_sum,
|
||||
box FlatExpression::Mult(
|
||||
box FlatExpression::Identifier(lhs_bits_be[i + 2]),
|
||||
box FlatExpression::Number(T::from(2).pow(bitwidth - 2 - i - 1)),
|
||||
box FlatExpression::Identifier(lhs_bits_be[i]),
|
||||
box FlatExpression::Number(T::from(2).pow(safe_width - i - 1)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -634,22 +635,22 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
|||
{
|
||||
// define variables for the bits
|
||||
let rhs_bits_be: Vec<FlatVariable> =
|
||||
(0..bitwidth).map(|_| self.use_sym()).collect();
|
||||
(0..safe_width).map(|_| self.use_sym()).collect();
|
||||
|
||||
// add a directive to get the bits
|
||||
statements_flattened.push(FlatStatement::Directive(FlatDirective::new(
|
||||
rhs_bits_be.clone(),
|
||||
Solver::bits(),
|
||||
Solver::bits(safe_width),
|
||||
vec![rhs_id],
|
||||
)));
|
||||
|
||||
// bitness checks
|
||||
for i in 0..bitwidth - 2 {
|
||||
for i in 0..safe_width {
|
||||
statements_flattened.push(FlatStatement::Condition(
|
||||
FlatExpression::Identifier(rhs_bits_be[i + 2]),
|
||||
FlatExpression::Identifier(rhs_bits_be[i]),
|
||||
FlatExpression::Mult(
|
||||
box FlatExpression::Identifier(rhs_bits_be[i + 2]),
|
||||
box FlatExpression::Identifier(rhs_bits_be[i + 2]),
|
||||
box FlatExpression::Identifier(rhs_bits_be[i]),
|
||||
box FlatExpression::Identifier(rhs_bits_be[i]),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
@ -657,12 +658,12 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
|||
// bit decomposition check
|
||||
let mut rhs_sum = FlatExpression::Number(T::from(0));
|
||||
|
||||
for i in 0..bitwidth - 2 {
|
||||
for i in 0..safe_width {
|
||||
rhs_sum = FlatExpression::Add(
|
||||
box rhs_sum,
|
||||
box FlatExpression::Mult(
|
||||
box FlatExpression::Identifier(rhs_bits_be[i + 2]),
|
||||
box FlatExpression::Number(T::from(2).pow(bitwidth - 2 - i - 1)),
|
||||
box FlatExpression::Identifier(rhs_bits_be[i]),
|
||||
box FlatExpression::Number(T::from(2).pow(safe_width - i - 1)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -687,17 +688,17 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
|||
|
||||
// define variables for the bits
|
||||
let sub_bits_be: Vec<FlatVariable> =
|
||||
(0..bitwidth).map(|_| self.use_sym()).collect();
|
||||
(0..bit_width).map(|_| self.use_sym()).collect();
|
||||
|
||||
// add a directive to get the bits
|
||||
statements_flattened.push(FlatStatement::Directive(FlatDirective::new(
|
||||
sub_bits_be.clone(),
|
||||
Solver::bits(),
|
||||
Solver::bits(bit_width),
|
||||
vec![subtraction_result.clone()],
|
||||
)));
|
||||
|
||||
// bitness checks
|
||||
for i in 0..bitwidth {
|
||||
for i in 0..bit_width {
|
||||
statements_flattened.push(FlatStatement::Condition(
|
||||
FlatExpression::Identifier(sub_bits_be[i]),
|
||||
FlatExpression::Mult(
|
||||
|
@ -710,19 +711,19 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
|||
// sum(sym_b{i} * 2**i)
|
||||
let mut expr = FlatExpression::Number(T::from(0));
|
||||
|
||||
for i in 0..bitwidth {
|
||||
for i in 0..bit_width {
|
||||
expr = FlatExpression::Add(
|
||||
box expr,
|
||||
box FlatExpression::Mult(
|
||||
box FlatExpression::Identifier(sub_bits_be[i]),
|
||||
box FlatExpression::Number(T::from(2).pow(bitwidth - i - 1)),
|
||||
box FlatExpression::Number(T::from(2).pow(bit_width - i - 1)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
statements_flattened.push(FlatStatement::Condition(subtraction_result, expr));
|
||||
|
||||
FlatExpression::Identifier(sub_bits_be[bitwidth - 1])
|
||||
FlatExpression::Identifier(sub_bits_be[bit_width - 1])
|
||||
}
|
||||
BooleanExpression::BoolEq(box lhs, box rhs) => {
|
||||
// lhs and rhs are booleans, they flatten to 0 or 1
|
||||
|
|
|
@ -96,7 +96,7 @@ impl ProofSystem for G16 {
|
|||
let mut raw: Vec<u8> = Vec::new();
|
||||
proof.write(&mut raw).unwrap();
|
||||
|
||||
Proof::<G16ProofPoints>::new(proof_points, inputs, Some(base64::encode(&raw)))
|
||||
Proof::<G16ProofPoints>::new(proof_points, inputs, Some(hex::encode(&raw)))
|
||||
.to_json_pretty()
|
||||
} else {
|
||||
Proof::<G16ProofPoints>::new(proof_points, inputs, None).to_json_pretty()
|
||||
|
@ -201,7 +201,7 @@ fn get_raw_proof(proof: &Proof<G16ProofPoints>) -> BellmanProof<Bn256> {
|
|||
proof.raw.is_some(),
|
||||
"Missing \"raw\" field in proof: pass \"--raw\" flag when generating proof"
|
||||
);
|
||||
let proof = base64::decode(proof.raw.as_ref().unwrap()).unwrap();
|
||||
let proof = hex::decode(proof.raw.as_ref().unwrap()).unwrap();
|
||||
BellmanProof::read(proof.as_slice()).unwrap()
|
||||
}
|
||||
|
||||
|
@ -212,7 +212,7 @@ fn get_raw_vk(vk: String) -> VerifyingKey<Bn256> {
|
|||
raw.is_some(),
|
||||
"Missing \"vk.raw\" key: pass \"--raw\" flag when running setup"
|
||||
);
|
||||
let raw = base64::decode(raw.unwrap()).unwrap();
|
||||
let raw = hex::decode(raw.unwrap()).unwrap();
|
||||
VerifyingKey::read(raw.as_slice()).unwrap()
|
||||
}
|
||||
|
||||
|
@ -252,7 +252,7 @@ fn serialize_vk(vk: VerifyingKey<Bn256>, include_raw: bool) -> String {
|
|||
vk.write(&mut raw).unwrap();
|
||||
|
||||
writer
|
||||
.write_record(&["vk.raw", base64::encode(&raw).as_str()])
|
||||
.write_record(&["vk.raw", hex::encode(&raw).as_str()])
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
|
|
@ -995,7 +995,7 @@ impl<'ast> Checker<'ast> {
|
|||
}
|
||||
_ => Err(ErrorInner {
|
||||
pos: Some(pos),
|
||||
message: format!("{} should be a FunctionCall", rhs),
|
||||
message: format!("{} should be a function call", rhs),
|
||||
}),
|
||||
}.map_err(|e| vec![e])
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use zokrates_field::field::Field;
|
|||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Hash, Eq)]
|
||||
pub enum Solver {
|
||||
ConditionEq,
|
||||
Bits,
|
||||
Bits(usize),
|
||||
Div,
|
||||
Sha256Round,
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ impl Signed for Solver {
|
|||
fn get_signature(&self) -> (usize, usize) {
|
||||
match self {
|
||||
Solver::ConditionEq => (1, 2),
|
||||
Solver::Bits => (1, 254),
|
||||
Solver::Bits(bit_width) => (1, *bit_width),
|
||||
Solver::Div => (2, 1),
|
||||
Solver::Sha256Round => (768, 26935),
|
||||
}
|
||||
|
@ -37,11 +37,11 @@ impl<T: Field> Executable<T> for Solver {
|
|||
true => vec![T::zero(), T::one()],
|
||||
false => vec![T::one(), T::one() / inputs[0].clone()],
|
||||
},
|
||||
Solver::Bits => {
|
||||
Solver::Bits(bit_width) => {
|
||||
let mut num = inputs[0].clone();
|
||||
let mut res = vec![];
|
||||
let bits = 254;
|
||||
for i in (0..bits).rev() {
|
||||
|
||||
for i in (0..*bit_width).rev() {
|
||||
if T::from(2).pow(i) <= num {
|
||||
num = num - T::from(2).pow(i);
|
||||
res.push(T::one());
|
||||
|
@ -73,8 +73,8 @@ impl<T: Field> Executable<T> for Solver {
|
|||
}
|
||||
|
||||
impl Solver {
|
||||
pub fn bits() -> Self {
|
||||
Solver::Bits
|
||||
pub fn bits(width: usize) -> Self {
|
||||
Solver::Bits(width)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,9 @@ mod tests {
|
|||
#[test]
|
||||
fn bits_of_one() {
|
||||
let inputs = vec![FieldPrime::from(1)];
|
||||
let res = Solver::Bits.execute(&inputs).unwrap();
|
||||
let res = Solver::Bits(FieldPrime::get_required_bits())
|
||||
.execute(&inputs)
|
||||
.unwrap();
|
||||
assert_eq!(res[253], FieldPrime::from(1));
|
||||
for i in 0..252 {
|
||||
assert_eq!(res[i], FieldPrime::from(0));
|
||||
|
@ -135,7 +137,9 @@ mod tests {
|
|||
#[test]
|
||||
fn bits_of_42() {
|
||||
let inputs = vec![FieldPrime::from(42)];
|
||||
let res = Solver::Bits.execute(&inputs).unwrap();
|
||||
let res = Solver::Bits(FieldPrime::get_required_bits())
|
||||
.execute(&inputs)
|
||||
.unwrap();
|
||||
assert_eq!(res[253], FieldPrime::from(0));
|
||||
assert_eq!(res[252], FieldPrime::from(1));
|
||||
assert_eq!(res[251], FieldPrime::from(0));
|
||||
|
|
|
@ -21,27 +21,59 @@ use typed_absy::types::{FunctionKey, StructMember, Type};
|
|||
use typed_absy::{folder::*, *};
|
||||
use zokrates_field::field::Field;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
||||
struct Location<'ast> {
|
||||
module: TypedModuleId,
|
||||
key: FunctionKey<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> Location<'ast> {
|
||||
fn module(&self) -> &TypedModuleId {
|
||||
&self.module
|
||||
}
|
||||
}
|
||||
|
||||
type CallCache<'ast, T> = HashMap<
|
||||
Location<'ast>,
|
||||
HashMap<
|
||||
FunctionKey<'ast>,
|
||||
HashMap<Vec<TypedExpression<'ast, T>>, Vec<TypedExpression<'ast, T>>>,
|
||||
>,
|
||||
>;
|
||||
|
||||
/// An inliner
|
||||
#[derive(Debug)]
|
||||
pub struct Inliner<'ast, T: Field> {
|
||||
modules: TypedModules<'ast, T>, // the modules in which to look for functions when inlining
|
||||
module_id: TypedModuleId, // the current module we're visiting
|
||||
statement_buffer: Vec<TypedStatement<'ast, T>>, // a buffer of statements to be added to the inlined statements
|
||||
stack: Vec<(TypedModuleId, FunctionKey<'ast>, usize)>, // the current call stack
|
||||
call_count: HashMap<(TypedModuleId, FunctionKey<'ast>), usize>, // the call count for each function
|
||||
/// the modules in which to look for functions when inlining
|
||||
modules: TypedModules<'ast, T>,
|
||||
/// the current module we're visiting
|
||||
location: Location<'ast>,
|
||||
/// a buffer of statements to be added to the inlined statements
|
||||
statement_buffer: Vec<TypedStatement<'ast, T>>,
|
||||
/// the current call stack
|
||||
stack: Vec<(TypedModuleId, FunctionKey<'ast>, usize)>,
|
||||
/// the call count for each function
|
||||
call_count: HashMap<(TypedModuleId, FunctionKey<'ast>), usize>,
|
||||
/// the cache for memoization: for each function body, tracks function calls
|
||||
call_cache: CallCache<'ast, T>,
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Inliner<'ast, T> {
|
||||
fn with_modules_and_module_id<S: Into<TypedModuleId>>(
|
||||
fn with_modules_and_module_id_and_key<S: Into<TypedModuleId>>(
|
||||
modules: TypedModules<'ast, T>,
|
||||
module_id: S,
|
||||
key: FunctionKey<'ast>,
|
||||
) -> Self {
|
||||
Inliner {
|
||||
modules,
|
||||
module_id: module_id.into(),
|
||||
location: Location {
|
||||
module: module_id.into(),
|
||||
key,
|
||||
},
|
||||
statement_buffer: vec![],
|
||||
stack: vec![],
|
||||
call_count: HashMap::new(),
|
||||
call_cache: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,7 +91,11 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
.unwrap();
|
||||
|
||||
// initialize an inliner over all modules, starting from the main module
|
||||
let mut inliner = Inliner::with_modules_and_module_id(p.modules, main_module_id);
|
||||
let mut inliner = Inliner::with_modules_and_module_id_and_key(
|
||||
p.modules,
|
||||
main_module_id,
|
||||
main_key.clone(),
|
||||
);
|
||||
|
||||
// inline all calls in the main function, recursively
|
||||
let main = inliner.fold_function_symbol(main);
|
||||
|
@ -101,24 +137,33 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
expressions: Vec<TypedExpression<'ast, T>>,
|
||||
) -> Result<Vec<TypedExpression<'ast, T>>, (FunctionKey<'ast>, Vec<TypedExpression<'ast, T>>)>
|
||||
{
|
||||
match self.call_cache().get(key).map(|m| m.get(&expressions)) {
|
||||
Some(Some(exprs)) => return Ok(exprs.clone()),
|
||||
_ => {}
|
||||
};
|
||||
|
||||
// here we clone a function symbol, which is cheap except when it contains the function body, in which case we'd clone anyways
|
||||
match self.module().functions.get(&key).unwrap().clone() {
|
||||
let res = match self.module().functions.get(&key).unwrap().clone() {
|
||||
// if the function called is in the same module, we can go ahead and inline in this module
|
||||
TypedFunctionSymbol::Here(function) => {
|
||||
let (current_module, current_key) =
|
||||
self.change_context(self.module_id().clone(), key.clone());
|
||||
|
||||
let module_id = self.module_id().clone();
|
||||
|
||||
// increase the number of calls for this function by one
|
||||
let count = self
|
||||
.call_count
|
||||
.entry((self.module_id.clone(), key.clone()))
|
||||
.entry((self.module_id().clone(), key.clone()))
|
||||
.and_modify(|i| *i += 1)
|
||||
.or_insert(1);
|
||||
// push this call to the stack
|
||||
self.stack
|
||||
.push((self.module_id.clone(), key.clone(), *count));
|
||||
self.stack.push((module_id, key.clone(), *count));
|
||||
// add definitions for the inputs
|
||||
let inputs_bindings: Vec<_> = function
|
||||
.arguments
|
||||
.iter()
|
||||
.zip(expressions)
|
||||
.zip(expressions.clone())
|
||||
.map(|(a, e)| {
|
||||
TypedStatement::Definition(
|
||||
self.fold_assignee(TypedAssignee::Identifier(a.id.clone())),
|
||||
|
@ -145,6 +190,8 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
// pop this call from the stack
|
||||
self.stack.pop();
|
||||
|
||||
self.change_context(current_module, current_key);
|
||||
|
||||
match ret.pop().unwrap() {
|
||||
TypedStatement::Return(exprs) => Ok(exprs),
|
||||
_ => unreachable!(""),
|
||||
|
@ -153,25 +200,64 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
// if the function called is in some other module, we switch focus to that module and call the function locally there
|
||||
TypedFunctionSymbol::There(function_key, module_id) => {
|
||||
// switch focus to `module_id`
|
||||
let current_module = self.change_module(module_id);
|
||||
let (current_module, current_key) =
|
||||
self.change_context(module_id, function_key.clone());
|
||||
// inline the call there
|
||||
let res = self.try_inline_call(&function_key, expressions)?;
|
||||
let res = self.try_inline_call(&function_key, expressions.clone())?;
|
||||
// switch back focus
|
||||
self.change_module(current_module);
|
||||
self.change_context(current_module, current_key);
|
||||
Ok(res)
|
||||
}
|
||||
// if the function is a flat symbol, replace the call with a call to the local function we provide so it can be inlined in flattening
|
||||
TypedFunctionSymbol::Flat(embed) => Err((embed.key::<T>(), expressions)),
|
||||
}
|
||||
TypedFunctionSymbol::Flat(embed) => Err((embed.key::<T>(), expressions.clone())),
|
||||
};
|
||||
|
||||
res.map(|exprs| {
|
||||
self.call_cache_mut()
|
||||
.entry(key.clone())
|
||||
.or_insert_with(|| HashMap::new())
|
||||
.insert(expressions, exprs.clone());
|
||||
exprs
|
||||
})
|
||||
}
|
||||
|
||||
// Focus the inliner on another module with id `module_id` and return the current `module_id`
|
||||
fn change_module(&mut self, module_id: TypedModuleId) -> TypedModuleId {
|
||||
std::mem::replace(&mut self.module_id, module_id)
|
||||
fn change_context(
|
||||
&mut self,
|
||||
module_id: TypedModuleId,
|
||||
function_key: FunctionKey<'ast>,
|
||||
) -> (TypedModuleId, FunctionKey<'ast>) {
|
||||
let current_module = std::mem::replace(&mut self.location.module, module_id);
|
||||
let current_key = std::mem::replace(&mut self.location.key, function_key);
|
||||
(current_module, current_key)
|
||||
}
|
||||
|
||||
fn module(&self) -> &TypedModule<'ast, T> {
|
||||
self.modules.get(&self.module_id).unwrap()
|
||||
self.modules.get(self.module_id()).unwrap()
|
||||
}
|
||||
|
||||
fn call_cache(
|
||||
&mut self,
|
||||
) -> &HashMap<
|
||||
FunctionKey<'ast>,
|
||||
HashMap<Vec<TypedExpression<'ast, T>>, Vec<TypedExpression<'ast, T>>>,
|
||||
> {
|
||||
self.call_cache
|
||||
.entry(self.location.clone())
|
||||
.or_insert_with(|| HashMap::new())
|
||||
}
|
||||
|
||||
fn call_cache_mut(
|
||||
&mut self,
|
||||
) -> &mut HashMap<
|
||||
FunctionKey<'ast>,
|
||||
HashMap<Vec<TypedExpression<'ast, T>>, Vec<TypedExpression<'ast, T>>>,
|
||||
> {
|
||||
self.call_cache.get_mut(&self.location).unwrap()
|
||||
}
|
||||
|
||||
fn module_id(&self) -> &TypedModuleId {
|
||||
self.location.module()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -567,6 +653,363 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn memoize_local_call() {
|
||||
// // foo
|
||||
// def foo(field a) -> (field):
|
||||
// return a
|
||||
|
||||
// // main
|
||||
// def main(field a) -> (field):
|
||||
// field b = foo(a) + foo(a)
|
||||
// return b
|
||||
|
||||
// inlined
|
||||
// def main(field a) -> (field)
|
||||
// field _0 = a + a
|
||||
// return _0
|
||||
|
||||
let signature = Signature::new()
|
||||
.outputs(vec![Type::FieldElement])
|
||||
.inputs(vec![Type::FieldElement]);
|
||||
|
||||
let main: TypedModule<FieldPrime> = TypedModule {
|
||||
functions: vec![
|
||||
(
|
||||
FunctionKey::with_id("main").signature(signature.clone()),
|
||||
TypedFunctionSymbol::Here(TypedFunction {
|
||||
arguments: vec![Parameter {
|
||||
id: Variable::field_element("a".into()),
|
||||
private: true,
|
||||
}],
|
||||
statements: vec![
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("b".into())),
|
||||
FieldElementExpression::Add(
|
||||
box FieldElementExpression::FunctionCall(
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
vec![FieldElementExpression::Identifier("a".into()).into()],
|
||||
),
|
||||
box FieldElementExpression::FunctionCall(
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
vec![FieldElementExpression::Identifier("a".into()).into()],
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
TypedStatement::Return(vec![FieldElementExpression::Identifier(
|
||||
"b".into(),
|
||||
)
|
||||
.into()]),
|
||||
],
|
||||
signature: signature.clone(),
|
||||
}),
|
||||
),
|
||||
(
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
TypedFunctionSymbol::There(
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
"foo".into(),
|
||||
),
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let foo: TypedModule<FieldPrime> = TypedModule {
|
||||
functions: vec![(
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
TypedFunctionSymbol::Here(TypedFunction {
|
||||
arguments: vec![Parameter {
|
||||
id: Variable::field_element("a".into()),
|
||||
private: true,
|
||||
}],
|
||||
statements: vec![TypedStatement::Return(vec![
|
||||
FieldElementExpression::Identifier("a".into()).into(),
|
||||
])],
|
||||
signature: signature.clone(),
|
||||
}),
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let modules: HashMap<_, _> = vec![("main".into(), main), ("foo".into(), foo)]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let program = TypedProgram {
|
||||
main: "main".into(),
|
||||
modules,
|
||||
};
|
||||
|
||||
let program = Inliner::inline(program);
|
||||
|
||||
assert_eq!(program.modules.len(), 1);
|
||||
assert_eq!(
|
||||
program
|
||||
.modules
|
||||
.get(&PathBuf::from("main"))
|
||||
.unwrap()
|
||||
.functions
|
||||
.get(&FunctionKey::with_id("main").signature(signature.clone()))
|
||||
.unwrap(),
|
||||
&TypedFunctionSymbol::Here(TypedFunction {
|
||||
arguments: vec![Parameter {
|
||||
id: Variable::field_element("a".into()),
|
||||
private: true,
|
||||
}],
|
||||
statements: vec![
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element(
|
||||
Identifier::from("a").stack(vec![(
|
||||
"foo".into(),
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
1
|
||||
)])
|
||||
)),
|
||||
FieldElementExpression::Identifier("a".into()).into()
|
||||
),
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("b".into())),
|
||||
FieldElementExpression::Add(
|
||||
box FieldElementExpression::Identifier(Identifier::from("a").stack(
|
||||
vec![(
|
||||
"foo".into(),
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
1
|
||||
)]
|
||||
)),
|
||||
box FieldElementExpression::Identifier(Identifier::from("a").stack(
|
||||
vec![(
|
||||
"foo".into(),
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
1
|
||||
)]
|
||||
))
|
||||
)
|
||||
.into()
|
||||
),
|
||||
TypedStatement::Return(vec![
|
||||
FieldElementExpression::Identifier("b".into()).into(),
|
||||
])
|
||||
],
|
||||
signature: signature.clone(),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_memoize_in_same_function() {
|
||||
// // foo
|
||||
// def foo(field a) -> (field):
|
||||
// return a
|
||||
|
||||
// // main
|
||||
// def main(field a) -> (field):
|
||||
// field b = foo(a) + bar(a)
|
||||
// return b
|
||||
//
|
||||
// def bar(field a) -> (field):
|
||||
// return foo(a)
|
||||
|
||||
// inlined
|
||||
// def main(field a) -> (field)
|
||||
// field _0 = a + a
|
||||
// return _0
|
||||
|
||||
let signature = Signature::new()
|
||||
.outputs(vec![Type::FieldElement])
|
||||
.inputs(vec![Type::FieldElement]);
|
||||
|
||||
let main: TypedModule<FieldPrime> = TypedModule {
|
||||
functions: vec![
|
||||
(
|
||||
FunctionKey::with_id("main").signature(
|
||||
Signature::new()
|
||||
.outputs(vec![Type::FieldElement])
|
||||
.inputs(vec![Type::FieldElement]),
|
||||
),
|
||||
TypedFunctionSymbol::Here(TypedFunction {
|
||||
arguments: vec![Parameter {
|
||||
id: Variable::field_element("a".into()),
|
||||
private: true,
|
||||
}],
|
||||
statements: vec![
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("b".into())),
|
||||
FieldElementExpression::Add(
|
||||
box FieldElementExpression::FunctionCall(
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
vec![FieldElementExpression::Identifier("a".into()).into()],
|
||||
),
|
||||
box FieldElementExpression::FunctionCall(
|
||||
FunctionKey::with_id("bar").signature(signature.clone()),
|
||||
vec![FieldElementExpression::Identifier("a".into()).into()],
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
TypedStatement::Return(vec![FieldElementExpression::Identifier(
|
||||
"b".into(),
|
||||
)
|
||||
.into()]),
|
||||
],
|
||||
signature: signature.clone(),
|
||||
}),
|
||||
),
|
||||
(
|
||||
FunctionKey::with_id("bar").signature(signature.clone()),
|
||||
TypedFunctionSymbol::Here(TypedFunction {
|
||||
arguments: vec![Parameter {
|
||||
id: Variable::field_element("a".into()),
|
||||
private: true,
|
||||
}],
|
||||
statements: vec![TypedStatement::Return(vec![
|
||||
FieldElementExpression::FunctionCall(
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
vec![FieldElementExpression::Identifier("a".into()).into()],
|
||||
)
|
||||
.into(),
|
||||
])],
|
||||
signature: signature.clone(),
|
||||
}),
|
||||
),
|
||||
(
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
TypedFunctionSymbol::There(
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
"foo".into(),
|
||||
),
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let foo: TypedModule<FieldPrime> = TypedModule {
|
||||
functions: vec![(
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
TypedFunctionSymbol::Here(TypedFunction {
|
||||
arguments: vec![Parameter {
|
||||
id: Variable::field_element("a".into()),
|
||||
private: true,
|
||||
}],
|
||||
statements: vec![TypedStatement::Return(vec![
|
||||
FieldElementExpression::Identifier("a".into()).into(),
|
||||
])],
|
||||
signature: signature.clone(),
|
||||
}),
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let modules: HashMap<_, _> = vec![("main".into(), main), ("foo".into(), foo)]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let program = TypedProgram {
|
||||
main: "main".into(),
|
||||
modules,
|
||||
};
|
||||
|
||||
let program = Inliner::inline(program);
|
||||
|
||||
assert_eq!(program.modules.len(), 1);
|
||||
assert_eq!(
|
||||
program
|
||||
.modules
|
||||
.get(&PathBuf::from("main"))
|
||||
.unwrap()
|
||||
.functions
|
||||
.get(&FunctionKey::with_id("main").signature(signature.clone()))
|
||||
.unwrap(),
|
||||
&TypedFunctionSymbol::Here(TypedFunction {
|
||||
arguments: vec![Parameter {
|
||||
id: Variable::field_element("a".into()),
|
||||
private: true,
|
||||
}],
|
||||
statements: vec![
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element(
|
||||
Identifier::from("a").stack(vec![(
|
||||
"foo".into(),
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
1
|
||||
)])
|
||||
)),
|
||||
FieldElementExpression::Identifier("a".into()).into()
|
||||
),
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element(
|
||||
Identifier::from("a").stack(vec![(
|
||||
"main".into(),
|
||||
FunctionKey::with_id("bar").signature(signature.clone()),
|
||||
1
|
||||
)])
|
||||
)),
|
||||
FieldElementExpression::Identifier("a".into()).into()
|
||||
),
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element(
|
||||
Identifier::from("a").stack(vec![
|
||||
(
|
||||
"main".into(),
|
||||
FunctionKey::with_id("bar").signature(signature.clone()),
|
||||
1
|
||||
),
|
||||
(
|
||||
"foo".into(),
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
2
|
||||
)
|
||||
])
|
||||
)),
|
||||
FieldElementExpression::Identifier(Identifier::from("a").stack(vec![(
|
||||
"main".into(),
|
||||
FunctionKey::with_id("bar").signature(signature.clone()),
|
||||
1
|
||||
)]))
|
||||
.into()
|
||||
),
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("b".into())),
|
||||
FieldElementExpression::Add(
|
||||
box FieldElementExpression::Identifier(Identifier::from("a").stack(
|
||||
vec![(
|
||||
"foo".into(),
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
1
|
||||
)]
|
||||
)),
|
||||
box FieldElementExpression::Identifier(Identifier::from("a").stack(
|
||||
vec![
|
||||
(
|
||||
"main".into(),
|
||||
FunctionKey::with_id("bar").signature(signature.clone()),
|
||||
1
|
||||
),
|
||||
(
|
||||
"foo".into(),
|
||||
FunctionKey::with_id("foo").signature(signature.clone()),
|
||||
2
|
||||
)
|
||||
]
|
||||
))
|
||||
)
|
||||
.into()
|
||||
),
|
||||
TypedStatement::Return(vec![
|
||||
FieldElementExpression::Identifier("b".into()).into(),
|
||||
])
|
||||
],
|
||||
signature: signature.clone(),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_def_from_other_module() {
|
||||
// // foo
|
||||
|
|
|
@ -9,14 +9,19 @@ mod flat_propagation;
|
|||
mod inline;
|
||||
mod propagate_unroll;
|
||||
mod propagation;
|
||||
mod return_binder;
|
||||
mod unconstrained_vars;
|
||||
mod unroll;
|
||||
|
||||
use self::constrain_inputs::InputConstrainer;
|
||||
use self::inline::Inliner;
|
||||
use self::propagate_unroll::PropagatedUnroller;
|
||||
use self::propagation::Propagator;
|
||||
use self::return_binder::ReturnBinder;
|
||||
use self::unconstrained_vars::UnconstrainedVariableDetector;
|
||||
use crate::flat_absy::FlatProg;
|
||||
use crate::typed_absy::TypedProgram;
|
||||
use ir::Prog;
|
||||
use zokrates_field::field::Field;
|
||||
|
||||
pub trait Analyse {
|
||||
|
@ -27,6 +32,8 @@ impl<'ast, T: Field> Analyse for TypedProgram<'ast, T> {
|
|||
fn analyse(self) -> Self {
|
||||
// propagated unrolling
|
||||
let r = PropagatedUnroller::unroll(self).unwrap_or_else(|e| panic!(e));
|
||||
// return binding
|
||||
let r = ReturnBinder::bind(r);
|
||||
// inline
|
||||
let r = Inliner::inline(r);
|
||||
// propagate
|
||||
|
@ -43,3 +50,10 @@ impl<T: Field> Analyse for FlatProg<T> {
|
|||
self.propagate()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Analyse for Prog<T> {
|
||||
fn analyse(self) -> Self {
|
||||
let r = UnconstrainedVariableDetector::detect(self);
|
||||
r
|
||||
}
|
||||
}
|
||||
|
|
55
zokrates_core/src/static_analysis/return_binder.rs
Normal file
55
zokrates_core/src/static_analysis/return_binder.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
use typed_absy::folder::fold_statement;
|
||||
use typed_absy::identifier::CoreIdentifier;
|
||||
use typed_absy::*;
|
||||
use zokrates_field::field::Field;
|
||||
|
||||
pub struct ReturnBinder;
|
||||
|
||||
impl ReturnBinder {
|
||||
pub fn bind<'ast, T: Field>(p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
|
||||
ReturnBinder {}.fold_program(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Folder<'ast, T> for ReturnBinder {
|
||||
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
|
||||
match s {
|
||||
TypedStatement::Return(exprs) => {
|
||||
let ret_identifiers: Vec<Identifier<'ast>> = (0..exprs.len())
|
||||
.map(|i| CoreIdentifier::Internal("RETURN", i).into())
|
||||
.collect();
|
||||
|
||||
let ret_expressions: Vec<TypedExpression<'ast, T>> = exprs
|
||||
.iter()
|
||||
.zip(ret_identifiers.iter())
|
||||
.map(|(e, i)| match e.get_type() {
|
||||
Type::FieldElement => FieldElementExpression::Identifier(i.clone()).into(),
|
||||
Type::Boolean => BooleanExpression::Identifier(i.clone()).into(),
|
||||
Type::Array(array_type) => ArrayExpressionInner::Identifier(i.clone())
|
||||
.annotate(*array_type.ty, array_type.size)
|
||||
.into(),
|
||||
Type::Struct(struct_type) => StructExpressionInner::Identifier(i.clone())
|
||||
.annotate(struct_type)
|
||||
.into(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
exprs
|
||||
.into_iter()
|
||||
.zip(ret_identifiers.iter())
|
||||
.map(|(e, i)| {
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::with_id_and_type(
|
||||
i.clone(),
|
||||
e.get_type(),
|
||||
)),
|
||||
e,
|
||||
)
|
||||
})
|
||||
.chain(std::iter::once(TypedStatement::Return(ret_expressions)))
|
||||
.collect()
|
||||
}
|
||||
s => fold_statement(self, s),
|
||||
}
|
||||
}
|
||||
}
|
177
zokrates_core/src/static_analysis/unconstrained_vars.rs
Normal file
177
zokrates_core/src/static_analysis/unconstrained_vars.rs
Normal file
|
@ -0,0 +1,177 @@
|
|||
use crate::ir::Prog;
|
||||
use flat_absy::FlatVariable;
|
||||
use ir::folder::Folder;
|
||||
use ir::Directive;
|
||||
use std::collections::HashSet;
|
||||
use zokrates_field::field::Field;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UnconstrainedVariableDetector {
|
||||
pub(self) variables: HashSet<FlatVariable>,
|
||||
}
|
||||
|
||||
impl UnconstrainedVariableDetector {
|
||||
fn new<T: Field>(p: &Prog<T>) -> Self {
|
||||
UnconstrainedVariableDetector {
|
||||
variables: p
|
||||
.parameters()
|
||||
.iter()
|
||||
.filter(|p| p.private)
|
||||
.map(|p| p.id)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
pub fn detect<T: Field>(p: Prog<T>) -> Prog<T> {
|
||||
let mut instance = Self::new(&p);
|
||||
let p = instance.fold_module(p);
|
||||
|
||||
// we should probably handle this case instead of asserting at some point
|
||||
assert!(
|
||||
instance.variables.is_empty(),
|
||||
format!(
|
||||
"Unconstrained variables are not allowed (found {} occasions)",
|
||||
instance.variables.len()
|
||||
)
|
||||
);
|
||||
p
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Folder<T> for UnconstrainedVariableDetector {
|
||||
fn fold_argument(&mut self, p: FlatVariable) -> FlatVariable {
|
||||
p
|
||||
}
|
||||
fn fold_variable(&mut self, v: FlatVariable) -> FlatVariable {
|
||||
self.variables.remove(&v);
|
||||
v
|
||||
}
|
||||
fn fold_directive(&mut self, d: Directive<T>) -> Directive<T> {
|
||||
self.variables.extend(d.outputs.iter());
|
||||
d
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use flat_absy::FlatVariable;
|
||||
use ir::{Function, LinComb, Prog, QuadComb, Statement};
|
||||
use num::Zero;
|
||||
use solvers::Solver;
|
||||
use zokrates_field::field::FieldPrime;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn should_detect_unconstrained_private_input() {
|
||||
// def main(_0) -> (1):
|
||||
// (1 * ~one) * (42 * ~one) == 1 * ~out_0
|
||||
// return ~out_0
|
||||
|
||||
let _0 = FlatVariable::new(0); // unused var
|
||||
|
||||
let one = FlatVariable::one();
|
||||
let out_0 = FlatVariable::public(0);
|
||||
|
||||
let main: Function<FieldPrime> = Function {
|
||||
id: "main".to_string(),
|
||||
arguments: vec![_0],
|
||||
statements: vec![Statement::constraint(
|
||||
QuadComb::from_linear_combinations(
|
||||
LinComb::summand(1, one),
|
||||
LinComb::summand(42, one),
|
||||
),
|
||||
LinComb::summand(1, out_0),
|
||||
)],
|
||||
returns: vec![out_0],
|
||||
};
|
||||
|
||||
let p: Prog<FieldPrime> = Prog {
|
||||
private: vec![true],
|
||||
main,
|
||||
};
|
||||
|
||||
UnconstrainedVariableDetector::detect(p);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_pass_with_constrained_private_input() {
|
||||
// def main(_0) -> (1):
|
||||
// (1 * ~one) * (1 * _0) == 1 * ~out_0
|
||||
// return ~out_0
|
||||
|
||||
let _0 = FlatVariable::new(0);
|
||||
let out_0 = FlatVariable::public(0);
|
||||
|
||||
let main: Function<FieldPrime> = Function {
|
||||
id: "main".to_string(),
|
||||
arguments: vec![_0],
|
||||
statements: vec![Statement::definition(out_0, LinComb::from(_0))],
|
||||
returns: vec![out_0],
|
||||
};
|
||||
|
||||
let p: Prog<FieldPrime> = Prog {
|
||||
private: vec![true],
|
||||
main,
|
||||
};
|
||||
|
||||
UnconstrainedVariableDetector::detect(p);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_pass_with_directive() {
|
||||
// def main(_0) -> (1):
|
||||
// # _1, _2 = ConditionEq((-42) * ~one + 1 * _0)
|
||||
// ((-42) * ~one + 1 * _0) * (1 * _2) == 1 * _1
|
||||
// (1 * ~one + (-1) * _1) * ((-42) * ~one + 1 * _0) == 0
|
||||
// (1 * ~one) * (1 * ~one + (-1) * _1) == 1 * ~out_0
|
||||
// return ~out_0
|
||||
|
||||
let _0 = FlatVariable::new(0);
|
||||
let _1 = FlatVariable::new(1);
|
||||
let _2 = FlatVariable::new(2);
|
||||
|
||||
let out_0 = FlatVariable::public(0);
|
||||
let one = FlatVariable::one();
|
||||
|
||||
let main: Function<FieldPrime> = Function {
|
||||
id: "main".to_string(),
|
||||
arguments: vec![_0],
|
||||
statements: vec![
|
||||
Statement::Directive(Directive {
|
||||
inputs: vec![LinComb::summand(-42, one) + LinComb::summand(1, _0)],
|
||||
outputs: vec![_1, _2],
|
||||
solver: Solver::ConditionEq,
|
||||
}),
|
||||
Statement::constraint(
|
||||
QuadComb::from_linear_combinations(
|
||||
LinComb::summand(-42, one) + LinComb::summand(1, _0),
|
||||
LinComb::summand(1, _2),
|
||||
),
|
||||
LinComb::summand(1, _1),
|
||||
),
|
||||
Statement::constraint(
|
||||
QuadComb::from_linear_combinations(
|
||||
LinComb::summand(1, one) + LinComb::summand(-1, _1),
|
||||
LinComb::summand(-42, one) + LinComb::summand(1, _0),
|
||||
),
|
||||
LinComb::zero(),
|
||||
),
|
||||
Statement::constraint(
|
||||
QuadComb::from_linear_combinations(
|
||||
LinComb::summand(1, one),
|
||||
LinComb::summand(1, one) + LinComb::summand(-1, _1),
|
||||
),
|
||||
LinComb::summand(1, out_0),
|
||||
),
|
||||
],
|
||||
returns: vec![out_0],
|
||||
};
|
||||
|
||||
let p: Prog<FieldPrime> = Prog {
|
||||
private: vec![true],
|
||||
main,
|
||||
};
|
||||
|
||||
UnconstrainedVariableDetector::detect(p);
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ use crate::typed_absy::types::{MemberId, Type};
|
|||
use crate::typed_absy::*;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use typed_absy::identifier::CoreIdentifier;
|
||||
use zokrates_field::field::Field;
|
||||
|
||||
pub enum Output<'ast, T: Field> {
|
||||
|
@ -18,7 +19,7 @@ pub enum Output<'ast, T: Field> {
|
|||
|
||||
pub struct Unroller<'ast> {
|
||||
// version index for any variable name
|
||||
substitution: HashMap<&'ast str, usize>,
|
||||
substitution: HashMap<CoreIdentifier<'ast>, usize>,
|
||||
// whether all statements could be unrolled so far. Loops with variable bounds cannot.
|
||||
complete: bool,
|
||||
statement_count: usize,
|
||||
|
@ -37,7 +38,7 @@ impl<'ast> Unroller<'ast> {
|
|||
let res = match self.substitution.get(&v.id.id) {
|
||||
Some(i) => Variable {
|
||||
id: Identifier {
|
||||
id: v.id.id,
|
||||
id: v.id.id.clone(),
|
||||
version: i + 1,
|
||||
stack: vec![],
|
||||
},
|
||||
|
|
|
@ -32,8 +32,7 @@ mod tests {
|
|||
use std::collections::HashMap;
|
||||
use typed_absy::types::{ArrayType, FunctionKey, StructMember};
|
||||
use typed_absy::{
|
||||
Identifier, Parameter, Type, TypedFunction, TypedFunctionSymbol, TypedModule, TypedProgram,
|
||||
Variable,
|
||||
Parameter, Type, TypedFunction, TypedFunctionSymbol, TypedModule, TypedProgram, Variable,
|
||||
};
|
||||
use zokrates_field::field::FieldPrime;
|
||||
|
||||
|
@ -45,19 +44,11 @@ mod tests {
|
|||
TypedFunctionSymbol::Here(TypedFunction {
|
||||
arguments: vec![
|
||||
Parameter {
|
||||
id: Variable::field_element(Identifier {
|
||||
id: "a",
|
||||
version: 0,
|
||||
stack: vec![],
|
||||
}),
|
||||
id: Variable::field_element("a".into()),
|
||||
private: true,
|
||||
},
|
||||
Parameter {
|
||||
id: Variable::boolean(Identifier {
|
||||
id: "b",
|
||||
version: 0,
|
||||
stack: vec![],
|
||||
}),
|
||||
id: Variable::boolean("b".into()),
|
||||
private: false,
|
||||
},
|
||||
],
|
||||
|
|
83
zokrates_core/src/typed_absy/identifier.rs
Normal file
83
zokrates_core/src/typed_absy/identifier.rs
Normal file
|
@ -0,0 +1,83 @@
|
|||
use std::fmt;
|
||||
use typed_absy::types::FunctionKey;
|
||||
use typed_absy::TypedModuleId;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Hash, Eq)]
|
||||
pub enum CoreIdentifier<'ast> {
|
||||
Source(&'ast str),
|
||||
Internal(&'static str, usize),
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for CoreIdentifier<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
CoreIdentifier::Source(s) => write!(f, "{}", s),
|
||||
CoreIdentifier::Internal(s, i) => write!(f, "#INTERNAL#_{}_{}", s, i),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A identifier for a variable
|
||||
#[derive(Debug, PartialEq, Clone, Hash, Eq)]
|
||||
pub struct Identifier<'ast> {
|
||||
/// the id of the variable
|
||||
pub id: CoreIdentifier<'ast>,
|
||||
/// the version of the variable, used after SSA transformation
|
||||
pub version: usize,
|
||||
/// the call stack of the variable, used when inlining
|
||||
pub stack: Vec<(TypedModuleId, FunctionKey<'ast>, usize)>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Identifier<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.stack.len() == 0 && self.version == 0 {
|
||||
write!(f, "{}", self.id)
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"{}_{}_{}",
|
||||
self.stack
|
||||
.iter()
|
||||
.map(|(name, sig, count)| format!(
|
||||
"{}_{}_{}",
|
||||
name.display(),
|
||||
sig.to_slug(),
|
||||
count
|
||||
))
|
||||
.collect::<Vec<_>>()
|
||||
.join("_"),
|
||||
self.id,
|
||||
self.version
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<&'ast str> for Identifier<'ast> {
|
||||
fn from(id: &'ast str) -> Identifier<'ast> {
|
||||
Identifier::from(CoreIdentifier::Source(id))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<CoreIdentifier<'ast>> for Identifier<'ast> {
|
||||
fn from(id: CoreIdentifier<'ast>) -> Identifier<'ast> {
|
||||
Identifier {
|
||||
id,
|
||||
version: 0,
|
||||
stack: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<'ast> Identifier<'ast> {
|
||||
pub fn version(mut self, version: usize) -> Self {
|
||||
self.version = version;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn stack(mut self, stack: Vec<(TypedModuleId, FunctionKey<'ast>, usize)>) -> Self {
|
||||
self.stack = stack;
|
||||
self
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
pub mod abi;
|
||||
pub mod folder;
|
||||
pub mod identifier;
|
||||
mod parameter;
|
||||
pub mod types;
|
||||
mod variable;
|
||||
|
@ -25,19 +26,9 @@ use zokrates_field::field::Field;
|
|||
|
||||
pub use self::folder::Folder;
|
||||
use typed_absy::abi::{Abi, AbiInput};
|
||||
pub use typed_absy::identifier::Identifier;
|
||||
use typed_absy::types::StructMember;
|
||||
|
||||
/// A identifier for a variable
|
||||
#[derive(Debug, PartialEq, Clone, Hash, Eq)]
|
||||
pub struct Identifier<'ast> {
|
||||
/// the id of the variable
|
||||
pub id: &'ast str,
|
||||
/// the version of the variable, used after SSA transformation
|
||||
pub version: usize,
|
||||
/// the call stack of the variable, used when inlining
|
||||
pub stack: Vec<(TypedModuleId, FunctionKey<'ast>, usize)>,
|
||||
}
|
||||
|
||||
/// An identifier for a `TypedModule`. Typically a path or uri.
|
||||
pub type TypedModuleId = PathBuf;
|
||||
|
||||
|
@ -114,54 +105,6 @@ pub struct TypedModule<'ast, T: Field> {
|
|||
pub functions: TypedFunctionSymbols<'ast, T>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Identifier<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.stack.len() == 0 && self.version == 0 {
|
||||
write!(f, "{}", self.id)
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"{}_{}_{}",
|
||||
self.stack
|
||||
.iter()
|
||||
.map(|(name, sig, count)| format!(
|
||||
"{}_{}_{}",
|
||||
name.display(),
|
||||
sig.to_slug(),
|
||||
count
|
||||
))
|
||||
.collect::<Vec<_>>()
|
||||
.join("_"),
|
||||
self.id,
|
||||
self.version
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<&'ast str> for Identifier<'ast> {
|
||||
fn from(id: &'ast str) -> Identifier<'ast> {
|
||||
Identifier {
|
||||
id,
|
||||
version: 0,
|
||||
stack: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<'ast> Identifier<'ast> {
|
||||
pub fn version(mut self, version: usize) -> Self {
|
||||
self.version = version;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn stack(mut self, stack: Vec<(TypedModuleId, FunctionKey<'ast>, usize)>) -> Self {
|
||||
self.stack = stack;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum TypedFunctionSymbol<'ast, T: Field> {
|
||||
Here(TypedFunction<'ast, T>),
|
||||
|
|
6
zokrates_core_test/tests/tests/arrays/fun_spread.json
Normal file
6
zokrates_core_test/tests/tests/arrays/fun_spread.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/arrays/fun_spread.zok",
|
||||
"max_constraint_count": 1050,
|
||||
"tests": [
|
||||
]
|
||||
}
|
7
zokrates_core_test/tests/tests/arrays/fun_spread.zok
Normal file
7
zokrates_core_test/tests/tests/arrays/fun_spread.zok
Normal file
|
@ -0,0 +1,7 @@
|
|||
import "utils/pack/nonStrictUnpack256.zok" as unpack256
|
||||
|
||||
def main(field[2] inputs) -> (field[512]):
|
||||
|
||||
field[512] preimage512 = [...unpack256(inputs[0]), ...unpack256(inputs[1])]
|
||||
|
||||
return preimage512
|
3
zokrates_core_test/tests/tests/memoize/dep.zok
Normal file
3
zokrates_core_test/tests/tests/memoize/dep.zok
Normal file
|
@ -0,0 +1,3 @@
|
|||
def dep(field a) -> (field): // this costs 2 constraits per call
|
||||
field res = a ** 4
|
||||
return res
|
16
zokrates_core_test/tests/tests/memoize/memoize.json
Normal file
16
zokrates_core_test/tests/tests/memoize/memoize.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/memoize/memoize.zok",
|
||||
"max_constraint_count": 14,
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": ["3"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": []
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
14
zokrates_core_test/tests/tests/memoize/memoize.zok
Normal file
14
zokrates_core_test/tests/tests/memoize/memoize.zok
Normal file
|
@ -0,0 +1,14 @@
|
|||
from "./dep.zok" import dep as dep
|
||||
|
||||
def local(field a) -> (field): // this costs 3 constraints per call
|
||||
field res = a ** 8
|
||||
return res // currently expressions in the return statement don't get memoized
|
||||
|
||||
def main(field a) -> ():
|
||||
// calling a local function many times with the same arg should cost only once
|
||||
local(a) + local(a) + local(a) + local(a) + local(a) == 5 * (a ** 8)
|
||||
|
||||
// calling an imported function many times with the same arg should cost only once
|
||||
dep(a) + dep(a) + dep(a) + dep(a) + dep(a) == 5 * (a ** 4)
|
||||
|
||||
return
|
|
@ -10,5 +10,5 @@ wasm = ["bellman_ce/wasm", "sapling-crypto_ce/wasm"]
|
|||
multicore = ["bellman_ce/multicore", "sapling-crypto_ce/multicore"]
|
||||
|
||||
[dependencies]
|
||||
bellman_ce = { git = "https://github.com/matter-labs/bellman", rev = "9e35737", default-features = false}
|
||||
bellman_ce = { version = "0.3.3", default-features = false}
|
||||
sapling-crypto_ce = { version = "0.1.1", default-features = false }
|
|
@ -12,8 +12,8 @@ bincode = "0.8.0"
|
|||
serde_json = "1.0"
|
||||
num-traits = { version = "0.2", default-features = false }
|
||||
num-integer = { version = "0.1", default-features = false }
|
||||
pairing_ce = "0.18"
|
||||
ff_ce = { features = ["derive"], version = "0.7" }
|
||||
pairing_ce = "0.20"
|
||||
ff_ce = { features = ["derive"], version = "0.9" }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.4"
|
||||
|
|
1054
zokrates_js/package-lock.json
generated
1054
zokrates_js/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -28,13 +28,13 @@
|
|||
"test": "mocha --require esm --recursive tests"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dree": "^2.1.10",
|
||||
"dree": "^2.4.14",
|
||||
"esm": "^3.2.25",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-cli": "^2.2.0",
|
||||
"mocha": "^6.2.2",
|
||||
"rimraf": "^3.0.0",
|
||||
"serve": "^11.2.0",
|
||||
"mocha": "^7.1.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"serve": "^11.3.0",
|
||||
"text-encoding": "^0.7.0"
|
||||
},
|
||||
"dependencies": {}
|
||||
|
|
|
@ -122,11 +122,22 @@ mod tests {
|
|||
rule: Rule::statement,
|
||||
tokens: [
|
||||
statement(0, 22, [
|
||||
multi_assignment_statement(0, 9, [
|
||||
optionally_typed_identifier(0, 1, [
|
||||
identifier(0, 1)
|
||||
definition_statement(0, 9, [
|
||||
optionally_typed_assignee(0, 2, [
|
||||
assignee(0, 2, [
|
||||
identifier(0, 1)
|
||||
])
|
||||
]),
|
||||
expression(4, 9, [
|
||||
term(4, 9, [
|
||||
postfix_expression(4, 9, [
|
||||
identifier(4, 7),
|
||||
access(7, 9, [
|
||||
call_access(7, 9)
|
||||
])
|
||||
])
|
||||
])
|
||||
]),
|
||||
identifier(4, 7),
|
||||
])
|
||||
])
|
||||
]
|
||||
|
|
|
@ -36,22 +36,18 @@ vis = { vis_private | vis_public }
|
|||
// Statements
|
||||
statement = { (return_statement // does not require subsequent newline
|
||||
| (iteration_statement
|
||||
| multi_assignment_statement // try this first as we want all assignments based on return of function calls match here and not later
|
||||
| definition_statement
|
||||
| assignment_statement
|
||||
| expression_statement
|
||||
) ~ NEWLINE
|
||||
) ~ NEWLINE* }
|
||||
|
||||
iteration_statement = { "for" ~ ty ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "do" ~ NEWLINE* ~ statement* ~ "endfor"}
|
||||
return_statement = { "return" ~ expression_list}
|
||||
multi_assignment_statement = { optionally_typed_identifier_list ~ "=" ~ identifier ~ "(" ~ expression_list ~ ")"} // This is very specific with regards to parsing. However, I think more generality is not needed here.
|
||||
definition_statement = {ty ~ identifier ~ "=" ~ expression} // declare and assign, so only identifiers are allowed, unlike `assignment_statement`
|
||||
assignment_statement = {assignee ~ "=" ~ expression } // TODO: Is this optimal? Can the left side be written more elegantly?
|
||||
definition_statement = { optionally_typed_assignee_list ~ "=" ~ expression } // declare and assign, so only identifiers are allowed, unlike `assignment_statement`
|
||||
expression_statement = {expression}
|
||||
|
||||
optionally_typed_identifier_list = _{ optionally_typed_identifier ~ ("," ~ optionally_typed_identifier)* }
|
||||
optionally_typed_identifier = { (identifier) | (ty ~ identifier) } // we don't use { ty? ~ identifier } as with a single token, it gets parsed as `ty` but we want `identifier`
|
||||
optionally_typed_assignee_list = _{ optionally_typed_assignee ~ ("," ~ optionally_typed_assignee)* }
|
||||
optionally_typed_assignee = { (ty ~ assignee) | (assignee) } // we don't use { ty? ~ identifier } as with a single token, it gets parsed as `ty` but we want `identifier`
|
||||
|
||||
// Expressions
|
||||
expression_list = _{(expression ~ ("," ~ expression)*)?}
|
||||
|
@ -118,7 +114,6 @@ op_unary = { op_not }
|
|||
WHITESPACE = _{ " " | "\t" | "\\" ~ NEWLINE}
|
||||
COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
|
||||
|
||||
// TODO: Order by alphabet
|
||||
keyword = @{"as"|"bool"|"byte"|"def"|"do"|"else"|"endfor"|"export"|"false"|"field"|"for"|"if"|"then"|"fi"|"import"|"from"|
|
||||
"in"|"private"|"public"|"return"|"struct"|"true"|"uint"
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ extern crate lazy_static;
|
|||
|
||||
pub use ast::{
|
||||
Access, ArrayAccess, ArrayInitializerExpression, ArrayType, AssertionStatement, Assignee,
|
||||
AssigneeAccess, AssignmentStatement, BasicOrStructType, BasicType, BinaryExpression,
|
||||
BinaryOperator, CallAccess, ConstantExpression, DefinitionStatement, Expression, File,
|
||||
AssigneeAccess, BasicOrStructType, BasicType, BinaryExpression, BinaryOperator, CallAccess,
|
||||
ConstantExpression, DecimalNumberExpression, DefinitionStatement, Expression, FieldType, File,
|
||||
FromExpression, Function, IdentifierExpression, ImportDirective, ImportSource,
|
||||
InlineArrayExpression, InlineStructExpression, InlineStructMember, IterationStatement,
|
||||
MultiAssignmentStatement, Parameter, PostfixExpression, Range, RangeOrExpression,
|
||||
OptionallyTypedAssignee, Parameter, PostfixExpression, Range, RangeOrExpression,
|
||||
ReturnStatement, Span, Spread, SpreadOrExpression, Statement, StructDefinition, StructField,
|
||||
TernaryExpression, ToExpression, Type, UnaryExpression, UnaryOperator, Visibility,
|
||||
};
|
||||
|
@ -315,24 +315,12 @@ mod ast {
|
|||
Definition(DefinitionStatement<'ast>),
|
||||
Assertion(AssertionStatement<'ast>),
|
||||
Iteration(IterationStatement<'ast>),
|
||||
Assignment(AssignmentStatement<'ast>),
|
||||
MultiAssignment(MultiAssignmentStatement<'ast>),
|
||||
}
|
||||
|
||||
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||
#[pest_ast(rule(Rule::definition_statement))]
|
||||
pub struct DefinitionStatement<'ast> {
|
||||
pub ty: Type<'ast>,
|
||||
pub id: IdentifierExpression<'ast>,
|
||||
pub expression: Expression<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||
#[pest_ast(rule(Rule::assignment_statement))]
|
||||
pub struct AssignmentStatement<'ast> {
|
||||
pub assignee: Assignee<'ast>,
|
||||
pub lhs: Vec<OptionallyTypedAssignee<'ast>>,
|
||||
pub expression: Expression<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
|
@ -358,16 +346,6 @@ mod ast {
|
|||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||
#[pest_ast(rule(Rule::multi_assignment_statement))]
|
||||
pub struct MultiAssignmentStatement<'ast> {
|
||||
pub lhs: Vec<OptionallyTypedIdentifier<'ast>>,
|
||||
pub function_id: IdentifierExpression<'ast>,
|
||||
pub arguments: Vec<Expression<'ast>>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||
#[pest_ast(rule(Rule::return_statement))]
|
||||
pub struct ReturnStatement<'ast> {
|
||||
|
@ -513,10 +491,10 @@ mod ast {
|
|||
}
|
||||
|
||||
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||
#[pest_ast(rule(Rule::optionally_typed_identifier))]
|
||||
pub struct OptionallyTypedIdentifier<'ast> {
|
||||
#[pest_ast(rule(Rule::optionally_typed_assignee))]
|
||||
pub struct OptionallyTypedAssignee<'ast> {
|
||||
pub ty: Option<Type<'ast>>,
|
||||
pub id: IdentifierExpression<'ast>,
|
||||
pub a: Assignee<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
@ -1018,54 +996,68 @@ mod tests {
|
|||
returns: vec![Type::Basic(BasicType::Field(FieldType {
|
||||
span: Span::new(&source, 15, 20).unwrap()
|
||||
}))],
|
||||
statements: vec![Statement::MultiAssignment(MultiAssignmentStatement {
|
||||
function_id: IdentifierExpression {
|
||||
value: String::from("foo"),
|
||||
span: Span::new(&source, 36, 39).unwrap()
|
||||
},
|
||||
statements: vec![Statement::Definition(DefinitionStatement {
|
||||
lhs: vec![
|
||||
OptionallyTypedIdentifier {
|
||||
OptionallyTypedAssignee {
|
||||
ty: Some(Type::Basic(BasicType::Field(FieldType {
|
||||
span: Span::new(&source, 23, 28).unwrap()
|
||||
}))),
|
||||
id: IdentifierExpression {
|
||||
value: String::from("a"),
|
||||
span: Span::new(&source, 29, 30).unwrap(),
|
||||
a: Assignee {
|
||||
id: IdentifierExpression {
|
||||
value: String::from("a"),
|
||||
span: Span::new(&source, 29, 30).unwrap(),
|
||||
},
|
||||
accesses: vec![],
|
||||
span: Span::new(&source, 29, 30).unwrap()
|
||||
},
|
||||
span: Span::new(&source, 23, 30).unwrap()
|
||||
},
|
||||
OptionallyTypedIdentifier {
|
||||
OptionallyTypedAssignee {
|
||||
ty: None,
|
||||
id: IdentifierExpression {
|
||||
value: String::from("b"),
|
||||
span: Span::new(&source, 32, 33).unwrap(),
|
||||
a: Assignee {
|
||||
id: IdentifierExpression {
|
||||
value: String::from("b"),
|
||||
span: Span::new(&source, 32, 33).unwrap(),
|
||||
},
|
||||
accesses: vec![],
|
||||
span: Span::new(&source, 32, 34).unwrap()
|
||||
},
|
||||
span: Span::new(&source, 32, 33).unwrap()
|
||||
span: Span::new(&source, 32, 34).unwrap()
|
||||
},
|
||||
],
|
||||
arguments: vec![
|
||||
Expression::Constant(ConstantExpression::DecimalNumber(
|
||||
DecimalNumberExpression {
|
||||
value: String::from("1"),
|
||||
span: Span::new(&source, 40, 41).unwrap()
|
||||
}
|
||||
)),
|
||||
Expression::add(
|
||||
Expression::Constant(ConstantExpression::DecimalNumber(
|
||||
DecimalNumberExpression {
|
||||
value: String::from("2"),
|
||||
span: Span::new(&source, 43, 44).unwrap()
|
||||
}
|
||||
)),
|
||||
Expression::Constant(ConstantExpression::DecimalNumber(
|
||||
DecimalNumberExpression {
|
||||
value: String::from("3"),
|
||||
span: Span::new(&source, 47, 48).unwrap()
|
||||
}
|
||||
)),
|
||||
Span::new(&source, 43, 48).unwrap()
|
||||
),
|
||||
],
|
||||
expression: Expression::Postfix(PostfixExpression {
|
||||
id: IdentifierExpression {
|
||||
value: String::from("foo"),
|
||||
span: Span::new(&source, 36, 39).unwrap()
|
||||
},
|
||||
accesses: vec![Access::Call(CallAccess {
|
||||
expressions: vec![
|
||||
Expression::Constant(ConstantExpression::DecimalNumber(
|
||||
DecimalNumberExpression {
|
||||
value: String::from("1"),
|
||||
span: Span::new(&source, 40, 41).unwrap()
|
||||
}
|
||||
)),
|
||||
Expression::add(
|
||||
Expression::Constant(ConstantExpression::DecimalNumber(
|
||||
DecimalNumberExpression {
|
||||
value: String::from("2"),
|
||||
span: Span::new(&source, 43, 44).unwrap()
|
||||
}
|
||||
)),
|
||||
Expression::Constant(ConstantExpression::DecimalNumber(
|
||||
DecimalNumberExpression {
|
||||
value: String::from("3"),
|
||||
span: Span::new(&source, 47, 48).unwrap()
|
||||
}
|
||||
)),
|
||||
Span::new(&source, 43, 48).unwrap()
|
||||
),
|
||||
],
|
||||
span: Span::new(&source, 39, 49).unwrap()
|
||||
})],
|
||||
span: Span::new(&source, 36, 49).unwrap(),
|
||||
}),
|
||||
span: Span::new(&source, 23, 49).unwrap()
|
||||
})],
|
||||
span: Span::new(&source, 0, 50).unwrap(),
|
||||
|
|
Loading…
Reference in a new issue