1
0
Fork 0
mirror of synced 2025-09-23 12:18:44 +00:00

Merge pull request #716 from Zokrates/remove-array-ssa

Remove array ssa
This commit is contained in:
Thibaut Schaeffer 2020-12-23 10:53:43 +01:00 committed by GitHub
commit 5595cf16ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 1056 additions and 1082 deletions

235
Cargo.lock generated
View file

@ -36,7 +36,7 @@ dependencies = [
[[package]]
name = "ark-bls12-377"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/curves#23e87bf224c23be5c5bccc6084aae31fff8bb83f"
source = "git+https://github.com/arkworks-rs/curves#7f1fcd66967328a1c5a3d12f8b148d69f7d86888"
dependencies = [
"ark-ec",
"ark-ff",
@ -46,7 +46,7 @@ dependencies = [
[[package]]
name = "ark-bn254"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/curves#23e87bf224c23be5c5bccc6084aae31fff8bb83f"
source = "git+https://github.com/arkworks-rs/curves#7f1fcd66967328a1c5a3d12f8b148d69f7d86888"
dependencies = [
"ark-ec",
"ark-ff",
@ -56,7 +56,7 @@ dependencies = [
[[package]]
name = "ark-bw6-761"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/curves#23e87bf224c23be5c5bccc6084aae31fff8bb83f"
source = "git+https://github.com/arkworks-rs/curves#7f1fcd66967328a1c5a3d12f8b148d69f7d86888"
dependencies = [
"ark-bls12-377",
"ark-ec",
@ -84,7 +84,7 @@ dependencies = [
[[package]]
name = "ark-ec"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/algebra#902c8c2882a8aa6f87395df888b50090e2705cac"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"ark-ff",
"ark-serialize",
@ -92,35 +92,49 @@ dependencies = [
"derivative",
"num-traits 0.2.14",
"rand 0.7.3",
"zeroize",
]
[[package]]
name = "ark-ff"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/algebra#902c8c2882a8aa6f87395df888b50090e2705cac"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"ark-ff-asm",
"ark-ff-macros",
"ark-serialize",
"ark-std",
"derivative",
"num-traits 0.2.14",
"rand 0.7.3",
"rustc_version",
"zeroize",
]
[[package]]
name = "ark-ff-asm"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/algebra#902c8c2882a8aa6f87395df888b50090e2705cac"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
name = "ark-ff-macros"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"num-bigint 0.3.1",
"num-traits 0.2.14",
"quote 1.0.7",
"syn 1.0.54",
]
[[package]]
name = "ark-gm17"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/gm17#4382f9103a18c50cc84dc673740286a7604a2ae5"
source = "git+https://github.com/arkworks-rs/gm17#f74debdb0557af2a873c8261970617e6aad7211d"
dependencies = [
"ark-crypto-primitives",
"ark-ec",
@ -136,7 +150,7 @@ dependencies = [
[[package]]
name = "ark-poly"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/algebra#902c8c2882a8aa6f87395df888b50090e2705cac"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"ark-ff",
"ark-serialize",
@ -148,7 +162,7 @@ dependencies = [
[[package]]
name = "ark-relations"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/snark#f074e77ab35489da12f2f6cb97d24b7d992b8a35"
source = "git+https://github.com/arkworks-rs/snark#0648c547e4f9fda46a40ad0a4896652b87c2316b"
dependencies = [
"ark-ff",
"ark-std",
@ -158,7 +172,7 @@ dependencies = [
[[package]]
name = "ark-serialize"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/algebra#902c8c2882a8aa6f87395df888b50090e2705cac"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"ark-serialize-derive",
"ark-std",
@ -167,17 +181,17 @@ dependencies = [
[[package]]
name = "ark-serialize-derive"
version = "0.1.1-alpha.0"
source = "git+https://github.com/arkworks-rs/algebra#902c8c2882a8aa6f87395df888b50090e2705cac"
source = "git+https://github.com/arkworks-rs/algebra#eac2dd72fd048ea7eac00dabe2ba8bda84287a64"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
name = "ark-snark"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/snark#f074e77ab35489da12f2f6cb97d24b7d992b8a35"
source = "git+https://github.com/arkworks-rs/snark#0648c547e4f9fda46a40ad0a4896652b87c2316b"
dependencies = [
"ark-ff",
"ark-relations",
@ -188,7 +202,7 @@ dependencies = [
[[package]]
name = "ark-std"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/utils#0825eeafe7a3fb54be5ca9b90b02b6057adca964"
source = "git+https://github.com/arkworks-rs/utils#f6974ac72f59339b7ab798a728a84c5a7b8bac45"
[[package]]
name = "arrayref"
@ -249,9 +263,9 @@ dependencies = [
[[package]]
name = "base64"
version = "0.12.3"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bellman_ce"
@ -272,8 +286,8 @@ dependencies = [
[[package]]
name = "bench-utils"
version = "0.1.1-alpha.0"
source = "git+https://github.com/arkworks-rs/utils#0825eeafe7a3fb54be5ca9b90b02b6057adca964"
version = "0.1.0"
source = "git+https://github.com/arkworks-rs/utils#f6974ac72f59339b7ab798a728a84c5a7b8bac45"
[[package]]
name = "bincode"
@ -288,9 +302,9 @@ dependencies = [
[[package]]
name = "bit-vec"
version = "0.6.2"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bitflags"
@ -368,9 +382,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "bytecount"
version = "0.6.1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c39a773ba75db12126d8d383f1bdbf7eb92ea47ec27dd0557aff1fedf172764c"
checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e"
[[package]]
name = "byteorder"
@ -392,9 +406,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.65"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15"
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
dependencies = [
"jobserver",
]
@ -473,7 +487,7 @@ dependencies = [
"crossbeam-deque",
"crossbeam-epoch",
"crossbeam-queue",
"crossbeam-utils",
"crossbeam-utils 0.7.2",
]
[[package]]
@ -482,7 +496,7 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
dependencies = [
"crossbeam-utils",
"crossbeam-utils 0.7.2",
"maybe-uninit",
]
@ -493,7 +507,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
"crossbeam-utils 0.7.2",
"maybe-uninit",
]
@ -505,7 +519,7 @@ checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
dependencies = [
"autocfg",
"cfg-if 0.1.10",
"crossbeam-utils",
"crossbeam-utils 0.7.2",
"lazy_static",
"maybe-uninit",
"memoffset",
@ -519,7 +533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
dependencies = [
"cfg-if 0.1.10",
"crossbeam-utils",
"crossbeam-utils 0.7.2",
"maybe-uninit",
]
@ -534,6 +548,17 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
dependencies = [
"autocfg",
"cfg-if 1.0.0",
"lazy_static",
]
[[package]]
name = "crypto-mac"
version = "0.7.0"
@ -546,9 +571,9 @@ dependencies = [
[[package]]
name = "csv"
version = "1.1.4"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc4666154fd004af3fd6f1da2e81a96fd5a81927fe8ddb6ecc79e2aa6e138b54"
checksum = "f9d58633299b24b515ac72a3f869f8b91306a3cec616a602843a383acd6f9e97"
dependencies = [
"bstr",
"csv-core",
@ -573,7 +598,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484"
dependencies = [
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
@ -584,7 +609,7 @@ checksum = "cb582b60359da160a9477ee80f15c8d784c477e69c217ef2cdd4169c24ea380f"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
@ -676,7 +701,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
"synstructure",
]
@ -715,12 +740,12 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50c052fa6d4c2f12305ec364bfb8ef884836f3f61ea015b202372ff996d1ac4b"
dependencies = [
"num-bigint",
"num-bigint 0.2.6",
"num-integer",
"num-traits 0.2.14",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
@ -941,9 +966,9 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.45"
version = "0.3.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8"
checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175"
dependencies = [
"wasm-bindgen",
]
@ -956,9 +981,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.80"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
[[package]]
name = "libgit2-sys"
@ -1075,6 +1100,17 @@ dependencies = [
"serde",
]
[[package]]
name = "num-bigint"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf"
dependencies = [
"autocfg",
"num-integer",
"num-traits 0.2.14",
]
[[package]]
name = "num-integer"
version = "0.1.44"
@ -1150,9 +1186,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
[[package]]
name = "openssl-sys"
version = "0.9.58"
version = "0.9.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de"
checksum = "de52d8eabd217311538a39bba130d7dea1f1e118010fee7a033d966845e7d5fe"
dependencies = [
"autocfg",
"cc",
@ -1229,7 +1265,7 @@ dependencies = [
"pest_meta",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
@ -1260,14 +1296,14 @@ checksum = "f8e8d2bf0b23038a4424865103a4df472855692821aab4e4f5c3312d461d9e5f"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
name = "pin-project-lite"
version = "0.1.11"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b"
checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c"
[[package]]
name = "pin-utils"
@ -1487,14 +1523,14 @@ dependencies = [
[[package]]
name = "rust-argon2"
version = "0.8.2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19"
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
dependencies = [
"base64",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils",
"crossbeam-utils 0.8.1",
]
[[package]]
@ -1575,29 +1611,29 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.117"
version = "1.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.117"
version = "1.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
]
[[package]]
name = "serde_json"
version = "1.0.59"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779"
dependencies = [
"itoa",
"ryu",
@ -1683,9 +1719,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.50"
version = "1.0.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443b4178719c5a851e1bde36ce12da21d74a0e60b4d982ec3385a933c812f0f6"
checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
@ -1700,7 +1736,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
"unicode-xid 0.2.1",
]
@ -1763,11 +1799,11 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tracing"
version = "0.1.21"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0987850db3733619253fe60e17cb59b82d37c7e6c0236bb81e4d6b87c879f27"
checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
"pin-project-lite",
"tracing-core",
]
@ -1858,9 +1894,9 @@ checksum = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba"
[[package]]
name = "vcpkg"
version = "0.2.10"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
[[package]]
name = "vec_map"
@ -1899,36 +1935,36 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasm-bindgen"
version = "0.2.68"
version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42"
checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.68"
version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68"
checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.18"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da"
checksum = "1fe9756085a84584ee9457a002b7cdfe0bfff169f45d2591d8be1345a6780e35"
dependencies = [
"cfg-if 0.1.10",
"cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
@ -1936,9 +1972,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.68"
version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038"
checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084"
dependencies = [
"quote 1.0.7",
"wasm-bindgen-macro-support",
@ -1946,28 +1982,28 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.68"
version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe"
checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.50",
"syn 1.0.54",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.68"
version = "0.2.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307"
checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158"
[[package]]
name = "wasm-bindgen-test"
version = "0.3.18"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34d1cdc8b98a557f24733d50a1199c4b0635e465eecba9c45b214544da197f64"
checksum = "0355fa0c1f9b792a09b6dcb6a8be24d51e71e6d74972f9eb4a44c4c004d24a25"
dependencies = [
"console_error_panic_hook",
"js-sys",
@ -1979,9 +2015,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.3.18"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8fb9c67be7439ee8ab1b7db502a49c05e51e2835b66796c705134d9b8e1a585"
checksum = "27e07b46b98024c2ba2f9e83a10c2ef0515f057f2da299c1762a2017de80438b"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
@ -1989,9 +2025,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.45"
version = "0.3.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d"
checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -2028,6 +2064,27 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "zeroize"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81a974bcdd357f0dca4d41677db03436324d45a4c9ed2d0b873a5a360ce41c36"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.7",
"syn 1.0.54",
"synstructure",
]
[[package]]
name = "zokrates_abi"
version = "0.1.3"
@ -2087,7 +2144,7 @@ dependencies = [
"hex",
"lazy_static",
"num",
"num-bigint",
"num-bigint 0.2.6",
"pairing_ce",
"pretty_assertions",
"rand 0.4.6",
@ -2123,7 +2180,7 @@ dependencies = [
"bellman_ce",
"bincode",
"lazy_static",
"num-bigint",
"num-bigint 0.2.6",
"num-integer",
"num-traits 0.2.14",
"rand 0.4.6",

View file

@ -2144,17 +2144,14 @@ impl<'ast, T: Field> Flattener<'ast, T> {
}
}
/// Checks if the given name is a not used variable and returns a fresh variable.
/// Returns a fresh FlatVariable for a given Variable
/// # Arguments
///
/// * `variable` - a variable in the program being flattened
fn use_variable(&mut self, variable: &Variable<'ast>) -> FlatVariable {
let var = self.issue_new_variable();
assert!(self
.layout
.insert(variable.id.clone(), var.clone())
.is_none());
self.layout.insert(variable.id.clone(), var.clone());
var
}
@ -2632,16 +2629,4 @@ mod tests {
]
);
}
#[test]
#[should_panic]
fn next_variable() {
let mut flattener: Flattener<Bn128Field> = Flattener::new();
assert_eq!(
FlatVariable::new(0),
flattener.use_variable(&Variable::field_element("a"))
);
// using the same variable a second time should panic
flattener.use_variable(&Variable::field_element("a"));
}
}

View file

@ -973,22 +973,9 @@ impl<'ast> Checker<'ast> {
return Err(errors.into_iter().map(|e| e.unwrap_err()).collect());
}
// constrain assignees to being identifiers
let (variables, errors): (Vec<_>, Vec<_>) = assignees.into_iter().map(|a| match a.unwrap() {
TypedAssignee::Identifier(v) => Ok(v),
a => Err(ErrorInner {
pos: Some(pos),
message: format!("Only assignment to identifiers is supported, found {}", a)
})
}).partition(|r| r.is_ok());
let assignees: Vec<_> = assignees.into_iter().map(|a| a.unwrap()).collect();
if errors.len() > 0 {
return Err(errors.into_iter().map(|e| e.unwrap_err()).collect());
}
let variables: Vec<_> = variables.into_iter().map(|v| v.unwrap()).collect();
let vars_types = variables.iter().map(|a| Some(a.get_type().clone())).collect();
let assignee_types = assignees.iter().map(|a| Some(a.get_type().clone())).collect();
// find argument types
let mut arguments_checked = vec![];
@ -1000,7 +987,7 @@ impl<'ast> Checker<'ast> {
let arguments_types =
arguments_checked.iter().map(|a| a.get_type()).collect();
let query = FunctionQuery::new(&fun_id, &arguments_types, &vars_types);
let query = FunctionQuery::new(&fun_id, &arguments_types, &assignee_types);
let f = self.find_function(&query);
@ -1010,7 +997,7 @@ impl<'ast> Checker<'ast> {
let call = TypedExpressionList::FunctionCall(f.clone(), arguments_checked, f.signature.outputs.clone());
Ok(TypedStatement::MultipleDefinition(variables, call))
Ok(TypedStatement::MultipleDefinition(assignees, call))
},
None => Err(ErrorInner { pos: Some(pos),
message: format!("Function definition for function {} with signature {} not found.", fun_id, query) }),
@ -3617,14 +3604,14 @@ mod tests {
}
#[test]
fn assign_to_non_variable() {
fn assign_to_select() {
// def foo() -> field:
// return 1
// def main():
// field[1] a = [0]
// a[0] = foo()
// return
// should fail
// should succeed
let foo_statements: Vec<StatementNode> = vec![Statement::Return(
ExpressionList {
@ -3711,16 +3698,7 @@ mod tests {
State::<Bn128Field>::new(vec![("main".into(), module)].into_iter().collect());
let mut checker = new_with_args(HashSet::new(), 0, HashSet::new());
assert_eq!(
checker.check_module(&"main".into(), &mut state),
Err(vec![Error {
inner: ErrorInner {
pos: Some((Position::mock(), Position::mock())),
message: "Only assignment to identifiers is supported, found a[0]".into()
},
module_id: "main".into()
}])
);
assert!(checker.check_module(&"main".into(), &mut state).is_ok());
}
#[test]
@ -3848,8 +3826,8 @@ mod tests {
TypedStatement::Declaration(typed_absy::Variable::field_element("b")),
TypedStatement::MultipleDefinition(
vec![
typed_absy::Variable::field_element("a"),
typed_absy::Variable::field_element("b"),
typed_absy::Variable::field_element("a").into(),
typed_absy::Variable::field_element("b").into(),
],
TypedExpressionList::FunctionCall(
FunctionKey::with_id("foo").signature(

View file

@ -100,7 +100,47 @@ impl<'ast, T: Field> Flattener<T> {
) -> Vec<zir::ZirAssignee<'ast>> {
match a {
typed_absy::TypedAssignee::Identifier(v) => self.fold_variable(v),
_ => unreachable!(),
typed_absy::TypedAssignee::Select(box a, box i) => {
use typed_absy::Typed;
let count = match a.get_type() {
typed_absy::Type::Array(array_ty) => array_ty.ty.get_primitive_count(),
_ => unreachable!(),
};
let a = self.fold_assignee(a);
match i {
typed_absy::FieldElementExpression::Number(n) => {
let index = n.to_dec_string().parse::<usize>().unwrap();
a[index * count..(index + 1) * count].to_vec()
}
i => unreachable!("index {} not allowed, should be a constant", i),
}
}
typed_absy::TypedAssignee::Member(box a, m) => {
use typed_absy::Typed;
let (offset, size) = match a.get_type() {
typed_absy::Type::Struct(struct_type) => {
struct_type
.members
.iter()
.fold((0, None), |(offset, size), member| match size {
Some(_) => (offset, size),
None => match m == member.id {
true => (offset, Some(member.ty.get_primitive_count())),
false => (offset + member.ty.get_primitive_count(), None),
},
})
}
_ => unreachable!(),
};
let size = size.unwrap();
let a = self.fold_assignee(a);
a[offset..offset + size].to_vec()
}
}
}
@ -257,7 +297,7 @@ pub fn fold_statement<'ast, T: Field>(
vec![zir::ZirStatement::MultipleDefinition(
variables
.into_iter()
.flat_map(|v| f.fold_variable(v))
.flat_map(|v| f.fold_assignee(v))
.collect(),
f.fold_expression_list(elist),
)]

View file

@ -290,24 +290,22 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
// add extra statements before the modified statement
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
let folded = match s {
TypedStatement::MultipleDefinition(variables, elist) => match elist {
TypedStatement::MultipleDefinition(assignees, elist) => match elist {
TypedExpressionList::FunctionCall(key, exps, types) => {
let variables: Vec<_> = variables
let assignees: Vec<_> = assignees
.into_iter()
.map(|a| self.fold_variable(a))
.map(|a| self.fold_assignee(a))
.collect();
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
match self.try_inline_call(&key, exps) {
Ok(ret) => variables
Ok(ret) => assignees
.into_iter()
.zip(ret.into_iter())
.map(|(v, e)| {
TypedStatement::Definition(TypedAssignee::Identifier(v), e)
})
.map(|(a, e)| TypedStatement::Definition(a, e))
.collect(),
Err((key, expressions)) => vec![TypedStatement::MultipleDefinition(
variables,
assignees,
TypedExpressionList::FunctionCall(key, expressions, types),
)],
}
@ -356,7 +354,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
};
self.statement_buffer
.push(TypedStatement::MultipleDefinition(
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()],
TypedExpressionList::FunctionCall(
key.clone(),
expressions.clone(),
@ -410,7 +408,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
};
self.statement_buffer
.push(TypedStatement::MultipleDefinition(
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()],
TypedExpressionList::FunctionCall(
key.clone(),
expressions.clone(),
@ -466,7 +464,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
};
self.statement_buffer
.push(TypedStatement::MultipleDefinition(
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()],
TypedExpressionList::FunctionCall(
embed_key.clone(),
expressions.clone(),
@ -523,7 +521,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
};
self.statement_buffer
.push(TypedStatement::MultipleDefinition(
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()],
TypedExpressionList::FunctionCall(
key.clone(),
expressions.clone(),
@ -577,7 +575,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
};
self.statement_buffer
.push(TypedStatement::MultipleDefinition(
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
vec![Variable::with_id_and_type(id.clone(), tys[0].clone()).into()],
TypedExpressionList::FunctionCall(
embed_key.clone(),
expressions.clone(),
@ -1259,7 +1257,7 @@ mod tests {
arguments: vec![],
statements: vec![
TypedStatement::MultipleDefinition(
vec![Variable::field_element("a")],
vec![Variable::field_element("a").into()],
TypedExpressionList::FunctionCall(
FunctionKey::with_id("foo").signature(
Signature::new().outputs(vec![Type::FieldElement]),
@ -1368,7 +1366,7 @@ mod tests {
arguments: vec![],
statements: vec![
TypedStatement::MultipleDefinition(
vec![Variable::field_element("a")],
vec![Variable::field_element("a").into()],
TypedExpressionList::FunctionCall(
FunctionKey::with_id("foo").signature(
Signature::new().outputs(vec![Type::FieldElement]),

View file

@ -14,7 +14,8 @@ mod return_binder;
mod uint_optimizer;
mod unconstrained_vars;
mod unroll;
mod variable_access_remover;
mod variable_read_remover;
mod variable_write_remover;
use self::flatten_complex_types::Flattener;
use self::inline::Inliner;
@ -24,7 +25,8 @@ use self::redefinition::RedefinitionOptimizer;
use self::return_binder::ReturnBinder;
use self::uint_optimizer::UintOptimizer;
use self::unconstrained_vars::UnconstrainedVariableDetector;
use self::variable_access_remover::VariableAccessRemover;
use self::variable_read_remover::VariableReadRemover;
use self::variable_write_remover::VariableWriteRemover;
use crate::flat_absy::FlatProg;
use crate::ir::Prog;
use crate::typed_absy::TypedProgram;
@ -52,8 +54,11 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
// optimize redefinitions
let r = RedefinitionOptimizer::optimize(r);
// remove assignment to variable index
let r = VariableWriteRemover::apply(r);
// remove variable access to complex types
let r = VariableAccessRemover::apply(r);
let r = VariableReadRemover::apply(r);
// convert to zir, removing complex types
let zir = Flattener::flatten(r);

View file

@ -20,7 +20,7 @@ use zokrates_field::Field;
pub struct Propagator<'ast, T: Field> {
// constants keeps track of constant expressions
// we currently do not support partially constant expressions: `field [x, 1][1]` is not considered constant, `field [0, 1][1]` is
constants: HashMap<TypedAssignee<'ast, T>, TypedExpression<'ast, T>>,
constants: HashMap<Identifier<'ast>, TypedExpression<'ast, T>>,
// the verbose mode doesn't remove statements which assign constants to variables
// it's required when using propagation in combination with unrolling
verbose: bool,
@ -48,6 +48,63 @@ impl<'ast, T: Field> Propagator<'ast, T> {
pub fn propagate_verbose(p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
Propagator::verbose().fold_program(p)
}
// get a mutable reference to the constant corresponding to a given assignee if any, otherwise
// return the identifier at the root of this assignee
fn try_get_constant_mut<'a>(
&mut self,
assignee: &'a TypedAssignee<'ast, T>,
) -> Result<(&'a Variable<'ast>, &mut TypedExpression<'ast, T>), &'a Variable<'ast>> {
match assignee {
TypedAssignee::Identifier(var) => self
.constants
.get_mut(&var.id)
.map(|c| Ok((var, c)))
.unwrap_or(Err(var)),
TypedAssignee::Select(box assignee, box index) => {
match self.try_get_constant_mut(&assignee) {
Ok((v, c)) => match index {
FieldElementExpression::Number(n) => {
let n = n.to_dec_string().parse::<usize>().unwrap();
match c {
TypedExpression::Array(a) => match a.as_inner_mut() {
ArrayExpressionInner::Value(value) => Ok((v, &mut value[n])),
_ => unreachable!(),
},
_ => unreachable!(),
}
}
_ => Err(v),
},
e => e,
}
}
TypedAssignee::Member(box assignee, m) => match self.try_get_constant_mut(&assignee) {
Ok((v, c)) => {
let ty = assignee.get_type();
let index = match ty {
Type::Struct(struct_ty) => struct_ty
.members
.iter()
.position(|member| *m == member.id)
.unwrap(),
_ => unreachable!(),
};
match c {
TypedExpression::Struct(a) => match a.as_inner_mut() {
StructExpressionInner::Value(value) => Ok((v, &mut value[index])),
_ => unreachable!(),
},
_ => unreachable!(),
}
}
e => e,
},
}
}
}
fn is_constant<'ast, T: Field>(e: &TypedExpression<'ast, T>) -> bool {
@ -78,44 +135,81 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
let res = match s {
TypedStatement::Declaration(v) => Some(TypedStatement::Declaration(v)),
TypedStatement::Return(expressions) => Some(TypedStatement::Return(
TypedStatement::Declaration(v) => vec![TypedStatement::Declaration(v)],
TypedStatement::Return(expressions) => vec![TypedStatement::Return(
expressions
.into_iter()
.map(|e| self.fold_expression(e))
.collect(),
)),
)],
// propagation to the defined variable if rhs is a constant
TypedStatement::Definition(TypedAssignee::Identifier(var), expr) => {
TypedStatement::Definition(assignee, expr) => {
let expr = self.fold_expression(expr);
let assignee = self.fold_assignee(assignee);
if is_constant(&expr) {
self.constants
.insert(TypedAssignee::Identifier(var.clone()), expr.clone());
match self.verbose {
true => Some(TypedStatement::Definition(
TypedAssignee::Identifier(var),
expr,
)),
false => None,
let verbose = self.verbose;
match assignee {
TypedAssignee::Identifier(var) => match verbose {
true => {
assert!(self
.constants
.insert(var.id.clone(), expr.clone())
.is_none());
vec![TypedStatement::Definition(
TypedAssignee::Identifier(var),
expr,
)]
}
false => {
assert!(self.constants.insert(var.id, expr).is_none());
vec![]
}
},
assignee => match self.try_get_constant_mut(&assignee) {
Ok((_, c)) => match verbose {
true => {
*c = expr.clone();
vec![TypedStatement::Definition(assignee, expr)]
}
false => {
*c = expr;
vec![]
}
},
Err(v) => match self.constants.remove(&v.id) {
// invalidate the cache for this identifier, and define the latest
// version of the constant in the program, if any
Some(c) => vec![
TypedStatement::Definition(v.clone().into(), c),
TypedStatement::Definition(assignee, expr),
],
None => vec![TypedStatement::Definition(assignee, expr)],
},
},
}
} else {
Some(TypedStatement::Definition(
TypedAssignee::Identifier(var),
expr,
))
// the expression being assigned is not constant, invalidate the cache
let v = self
.try_get_constant_mut(&assignee)
.map(|(v, _)| v)
.unwrap_or_else(|v| v);
match self.constants.remove(&v.id) {
Some(c) => vec![
TypedStatement::Definition(v.clone().into(), c),
TypedStatement::Definition(assignee, expr),
],
None => vec![TypedStatement::Definition(assignee, expr)],
}
}
}
TypedStatement::Definition(TypedAssignee::Select(..), _) => {
unreachable!("array updates should have been replaced with full array redef")
}
TypedStatement::Definition(TypedAssignee::Member(..), _) => {
unreachable!("struct update should have been replaced with full struct redef")
}
// propagate the boolean
TypedStatement::Assertion(e) => {
// could stop execution here if condition is known to fail
Some(TypedStatement::Assertion(self.fold_boolean_expression(e)))
vec![TypedStatement::Assertion(self.fold_boolean_expression(e))]
}
// only loops with variable bounds are expected here
// we stop propagation here as constants maybe be modified inside the loop body
@ -127,10 +221,15 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
// invalidate the constants map as any constant could be modified inside the loop body, which we don't visit
self.constants.clear();
Some(TypedStatement::For(v, from, to, statements))
vec![TypedStatement::For(v, from, to, statements)]
}
TypedStatement::MultipleDefinition(variables, expression_list) => {
TypedStatement::MultipleDefinition(assignees, expression_list) => {
let assignees: Vec<TypedAssignee<'ast, T>> = assignees
.into_iter()
.map(|a| self.fold_assignee(a))
.collect();
let expression_list = self.fold_expression_list(expression_list);
match expression_list {
TypedExpressionList::FunctionCall(key, arguments, types) => {
let arguments: Vec<_> = arguments
@ -139,7 +238,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
.collect();
fn process_u_from_bits<'ast, T: Field>(
variables: Vec<Variable<'ast>>,
variables: Vec<TypedAssignee<'ast, T>>,
arguments: Vec<TypedExpression<'ast, T>>,
bitwidth: UBitwidth,
) -> TypedExpression<'ast, T> {
@ -183,7 +282,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
fn process_u_to_bits<'ast, T: Field>(
variables: Vec<Variable<'ast>>,
variables: Vec<TypedAssignee<'ast, T>>,
arguments: Vec<TypedExpression<'ast, T>>,
bitwidth: UBitwidth,
) -> TypedExpression<'ast, T> {
@ -224,37 +323,37 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
true => {
let r: Option<TypedExpression<'ast, T>> = match key.id {
"_U32_FROM_BITS" => Some(process_u_from_bits(
variables.clone(),
assignees.clone(),
arguments.clone(),
UBitwidth::B32,
)),
"_U16_FROM_BITS" => Some(process_u_from_bits(
variables.clone(),
assignees.clone(),
arguments.clone(),
UBitwidth::B16,
)),
"_U8_FROM_BITS" => Some(process_u_from_bits(
variables.clone(),
assignees.clone(),
arguments.clone(),
UBitwidth::B8,
)),
"_U32_TO_BITS" => Some(process_u_to_bits(
variables.clone(),
assignees.clone(),
arguments.clone(),
UBitwidth::B32,
)),
"_U16_TO_BITS" => Some(process_u_to_bits(
variables.clone(),
assignees.clone(),
arguments.clone(),
UBitwidth::B16,
)),
"_U8_TO_BITS" => Some(process_u_to_bits(
variables.clone(),
assignees.clone(),
arguments.clone(),
UBitwidth::B8,
)),
"_UNPACK" => {
assert_eq!(variables.len(), 1);
assert_eq!(assignees.len(), 1);
assert_eq!(arguments.len(), 1);
match FieldElementExpression::try_from(arguments[0].clone())
@ -294,32 +393,120 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
};
match r {
// if the function call returns a constant
Some(expr) => {
self.constants.insert(
TypedAssignee::Identifier(variables[0].clone()),
expr.clone(),
);
match self.verbose {
true => Some(TypedStatement::MultipleDefinition(
variables,
TypedExpressionList::FunctionCall(
key, arguments, types,
),
)),
false => None,
let verbose = self.verbose;
let mut assignees = assignees;
match assignees.pop().unwrap() {
TypedAssignee::Identifier(var) => match verbose {
true => {
self.constants
.insert(var.id.clone(), expr.clone());
vec![TypedStatement::Definition(
TypedAssignee::Identifier(var),
expr,
)]
}
false => {
self.constants.insert(var.id, expr);
vec![]
}
},
assignee => {
match self.try_get_constant_mut(&assignee) {
Ok((_, c)) => match verbose {
true => {
*c = expr.clone();
vec![TypedStatement::Definition(
assignee, expr,
)]
}
false => {
*c = expr;
vec![]
}
},
Err(v) => match self.constants.remove(&v.id) {
Some(c) => vec![
TypedStatement::Definition(
v.clone().into(),
c,
),
TypedStatement::Definition(
assignee, expr,
),
],
None => vec![TypedStatement::Definition(
assignee, expr,
)],
},
}
}
}
}
None => {
let l = TypedExpressionList::FunctionCall(
key, arguments, types,
);
Some(TypedStatement::MultipleDefinition(variables, l))
// if the function call does not return a constant, invalidate the cache
// this happpens because we only propagate certain calls here
let mut assignees = assignees;
let assignee = assignees.pop().unwrap();
let v = self
.try_get_constant_mut(&assignee)
.map(|(v, _)| v)
.unwrap_or_else(|v| v);
match self.constants.remove(&v.id) {
Some(c) => vec![
TypedStatement::Definition(v.clone().into(), c),
TypedStatement::MultipleDefinition(
vec![assignee],
TypedExpressionList::FunctionCall(
key, arguments, types,
),
),
],
None => vec![TypedStatement::MultipleDefinition(
vec![assignee],
TypedExpressionList::FunctionCall(
key, arguments, types,
),
)],
}
}
}
}
false => {
// if the function arguments are not constant, invalidate the cache
// for the return assignees
let invalidations = assignees
.iter()
.flat_map(|assignee| {
let v = self
.try_get_constant_mut(&assignee)
.map(|(v, _)| v)
.unwrap_or_else(|v| v);
match self.constants.remove(&v.id) {
Some(c) => vec![TypedStatement::Definition(
v.clone().into(),
c,
)],
None => vec![],
}
})
.collect::<Vec<_>>();
let l = TypedExpressionList::FunctionCall(key, arguments, types);
Some(TypedStatement::MultipleDefinition(variables, l))
invalidations
.into_iter()
.chain(std::iter::once(TypedStatement::MultipleDefinition(
assignees, l,
)))
.collect()
}
}
}
@ -327,13 +514,10 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
};
// In verbose mode, we always return a statement
assert!(res.is_some() || !self.verbose);
// In verbose mode, we always return at least a statement
assert!(res.len() > 0 || !self.verbose);
match res {
Some(v) => vec![v],
None => vec![],
}
res
}
fn fold_uint_expression_inner(
@ -342,20 +526,13 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
e: UExpressionInner<'ast, T>,
) -> UExpressionInner<'ast, T> {
match e {
UExpressionInner::Identifier(id) => {
match self
.constants
.get(&TypedAssignee::Identifier(Variable::uint(
id.clone(),
bitwidth,
))) {
Some(e) => match e {
TypedExpression::Uint(e) => e.as_inner().clone(),
_ => unreachable!("constant stored for a uint should be a uint"),
},
None => UExpressionInner::Identifier(id),
}
}
UExpressionInner::Identifier(id) => match self.constants.get(&id) {
Some(e) => match e {
TypedExpression::Uint(e) => e.as_inner().clone(),
_ => unreachable!("constant stored for a uint should be a uint"),
},
None => UExpressionInner::Identifier(id),
},
UExpressionInner::Add(box e1, box e2) => match (
self.fold_uint_expression(e1).into_inner(),
self.fold_uint_expression(e2).into_inner(),
@ -567,16 +744,16 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
}
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
match self.constants.get(&TypedAssignee::Select(
box TypedAssignee::Identifier(Variable::array(
id.clone(),
inner_type.clone(),
size,
)),
box FieldElementExpression::Number(n.clone()).into(),
)) {
Some(e) => match e {
TypedExpression::Uint(e) => e.clone().into_inner(),
match self.constants.get(&id) {
Some(a) => match a {
TypedExpression::Array(a) => match a.as_inner() {
ArrayExpressionInner::Value(v) => UExpression::try_from(
v[n.to_dec_string().parse::<usize>().unwrap()].clone(),
)
.unwrap()
.into_inner(),
_ => unreachable!(),
},
_ => unreachable!(""),
},
None => UExpressionInner::Select(
@ -608,21 +785,15 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
e: FieldElementExpression<'ast, T>,
) -> FieldElementExpression<'ast, T> {
match e {
FieldElementExpression::Identifier(id) => {
match self
.constants
.get(&TypedAssignee::Identifier(Variable::field_element(
id.clone(),
))) {
Some(e) => match e {
TypedExpression::FieldElement(e) => e.clone(),
_ => unreachable!(
"constant stored for a field element should be a field element"
),
},
None => FieldElementExpression::Identifier(id),
}
}
FieldElementExpression::Identifier(id) => match self.constants.get(&id) {
Some(e) => match e {
TypedExpression::FieldElement(e) => e.clone(),
_ => unreachable!(
"constant stored for a field element should be a field element"
),
},
None => FieldElementExpression::Identifier(id),
},
FieldElementExpression::Add(box e1, box e2) => match (
self.fold_field_expression(e1),
self.fold_field_expression(e2),
@ -707,17 +878,18 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
}
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
match self.constants.get(&TypedAssignee::Select(
box TypedAssignee::Identifier(Variable::array(
id.clone(),
inner_type.clone(),
size,
)),
box FieldElementExpression::Number(n.clone()).into(),
)) {
Some(e) => match e {
TypedExpression::FieldElement(e) => e.clone(),
_ => unreachable!("??"),
match self.constants.get(&id) {
Some(a) => match a {
TypedExpression::Array(a) => match a.as_inner() {
ArrayExpressionInner::Value(v) => {
FieldElementExpression::try_from(
v[n.to_dec_string().parse::<usize>().unwrap()].clone(),
)
.unwrap()
}
_ => unreachable!(),
},
_ => unreachable!(""),
},
None => FieldElementExpression::Select(
box ArrayExpressionInner::Identifier(id).annotate(inner_type, size),
@ -772,21 +944,13 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
e: ArrayExpressionInner<'ast, T>,
) -> ArrayExpressionInner<'ast, T> {
match e {
ArrayExpressionInner::Identifier(id) => {
match self
.constants
.get(&TypedAssignee::Identifier(Variable::array(
id.clone(),
ty.clone(),
size,
))) {
Some(e) => match e {
TypedExpression::Array(e) => e.as_inner().clone(),
_ => panic!("constant stored for an array should be an array"),
},
None => ArrayExpressionInner::Identifier(id),
}
}
ArrayExpressionInner::Identifier(id) => match self.constants.get(&id) {
Some(e) => match e {
TypedExpression::Array(e) => e.as_inner().clone(),
_ => panic!("constant stored for an array should be an array"),
},
None => ArrayExpressionInner::Identifier(id),
},
ArrayExpressionInner::Select(box array, box index) => {
let array = self.fold_array_expression(array);
let index = self.fold_field_expression(index);
@ -809,17 +973,17 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
}
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
match self.constants.get(&TypedAssignee::Select(
box TypedAssignee::Identifier(Variable::array(
id.clone(),
inner_type.clone(),
size,
)),
box FieldElementExpression::Number(n.clone()).into(),
)) {
Some(e) => match e {
TypedExpression::Array(e) => e.clone().into_inner(),
_ => unreachable!("should be an array"),
match self.constants.get(&id) {
Some(a) => match a {
TypedExpression::Array(a) => match a.as_inner() {
ArrayExpressionInner::Value(v) => ArrayExpression::try_from(
v[n.to_dec_string().parse::<usize>().unwrap()].clone(),
)
.unwrap()
.into_inner(),
_ => unreachable!(),
},
_ => unreachable!(""),
},
None => ArrayExpressionInner::Select(
box ArrayExpressionInner::Identifier(id).annotate(inner_type, size),
@ -885,20 +1049,13 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
e: StructExpressionInner<'ast, T>,
) -> StructExpressionInner<'ast, T> {
match e {
StructExpressionInner::Identifier(id) => {
match self
.constants
.get(&TypedAssignee::Identifier(Variable::struc(
id.clone(),
ty.clone(),
))) {
Some(e) => match e {
TypedExpression::Struct(e) => e.as_inner().clone(),
_ => panic!("constant stored for an array should be an array"),
},
None => StructExpressionInner::Identifier(id),
}
}
StructExpressionInner::Identifier(id) => match self.constants.get(&id) {
Some(e) => match e {
TypedExpression::Struct(e) => e.as_inner().clone(),
_ => panic!("constant stored for an array should be an array"),
},
None => StructExpressionInner::Identifier(id),
},
StructExpressionInner::Select(box array, box index) => {
let array = self.fold_array_expression(array);
let index = self.fold_field_expression(index);
@ -921,17 +1078,17 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
}
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
match self.constants.get(&TypedAssignee::Select(
box TypedAssignee::Identifier(Variable::array(
id.clone(),
inner_type.clone(),
size,
)),
box FieldElementExpression::Number(n.clone()).into(),
)) {
Some(e) => match e {
TypedExpression::Struct(e) => e.clone().into_inner(),
_ => unreachable!("should be a struct"),
match self.constants.get(&id) {
Some(a) => match a {
TypedExpression::Array(a) => match a.as_inner() {
ArrayExpressionInner::Value(v) => StructExpression::try_from(
v[n.to_dec_string().parse::<usize>().unwrap()].clone(),
)
.unwrap()
.into_inner(),
_ => unreachable!(),
},
_ => unreachable!(""),
},
None => StructExpressionInner::Select(
box ArrayExpressionInner::Identifier(id).annotate(inner_type, size),
@ -1002,10 +1159,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
// These kind of reduction rules are easier to apply later in the process, when we have canonical representations
// of expressions, ie `a + a` would always be written `2 * a`
match e {
BooleanExpression::Identifier(id) => match self
.constants
.get(&TypedAssignee::Identifier(Variable::boolean(id.clone())))
{
BooleanExpression::Identifier(id) => match self.constants.get(&id) {
Some(e) => match e {
TypedExpression::Boolean(e) => e.clone(),
_ => panic!("constant stored for a boolean should be a boolean"),
@ -1152,17 +1306,16 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
}
}
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
match self.constants.get(&TypedAssignee::Select(
box TypedAssignee::Identifier(Variable::array(
id.clone(),
inner_type.clone(),
size,
)),
box FieldElementExpression::Number(n.clone()).into(),
)) {
Some(e) => match e {
TypedExpression::Boolean(e) => e.clone(),
_ => unreachable!("Should be a boolean"),
match self.constants.get(&id) {
Some(a) => match a {
TypedExpression::Array(a) => match a.as_inner() {
ArrayExpressionInner::Value(v) => BooleanExpression::try_from(
v[n.to_dec_string().parse::<usize>().unwrap()].clone(),
)
.unwrap(),
_ => unreachable!(),
},
_ => unreachable!(""),
},
None => BooleanExpression::Select(
box ArrayExpressionInner::Identifier(id).annotate(inner_type, size),

View file

@ -6,10 +6,8 @@
use crate::typed_absy::folder::*;
use crate::typed_absy::identifier::CoreIdentifier;
use crate::typed_absy::types::{MemberId, Type};
use crate::typed_absy::*;
use std::collections::HashMap;
use std::collections::HashSet;
use zokrates_field::Field;
pub enum Output<'ast, T: Field> {
@ -63,320 +61,6 @@ impl<'ast> Unroller<'ast> {
false => Output::Incomplete(p, unroller.statement_count),
}
}
fn choose_many<T: Field>(
base: TypedExpression<'ast, T>,
indices: Vec<Access<'ast, T>>,
new_expression: TypedExpression<'ast, T>,
statements: &mut HashSet<TypedStatement<'ast, T>>,
) -> TypedExpression<'ast, T> {
let mut indices = indices;
match indices.len() {
0 => new_expression,
_ => match base {
TypedExpression::Array(base) => {
let inner_ty = base.inner_type();
let size = base.size();
let head = indices.remove(0);
let tail = indices;
match head {
Access::Select(head) => {
statements.insert(TypedStatement::Assertion(
BooleanExpression::Lt(
box head.clone(),
box FieldElementExpression::Number(T::from(size)),
)
.into(),
));
ArrayExpressionInner::Value(
(0..size)
.map(|i| match inner_ty {
Type::Array(..) => ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
ArrayExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Array(e) => e,
e => unreachable!(
"the interior was expected to be an array, was {}",
e.get_type()
),
},
ArrayExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::Struct(..) => StructExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
StructExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Struct(e) => e,
e => unreachable!(
"the interior was expected to be a struct, was {}",
e.get_type()
),
},
StructExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::FieldElement => FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
FieldElementExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::FieldElement(e) => e,
e => unreachable!(
"the interior was expected to be a field, was {}",
e.get_type()
),
},
FieldElementExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::Boolean => BooleanExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
BooleanExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Boolean(e) => e,
e => unreachable!(
"the interior was expected to be a boolean, was {}",
e.get_type()
),
},
BooleanExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::Uint(..) => UExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
UExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Uint(e) => e,
e => unreachable!(
"the interior was expected to be a uint, was {}",
e.get_type()
),
},
UExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
})
.collect(),
)
.annotate(inner_ty.clone(), size)
.into()
}
Access::Member(..) => unreachable!("can't get a member from an array"),
}
}
TypedExpression::Struct(base) => {
let members = match base.get_type() {
Type::Struct(members) => members.clone(),
_ => unreachable!(),
};
let head = indices.remove(0);
let tail = indices;
match head {
Access::Member(head) => StructExpressionInner::Value(
members
.clone()
.into_iter()
.map(|member| match *member.ty {
Type::FieldElement => {
if member.id == head {
Self::choose_many(
FieldElementExpression::member(
base.clone(),
head.clone(),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
FieldElementExpression::member(
base.clone(),
member.id.clone(),
)
.into()
}
}
Type::Uint(..) => {
if member.id == head {
Self::choose_many(
UExpression::member(base.clone(), head.clone())
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
UExpression::member(base.clone(), member.id.clone())
.into()
}
}
Type::Boolean => {
if member.id == head {
Self::choose_many(
BooleanExpression::member(
base.clone(),
head.clone(),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
BooleanExpression::member(
base.clone(),
member.id.clone(),
)
.into()
}
}
Type::Array(..) => {
if member.id == head {
Self::choose_many(
ArrayExpression::member(base.clone(), head.clone())
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
ArrayExpression::member(base.clone(), member.id.clone())
.into()
}
}
Type::Struct(..) => {
if member.id == head {
Self::choose_many(
StructExpression::member(
base.clone(),
head.clone(),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
StructExpression::member(
base.clone(),
member.id.clone(),
)
.into()
}
}
})
.collect(),
)
.annotate(members)
.into(),
Access::Select(..) => unreachable!("can't get a element from a struct"),
}
}
e => unreachable!("can't make an access on a {}", e.get_type()),
},
}
}
}
#[derive(Clone, Debug)]
enum Access<'ast, T: Field> {
Select(FieldElementExpression<'ast, T>),
Member(MemberId),
}
/// Turn an assignee into its representation as a base variable and a list accesses
/// a[2][3][4] -> (a, [2, 3, 4])
fn linear<'ast, T: Field>(a: TypedAssignee<'ast, T>) -> (Variable, Vec<Access<'ast, T>>) {
match a {
TypedAssignee::Identifier(v) => (v, vec![]),
TypedAssignee::Select(box array, box index) => {
let (v, mut indices) = linear(array);
indices.push(Access::Select(index));
(v, indices)
}
TypedAssignee::Member(box s, m) => {
let (v, mut indices) = linear(s);
indices.push(Access::Member(m));
(v, indices)
}
}
}
impl<'ast, T: Field> Folder<'ast, T> for Unroller<'ast> {
@ -384,64 +68,31 @@ impl<'ast, T: Field> Folder<'ast, T> for Unroller<'ast> {
self.statement_count += 1;
match s {
TypedStatement::Declaration(_) => vec![],
TypedStatement::Definition(assignee, expr) => {
let expr = self.fold_expression(expr);
TypedStatement::Definition(a, e) => {
let e = self.fold_expression(e);
let (variable, indices) = linear(assignee);
let base = match variable.get_type() {
Type::FieldElement => {
FieldElementExpression::Identifier(variable.id.clone().into()).into()
}
Type::Boolean => {
BooleanExpression::Identifier(variable.id.clone().into()).into()
}
Type::Uint(bitwidth) => {
UExpressionInner::Identifier(variable.id.clone().into())
.annotate(bitwidth)
.into()
}
Type::Array(array_type) => {
ArrayExpressionInner::Identifier(variable.id.clone().into())
.annotate(*array_type.ty, array_type.size)
.into()
}
Type::Struct(members) => {
StructExpressionInner::Identifier(variable.id.clone().into())
.annotate(members)
.into()
let a = match a {
TypedAssignee::Identifier(v) => {
TypedAssignee::Identifier(self.issue_next_ssa_variable(v))
}
a => fold_assignee(self, a),
};
let base = self.fold_expression(base);
let indices = indices
vec![TypedStatement::Definition(a, e)]
}
TypedStatement::MultipleDefinition(assignees, exprs) => {
let exprs = self.fold_expression_list(exprs);
let assignees = assignees
.into_iter()
.map(|a| match a {
Access::Select(i) => Access::Select(self.fold_field_expression(i)),
a => a,
TypedAssignee::Identifier(v) => {
TypedAssignee::Identifier(self.issue_next_ssa_variable(v))
}
a => fold_assignee(self, a),
})
.collect();
let mut range_checks = HashSet::new();
let e = Self::choose_many(base, indices, expr, &mut range_checks);
range_checks
.into_iter()
.chain(std::iter::once(TypedStatement::Definition(
TypedAssignee::Identifier(self.issue_next_ssa_variable(variable)),
e,
)))
.collect()
}
TypedStatement::MultipleDefinition(variables, exprs) => {
let exprs = self.fold_expression_list(exprs);
let variables = variables
.into_iter()
.map(|v| self.issue_next_ssa_variable(v))
.collect();
vec![TypedStatement::MultipleDefinition(variables, exprs)]
vec![TypedStatement::MultipleDefinition(assignees, exprs)]
}
TypedStatement::For(v, from, to, stats) => {
let from = self.fold_field_expression(from);
@ -510,246 +161,6 @@ mod tests {
use super::*;
use zokrates_field::Bn128Field;
#[test]
fn ssa_array() {
let a0 = ArrayExpressionInner::Identifier("a".into()).annotate(Type::FieldElement, 3);
let e = FieldElementExpression::Number(Bn128Field::from(42)).into();
let index = FieldElementExpression::Number(Bn128Field::from(1));
let a1 = Unroller::choose_many(
a0.clone().into(),
vec![Access::Select(index)],
e,
&mut HashSet::new(),
);
// a[1] = 42
// -> a = [0 == 1 ? 42 : a[0], 1 == 1 ? 42 : a[1], 2 == 1 ? 42 : a[2]]
assert_eq!(
a1,
ArrayExpressionInner::Value(vec![
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
FieldElementExpression::Number(Bn128Field::from(42)),
FieldElementExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(0))
)
)
.into(),
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
FieldElementExpression::Number(Bn128Field::from(42)),
FieldElementExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(1))
)
)
.into(),
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(2)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
FieldElementExpression::Number(Bn128Field::from(42)),
FieldElementExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(2))
)
)
.into()
])
.annotate(Type::FieldElement, 3)
.into()
);
let a0 = ArrayExpressionInner::Identifier("a".into())
.annotate(Type::array(Type::FieldElement, 3), 3);
let e = ArrayExpressionInner::Identifier("b".into()).annotate(Type::FieldElement, 3);
let index = FieldElementExpression::Number(Bn128Field::from(1));
let a1 = Unroller::choose_many(
a0.clone().into(),
vec![Access::Select(index)],
e.clone().into(),
&mut HashSet::new(),
);
// a[0] = b
// -> a = [0 == 1 ? b : a[0], 1 == 1 ? b : a[1], 2 == 1 ? b : a[2]]
assert_eq!(
a1,
ArrayExpressionInner::Value(vec![
ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
e.clone(),
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(0))
)
)
.into(),
ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
e.clone(),
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(1))
)
)
.into(),
ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(2)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
e.clone(),
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(2))
)
)
.into()
])
.annotate(Type::array(Type::FieldElement, 3), 3)
.into()
);
let a0 = ArrayExpressionInner::Identifier("a".into())
.annotate(Type::array(Type::FieldElement, 2), 2);
let e = FieldElementExpression::Number(Bn128Field::from(42));
let indices = vec![
Access::Select(FieldElementExpression::Number(Bn128Field::from(0))),
Access::Select(FieldElementExpression::Number(Bn128Field::from(0))),
];
let a1 = Unroller::choose_many(
a0.clone().into(),
indices,
e.clone().into(),
&mut HashSet::new(),
);
// a[0][0] = 42
// -> a = [0 == 0 ? [0 == 0 ? 42 : a[0][0], 1 == 0 ? 42 : a[0][1]] : a[0], 1 == 0 ? [0 == 0 ? 42 : a[1][0], 1 == 0 ? 42 : a[1][1]] : a[1]]
assert_eq!(
a1,
ArrayExpressionInner::Value(vec![
ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(0))
),
ArrayExpressionInner::Value(vec![
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(0))
),
e.clone(),
FieldElementExpression::select(
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(0))
),
FieldElementExpression::Number(Bn128Field::from(0))
)
)
.into(),
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(0))
),
e.clone(),
FieldElementExpression::select(
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(0))
),
FieldElementExpression::Number(Bn128Field::from(1))
)
)
.into()
])
.annotate(Type::FieldElement, 2),
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(0))
)
)
.into(),
ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(0))
),
ArrayExpressionInner::Value(vec![
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(0))
),
e.clone(),
FieldElementExpression::select(
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(1))
),
FieldElementExpression::Number(Bn128Field::from(0))
)
)
.into(),
FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(0))
),
e.clone(),
FieldElementExpression::select(
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(1))
),
FieldElementExpression::Number(Bn128Field::from(1))
)
)
.into()
])
.annotate(Type::FieldElement, 2),
ArrayExpression::select(
a0.clone(),
FieldElementExpression::Number(Bn128Field::from(1))
)
)
.into(),
])
.annotate(Type::array(Type::FieldElement, 2), 2)
.into()
);
}
#[cfg(test)]
mod statement {
use super::*;
@ -829,17 +240,45 @@ mod tests {
fn idempotence() {
// an already unrolled program should not be modified by unrolling again
// b = [5]
// b[0] = 1
// a = 5
// a_1 = 6
// a_2 = 7
// should be turned into
// b = [5]
// b[0] = 1
// a = 5
// a_1 = 6
// a_2 = 7
let mut u = Unroller::new();
let s = TypedStatement::Definition(
TypedAssignee::Identifier(Variable::array(
Identifier::from("b").version(0),
Type::FieldElement,
1,
)),
ArrayExpressionInner::Value(vec![FieldElementExpression::from(Bn128Field::from(
5,
))
.into()])
.annotate(Type::FieldElement, 1)
.into(),
);
assert_eq!(u.fold_statement(s.clone()), vec![s]);
let s = TypedStatement::Definition(
TypedAssignee::Select(
box Variable::field_element(Identifier::from("b").version(0)).into(),
box FieldElementExpression::Number(Bn128Field::from(0)),
),
FieldElementExpression::Number(Bn128Field::from(1)).into(),
);
assert_eq!(u.fold_statement(s.clone()), vec![s]);
let s = TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element(
Identifier::from("a").version(0),
@ -1005,7 +444,7 @@ mod tests {
);
let s: TypedStatement<Bn128Field> = TypedStatement::MultipleDefinition(
vec![Variable::field_element("a")],
vec![Variable::field_element("a").into()],
TypedExpressionList::FunctionCall(
FunctionKey::with_id("foo").signature(
Signature::new()
@ -1019,7 +458,7 @@ mod tests {
assert_eq!(
u.fold_statement(s),
vec![TypedStatement::MultipleDefinition(
vec![Variable::field_element(Identifier::from("a").version(1))],
vec![Variable::field_element(Identifier::from("a").version(1)).into()],
TypedExpressionList::FunctionCall(
FunctionKey::with_id("foo").signature(
Signature::new()
@ -1043,7 +482,7 @@ mod tests {
// should be turned into
// a_0 = [1, 1]
// a_1 = [if 0 == 1 then 2 else a_0[0], if 1 == 1 then 2 else a_0[1]]
// a_0[1] = 2
let mut u = Unroller::new();
@ -1085,58 +524,7 @@ mod tests {
FieldElementExpression::Number(Bn128Field::from(2)).into(),
);
assert_eq!(
u.fold_statement(s),
vec![
TypedStatement::Assertion(
BooleanExpression::Lt(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(2))
)
.into(),
),
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_array(
Identifier::from("a").version(1),
2
)),
ArrayExpressionInner::Value(vec![
FieldElementExpression::IfElse(
box BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
box FieldElementExpression::Number(Bn128Field::from(2)),
box FieldElementExpression::Select(
box ArrayExpressionInner::Identifier(
Identifier::from("a").version(0)
)
.annotate(Type::FieldElement, 2),
box FieldElementExpression::Number(Bn128Field::from(0))
),
)
.into(),
FieldElementExpression::IfElse(
box BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
box FieldElementExpression::Number(Bn128Field::from(2)),
box FieldElementExpression::Select(
box ArrayExpressionInner::Identifier(
Identifier::from("a").version(0)
)
.annotate(Type::FieldElement, 2),
box FieldElementExpression::Number(Bn128Field::from(1))
),
)
.into(),
])
.annotate(Type::FieldElement, 2)
.into()
)
]
);
assert_eq!(u.fold_statement(s.clone()), vec![s]);
}
#[test]
@ -1146,7 +534,7 @@ mod tests {
// should be turned into
// a_0 = [[0, 1], [2, 3]]
// a_1 = [if 0 == 1 then [4, 5] else a_0[0], if 1 == 1 then [4, 5] else a_0[1]]
// a_0 = [4, 5]
let mut u = Unroller::new();
@ -1222,72 +610,7 @@ mod tests {
.into(),
);
assert_eq!(
u.fold_statement(s),
vec![
TypedStatement::Assertion(
BooleanExpression::Lt(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(2))
)
.into(),
),
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::with_id_and_type(
Identifier::from("a").version(1),
array_of_array_ty.clone()
)),
ArrayExpressionInner::Value(vec![
ArrayExpressionInner::IfElse(
box BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(0)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
box ArrayExpressionInner::Value(vec![
FieldElementExpression::Number(Bn128Field::from(4)).into(),
FieldElementExpression::Number(Bn128Field::from(5)).into(),
])
.annotate(Type::FieldElement, 2)
.into(),
box ArrayExpressionInner::Select(
box ArrayExpressionInner::Identifier(
Identifier::from("a").version(0)
)
.annotate(Type::array(Type::FieldElement, 2), 2),
box FieldElementExpression::Number(Bn128Field::from(0))
)
.annotate(Type::FieldElement, 2),
)
.annotate(Type::FieldElement, 2)
.into(),
ArrayExpressionInner::IfElse(
box BooleanExpression::FieldEq(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(1))
),
box ArrayExpressionInner::Value(vec![
FieldElementExpression::Number(Bn128Field::from(4)).into(),
FieldElementExpression::Number(Bn128Field::from(5)).into(),
])
.annotate(Type::FieldElement, 2)
.into(),
box ArrayExpressionInner::Select(
box ArrayExpressionInner::Identifier(
Identifier::from("a").version(0)
)
.annotate(Type::array(Type::FieldElement, 2), 2),
box FieldElementExpression::Number(Bn128Field::from(1))
)
.annotate(Type::FieldElement, 2),
)
.annotate(Type::FieldElement, 2)
.into(),
])
.annotate(Type::array(Type::FieldElement, 2), 2)
.into()
)
]
);
assert_eq!(u.fold_statement(s.clone()), vec![s]);
}
}
}

View file

@ -13,11 +13,11 @@
use crate::typed_absy::{folder::*, *};
use zokrates_field::Field;
pub struct VariableAccessRemover<'ast, T: Field> {
pub struct VariableReadRemover<'ast, T: Field> {
statements: Vec<TypedStatement<'ast, T>>,
}
impl<'ast, T: Field> VariableAccessRemover<'ast, T> {
impl<'ast, T: Field> VariableReadRemover<'ast, T> {
fn new() -> Self {
Self { statements: vec![] }
}
@ -76,7 +76,7 @@ impl<'ast, T: Field> VariableAccessRemover<'ast, T> {
}
}
impl<'ast, T: Field> Folder<'ast, T> for VariableAccessRemover<'ast, T> {
impl<'ast, T: Field> Folder<'ast, T> for VariableReadRemover<'ast, T> {
fn fold_field_expression(
&mut self,
e: FieldElementExpression<'ast, T>,
@ -167,7 +167,7 @@ mod tests {
);
assert_eq!(
VariableAccessRemover::new().fold_statement(access),
VariableReadRemover::new().fold_statement(access),
vec![
TypedStatement::Assertion(
BooleanExpression::Or(

View file

@ -0,0 +1,413 @@
//! Module containing SSA reduction, including for-loop unrolling
//!
//! @file unroll.rs
//! @author Thibaut Schaeffer <thibaut@schaeff.fr>
//! @date 2018
use crate::typed_absy::folder::*;
use crate::typed_absy::types::{MemberId, Type};
use crate::typed_absy::*;
use std::collections::HashSet;
use zokrates_field::Field;
pub struct VariableWriteRemover;
impl<'ast> VariableWriteRemover {
fn new() -> Self {
VariableWriteRemover
}
pub fn apply<T: Field>(p: TypedProgram<T>) -> TypedProgram<T> {
let mut remover = VariableWriteRemover::new();
remover.fold_program(p)
}
fn choose_many<T: Field>(
base: TypedExpression<'ast, T>,
indices: Vec<Access<'ast, T>>,
new_expression: TypedExpression<'ast, T>,
statements: &mut HashSet<TypedStatement<'ast, T>>,
) -> TypedExpression<'ast, T> {
let mut indices = indices;
match indices.len() {
0 => new_expression,
_ => match base {
TypedExpression::Array(base) => {
let inner_ty = base.inner_type();
let size = base.size();
let head = indices.remove(0);
let tail = indices;
match head {
Access::Select(head) => {
statements.insert(TypedStatement::Assertion(
BooleanExpression::Lt(
box head.clone(),
box FieldElementExpression::Number(T::from(size)),
)
.into(),
));
ArrayExpressionInner::Value(
(0..size)
.map(|i| match inner_ty {
Type::Array(..) => ArrayExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
ArrayExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Array(e) => e,
e => unreachable!(
"the interior was expected to be an array, was {}",
e.get_type()
),
},
ArrayExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::Struct(..) => StructExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
StructExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Struct(e) => e,
e => unreachable!(
"the interior was expected to be a struct, was {}",
e.get_type()
),
},
StructExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::FieldElement => FieldElementExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
FieldElementExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::FieldElement(e) => e,
e => unreachable!(
"the interior was expected to be a field, was {}",
e.get_type()
),
},
FieldElementExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::Boolean => BooleanExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
BooleanExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Boolean(e) => e,
e => unreachable!(
"the interior was expected to be a boolean, was {}",
e.get_type()
),
},
BooleanExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
Type::Uint(..) => UExpression::if_else(
BooleanExpression::FieldEq(
box FieldElementExpression::Number(T::from(i)),
box head.clone(),
),
match Self::choose_many(
UExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
) {
TypedExpression::Uint(e) => e,
e => unreachable!(
"the interior was expected to be a uint, was {}",
e.get_type()
),
},
UExpression::select(
base.clone(),
FieldElementExpression::Number(T::from(i)),
),
)
.into(),
})
.collect(),
)
.annotate(inner_ty.clone(), size)
.into()
}
Access::Member(..) => unreachable!("can't get a member from an array"),
}
}
TypedExpression::Struct(base) => {
let members = match base.get_type() {
Type::Struct(members) => members.clone(),
_ => unreachable!(),
};
let head = indices.remove(0);
let tail = indices;
match head {
Access::Member(head) => StructExpressionInner::Value(
members
.clone()
.into_iter()
.map(|member| match *member.ty {
Type::FieldElement => {
if member.id == head {
Self::choose_many(
FieldElementExpression::member(
base.clone(),
head.clone(),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
FieldElementExpression::member(
base.clone(),
member.id.clone(),
)
.into()
}
}
Type::Uint(..) => {
if member.id == head {
Self::choose_many(
UExpression::member(base.clone(), head.clone())
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
UExpression::member(base.clone(), member.id.clone())
.into()
}
}
Type::Boolean => {
if member.id == head {
Self::choose_many(
BooleanExpression::member(
base.clone(),
head.clone(),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
BooleanExpression::member(
base.clone(),
member.id.clone(),
)
.into()
}
}
Type::Array(..) => {
if member.id == head {
Self::choose_many(
ArrayExpression::member(base.clone(), head.clone())
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
ArrayExpression::member(base.clone(), member.id.clone())
.into()
}
}
Type::Struct(..) => {
if member.id == head {
Self::choose_many(
StructExpression::member(
base.clone(),
head.clone(),
)
.into(),
tail.clone(),
new_expression.clone(),
statements,
)
} else {
StructExpression::member(
base.clone(),
member.id.clone(),
)
.into()
}
}
})
.collect(),
)
.annotate(members)
.into(),
Access::Select(..) => unreachable!("can't get a element from a struct"),
}
}
e => unreachable!("can't make an access on a {}", e.get_type()),
},
}
}
}
#[derive(Clone, Debug)]
enum Access<'ast, T: Field> {
Select(FieldElementExpression<'ast, T>),
Member(MemberId),
}
/// Turn an assignee into its representation as a base variable and a list accesses
/// a[2][3][4] -> (a, [2, 3, 4])
fn linear<'ast, T: Field>(a: TypedAssignee<'ast, T>) -> (Variable, Vec<Access<'ast, T>>) {
match a {
TypedAssignee::Identifier(v) => (v, vec![]),
TypedAssignee::Select(box array, box index) => {
let (v, mut indices) = linear(array);
indices.push(Access::Select(index));
(v, indices)
}
TypedAssignee::Member(box s, m) => {
let (v, mut indices) = linear(s);
indices.push(Access::Member(m));
(v, indices)
}
}
}
fn is_constant<'ast, T>(assignee: &TypedAssignee<'ast, T>) -> bool {
match assignee {
TypedAssignee::Identifier(_) => true,
TypedAssignee::Select(box assignee, box index) => match index {
FieldElementExpression::Number(_) => is_constant(assignee),
_ => false,
},
TypedAssignee::Member(box assignee, _) => is_constant(assignee),
}
}
impl<'ast, T: Field> Folder<'ast, T> for VariableWriteRemover {
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
match s {
TypedStatement::Definition(assignee, expr) => {
if is_constant(&assignee) {
vec![TypedStatement::Definition(assignee, expr)]
} else {
// Note: here we redefine the whole object, ideally we would only redefine some of it
// Example: `a[0][i] = 42` we redefine `a` but we could redefine just `a[0]`
let expr = self.fold_expression(expr);
let (variable, indices) = linear(assignee);
let base = match variable.get_type() {
Type::FieldElement => {
FieldElementExpression::Identifier(variable.id.clone().into()).into()
}
Type::Boolean => {
BooleanExpression::Identifier(variable.id.clone().into()).into()
}
Type::Uint(bitwidth) => {
UExpressionInner::Identifier(variable.id.clone().into())
.annotate(bitwidth)
.into()
}
Type::Array(array_type) => {
ArrayExpressionInner::Identifier(variable.id.clone().into())
.annotate(*array_type.ty, array_type.size)
.into()
}
Type::Struct(members) => {
StructExpressionInner::Identifier(variable.id.clone().into())
.annotate(members)
.into()
}
};
let base = self.fold_expression(base);
let indices = indices
.into_iter()
.map(|a| match a {
Access::Select(i) => Access::Select(self.fold_field_expression(i)),
a => a,
})
.collect();
let mut range_checks = HashSet::new();
let e = Self::choose_many(base, indices, expr, &mut range_checks);
range_checks
.into_iter()
.chain(std::iter::once(TypedStatement::Definition(
TypedAssignee::Identifier(variable),
e,
)))
.collect()
}
}
s => fold_statement(self, s),
}
}
}

View file

@ -42,14 +42,7 @@ pub trait Folder<'ast, T: Field>: Sized {
}
fn fold_assignee(&mut self, a: TypedAssignee<'ast, T>) -> TypedAssignee<'ast, T> {
match a {
TypedAssignee::Identifier(v) => TypedAssignee::Identifier(self.fold_variable(v)),
TypedAssignee::Select(box a, box index) => TypedAssignee::Select(
box self.fold_assignee(a),
box self.fold_field_expression(index),
),
TypedAssignee::Member(box s, m) => TypedAssignee::Member(box self.fold_assignee(s), m),
}
fold_assignee(self, a)
}
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
@ -175,8 +168,8 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
.flat_map(|s| f.fold_statement(s))
.collect(),
),
TypedStatement::MultipleDefinition(variables, elist) => TypedStatement::MultipleDefinition(
variables.into_iter().map(|v| f.fold_variable(v)).collect(),
TypedStatement::MultipleDefinition(assignees, elist) => TypedStatement::MultipleDefinition(
assignees.into_iter().map(|a| f.fold_assignee(a)).collect(),
f.fold_expression_list(elist),
),
};
@ -548,6 +541,19 @@ pub fn fold_function_symbol<'ast, T: Field, F: Folder<'ast, T>>(
}
}
pub fn fold_assignee<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
a: TypedAssignee<'ast, T>,
) -> TypedAssignee<'ast, T> {
match a {
TypedAssignee::Identifier(v) => TypedAssignee::Identifier(f.fold_variable(v)),
TypedAssignee::Select(box a, box index) => {
TypedAssignee::Select(box f.fold_assignee(a), box f.fold_field_expression(index))
}
TypedAssignee::Member(box s, m) => TypedAssignee::Member(box f.fold_assignee(s), m),
}
}
pub fn fold_program<'ast, T: Field, F: Folder<'ast, T>>(
f: &mut F,
p: TypedProgram<'ast, T>,

View file

@ -259,6 +259,12 @@ pub enum TypedAssignee<'ast, T> {
Member(Box<TypedAssignee<'ast, T>>, MemberId),
}
impl<'ast, T> From<Variable<'ast>> for TypedAssignee<'ast, T> {
fn from(v: Variable<'ast>) -> Self {
TypedAssignee::Identifier(v)
}
}
impl<'ast, T> Typed for TypedAssignee<'ast, T> {
fn get_type(&self) -> Type {
match *self {
@ -319,7 +325,7 @@ pub enum TypedStatement<'ast, T> {
FieldElementExpression<'ast, T>,
Vec<TypedStatement<'ast, T>>,
),
MultipleDefinition(Vec<Variable<'ast>>, TypedExpressionList<'ast, T>),
MultipleDefinition(Vec<TypedAssignee<'ast, T>>, TypedExpressionList<'ast, T>),
}
impl<'ast, T: fmt::Debug> fmt::Debug for TypedStatement<'ast, T> {
@ -628,6 +634,12 @@ pub enum FieldElementExpression<'ast, T> {
),
}
impl<'ast, T> From<T> for FieldElementExpression<'ast, T> {
fn from(n: T) -> Self {
FieldElementExpression::Number(n)
}
}
/// An expression of type `bool`
#[derive(Clone, PartialEq, Hash, Eq)]
pub enum BooleanExpression<'ast, T> {
@ -737,6 +749,10 @@ impl<'ast, T> ArrayExpression<'ast, T> {
&self.inner
}
pub fn as_inner_mut(&mut self) -> &mut ArrayExpressionInner<'ast, T> {
&mut self.inner
}
pub fn into_inner(self) -> ArrayExpressionInner<'ast, T> {
self.inner
}
@ -757,6 +773,10 @@ impl<'ast, T> StructExpression<'ast, T> {
&self.inner
}
pub fn as_inner_mut(&mut self) -> &mut StructExpressionInner<'ast, T> {
&mut self.inner
}
pub fn into_inner(self) -> StructExpressionInner<'ast, T> {
self.inner
}

View file

@ -192,7 +192,7 @@ pub enum ZirStatement<'ast, T> {
Definition(ZirAssignee<'ast>, ZirExpression<'ast, T>),
Declaration(Variable<'ast>),
Assertion(BooleanExpression<'ast, T>),
MultipleDefinition(Vec<Variable<'ast>>, ZirExpressionList<'ast, T>),
MultipleDefinition(Vec<ZirAssignee<'ast>>, ZirExpressionList<'ast, T>),
}
impl<'ast, T: fmt::Debug> fmt::Debug for ZirStatement<'ast, T> {

View file

@ -85,8 +85,7 @@ def main(u32[16] input, u32[8] current) -> u32[8]:
u32[64] w = [...input, ...[0x00000000; 48]]
for field i in 16..64 do
u32 r = extend(w, i)
w[i] = r
w[i] = extend(w, i)
endfor
u32 a = h0

View file

@ -8,12 +8,9 @@ def main(u32[4] a, u16[4] b, u8[4] c) -> (bool[4][32], bool[4][16], bool[4][8]):
bool[4][8] f = [[false; 8]; 4]
for field i in 0..4 do
bool[32] g = u32_to_bits(a[i])
d[i] = g
bool[16] h = u16_to_bits(b[i])
e[i] = h
bool[8] j = u8_to_bits(c[i])
f[i] = j
d[i] = u32_to_bits(a[i])
e[i] = u16_to_bits(b[i])
f[i] = u8_to_bits(c[i])
endfor
return d, e, f