mirror of
https://github.com/circify/circ.git
synced 2026-01-09 13:48:02 -05:00
start interpreting ZoKrates
This commit is contained in:
353
Cargo.lock
generated
353
Cargo.lock
generated
@@ -1,5 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.14.1"
|
||||
@@ -24,6 +26,17 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
@@ -50,6 +63,39 @@ dependencies = [
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
|
||||
dependencies = [
|
||||
"block-padding",
|
||||
"byte-tools",
|
||||
"byteorder",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
|
||||
dependencies = [
|
||||
"byte-tools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
@@ -60,25 +106,48 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
name = "circ"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"fnv",
|
||||
"hashconsing",
|
||||
"ieee754",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"quickcheck",
|
||||
"quickcheck_macros",
|
||||
"rand",
|
||||
"rsmt2",
|
||||
"rug",
|
||||
"typed-arena",
|
||||
"zokrates_parser",
|
||||
"zokrates_pest_ast",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26ecb66b4bdca6c1409b40fb255eefc2bd4f6d135dab3c3124f80ffa2a9661e"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -91,12 +160,59 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"failure_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure_derive"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.60",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "from-pest"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aba9389cedcba1fb3a2aa2ed00f584f2606bce8e0106614a17327a24513bc60f"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.2"
|
||||
@@ -133,12 +249,36 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "ieee754"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9007da9cacbd3e6343da136e98b0d2df013f553d35bdec8b518f07bea768e19c"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.7.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@@ -160,6 +300,12 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maplit"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.4"
|
||||
@@ -188,19 +334,90 @@ version = "1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
|
||||
dependencies = [
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest-ast"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fbf404899169771dd6a32c84248b83cd67a26cc7cc957aac87661490e1227e4"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.13",
|
||||
"single",
|
||||
"syn 0.15.44",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
|
||||
dependencies = [
|
||||
"maplit",
|
||||
"pest",
|
||||
"sha-1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
"unicode-xid 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -220,9 +437,18 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b22a693222d716a9587786f37ac3f6b4faedb5b80c23914e7303ff5a1d8016e9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -231,7 +457,7 @@ version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"proc-macro2 1.0.24",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -318,15 +544,68 @@ version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"fake-simd",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "single"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd5add732a1ab689845591a1b50339cf5310b563e08dc5813c65991f30369ea2"
|
||||
dependencies = [
|
||||
"failure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.13",
|
||||
"unicode-xid 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.8",
|
||||
"unicode-xid 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.24",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.60",
|
||||
"unicode-xid 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -338,6 +617,30 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typed-arena"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
@@ -350,6 +653,12 @@ version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
@@ -372,8 +681,36 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "zokrates_parser"
|
||||
version = "0.1.6"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zokrates_pest_ast"
|
||||
version = "0.1.5"
|
||||
dependencies = [
|
||||
"from-pest",
|
||||
"lazy_static",
|
||||
"pest",
|
||||
"pest-ast",
|
||||
"zokrates_parser",
|
||||
]
|
||||
|
||||
@@ -14,10 +14,15 @@ lazy_static = "1.4"
|
||||
rand = "0.8"
|
||||
rsmt2 = "0.11"
|
||||
ieee754 = "0.2"
|
||||
zokrates_parser = { path = "third_party/ZoKrates/zokrates_parser" }
|
||||
zokrates_pest_ast = { path = "third_party/ZoKrates/zokrates_pest_ast" }
|
||||
typed-arena = "2.0"
|
||||
log = "0.4"
|
||||
|
||||
[dev-dependencies]
|
||||
quickcheck = "1"
|
||||
quickcheck_macros = "1"
|
||||
env_logger = "0.8"
|
||||
|
||||
[profile.release]
|
||||
#debug = true
|
||||
|
||||
14
examples/circ.rs
Normal file
14
examples/circ.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use std::env::args;
|
||||
use circ::front::FrontEnd;
|
||||
use circ::front::zokrates::{Zokrates, Inputs};
|
||||
use std::path::PathBuf;
|
||||
use env_logger;
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
let inputs = Inputs {
|
||||
file: PathBuf::from(args().nth(1).unwrap()),
|
||||
inputs: None,
|
||||
};
|
||||
let cs = Zokrates::gen(inputs);
|
||||
}
|
||||
29
src/circify/includer.rs
Normal file
29
src/circify/includer.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub trait Loader: Sized {
|
||||
type AST;
|
||||
type ParseError;
|
||||
fn parse<P: AsRef<Path>>(&self, p: &P) -> Result<Self::AST, Self::ParseError>;
|
||||
fn includes<P: AsRef<Path>>(&self, ast: &Self::AST, p: &P) -> Vec<PathBuf>;
|
||||
fn recursive_load<P: AsRef<Path>>(
|
||||
&self,
|
||||
p: &P,
|
||||
) -> Result<HashMap<PathBuf, Self::AST>, Self::ParseError> {
|
||||
let mut m = HashMap::new();
|
||||
let mut q = VecDeque::new();
|
||||
q.push_back(p.as_ref().to_path_buf());
|
||||
while let Some(p) = q.pop_front() {
|
||||
if !m.contains_key(&p) {
|
||||
let ast = self.parse(&p)?;
|
||||
for c in self.includes(&ast, &p) {
|
||||
if !m.contains_key(&c) {
|
||||
q.push_back(c);
|
||||
}
|
||||
}
|
||||
m.insert(p, ast);
|
||||
}
|
||||
}
|
||||
Ok(m)
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ use std::collections::HashMap;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub mod includer;
|
||||
pub mod mem;
|
||||
|
||||
type Version = usize;
|
||||
@@ -272,6 +273,7 @@ pub struct Circify<E: Embeddable> {
|
||||
globals: LexScope<E::Ty>,
|
||||
cir_ctx: CirCtx,
|
||||
condition: Term,
|
||||
typedefs: HashMap<String, E::Ty>,
|
||||
}
|
||||
|
||||
impl<E: Embeddable> Circify<E> {
|
||||
@@ -288,6 +290,7 @@ impl<E: Embeddable> Circify<E> {
|
||||
cs,
|
||||
},
|
||||
condition: leaf_term(Op::Const(Value::Bool(true))),
|
||||
typedefs: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,6 +508,16 @@ impl<E: Embeddable> Circify<E> {
|
||||
idx: Some(idx),
|
||||
})
|
||||
}
|
||||
pub fn def_type(&mut self, name: &str, ty: E::Ty) {
|
||||
if let Some(old_ty) = self.typedefs.insert(name.to_owned(), ty) {
|
||||
panic!("{} already defined as {}", name, old_ty)
|
||||
}
|
||||
}
|
||||
pub fn get_type(&mut self, name: &str) -> &E::Ty {
|
||||
self.typedefs
|
||||
.get(name)
|
||||
.unwrap_or_else(|| panic!("No type {}", name))
|
||||
}
|
||||
}
|
||||
|
||||
const RET_NAME: &str = "return";
|
||||
|
||||
@@ -1 +1,7 @@
|
||||
pub mod zokrates;
|
||||
use super::ir::term::Constraints;
|
||||
|
||||
pub trait FrontEnd {
|
||||
type Inputs;
|
||||
fn gen(i: Self::Inputs) -> Constraints;
|
||||
}
|
||||
|
||||
@@ -1,673 +1,189 @@
|
||||
#![allow(dead_code)]
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::sync::Arc;
|
||||
pub mod parser;
|
||||
pub mod term;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use rug::Integer;
|
||||
|
||||
use crate::circify::{CirCtx, Embeddable};
|
||||
use super::FrontEnd;
|
||||
use crate::circify::{Circify, Loc};
|
||||
use crate::ir::term::*;
|
||||
use log::debug;
|
||||
use rug::Integer;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use zokrates_pest_ast as ast;
|
||||
|
||||
lazy_static! {
|
||||
// TODO: handle this better
|
||||
pub static ref ZOKRATES_MODULUS: Integer = Integer::from_str_radix(
|
||||
"21888242871839275222246405745257275088548364400416034343698204186575808495617",
|
||||
10
|
||||
)
|
||||
.unwrap();
|
||||
pub static ref ZOKRATES_MODULUS_ARC: Arc<Integer> = Arc::new(ZOKRATES_MODULUS.clone());
|
||||
use term::*;
|
||||
|
||||
pub struct Inputs {
|
||||
pub file: PathBuf,
|
||||
pub inputs: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
enum Ty {
|
||||
Uint(usize),
|
||||
Bool,
|
||||
Field,
|
||||
Struct(String, BTreeMap<String, Ty>),
|
||||
Array(usize, Box<Ty>),
|
||||
pub struct Zokrates;
|
||||
|
||||
impl FrontEnd for Zokrates {
|
||||
type Inputs = Inputs;
|
||||
fn gen(i: Inputs) -> Constraints {
|
||||
let loader = parser::ZLoad::new();
|
||||
let asts = loader.load(&i.file);
|
||||
let mut g = ZGen::new(i.inputs, asts);
|
||||
g.visit_files();
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Ty {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Ty::Bool => write!(f, "bool"),
|
||||
Ty::Uint(w) => write!(f, "u{}", w),
|
||||
Ty::Field => write!(f, "field"),
|
||||
Ty::Struct(n, _) => write!(f, "{}", n),
|
||||
Ty::Array(n, b) => write!(f, "{}[{}]", b, n),
|
||||
pub struct ZGen<'ast> {
|
||||
circ: Circify<ZoKrates>,
|
||||
stdlib: parser::ZStdLib,
|
||||
asts: HashMap<PathBuf, ast::File<'ast>>,
|
||||
file_stack: Vec<PathBuf>,
|
||||
functions: HashMap<(PathBuf, String), ast::Function<'ast>>,
|
||||
import_map: HashMap<(PathBuf, String), (PathBuf, String)>,
|
||||
}
|
||||
|
||||
enum ZLoc {
|
||||
Var(Loc),
|
||||
Member(Box<ZLoc>, String),
|
||||
Idx(Box<ZLoc>, T),
|
||||
}
|
||||
|
||||
fn unwrap_sp<T, E: Display>(r: Result<T, E>, s: &ast::Span) -> T {
|
||||
r.unwrap_or_else(|e| {
|
||||
println!("Error: {}\nAt:\n{}", e, s.as_str());
|
||||
panic!("Error")
|
||||
})
|
||||
}
|
||||
|
||||
impl<'ast> ZGen<'ast> {
|
||||
fn new(inputs: Option<PathBuf>, asts: HashMap<PathBuf, ast::File<'ast>>) -> Self {
|
||||
Self {
|
||||
circ: Circify::new(ZoKrates::new(inputs.map(|i| parser::parse_inputs(i)))),
|
||||
asts,
|
||||
stdlib: parser::ZStdLib::new(),
|
||||
file_stack: vec![],
|
||||
functions: HashMap::new(),
|
||||
import_map: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum T {
|
||||
Uint(usize, Term),
|
||||
Bool(Term),
|
||||
Field(Term),
|
||||
/// TODO: special case primitive arrays with Vec<T>.
|
||||
Array(Ty, Vec<T>),
|
||||
Struct(String, BTreeMap<String, T>),
|
||||
}
|
||||
|
||||
impl T {
|
||||
fn type_(&self) -> Ty {
|
||||
match self {
|
||||
T::Uint(w, _) => Ty::Uint(*w),
|
||||
T::Bool(_) => Ty::Bool,
|
||||
T::Field(_) => Ty::Field,
|
||||
T::Array(b, v) => Ty::Array(v.len(), Box::new(b.clone())),
|
||||
T::Struct(name, map) => Ty::Struct(
|
||||
name.clone(),
|
||||
map.iter()
|
||||
.map(|(f_name, f_term)| (f_name.clone(), f_term.type_()))
|
||||
.collect(),
|
||||
),
|
||||
fn builtin_call(fn_name: &str, mut args: Vec<T>) -> Result<T, String> {
|
||||
match fn_name {
|
||||
"to_bits" if args.len() == 1 => u32_to_bits(args.pop().unwrap()),
|
||||
"from_bits" if args.len() == 1 => u32_from_bits(args.pop().unwrap()),
|
||||
"unpack" if args.len() == 1 => field_to_bits(args.pop().unwrap()),
|
||||
_ => Err(format!("Unknown builtin '{}'", fn_name)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for T {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
T::Bool(x) => write!(f, "{}", x),
|
||||
T::Uint(_, x) => write!(f, "{}", x),
|
||||
T::Field(x) => write!(f, "{}", x),
|
||||
T::Struct(_, _) => write!(f, "struct"),
|
||||
T::Array(_, _) => write!(f, "array"),
|
||||
fn stmt(&mut self, s: &ast::Statement<'ast>) {
|
||||
unimplemented!()
|
||||
}
|
||||
fn const_(&mut self, e: &ast::ConstantExpression<'ast>) -> T {
|
||||
match e {
|
||||
ast::ConstantExpression::U8(u) => T::Uint(8, bv_lit(u8::from_str_radix(&u.value[2..], 16).unwrap(), 8)),
|
||||
ast::ConstantExpression::U16(u) => T::Uint(16, bv_lit(u16::from_str_radix(&u.value[2..], 16).unwrap(), 16)),
|
||||
ast::ConstantExpression::U32(u) => T::Uint(32, bv_lit(u32::from_str_radix(&u.value[2..], 16).unwrap(), 32)),
|
||||
ast::ConstantExpression::DecimalNumber(u) => T::Field(pf_lit(Integer::from_str_radix(&u.value, 10).unwrap())),
|
||||
ast::ConstantExpression::BooleanLiteral(u) => T::Bool(leaf_term(Op::Const(Value::Bool(bool::from_str(&u.value).unwrap())))),
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap_bin_op(
|
||||
name: &str,
|
||||
fu: Option<fn(Term, Term) -> Term>,
|
||||
ff: Option<fn(Term, Term) -> Term>,
|
||||
fb: Option<fn(Term, Term) -> Term>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> Result<T, String> {
|
||||
match (a, b, fu, ff, fb) {
|
||||
(T::Uint(na, a), T::Uint(nb, b), Some(fu), _, _) if na == nb => Ok(T::Uint(na, fu(a, b))),
|
||||
(T::Bool(a), T::Bool(b), _, _, Some(fb)) => Ok(T::Bool(fb(a, b))),
|
||||
(T::Field(a), T::Field(b), _, Some(ff), _) => Ok(T::Field(ff(a, b))),
|
||||
(x, y, _, _, _) => Err(format!("Cannot perform op '{}' on {} and {}", name, x, y)),
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap_bin_pred(
|
||||
name: &str,
|
||||
fu: Option<fn(Term, Term) -> Term>,
|
||||
ff: Option<fn(Term, Term) -> Term>,
|
||||
fb: Option<fn(Term, Term) -> Term>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> Result<T, String> {
|
||||
match (a, b, fu, ff, fb) {
|
||||
(T::Uint(na, a), T::Uint(nb, b), Some(fu), _, _) if na == nb => Ok(T::Bool(fu(a, b))),
|
||||
(T::Bool(a), T::Bool(b), _, _, Some(fb)) => Ok(T::Bool(fb(a, b))),
|
||||
(T::Field(a), T::Field(b), _, Some(ff), _) => Ok(T::Bool(ff(a, b))),
|
||||
(x, y, _, _, _) => Err(format!("Cannot perform op '{}' on {} and {}", name, x, y)),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvNaryOp(BvNaryOp::Add); a, b]
|
||||
}
|
||||
|
||||
fn add_field(a: Term, b: Term) -> Term {
|
||||
term![Op::PfNaryOp(PfNaryOp::Add); a, b]
|
||||
}
|
||||
|
||||
fn add(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("+", Some(add_uint), Some(add_field), None, a, b)
|
||||
}
|
||||
|
||||
fn sub_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvBinOp(BvBinOp::Sub); a, b]
|
||||
}
|
||||
|
||||
fn sub_field(a: Term, b: Term) -> Term {
|
||||
term![Op::PfNaryOp(PfNaryOp::Add); a, term![Op::PfUnOp(PfUnOp::Neg); b]]
|
||||
}
|
||||
|
||||
fn sub(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("-", Some(sub_uint), Some(sub_field), None, a, b)
|
||||
}
|
||||
|
||||
fn mul_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvNaryOp(BvNaryOp::Mul); a, b]
|
||||
}
|
||||
|
||||
fn mul_field(a: Term, b: Term) -> Term {
|
||||
term![Op::PfNaryOp(PfNaryOp::Mul); a, b]
|
||||
}
|
||||
|
||||
fn mul(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("*", Some(mul_uint), Some(mul_field), None, a, b)
|
||||
}
|
||||
|
||||
fn div_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvBinOp(BvBinOp::Udiv); a, b]
|
||||
}
|
||||
|
||||
fn div_field(a: Term, b: Term) -> Term {
|
||||
term![Op::PfNaryOp(PfNaryOp::Mul); a, term![Op::PfUnOp(PfUnOp::Recip); b]]
|
||||
}
|
||||
|
||||
fn div(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("/", Some(div_uint), Some(div_field), None, a, b)
|
||||
}
|
||||
|
||||
fn bitand_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvNaryOp(BvNaryOp::And); a, b]
|
||||
}
|
||||
|
||||
fn bitand(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("&", Some(bitand_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn bitor_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvNaryOp(BvNaryOp::Or); a, b]
|
||||
}
|
||||
|
||||
fn bitor(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("|", Some(bitor_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn bitxor_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvNaryOp(BvNaryOp::Xor); a, b]
|
||||
}
|
||||
|
||||
fn bitxor(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("^", Some(bitxor_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn or_bool(a: Term, b: Term) -> Term {
|
||||
term![Op::BoolNaryOp(BoolNaryOp::Or); a, b]
|
||||
}
|
||||
|
||||
fn or(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("||", None, None, Some(or_bool), a, b)
|
||||
}
|
||||
|
||||
fn and_bool(a: Term, b: Term) -> Term {
|
||||
term![Op::BoolNaryOp(BoolNaryOp::And); a, b]
|
||||
}
|
||||
|
||||
fn and(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("&&", None, None, Some(and_bool), a, b)
|
||||
}
|
||||
|
||||
fn eq_base(a: Term, b: Term) -> Term {
|
||||
term![Op::Eq; a, b]
|
||||
}
|
||||
|
||||
fn eq(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_pred("==", Some(eq_base), Some(eq_base), Some(eq_base), a, b)
|
||||
}
|
||||
|
||||
fn neq_base(a: Term, b: Term) -> Term {
|
||||
term![Op::Not; term![Op::Eq; a, b]]
|
||||
}
|
||||
|
||||
fn neq(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_pred("!=", Some(neq_base), Some(neq_base), Some(neq_base), a, b)
|
||||
}
|
||||
|
||||
fn ult_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvBinPred(BvBinPred::Ult); a, b]
|
||||
}
|
||||
|
||||
fn ult(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_pred("<", Some(ult_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn ule_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvBinPred(BvBinPred::Ule); a, b]
|
||||
}
|
||||
|
||||
fn ule(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_pred("<=", Some(ule_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn ugt_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvBinPred(BvBinPred::Ugt); a, b]
|
||||
}
|
||||
|
||||
fn ugt(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_pred(">", Some(ugt_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn uge_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvBinPred(BvBinPred::Uge); a, b]
|
||||
}
|
||||
|
||||
fn uge(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_pred(">=", Some(uge_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn wrap_un_op(
|
||||
name: &str,
|
||||
fu: Option<fn(Term) -> Term>,
|
||||
ff: Option<fn(Term) -> Term>,
|
||||
fb: Option<fn(Term) -> Term>,
|
||||
a: T,
|
||||
) -> Result<T, String> {
|
||||
match (a, fu, ff, fb) {
|
||||
(T::Uint(na, a), Some(fu), _, _) => Ok(T::Uint(na, fu(a))),
|
||||
(T::Bool(a), _, _, Some(fb)) => Ok(T::Bool(fb(a))),
|
||||
(T::Field(a), _, Some(ff), _) => Ok(T::Field(ff(a))),
|
||||
(x, _, _, _) => Err(format!("Cannot perform op '{}' on {}", name, x)),
|
||||
}
|
||||
}
|
||||
|
||||
fn neg_field(a: Term) -> Term {
|
||||
term![Op::PfUnOp(PfUnOp::Neg); a]
|
||||
}
|
||||
|
||||
fn neg_uint(a: Term) -> Term {
|
||||
term![Op::BvUnOp(BvUnOp::Neg); a]
|
||||
}
|
||||
|
||||
fn neg(a: T) -> Result<T, String> {
|
||||
wrap_un_op("unary-", Some(neg_uint), Some(neg_field), None, a)
|
||||
}
|
||||
|
||||
fn not_bool(a: Term) -> Term {
|
||||
term![Op::Not; a]
|
||||
}
|
||||
|
||||
fn not_uint(a: Term) -> Term {
|
||||
term![Op::BvUnOp(BvUnOp::Not); a]
|
||||
}
|
||||
|
||||
fn not(a: T) -> Result<T, String> {
|
||||
wrap_un_op("!", Some(not_uint), None, Some(not_bool), a)
|
||||
}
|
||||
|
||||
fn const_int(a: T) -> Result<Integer, String> {
|
||||
let s = match &a {
|
||||
T::Field(b) => match &b.op {
|
||||
Op::Const(Value::Field(f)) => Some(f.i().clone()),
|
||||
_ => None,
|
||||
},
|
||||
T::Uint(_, i) => match &i.op {
|
||||
Op::Const(Value::BitVector(f)) => Some(f.uint().clone()),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
s.ok_or_else(|| format!("{} is not a constant integer", a))
|
||||
}
|
||||
|
||||
fn bool(a: T) -> Result<Term, String> {
|
||||
match a {
|
||||
T::Bool(b) => Ok(b),
|
||||
a => Err(format!("{} is not a boolean", a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap_shift(name: &str, op: BvBinOp, a: T, b: T) -> Result<T, String> {
|
||||
let bc = const_int(b)?;
|
||||
match a {
|
||||
T::Uint(na, a) => Ok(T::Uint(na, term![Op::BvBinOp(op); a, bv_lit(bc, na)])),
|
||||
x => Err(format!("Cannot perform op '{}' on {} and {}", name, x, bc)),
|
||||
}
|
||||
}
|
||||
|
||||
fn shl(a: T, b: T) -> Result<T, String> {
|
||||
wrap_shift("<<", BvBinOp::Shl, a, b)
|
||||
}
|
||||
|
||||
fn shr(a: T, b: T) -> Result<T, String> {
|
||||
wrap_shift(">>", BvBinOp::Lshr, a, b)
|
||||
}
|
||||
|
||||
fn ite(c: Term, a: T, b: T) -> Result<T, String> {
|
||||
match (a, b) {
|
||||
(T::Uint(na, a), T::Uint(nb, b)) if na == nb => Ok(T::Uint(na, term![Op::Ite; c, a, b])),
|
||||
(T::Bool(a), T::Bool(b)) => Ok(T::Bool(term![Op::Ite; c, a, b])),
|
||||
(T::Field(a), T::Field(b)) => Ok(T::Field(term![Op::Ite; c, a, b])),
|
||||
(T::Array(ta, a), T::Array(tb, b)) if a.len() == b.len() && ta == tb => Ok(T::Array(
|
||||
ta,
|
||||
a.into_iter()
|
||||
.zip(b.into_iter())
|
||||
.map(|(a_i, b_i)| ite(c.clone(), a_i, b_i))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
)),
|
||||
(T::Struct(na, a), T::Struct(nb, b)) if na == nb => Ok(T::Struct(na.clone(), {
|
||||
a.into_iter()
|
||||
.zip(b.into_iter())
|
||||
.map(|((af, av), (bf, bv))| {
|
||||
if af == bf {
|
||||
Ok((af, ite(c.clone(), av, bv)?))
|
||||
} else {
|
||||
Err(format!("Field mismatch: {} vs {}", af, bf))
|
||||
}
|
||||
})
|
||||
.collect::<Result<BTreeMap<_, _>, String>>()?
|
||||
})),
|
||||
(x, y) => Err(format!("Cannot perform ITE on {} and {}", x, y)),
|
||||
}
|
||||
}
|
||||
|
||||
fn cond(c: T, a: T, b: T) -> Result<T, String> {
|
||||
ite(bool(c)?, a, b)
|
||||
}
|
||||
|
||||
fn pf_lit<I>(i: I) -> Term
|
||||
where
|
||||
Integer: From<I>,
|
||||
{
|
||||
leaf_term(Op::Const(Value::Field(FieldElem::new(
|
||||
Integer::from(i),
|
||||
ZOKRATES_MODULUS_ARC.clone(),
|
||||
))))
|
||||
}
|
||||
|
||||
fn slice(array: T, start: Option<usize>, end: Option<usize>) -> Result<T, String> {
|
||||
match array {
|
||||
T::Array(b, mut list) => {
|
||||
let start = start.unwrap_or(0);
|
||||
let end = end.unwrap_or(list.len() - 1);
|
||||
Ok(T::Array(b, list.drain(start..end).collect()))
|
||||
}
|
||||
a => Err(format!("Cannot slice {}", a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn spread(array: T) -> Result<Vec<T>, String> {
|
||||
match array {
|
||||
T::Array(_, list) => Ok(list),
|
||||
a => Err(format!("Cannot spread {}", a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn field_select(struct_: &T, field: &str) -> Result<T, String> {
|
||||
match struct_ {
|
||||
T::Struct(_, map) => map
|
||||
.get(field)
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("No field '{}'", field)),
|
||||
a => Err(format!("{} is not a struct", a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn field_store(struct_: T, field: &str, val: T) -> Result<T, String> {
|
||||
match struct_ {
|
||||
T::Struct(name, mut map) => Ok(T::Struct(name, {
|
||||
if map.insert(field.to_owned(), val).is_some() {
|
||||
map
|
||||
} else {
|
||||
return Err(format!("No '{}' field", field));
|
||||
}
|
||||
})),
|
||||
a => Err(format!("{} is not a struct", a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn array_select(array: T, idx: T) -> Result<T, String> {
|
||||
match (array, idx) {
|
||||
(T::Array(_, list), T::Field(idx)) => {
|
||||
let mut it = list.into_iter().enumerate();
|
||||
let first = it
|
||||
.next()
|
||||
.ok_or_else(|| format!("Cannot index empty array"))?;
|
||||
it.fold(Ok(first.1), |acc, (i, elem)| {
|
||||
ite(term![Op::Eq; pf_lit(i), idx.clone()], elem, acc?)
|
||||
})
|
||||
}
|
||||
(a, b) => Err(format!("Cannot index {} by {}", b, a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn array_store(array: T, idx: T, val: T) -> Result<T, String> {
|
||||
match (array, idx) {
|
||||
(T::Array(ty, list), T::Field(idx)) => Ok(T::Array(
|
||||
ty,
|
||||
list.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, elem)| ite(term![Op::Eq; pf_lit(i), idx.clone()], val.clone(), elem))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
)),
|
||||
(a, b) => Err(format!("Cannot index {} by {}", b, a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn array<I: IntoIterator<Item = T>>(elems: I) -> Result<T, String> {
|
||||
let v: Vec<T> = elems.into_iter().collect();
|
||||
if let Some(e) = v.first() {
|
||||
let ty = e.type_();
|
||||
if v.iter().skip(1).any(|a| a.type_() != ty) {
|
||||
Err(format!("Inconsistent types in array"))
|
||||
} else {
|
||||
Ok(T::Array(ty, v))
|
||||
}
|
||||
} else {
|
||||
Err(format!("Empty array"))
|
||||
}
|
||||
}
|
||||
|
||||
fn u32_to_bits(u: T) -> Result<T, String> {
|
||||
match u {
|
||||
T::Uint(32, t) => Ok(T::Array(
|
||||
Ty::Bool,
|
||||
(0..32)
|
||||
.map(|i| T::Bool(term![Op::BvBit(i); t.clone()]))
|
||||
.collect(),
|
||||
)),
|
||||
u => Err(format!("Cannot do u32-to-bits on {}", u)),
|
||||
}
|
||||
}
|
||||
|
||||
fn u32_from_bits(u: T) -> Result<T, String> {
|
||||
match u {
|
||||
T::Array(Ty::Bool, list) => {
|
||||
if list.len() == 32 {
|
||||
Ok(T::Uint(
|
||||
32,
|
||||
term(
|
||||
Op::BvConcat,
|
||||
list.into_iter()
|
||||
.map(|z: T| -> Result<Term, String> {
|
||||
Ok(term![Op::BoolToBv; bool(z)?])
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
),
|
||||
))
|
||||
} else {
|
||||
Err(format!(
|
||||
"Cannot do u32-from-bits on len {} array",
|
||||
list.len()
|
||||
))
|
||||
}
|
||||
}
|
||||
u => Err(format!("Cannot do u32-from-bits on {}", u)),
|
||||
}
|
||||
}
|
||||
|
||||
fn field_to_bits(f: T) -> Result<T, String> {
|
||||
match f {
|
||||
T::Field(t) => {
|
||||
let u = term![Op::PfToBv(254); t];
|
||||
Ok(T::Array(
|
||||
Ty::Bool,
|
||||
(0..254)
|
||||
.map(|i| T::Bool(term![Op::BvBit(i); u.clone()]))
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
u => Err(format!("Cannot do field-to-bits on {}", u)),
|
||||
}
|
||||
}
|
||||
|
||||
struct ZoKrates {
|
||||
values: Option<HashMap<String, Integer>>,
|
||||
modulus: Arc<Integer>,
|
||||
}
|
||||
|
||||
fn field_name(struct_name: &str, field_name: &str) -> String {
|
||||
format!("{}.{}", struct_name, field_name)
|
||||
}
|
||||
|
||||
fn idx_name(struct_name: &str, idx: usize) -> String {
|
||||
format!("{}.{}", struct_name, idx)
|
||||
}
|
||||
|
||||
impl Embeddable for ZoKrates {
|
||||
type T = T;
|
||||
type Ty = Ty;
|
||||
fn declare(
|
||||
&self,
|
||||
ctx: &mut CirCtx,
|
||||
ty: &Self::Ty,
|
||||
raw_name: String,
|
||||
user_name: Option<String>,
|
||||
) -> Self::T {
|
||||
let get_int_val = || -> Integer {
|
||||
self.values
|
||||
.as_ref()
|
||||
.and_then(|vs| {
|
||||
user_name
|
||||
.as_ref()
|
||||
.and_then(|n| vs.get(n))
|
||||
.or_else(|| vs.get(&raw_name))
|
||||
})
|
||||
.cloned()
|
||||
.unwrap_or_else(|| Integer::from(0))
|
||||
};
|
||||
match ty {
|
||||
Ty::Bool => T::Bool(ctx.cs.borrow_mut().new_var(
|
||||
&raw_name,
|
||||
Sort::Bool,
|
||||
|| Value::Bool(get_int_val() != 0),
|
||||
user_name.is_some(),
|
||||
)),
|
||||
Ty::Field => T::Field(ctx.cs.borrow_mut().new_var(
|
||||
&raw_name,
|
||||
Sort::Field(self.modulus.clone()),
|
||||
|| Value::Field(FieldElem::new(get_int_val(), self.modulus.clone())),
|
||||
user_name.is_some(),
|
||||
)),
|
||||
Ty::Uint(w) => T::Field(ctx.cs.borrow_mut().new_var(
|
||||
&raw_name,
|
||||
Sort::BitVector(*w),
|
||||
|| Value::BitVector(BitVector::new(get_int_val(), *w)),
|
||||
user_name.is_some(),
|
||||
)),
|
||||
Ty::Array(n, ty) => T::Array(
|
||||
(**ty).clone(),
|
||||
(0..*n)
|
||||
.map(|i| {
|
||||
self.declare(
|
||||
ctx,
|
||||
&*ty,
|
||||
idx_name(&raw_name, i),
|
||||
user_name.as_ref().map(|u| idx_name(u, i)),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
Ty::Struct(n, fs) => T::Struct(
|
||||
n.clone(),
|
||||
fs.iter()
|
||||
.map(|(f_name, f_ty)| {
|
||||
(
|
||||
f_name.clone(),
|
||||
self.declare(
|
||||
ctx,
|
||||
f_ty,
|
||||
field_name(&raw_name, f_name),
|
||||
user_name.as_ref().map(|u| field_name(u, f_name)),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
fn ite(&self, ctx: &mut CirCtx, cond: Term, t: Self::T, f: Self::T) -> Self::T {
|
||||
match (t, f) {
|
||||
(T::Bool(a), T::Bool(b)) => T::Bool(term![Op::Ite; cond, a, b]),
|
||||
(T::Uint(wa, a), T::Uint(wb, b)) if wa == wb => T::Uint(wa, term![Op::Ite; cond, a, b]),
|
||||
(T::Field(a), T::Field(b)) => T::Field(term![Op::Ite; cond, a, b]),
|
||||
(T::Array(a_ty, a), T::Array(b_ty, b)) if a_ty == b_ty => T::Array(
|
||||
a_ty,
|
||||
a.into_iter()
|
||||
.zip(b.into_iter())
|
||||
.map(|(a_i, b_i)| self.ite(ctx, cond.clone(), a_i, b_i))
|
||||
.collect(),
|
||||
),
|
||||
(T::Struct(a_nm, a), T::Struct(b_nm, b)) if a_nm == b_nm => T::Struct(
|
||||
a_nm,
|
||||
a.into_iter()
|
||||
.zip(b.into_iter())
|
||||
.map(|((a_f, a_i), (b_f, b_i))| {
|
||||
if a_f == b_f {
|
||||
(a_f, self.ite(ctx, cond.clone(), a_i, b_i))
|
||||
} else {
|
||||
panic!("Field mismatch: '{}' vs '{}'", a_f, b_f)
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
(t, f) => panic!("Cannot ITE {} and {}", t, f),
|
||||
}
|
||||
}
|
||||
fn assign(&self, ctx: &mut CirCtx, ty: &Self::Ty, name: String, t: Self::T) -> Self::T {
|
||||
assert!(&t.type_() == ty);
|
||||
match (ty, t) {
|
||||
(_, T::Bool(b)) => {
|
||||
ctx.cs.borrow_mut().eval_and_save(&name, &b);
|
||||
let v = leaf_term(Op::Var(name, Sort::Bool));
|
||||
ctx.cs
|
||||
.borrow_mut()
|
||||
.assertions
|
||||
.push(term![Op::Eq; v.clone(), b]);
|
||||
T::Bool(v)
|
||||
}
|
||||
(_, T::Field(b)) => {
|
||||
ctx.cs.borrow_mut().eval_and_save(&name, &b);
|
||||
let v = leaf_term(Op::Var(name, Sort::Field(self.modulus.clone())));
|
||||
ctx.cs
|
||||
.borrow_mut()
|
||||
.assertions
|
||||
.push(term![Op::Eq; v.clone(), b]);
|
||||
T::Field(v)
|
||||
}
|
||||
(_, T::Uint(w, b)) => {
|
||||
ctx.cs.borrow_mut().eval_and_save(&name, &b);
|
||||
let v = leaf_term(Op::Var(name, Sort::BitVector(w)));
|
||||
ctx.cs
|
||||
.borrow_mut()
|
||||
.assertions
|
||||
.push(term![Op::Eq; v.clone(), b]);
|
||||
T::Uint(w, v)
|
||||
}
|
||||
(_, T::Array(ety, list)) => T::Array(
|
||||
ety.clone(),
|
||||
list.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, elem)| self.assign(ctx, &ety, idx_name(&name, i), elem))
|
||||
.collect(),
|
||||
),
|
||||
(Ty::Struct(_, tys), T::Struct(s_name, list)) => T::Struct(
|
||||
s_name,
|
||||
list.into_iter()
|
||||
.zip(tys.into_iter())
|
||||
.map(|((f_name, elem), (_, f_ty))| {
|
||||
(
|
||||
f_name.clone(),
|
||||
self.assign(ctx, &f_ty, field_name(&name, &f_name), elem),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
fn expr(&mut self, e: &ast::Expression<'ast>) -> T {
|
||||
match e {
|
||||
ast::Expression::Constant(c) => self.const_(c),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
fn values(&self) -> bool {
|
||||
self.values.is_some()
|
||||
fn array_lit_elem(&mut self, e: &ast::Expression<'ast>) -> Vec<T> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn entry_fn(&mut self, f: &ast::Function<'ast>) {}
|
||||
fn cur_path(&self) -> &Path {
|
||||
self.file_stack.last().unwrap()
|
||||
}
|
||||
|
||||
fn struct_(&mut self, s: &ast::StructDefinition<'ast>) {}
|
||||
|
||||
fn const_int(&mut self, e: &ast::Expression<'ast>) -> Integer {
|
||||
unwrap_sp(const_int(self.expr(e)), e.span())
|
||||
}
|
||||
|
||||
fn type_(&mut self, t: &ast::Type<'ast>) -> Ty {
|
||||
fn lift<'ast>(t: &ast::BasicOrStructType<'ast>) -> ast::Type<'ast> {
|
||||
match t {
|
||||
ast::BasicOrStructType::Basic(b) => ast::Type::Basic(b.clone()),
|
||||
ast::BasicOrStructType::Struct(b) => ast::Type::Struct(b.clone()),
|
||||
}
|
||||
}
|
||||
match t {
|
||||
ast::Type::Basic(ast::BasicType::U8(_)) => Ty::Uint(8),
|
||||
ast::Type::Basic(ast::BasicType::U16(_)) => Ty::Uint(16),
|
||||
ast::Type::Basic(ast::BasicType::U32(_)) => Ty::Uint(32),
|
||||
ast::Type::Basic(ast::BasicType::Boolean(_)) => Ty::Bool,
|
||||
ast::Type::Basic(ast::BasicType::Field(_)) => Ty::Field,
|
||||
ast::Type::Array(a) => {
|
||||
let b = self.type_(&lift(&a.ty));
|
||||
a.dimensions
|
||||
.iter()
|
||||
.map(|d| self.const_int(d).to_usize().unwrap())
|
||||
.fold(b, |b, d| Ty::Array(d, Box::new(b)))
|
||||
}
|
||||
ast::Type::Struct(s) => self.circ.get_type(&s.id.value).clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_files(&mut self) {
|
||||
let t = std::mem::take(&mut self.asts);
|
||||
for (p, f) in &t {
|
||||
self.file_stack.push(p.to_owned());
|
||||
for func in &f.functions {
|
||||
debug!("fn {} in {}", func.id.value, self.cur_path().display());
|
||||
self.functions.insert(
|
||||
(self.cur_path().to_owned(), func.id.value.clone()),
|
||||
func.clone(),
|
||||
);
|
||||
}
|
||||
for i in &f.imports {
|
||||
let (src_path, src_name, dst_name_opt) = match i {
|
||||
ast::ImportDirective::Main(m) => (
|
||||
m.source.value.clone(),
|
||||
"main".to_owned(),
|
||||
m.alias.as_ref().map(|a| a.value.clone()),
|
||||
),
|
||||
ast::ImportDirective::From(m) => (
|
||||
m.source.value.clone(),
|
||||
m.symbol.value.clone(),
|
||||
m.alias.as_ref().map(|a| a.value.clone()),
|
||||
),
|
||||
};
|
||||
let dst_name = dst_name_opt.unwrap_or_else(|| src_name.clone());
|
||||
let abs_src_path = self.stdlib.canonicalize(self.cur_path(), src_path.as_str());
|
||||
debug!(
|
||||
"Import of {} from {} as {}",
|
||||
src_name,
|
||||
abs_src_path.display(),
|
||||
dst_name
|
||||
);
|
||||
self.import_map.insert(
|
||||
(self.cur_path().to_path_buf(), dst_name),
|
||||
(abs_src_path, src_name),
|
||||
);
|
||||
}
|
||||
for s in &f.structs {
|
||||
let ty = Ty::Struct(
|
||||
s.id.value.clone(),
|
||||
s.fields
|
||||
.clone()
|
||||
.iter()
|
||||
.map(|f| (f.id.value.clone(), self.type_(&f.ty)))
|
||||
.collect(),
|
||||
);
|
||||
debug!("struct {}", s.id.value);
|
||||
self.circ.def_type(&s.id.value, ty);
|
||||
}
|
||||
self.file_stack.pop();
|
||||
}
|
||||
self.asts = t;
|
||||
}
|
||||
}
|
||||
|
||||
107
src/front/zokrates/parser.rs
Normal file
107
src/front/zokrates/parser.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
use zokrates_pest_ast as ast;
|
||||
|
||||
use log::debug;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::circify::includer::Loader;
|
||||
use rug::Integer;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
use typed_arena::Arena;
|
||||
|
||||
pub fn parse_inputs(p: PathBuf) -> HashMap<String, Integer> {
|
||||
let mut m = HashMap::new();
|
||||
for l in BufReader::new(File::open(p).unwrap()).lines() {
|
||||
let l = l.unwrap();
|
||||
let l = l.trim();
|
||||
if l.len() > 0 {
|
||||
let mut s = l.split_whitespace();
|
||||
let key = s.next().unwrap().to_owned();
|
||||
let value = Integer::from(Integer::parse_radix(&s.next().unwrap(), 10).unwrap());
|
||||
m.insert(key, value);
|
||||
}
|
||||
}
|
||||
m
|
||||
}
|
||||
|
||||
pub struct ZStdLib {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl ZStdLib {
|
||||
pub fn new() -> Self {
|
||||
let p = std::env::current_dir().unwrap().canonicalize().unwrap();
|
||||
assert!(p.is_absolute());
|
||||
for a in p.ancestors() {
|
||||
let mut q = a.to_path_buf();
|
||||
q.push("ZoKrates/zokrates_stdlib/stdlib");
|
||||
if q.exists() {
|
||||
return Self { path: q };
|
||||
}
|
||||
}
|
||||
panic!("Could not find ZoKrates stdlibfrom {}", p.display())
|
||||
}
|
||||
pub fn canonicalize(&self, parent: &Path, child: &str) -> PathBuf {
|
||||
if parent.to_str().map(|s| s.contains("EMBED")).unwrap_or(false) {
|
||||
return PathBuf::from("EMBED");
|
||||
}
|
||||
let paths = vec![parent.to_path_buf(), self.path.clone()];
|
||||
for mut p in paths {
|
||||
p.push(child);
|
||||
if p.extension().is_none() {
|
||||
p.set_extension("zok");
|
||||
}
|
||||
if p.exists() {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
panic!("Could not find {} from {}", child, parent.display())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ZLoad {
|
||||
sources: Arena<String>,
|
||||
stdlib: ZStdLib,
|
||||
}
|
||||
|
||||
impl ZLoad {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
sources: Arena::new(),
|
||||
stdlib: ZStdLib::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load<P: AsRef<Path>>(&self, p: &P) -> HashMap<PathBuf, ast::File> {
|
||||
self.recursive_load(p).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Loader for &'a ZLoad {
|
||||
type ParseError = ();
|
||||
type AST = zokrates_pest_ast::File<'a>;
|
||||
|
||||
fn parse<P: AsRef<Path>>(&self, p: &P) -> Result<Self::AST, Self::ParseError> {
|
||||
let mut s = String::new();
|
||||
File::open(p).unwrap().read_to_string(&mut s).unwrap();
|
||||
debug!("Parsing: {}", p.as_ref().display());
|
||||
let s = self.sources.alloc(s);
|
||||
Ok(ast::generate_ast(s).unwrap())
|
||||
}
|
||||
fn includes<P: AsRef<Path>>(&self, ast: &Self::AST, p: &P) -> Vec<PathBuf> {
|
||||
let mut c = p.as_ref().to_path_buf();
|
||||
c.pop();
|
||||
ast.imports
|
||||
.iter()
|
||||
.map(|i| {
|
||||
let ext = match i {
|
||||
ast::ImportDirective::Main(m) => &m.source.value,
|
||||
ast::ImportDirective::From(m) => &m.source.value,
|
||||
};
|
||||
self.stdlib.canonicalize(&c, ext)
|
||||
})
|
||||
.filter(|p| p.to_str().map(|s| !s.contains("EMBED")).unwrap_or(true))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
682
src/front/zokrates/term.rs
Normal file
682
src/front/zokrates/term.rs
Normal file
@@ -0,0 +1,682 @@
|
||||
#![allow(dead_code)]
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::sync::Arc;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use rug::Integer;
|
||||
|
||||
use crate::circify::{CirCtx, Embeddable};
|
||||
use crate::ir::term::*;
|
||||
|
||||
lazy_static! {
|
||||
// TODO: handle this better
|
||||
pub static ref ZOKRATES_MODULUS: Integer = Integer::from_str_radix(
|
||||
"21888242871839275222246405745257275088548364400416034343698204186575808495617",
|
||||
10
|
||||
)
|
||||
.unwrap();
|
||||
pub static ref ZOKRATES_MODULUS_ARC: Arc<Integer> = Arc::new(ZOKRATES_MODULUS.clone());
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum Ty {
|
||||
Uint(usize),
|
||||
Bool,
|
||||
Field,
|
||||
Struct(String, BTreeMap<String, Ty>),
|
||||
Array(usize, Box<Ty>),
|
||||
}
|
||||
|
||||
impl Display for Ty {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Ty::Bool => write!(f, "bool"),
|
||||
Ty::Uint(w) => write!(f, "u{}", w),
|
||||
Ty::Field => write!(f, "field"),
|
||||
Ty::Struct(n, _) => write!(f, "{}", n),
|
||||
Ty::Array(n, b) => write!(f, "{}[{}]", b, n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum T {
|
||||
Uint(usize, Term),
|
||||
Bool(Term),
|
||||
Field(Term),
|
||||
/// TODO: special case primitive arrays with Vec<T>.
|
||||
Array(Ty, Vec<T>),
|
||||
Struct(String, BTreeMap<String, T>),
|
||||
}
|
||||
|
||||
impl T {
|
||||
fn type_(&self) -> Ty {
|
||||
match self {
|
||||
T::Uint(w, _) => Ty::Uint(*w),
|
||||
T::Bool(_) => Ty::Bool,
|
||||
T::Field(_) => Ty::Field,
|
||||
T::Array(b, v) => Ty::Array(v.len(), Box::new(b.clone())),
|
||||
T::Struct(name, map) => Ty::Struct(
|
||||
name.clone(),
|
||||
map.iter()
|
||||
.map(|(f_name, f_term)| (f_name.clone(), f_term.type_()))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for T {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
T::Bool(x) => write!(f, "{}", x),
|
||||
T::Uint(_, x) => write!(f, "{}", x),
|
||||
T::Field(x) => write!(f, "{}", x),
|
||||
T::Struct(_, _) => write!(f, "struct"),
|
||||
T::Array(_, _) => write!(f, "array"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap_bin_op(
|
||||
name: &str,
|
||||
fu: Option<fn(Term, Term) -> Term>,
|
||||
ff: Option<fn(Term, Term) -> Term>,
|
||||
fb: Option<fn(Term, Term) -> Term>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> Result<T, String> {
|
||||
match (a, b, fu, ff, fb) {
|
||||
(T::Uint(na, a), T::Uint(nb, b), Some(fu), _, _) if na == nb => Ok(T::Uint(na, fu(a, b))),
|
||||
(T::Bool(a), T::Bool(b), _, _, Some(fb)) => Ok(T::Bool(fb(a, b))),
|
||||
(T::Field(a), T::Field(b), _, Some(ff), _) => Ok(T::Field(ff(a, b))),
|
||||
(x, y, _, _, _) => Err(format!("Cannot perform op '{}' on {} and {}", name, x, y)),
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap_bin_pred(
|
||||
name: &str,
|
||||
fu: Option<fn(Term, Term) -> Term>,
|
||||
ff: Option<fn(Term, Term) -> Term>,
|
||||
fb: Option<fn(Term, Term) -> Term>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> Result<T, String> {
|
||||
match (a, b, fu, ff, fb) {
|
||||
(T::Uint(na, a), T::Uint(nb, b), Some(fu), _, _) if na == nb => Ok(T::Bool(fu(a, b))),
|
||||
(T::Bool(a), T::Bool(b), _, _, Some(fb)) => Ok(T::Bool(fb(a, b))),
|
||||
(T::Field(a), T::Field(b), _, Some(ff), _) => Ok(T::Bool(ff(a, b))),
|
||||
(x, y, _, _, _) => Err(format!("Cannot perform op '{}' on {} and {}", name, x, y)),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvNaryOp(BvNaryOp::Add); a, b]
|
||||
}
|
||||
|
||||
fn add_field(a: Term, b: Term) -> Term {
|
||||
term![Op::PfNaryOp(PfNaryOp::Add); a, b]
|
||||
}
|
||||
|
||||
fn add(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("+", Some(add_uint), Some(add_field), None, a, b)
|
||||
}
|
||||
|
||||
fn sub_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvBinOp(BvBinOp::Sub); a, b]
|
||||
}
|
||||
|
||||
fn sub_field(a: Term, b: Term) -> Term {
|
||||
term![Op::PfNaryOp(PfNaryOp::Add); a, term![Op::PfUnOp(PfUnOp::Neg); b]]
|
||||
}
|
||||
|
||||
fn sub(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("-", Some(sub_uint), Some(sub_field), None, a, b)
|
||||
}
|
||||
|
||||
fn mul_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvNaryOp(BvNaryOp::Mul); a, b]
|
||||
}
|
||||
|
||||
fn mul_field(a: Term, b: Term) -> Term {
|
||||
term![Op::PfNaryOp(PfNaryOp::Mul); a, b]
|
||||
}
|
||||
|
||||
fn mul(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("*", Some(mul_uint), Some(mul_field), None, a, b)
|
||||
}
|
||||
|
||||
fn div_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvBinOp(BvBinOp::Udiv); a, b]
|
||||
}
|
||||
|
||||
fn div_field(a: Term, b: Term) -> Term {
|
||||
term![Op::PfNaryOp(PfNaryOp::Mul); a, term![Op::PfUnOp(PfUnOp::Recip); b]]
|
||||
}
|
||||
|
||||
fn div(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("/", Some(div_uint), Some(div_field), None, a, b)
|
||||
}
|
||||
|
||||
fn bitand_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvNaryOp(BvNaryOp::And); a, b]
|
||||
}
|
||||
|
||||
fn bitand(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("&", Some(bitand_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn bitor_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvNaryOp(BvNaryOp::Or); a, b]
|
||||
}
|
||||
|
||||
fn bitor(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("|", Some(bitor_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn bitxor_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvNaryOp(BvNaryOp::Xor); a, b]
|
||||
}
|
||||
|
||||
fn bitxor(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("^", Some(bitxor_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn or_bool(a: Term, b: Term) -> Term {
|
||||
term![Op::BoolNaryOp(BoolNaryOp::Or); a, b]
|
||||
}
|
||||
|
||||
fn or(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("||", None, None, Some(or_bool), a, b)
|
||||
}
|
||||
|
||||
fn and_bool(a: Term, b: Term) -> Term {
|
||||
term![Op::BoolNaryOp(BoolNaryOp::And); a, b]
|
||||
}
|
||||
|
||||
fn and(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_op("&&", None, None, Some(and_bool), a, b)
|
||||
}
|
||||
|
||||
fn eq_base(a: Term, b: Term) -> Term {
|
||||
term![Op::Eq; a, b]
|
||||
}
|
||||
|
||||
fn eq(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_pred("==", Some(eq_base), Some(eq_base), Some(eq_base), a, b)
|
||||
}
|
||||
|
||||
fn neq_base(a: Term, b: Term) -> Term {
|
||||
term![Op::Not; term![Op::Eq; a, b]]
|
||||
}
|
||||
|
||||
fn neq(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_pred("!=", Some(neq_base), Some(neq_base), Some(neq_base), a, b)
|
||||
}
|
||||
|
||||
fn ult_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvBinPred(BvBinPred::Ult); a, b]
|
||||
}
|
||||
|
||||
fn ult(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_pred("<", Some(ult_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn ule_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvBinPred(BvBinPred::Ule); a, b]
|
||||
}
|
||||
|
||||
fn ule(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_pred("<=", Some(ule_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn ugt_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvBinPred(BvBinPred::Ugt); a, b]
|
||||
}
|
||||
|
||||
fn ugt(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_pred(">", Some(ugt_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn uge_uint(a: Term, b: Term) -> Term {
|
||||
term![Op::BvBinPred(BvBinPred::Uge); a, b]
|
||||
}
|
||||
|
||||
fn uge(a: T, b: T) -> Result<T, String> {
|
||||
wrap_bin_pred(">=", Some(uge_uint), None, None, a, b)
|
||||
}
|
||||
|
||||
fn wrap_un_op(
|
||||
name: &str,
|
||||
fu: Option<fn(Term) -> Term>,
|
||||
ff: Option<fn(Term) -> Term>,
|
||||
fb: Option<fn(Term) -> Term>,
|
||||
a: T,
|
||||
) -> Result<T, String> {
|
||||
match (a, fu, ff, fb) {
|
||||
(T::Uint(na, a), Some(fu), _, _) => Ok(T::Uint(na, fu(a))),
|
||||
(T::Bool(a), _, _, Some(fb)) => Ok(T::Bool(fb(a))),
|
||||
(T::Field(a), _, Some(ff), _) => Ok(T::Field(ff(a))),
|
||||
(x, _, _, _) => Err(format!("Cannot perform op '{}' on {}", name, x)),
|
||||
}
|
||||
}
|
||||
|
||||
fn neg_field(a: Term) -> Term {
|
||||
term![Op::PfUnOp(PfUnOp::Neg); a]
|
||||
}
|
||||
|
||||
fn neg_uint(a: Term) -> Term {
|
||||
term![Op::BvUnOp(BvUnOp::Neg); a]
|
||||
}
|
||||
|
||||
fn neg(a: T) -> Result<T, String> {
|
||||
wrap_un_op("unary-", Some(neg_uint), Some(neg_field), None, a)
|
||||
}
|
||||
|
||||
fn not_bool(a: Term) -> Term {
|
||||
term![Op::Not; a]
|
||||
}
|
||||
|
||||
fn not_uint(a: Term) -> Term {
|
||||
term![Op::BvUnOp(BvUnOp::Not); a]
|
||||
}
|
||||
|
||||
fn not(a: T) -> Result<T, String> {
|
||||
wrap_un_op("!", Some(not_uint), None, Some(not_bool), a)
|
||||
}
|
||||
|
||||
pub fn const_int(a: T) -> Result<Integer, String> {
|
||||
let s = match &a {
|
||||
T::Field(b) => match &b.op {
|
||||
Op::Const(Value::Field(f)) => Some(f.i().clone()),
|
||||
_ => None,
|
||||
},
|
||||
T::Uint(_, i) => match &i.op {
|
||||
Op::Const(Value::BitVector(f)) => Some(f.uint().clone()),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
s.ok_or_else(|| format!("{} is not a constant integer", a))
|
||||
}
|
||||
|
||||
fn bool(a: T) -> Result<Term, String> {
|
||||
match a {
|
||||
T::Bool(b) => Ok(b),
|
||||
a => Err(format!("{} is not a boolean", a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn wrap_shift(name: &str, op: BvBinOp, a: T, b: T) -> Result<T, String> {
|
||||
let bc = const_int(b)?;
|
||||
match a {
|
||||
T::Uint(na, a) => Ok(T::Uint(na, term![Op::BvBinOp(op); a, bv_lit(bc, na)])),
|
||||
x => Err(format!("Cannot perform op '{}' on {} and {}", name, x, bc)),
|
||||
}
|
||||
}
|
||||
|
||||
fn shl(a: T, b: T) -> Result<T, String> {
|
||||
wrap_shift("<<", BvBinOp::Shl, a, b)
|
||||
}
|
||||
|
||||
fn shr(a: T, b: T) -> Result<T, String> {
|
||||
wrap_shift(">>", BvBinOp::Lshr, a, b)
|
||||
}
|
||||
|
||||
fn ite(c: Term, a: T, b: T) -> Result<T, String> {
|
||||
match (a, b) {
|
||||
(T::Uint(na, a), T::Uint(nb, b)) if na == nb => Ok(T::Uint(na, term![Op::Ite; c, a, b])),
|
||||
(T::Bool(a), T::Bool(b)) => Ok(T::Bool(term![Op::Ite; c, a, b])),
|
||||
(T::Field(a), T::Field(b)) => Ok(T::Field(term![Op::Ite; c, a, b])),
|
||||
(T::Array(ta, a), T::Array(tb, b)) if a.len() == b.len() && ta == tb => Ok(T::Array(
|
||||
ta,
|
||||
a.into_iter()
|
||||
.zip(b.into_iter())
|
||||
.map(|(a_i, b_i)| ite(c.clone(), a_i, b_i))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
)),
|
||||
(T::Struct(na, a), T::Struct(nb, b)) if na == nb => Ok(T::Struct(na.clone(), {
|
||||
a.into_iter()
|
||||
.zip(b.into_iter())
|
||||
.map(|((af, av), (bf, bv))| {
|
||||
if af == bf {
|
||||
Ok((af, ite(c.clone(), av, bv)?))
|
||||
} else {
|
||||
Err(format!("Field mismatch: {} vs {}", af, bf))
|
||||
}
|
||||
})
|
||||
.collect::<Result<BTreeMap<_, _>, String>>()?
|
||||
})),
|
||||
(x, y) => Err(format!("Cannot perform ITE on {} and {}", x, y)),
|
||||
}
|
||||
}
|
||||
|
||||
fn cond(c: T, a: T, b: T) -> Result<T, String> {
|
||||
ite(bool(c)?, a, b)
|
||||
}
|
||||
|
||||
pub fn pf_lit<I>(i: I) -> Term
|
||||
where
|
||||
Integer: From<I>,
|
||||
{
|
||||
leaf_term(Op::Const(Value::Field(FieldElem::new(
|
||||
Integer::from(i),
|
||||
ZOKRATES_MODULUS_ARC.clone(),
|
||||
))))
|
||||
}
|
||||
|
||||
fn slice(array: T, start: Option<usize>, end: Option<usize>) -> Result<T, String> {
|
||||
match array {
|
||||
T::Array(b, mut list) => {
|
||||
let start = start.unwrap_or(0);
|
||||
let end = end.unwrap_or(list.len() - 1);
|
||||
Ok(T::Array(b, list.drain(start..end).collect()))
|
||||
}
|
||||
a => Err(format!("Cannot slice {}", a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn spread(array: T) -> Result<Vec<T>, String> {
|
||||
match array {
|
||||
T::Array(_, list) => Ok(list),
|
||||
a => Err(format!("Cannot spread {}", a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn field_select(struct_: &T, field: &str) -> Result<T, String> {
|
||||
match struct_ {
|
||||
T::Struct(_, map) => map
|
||||
.get(field)
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("No field '{}'", field)),
|
||||
a => Err(format!("{} is not a struct", a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn field_store(struct_: T, field: &str, val: T) -> Result<T, String> {
|
||||
match struct_ {
|
||||
T::Struct(name, mut map) => Ok(T::Struct(name, {
|
||||
if map.insert(field.to_owned(), val).is_some() {
|
||||
map
|
||||
} else {
|
||||
return Err(format!("No '{}' field", field));
|
||||
}
|
||||
})),
|
||||
a => Err(format!("{} is not a struct", a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn array_select(array: T, idx: T) -> Result<T, String> {
|
||||
match (array, idx) {
|
||||
(T::Array(_, list), T::Field(idx)) => {
|
||||
let mut it = list.into_iter().enumerate();
|
||||
let first = it
|
||||
.next()
|
||||
.ok_or_else(|| format!("Cannot index empty array"))?;
|
||||
it.fold(Ok(first.1), |acc, (i, elem)| {
|
||||
ite(term![Op::Eq; pf_lit(i), idx.clone()], elem, acc?)
|
||||
})
|
||||
}
|
||||
(a, b) => Err(format!("Cannot index {} by {}", b, a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn array_store(array: T, idx: T, val: T) -> Result<T, String> {
|
||||
match (array, idx) {
|
||||
(T::Array(ty, list), T::Field(idx)) => Ok(T::Array(
|
||||
ty,
|
||||
list.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, elem)| ite(term![Op::Eq; pf_lit(i), idx.clone()], val.clone(), elem))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
)),
|
||||
(a, b) => Err(format!("Cannot index {} by {}", b, a)),
|
||||
}
|
||||
}
|
||||
|
||||
fn array<I: IntoIterator<Item = T>>(elems: I) -> Result<T, String> {
|
||||
let v: Vec<T> = elems.into_iter().collect();
|
||||
if let Some(e) = v.first() {
|
||||
let ty = e.type_();
|
||||
if v.iter().skip(1).any(|a| a.type_() != ty) {
|
||||
Err(format!("Inconsistent types in array"))
|
||||
} else {
|
||||
Ok(T::Array(ty, v))
|
||||
}
|
||||
} else {
|
||||
Err(format!("Empty array"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn u32_to_bits(u: T) -> Result<T, String> {
|
||||
match u {
|
||||
T::Uint(32, t) => Ok(T::Array(
|
||||
Ty::Bool,
|
||||
(0..32)
|
||||
.map(|i| T::Bool(term![Op::BvBit(i); t.clone()]))
|
||||
.collect(),
|
||||
)),
|
||||
u => Err(format!("Cannot do u32-to-bits on {}", u)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn u32_from_bits(u: T) -> Result<T, String> {
|
||||
match u {
|
||||
T::Array(Ty::Bool, list) => {
|
||||
if list.len() == 32 {
|
||||
Ok(T::Uint(
|
||||
32,
|
||||
term(
|
||||
Op::BvConcat,
|
||||
list.into_iter()
|
||||
.map(|z: T| -> Result<Term, String> {
|
||||
Ok(term![Op::BoolToBv; bool(z)?])
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
),
|
||||
))
|
||||
} else {
|
||||
Err(format!(
|
||||
"Cannot do u32-from-bits on len {} array",
|
||||
list.len()
|
||||
))
|
||||
}
|
||||
}
|
||||
u => Err(format!("Cannot do u32-from-bits on {}", u)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field_to_bits(f: T) -> Result<T, String> {
|
||||
match f {
|
||||
T::Field(t) => {
|
||||
let u = term![Op::PfToBv(254); t];
|
||||
Ok(T::Array(
|
||||
Ty::Bool,
|
||||
(0..254)
|
||||
.map(|i| T::Bool(term![Op::BvBit(i); u.clone()]))
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
u => Err(format!("Cannot do field-to-bits on {}", u)),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ZoKrates {
|
||||
values: Option<HashMap<String, Integer>>,
|
||||
modulus: Arc<Integer>,
|
||||
}
|
||||
|
||||
fn field_name(struct_name: &str, field_name: &str) -> String {
|
||||
format!("{}.{}", struct_name, field_name)
|
||||
}
|
||||
|
||||
fn idx_name(struct_name: &str, idx: usize) -> String {
|
||||
format!("{}.{}", struct_name, idx)
|
||||
}
|
||||
|
||||
impl ZoKrates {
|
||||
pub fn new(values: Option<HashMap<String, Integer>>) -> Self {
|
||||
Self {
|
||||
values,
|
||||
modulus: ZOKRATES_MODULUS_ARC.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Embeddable for ZoKrates {
|
||||
type T = T;
|
||||
type Ty = Ty;
|
||||
fn declare(
|
||||
&self,
|
||||
ctx: &mut CirCtx,
|
||||
ty: &Self::Ty,
|
||||
raw_name: String,
|
||||
user_name: Option<String>,
|
||||
) -> Self::T {
|
||||
let get_int_val = || -> Integer {
|
||||
self.values
|
||||
.as_ref()
|
||||
.and_then(|vs| {
|
||||
user_name
|
||||
.as_ref()
|
||||
.and_then(|n| vs.get(n))
|
||||
.or_else(|| vs.get(&raw_name))
|
||||
})
|
||||
.cloned()
|
||||
.unwrap_or_else(|| Integer::from(0))
|
||||
};
|
||||
match ty {
|
||||
Ty::Bool => T::Bool(ctx.cs.borrow_mut().new_var(
|
||||
&raw_name,
|
||||
Sort::Bool,
|
||||
|| Value::Bool(get_int_val() != 0),
|
||||
user_name.is_some(),
|
||||
)),
|
||||
Ty::Field => T::Field(ctx.cs.borrow_mut().new_var(
|
||||
&raw_name,
|
||||
Sort::Field(self.modulus.clone()),
|
||||
|| Value::Field(FieldElem::new(get_int_val(), self.modulus.clone())),
|
||||
user_name.is_some(),
|
||||
)),
|
||||
Ty::Uint(w) => T::Field(ctx.cs.borrow_mut().new_var(
|
||||
&raw_name,
|
||||
Sort::BitVector(*w),
|
||||
|| Value::BitVector(BitVector::new(get_int_val(), *w)),
|
||||
user_name.is_some(),
|
||||
)),
|
||||
Ty::Array(n, ty) => T::Array(
|
||||
(**ty).clone(),
|
||||
(0..*n)
|
||||
.map(|i| {
|
||||
self.declare(
|
||||
ctx,
|
||||
&*ty,
|
||||
idx_name(&raw_name, i),
|
||||
user_name.as_ref().map(|u| idx_name(u, i)),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
Ty::Struct(n, fs) => T::Struct(
|
||||
n.clone(),
|
||||
fs.iter()
|
||||
.map(|(f_name, f_ty)| {
|
||||
(
|
||||
f_name.clone(),
|
||||
self.declare(
|
||||
ctx,
|
||||
f_ty,
|
||||
field_name(&raw_name, f_name),
|
||||
user_name.as_ref().map(|u| field_name(u, f_name)),
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
fn ite(&self, ctx: &mut CirCtx, cond: Term, t: Self::T, f: Self::T) -> Self::T {
|
||||
match (t, f) {
|
||||
(T::Bool(a), T::Bool(b)) => T::Bool(term![Op::Ite; cond, a, b]),
|
||||
(T::Uint(wa, a), T::Uint(wb, b)) if wa == wb => T::Uint(wa, term![Op::Ite; cond, a, b]),
|
||||
(T::Field(a), T::Field(b)) => T::Field(term![Op::Ite; cond, a, b]),
|
||||
(T::Array(a_ty, a), T::Array(b_ty, b)) if a_ty == b_ty => T::Array(
|
||||
a_ty,
|
||||
a.into_iter()
|
||||
.zip(b.into_iter())
|
||||
.map(|(a_i, b_i)| self.ite(ctx, cond.clone(), a_i, b_i))
|
||||
.collect(),
|
||||
),
|
||||
(T::Struct(a_nm, a), T::Struct(b_nm, b)) if a_nm == b_nm => T::Struct(
|
||||
a_nm,
|
||||
a.into_iter()
|
||||
.zip(b.into_iter())
|
||||
.map(|((a_f, a_i), (b_f, b_i))| {
|
||||
if a_f == b_f {
|
||||
(a_f, self.ite(ctx, cond.clone(), a_i, b_i))
|
||||
} else {
|
||||
panic!("Field mismatch: '{}' vs '{}'", a_f, b_f)
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
(t, f) => panic!("Cannot ITE {} and {}", t, f),
|
||||
}
|
||||
}
|
||||
fn assign(&self, ctx: &mut CirCtx, ty: &Self::Ty, name: String, t: Self::T) -> Self::T {
|
||||
assert!(&t.type_() == ty);
|
||||
match (ty, t) {
|
||||
(_, T::Bool(b)) => {
|
||||
ctx.cs.borrow_mut().eval_and_save(&name, &b);
|
||||
let v = leaf_term(Op::Var(name, Sort::Bool));
|
||||
ctx.cs
|
||||
.borrow_mut()
|
||||
.assertions
|
||||
.push(term![Op::Eq; v.clone(), b]);
|
||||
T::Bool(v)
|
||||
}
|
||||
(_, T::Field(b)) => {
|
||||
ctx.cs.borrow_mut().eval_and_save(&name, &b);
|
||||
let v = leaf_term(Op::Var(name, Sort::Field(self.modulus.clone())));
|
||||
ctx.cs
|
||||
.borrow_mut()
|
||||
.assertions
|
||||
.push(term![Op::Eq; v.clone(), b]);
|
||||
T::Field(v)
|
||||
}
|
||||
(_, T::Uint(w, b)) => {
|
||||
ctx.cs.borrow_mut().eval_and_save(&name, &b);
|
||||
let v = leaf_term(Op::Var(name, Sort::BitVector(w)));
|
||||
ctx.cs
|
||||
.borrow_mut()
|
||||
.assertions
|
||||
.push(term![Op::Eq; v.clone(), b]);
|
||||
T::Uint(w, v)
|
||||
}
|
||||
(_, T::Array(ety, list)) => T::Array(
|
||||
ety.clone(),
|
||||
list.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, elem)| self.assign(ctx, &ety, idx_name(&name, i), elem))
|
||||
.collect(),
|
||||
),
|
||||
(Ty::Struct(_, tys), T::Struct(s_name, list)) => T::Struct(
|
||||
s_name,
|
||||
list.into_iter()
|
||||
.zip(tys.into_iter())
|
||||
.map(|((f_name, elem), (_, f_ty))| {
|
||||
(
|
||||
f_name.clone(),
|
||||
self.assign(ctx, &f_ty, field_name(&name, &f_name), elem),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
fn values(&self) -> bool {
|
||||
self.values.is_some()
|
||||
}
|
||||
}
|
||||
7
third_party/README.md
vendored
Normal file
7
third_party/README.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# Third Party Dependencies
|
||||
|
||||
This directory contains source copied from other projects
|
||||
|
||||
## Dependencies
|
||||
|
||||
* ZoKrates Parser & AST, version 0.6.3
|
||||
165
third_party/ZoKrates/LICENSE
vendored
Normal file
165
third_party/ZoKrates/LICENSE
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
12
third_party/ZoKrates/zokrates_parser/Cargo.toml
vendored
Normal file
12
third_party/ZoKrates/zokrates_parser/Cargo.toml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "zokrates_parser"
|
||||
version = "0.1.6"
|
||||
authors = ["JacobEberhardt <jacob.eberhardt@tu-berlin.de>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
pest = "2.0"
|
||||
pest_derive = "2.0"
|
||||
|
||||
[dev-dependencies]
|
||||
glob = "0.2"
|
||||
3
third_party/ZoKrates/zokrates_parser/README.md
vendored
Normal file
3
third_party/ZoKrates/zokrates_parser/README.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# zokrates_parser
|
||||
|
||||
Formal grammar specification of the ZoKrates DSL in PEG (Pest).
|
||||
4
third_party/ZoKrates/zokrates_parser/src/ace_mode/README.md
vendored
Normal file
4
third_party/ZoKrates/zokrates_parser/src/ace_mode/README.md
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
### ZoKrates Ace Mode (Syntax Highlighting for Ace/Brace)
|
||||
|
||||
[Ace](https://ace.c9.io/) Edit Mode for [ZoKrates DSL](https://github.com/Zokrates/ZoKrates).
|
||||
Compatible with browserify version of the ace editor, [brace](https://www.npmjs.com/package/brace).
|
||||
120
third_party/ZoKrates/zokrates_parser/src/ace_mode/index.js
vendored
Normal file
120
third_party/ZoKrates/zokrates_parser/src/ace_mode/index.js
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2019, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
ace.define("ace/mode/zokrates_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"], function(acequire, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = acequire("../lib/oop");
|
||||
var TextHighlightRules = acequire("./text_highlight_rules").TextHighlightRules;
|
||||
|
||||
var ZoKratesHighlightRules = function () {
|
||||
|
||||
var keywords = (
|
||||
"assert|as|bool|byte|def|do|else|endfor|export|false|field|for|if|then|fi|import|from|in|private|public|return|struct|true|u8|u16|u32"
|
||||
);
|
||||
|
||||
var keywordMapper = this.createKeywordMapper({
|
||||
"keyword": keywords
|
||||
}, "identifier");
|
||||
|
||||
var decimalInteger = "(?:(?:[1-9]\\d*)|(?:0))";
|
||||
var hexInteger = "(?:0[xX][\\dA-Fa-f]+)";
|
||||
var integer = "(?:" + decimalInteger + "|" + hexInteger + ")\\b";
|
||||
|
||||
this.$rules = {
|
||||
"start": [
|
||||
{
|
||||
token: "comment", // single line comment
|
||||
regex: "\\/\\/.*$"
|
||||
}, {
|
||||
token: "comment", // multi line comment
|
||||
regex: "\\/\\*",
|
||||
next: "comment"
|
||||
}, {
|
||||
token: "string", // single line
|
||||
regex: '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
|
||||
}, {
|
||||
token: "constant.numeric", // integer
|
||||
regex: integer
|
||||
}, {
|
||||
token: keywordMapper,
|
||||
regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
|
||||
}, {
|
||||
token: "keyword.operator",
|
||||
regex: "\\+|\\-|\\*\\*?|\\/|\\|\\|?|&&?|\\^|!|<<?|>>?|<=|=>|==|!=|="
|
||||
}, {
|
||||
token: "punctuation",
|
||||
regex: ",|:|;"
|
||||
}, {
|
||||
token: "lparen",
|
||||
regex: "[[({]"
|
||||
}, {
|
||||
token: "rparen",
|
||||
regex: "[\\])}]"
|
||||
}, {
|
||||
token: "text",
|
||||
regex: "\\s+"
|
||||
}
|
||||
],
|
||||
"comment": [
|
||||
{
|
||||
token: "comment", // closing comment
|
||||
regex: "\\*\\/",
|
||||
next: "start"
|
||||
}, {
|
||||
defaultToken: "comment"
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
oop.inherits(ZoKratesHighlightRules, TextHighlightRules);
|
||||
|
||||
exports.ZoKratesHighlightRules = ZoKratesHighlightRules;
|
||||
});
|
||||
|
||||
ace.define("ace/mode/zokrates",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/zokrates_highlight_rules"], function(acequire, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = acequire("../lib/oop");
|
||||
var TextMode = acequire("./text").Mode;
|
||||
var ZoKratesHighlightRules = acequire("./zokrates_highlight_rules").ZoKratesHighlightRules;
|
||||
|
||||
var Mode = function () {
|
||||
this.HighlightRules = ZoKratesHighlightRules;
|
||||
};
|
||||
oop.inherits(Mode, TextMode);
|
||||
|
||||
(function () {
|
||||
this.$id = "ace/mode/zokrates";
|
||||
}).call(Mode.prototype);
|
||||
|
||||
exports.Mode = Mode;
|
||||
});
|
||||
17
third_party/ZoKrates/zokrates_parser/src/ace_mode/package.json
vendored
Normal file
17
third_party/ZoKrates/zokrates_parser/src/ace_mode/package.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "ace-mode-zokrates",
|
||||
"version": "1.0.2",
|
||||
"description": "Ace Mode for ZoKrates DSL",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"zokrates",
|
||||
"ace",
|
||||
"mode",
|
||||
"brace"
|
||||
],
|
||||
"author": "Darko Macesic",
|
||||
"license": "LGPL"
|
||||
}
|
||||
295
third_party/ZoKrates/zokrates_parser/src/lib.rs
vendored
Normal file
295
third_party/ZoKrates/zokrates_parser/src/lib.rs
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
extern crate pest;
|
||||
#[macro_use]
|
||||
extern crate pest_derive;
|
||||
|
||||
use pest::error::Error;
|
||||
use pest::iterators::Pairs;
|
||||
use pest::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[grammar = "zokrates.pest"]
|
||||
struct ZoKratesParser;
|
||||
|
||||
pub fn parse(input: &str) -> Result<Pairs<Rule>, Error<Rule>> {
|
||||
ZoKratesParser::parse(Rule::file, input)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use pest::*;
|
||||
|
||||
mod examples {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn examples_dir() {
|
||||
use glob::glob;
|
||||
use std::fs;
|
||||
use std::io::Read;
|
||||
// Traverse all .zok files in examples dir
|
||||
for entry in
|
||||
glob("../zokrates_cli/examples/**/*.zok").expect("Failed to read glob pattern")
|
||||
{
|
||||
match entry {
|
||||
Ok(path) => {
|
||||
if path.to_str().unwrap().contains("error") {
|
||||
continue;
|
||||
}
|
||||
|
||||
println!("Parsing {:?}", path.display());
|
||||
let mut file = fs::File::open(path).unwrap();
|
||||
|
||||
let mut data = String::new();
|
||||
file.read_to_string(&mut data).unwrap();
|
||||
|
||||
assert!(ZoKratesParser::parse(Rule::file, &data).is_ok());
|
||||
}
|
||||
Err(e) => panic!("{:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod rules {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn parse_valid_identifier() {
|
||||
parses_to! {
|
||||
parser: ZoKratesParser,
|
||||
input: "valididentifier_01",
|
||||
rule: Rule::identifier,
|
||||
tokens: [
|
||||
identifier(0, 18)
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_parameter_list() {
|
||||
parses_to! {
|
||||
parser: ZoKratesParser,
|
||||
input: "def foo(field a) -> (field, field): return 1
|
||||
",
|
||||
rule: Rule::function_definition,
|
||||
tokens: [
|
||||
function_definition(0, 45, [
|
||||
identifier(4, 7),
|
||||
// parameter_list is not created (silent rule)
|
||||
parameter(8, 15, [
|
||||
ty(8, 13, [
|
||||
ty_basic(8, 13, [
|
||||
ty_field(8, 13)
|
||||
])
|
||||
]),
|
||||
identifier(14, 15)
|
||||
]),
|
||||
// type_list is not created (silent rule)
|
||||
ty(21, 26, [
|
||||
ty_basic(21, 26, [
|
||||
ty_field(21, 26)
|
||||
])
|
||||
]),
|
||||
ty(28, 33, [
|
||||
ty_basic(28, 33, [
|
||||
ty_field(28, 33)
|
||||
])
|
||||
]),
|
||||
statement(36, 45, [
|
||||
return_statement(36, 44, [
|
||||
expression(43, 44, [
|
||||
term(43, 44, [
|
||||
primary_expression(43, 44, [
|
||||
constant(43, 44, [
|
||||
decimal_number(43, 44)
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_single_def_to_multi() {
|
||||
parses_to! {
|
||||
parser: ZoKratesParser,
|
||||
input: r#"a = foo()
|
||||
"#,
|
||||
rule: Rule::statement,
|
||||
tokens: [
|
||||
statement(0, 22, [
|
||||
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)
|
||||
])
|
||||
])
|
||||
])
|
||||
]),
|
||||
])
|
||||
])
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_field_def_to_multi() {
|
||||
parses_to! {
|
||||
parser: ZoKratesParser,
|
||||
input: r#"field a = foo()
|
||||
"#,
|
||||
rule: Rule::statement,
|
||||
tokens: [
|
||||
statement(0, 28, [
|
||||
definition_statement(0, 15, [
|
||||
optionally_typed_assignee(0, 8, [
|
||||
ty(0, 5, [
|
||||
ty_basic(0, 5, [
|
||||
ty_field(0, 5)
|
||||
])
|
||||
]),
|
||||
assignee(6, 8, [
|
||||
identifier(6, 7)
|
||||
])
|
||||
]),
|
||||
expression(10, 15, [
|
||||
term(10, 15, [
|
||||
postfix_expression(10, 15, [
|
||||
identifier(10, 13),
|
||||
access(13, 15, [
|
||||
call_access(13, 15)
|
||||
])
|
||||
])
|
||||
])
|
||||
]),
|
||||
])
|
||||
])
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_u8_def_to_multi() {
|
||||
parses_to! {
|
||||
parser: ZoKratesParser,
|
||||
input: r#"u32 a = foo()
|
||||
"#,
|
||||
rule: Rule::statement,
|
||||
tokens: [
|
||||
statement(0, 26, [
|
||||
definition_statement(0, 13, [
|
||||
optionally_typed_assignee(0, 6, [
|
||||
ty(0, 3, [
|
||||
ty_basic(0, 3, [
|
||||
ty_u32(0, 3)
|
||||
])
|
||||
]),
|
||||
assignee(4, 6, [
|
||||
identifier(4, 5)
|
||||
])
|
||||
]),
|
||||
expression(8, 13, [
|
||||
term(8, 13, [
|
||||
postfix_expression(8, 13, [
|
||||
identifier(8, 11),
|
||||
access(11, 13, [
|
||||
call_access(11, 13)
|
||||
])
|
||||
])
|
||||
])
|
||||
]),
|
||||
])
|
||||
])
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_invalid_identifier() {
|
||||
fails_with! {
|
||||
parser: ZoKratesParser,
|
||||
input: "0_invalididentifier",
|
||||
rule: Rule::identifier,
|
||||
positives: vec![Rule::identifier],
|
||||
negatives: vec![],
|
||||
pos: 0
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_struct_def() {
|
||||
parses_to! {
|
||||
parser: ZoKratesParser,
|
||||
input: "struct Foo { field foo\n field[2] bar }
|
||||
",
|
||||
rule: Rule::ty_struct_definition,
|
||||
tokens: [
|
||||
ty_struct_definition(0, 39, [
|
||||
identifier(7, 10),
|
||||
struct_field(13, 22, [
|
||||
ty(13, 18, [
|
||||
ty_basic(13, 18, [
|
||||
ty_field(13, 18)
|
||||
])
|
||||
]),
|
||||
identifier(19, 22)
|
||||
]),
|
||||
struct_field(24, 36, [
|
||||
ty(24, 33, [
|
||||
ty_array(24, 33, [
|
||||
ty_basic_or_struct(24, 29, [
|
||||
ty_basic(24, 29, [
|
||||
ty_field(24, 29)
|
||||
])
|
||||
]),
|
||||
expression(30, 31, [
|
||||
term(30, 31, [
|
||||
primary_expression(30, 31, [
|
||||
constant(30, 31, [
|
||||
decimal_number(30, 31)
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
]),
|
||||
identifier(33, 36)
|
||||
])
|
||||
])
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_invalid_identifier_because_keyword() {
|
||||
fails_with! {
|
||||
parser: ZoKratesParser,
|
||||
input: "endfor",
|
||||
rule: Rule::identifier,
|
||||
positives: vec![Rule::identifier],
|
||||
negatives: vec![],
|
||||
pos: 0
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_for_loop() {
|
||||
let input = "for field i in 0..3 do \n c = c + a[i] \n endfor";
|
||||
|
||||
let parse = ZoKratesParser::parse(Rule::iteration_statement, input);
|
||||
assert!(parse.is_ok());
|
||||
}
|
||||
}
|
||||
}
|
||||
133
third_party/ZoKrates/zokrates_parser/src/zokrates.pest
vendored
Normal file
133
third_party/ZoKrates/zokrates_parser/src/zokrates.pest
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
|
||||
file = { SOI ~ NEWLINE* ~ pragma? ~ NEWLINE* ~ import_directive* ~ NEWLINE* ~ ty_struct_definition* ~ NEWLINE* ~ function_definition* ~ EOI }
|
||||
|
||||
pragma = { "#pragma" ~ "curve" ~ curve }
|
||||
curve = @{ (ASCII_ALPHANUMERIC | "_") * }
|
||||
|
||||
import_directive = { main_import_directive | from_import_directive }
|
||||
from_import_directive = { "from" ~ "\"" ~ import_source ~ "\"" ~ "import" ~ identifier ~ ("as" ~ identifier)? ~ NEWLINE*}
|
||||
main_import_directive = {"import" ~ "\"" ~ import_source ~ "\"" ~ ("as" ~ identifier)? ~ NEWLINE+}
|
||||
import_source = @{(!"\"" ~ ANY)*}
|
||||
function_definition = {"def" ~ identifier ~ "(" ~ parameter_list ~ ")" ~ return_types ~ ":" ~ NEWLINE* ~ statement* }
|
||||
return_types = _{ ( "->" ~ ( "(" ~ type_list ~ ")" | ty ))? }
|
||||
|
||||
parameter_list = _{(parameter ~ ("," ~ parameter)*)?}
|
||||
parameter = {vis? ~ ty ~ identifier}
|
||||
|
||||
// basic types
|
||||
ty_field = {"field"}
|
||||
ty_bool = {"bool"}
|
||||
ty_u8 = {"u8"}
|
||||
ty_u32 = {"u32"}
|
||||
ty_u16 = {"u16"}
|
||||
ty_basic = { ty_field | ty_bool | ty_u8 | ty_u16 | ty_u32 }
|
||||
ty_basic_or_struct = { ty_basic | ty_struct }
|
||||
ty_array = { ty_basic_or_struct ~ ("[" ~ expression ~ "]")+ }
|
||||
ty = { ty_array | ty_basic | ty_struct }
|
||||
type_list = _{(ty ~ ("," ~ ty)*)?}
|
||||
// structs
|
||||
ty_struct = { identifier }
|
||||
// type definitions
|
||||
ty_struct_definition = { "struct" ~ identifier ~ "{" ~ NEWLINE* ~ struct_field_list ~ NEWLINE* ~ "}" ~ NEWLINE* }
|
||||
struct_field_list = _{(struct_field ~ (NEWLINE+ ~ struct_field)*)? }
|
||||
struct_field = { ty ~ identifier }
|
||||
|
||||
vis_private = {"private"}
|
||||
vis_public = {"public"}
|
||||
vis = { vis_private | vis_public }
|
||||
|
||||
// Statements
|
||||
statement = { (return_statement // does not require subsequent newline
|
||||
| (iteration_statement
|
||||
| definition_statement
|
||||
| expression_statement
|
||||
) ~ NEWLINE
|
||||
) ~ NEWLINE* }
|
||||
|
||||
iteration_statement = { "for" ~ ty ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "do" ~ NEWLINE* ~ statement* ~ "endfor"}
|
||||
return_statement = { "return" ~ expression_list}
|
||||
definition_statement = { optionally_typed_assignee_list ~ "=" ~ expression } // declare and assign, so only identifiers are allowed, unlike `assignment_statement`
|
||||
expression_statement = {"assert" ~ "(" ~ expression ~ ")"}
|
||||
|
||||
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)*)?}
|
||||
|
||||
expression = { term ~ (op_binary ~ term)* }
|
||||
term = { ("(" ~ expression ~ ")") | inline_struct_expression | conditional_expression | postfix_expression | primary_expression | inline_array_expression | array_initializer_expression | unary_expression }
|
||||
spread = { "..." ~ expression }
|
||||
range = { from_expression? ~ ".." ~ to_expression? }
|
||||
from_expression = { expression }
|
||||
to_expression = { expression }
|
||||
|
||||
conditional_expression = { "if" ~ expression ~ "then" ~ expression ~ "else" ~ expression ~ "fi"}
|
||||
|
||||
postfix_expression = { identifier ~ access+ } // we force there to be at least one access, otherwise this matches single identifiers. Not sure that's what we want.
|
||||
access = { array_access | call_access | member_access }
|
||||
array_access = { "[" ~ range_or_expression ~ "]" }
|
||||
call_access = { "(" ~ expression_list ~ ")" }
|
||||
member_access = { "." ~ identifier }
|
||||
|
||||
primary_expression = { identifier
|
||||
| constant
|
||||
}
|
||||
|
||||
inline_struct_expression = { identifier ~ "{" ~ NEWLINE* ~ inline_struct_member_list ~ NEWLINE* ~ "}" }
|
||||
inline_struct_member_list = _{(inline_struct_member ~ ("," ~ NEWLINE* ~ inline_struct_member)*)? ~ ","? }
|
||||
inline_struct_member = { identifier ~ ":" ~ expression }
|
||||
|
||||
inline_array_expression = { "[" ~ NEWLINE* ~ inline_array_inner ~ NEWLINE* ~ "]" }
|
||||
inline_array_inner = _{(spread_or_expression ~ ("," ~ NEWLINE* ~ spread_or_expression)*)?}
|
||||
spread_or_expression = { spread | expression }
|
||||
range_or_expression = { range | expression }
|
||||
array_initializer_expression = { "[" ~ expression ~ ";" ~ constant ~ "]" }
|
||||
|
||||
unary_expression = { op_unary ~ term }
|
||||
|
||||
// End Expressions
|
||||
|
||||
assignee = { identifier ~ assignee_access* }
|
||||
assignee_access = { array_access | member_access }
|
||||
identifier = @{ ((!keyword ~ ASCII_ALPHA) | (keyword ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* }
|
||||
constant = { hex_number | decimal_number | boolean_literal }
|
||||
decimal_number = @{ "0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* }
|
||||
boolean_literal = { "true" | "false" }
|
||||
hex_number = _{ hex_number_32 | hex_number_16 | hex_number_8 }
|
||||
hex_number_8 = @{ "0x" ~ ASCII_HEX_DIGIT{2} }
|
||||
hex_number_16 = @{ "0x" ~ ASCII_HEX_DIGIT{4} }
|
||||
hex_number_32 = @{ "0x" ~ ASCII_HEX_DIGIT{8} }
|
||||
|
||||
op_or = @{"||"}
|
||||
op_and = @{"&&"}
|
||||
op_bit_xor = {"^"}
|
||||
op_bit_and = {"&"}
|
||||
op_bit_or = {"|"}
|
||||
op_equal = @{"=="}
|
||||
op_not_equal = @{"!="}
|
||||
op_lt = {"<"}
|
||||
op_lte = @{"<="}
|
||||
op_gt = {">"}
|
||||
op_gte = @{">="}
|
||||
op_add = {"+"}
|
||||
op_sub = {"-"}
|
||||
op_mul = {"*"}
|
||||
op_div = {"/"}
|
||||
op_rem = {"%"}
|
||||
op_pow = @{"**"}
|
||||
op_not = {"!"}
|
||||
op_left_shift = @{"<<"}
|
||||
op_right_shift = @{">>"}
|
||||
op_binary = _ { op_pow | op_or | op_and | op_bit_xor | op_bit_and | op_bit_or | op_left_shift | op_right_shift | op_equal | op_not_equal | op_lte | op_lt | op_gte | op_gt | op_add | op_sub | op_mul | op_div | op_rem }
|
||||
op_unary = { op_not }
|
||||
|
||||
|
||||
WHITESPACE = _{ " " | "\t" | "\\" ~ NEWLINE}
|
||||
COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
|
||||
|
||||
// the ordering of reserved keywords matters: if "as" is before "assert", then "assert" gets parsed as (as)(sert) and incorrectly
|
||||
// accepted
|
||||
keyword = @{"assert"|"as"|"bool"|"byte"|"def"|"do"|"else"|"endfor"|"export"|"false"|"field"|"for"|"if"|"then"|"fi"|"import"|"from"|
|
||||
"in"|"private"|"public"|"return"|"struct"|"true"|"u8"|"u16"|"u32"
|
||||
}
|
||||
15
third_party/ZoKrates/zokrates_pest_ast/Cargo.toml
vendored
Normal file
15
third_party/ZoKrates/zokrates_pest_ast/Cargo.toml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "zokrates_pest_ast"
|
||||
version = "0.1.5"
|
||||
authors = ["schaeff <thibaut@schaeff.fr>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
zokrates_parser = { version = "0.1.0", path = "../zokrates_parser" }
|
||||
pest = "2.0"
|
||||
pest-ast = "0.3.3"
|
||||
from-pest = "0.3.1"
|
||||
lazy_static = "1.3.0"
|
||||
|
||||
[dev-dependencies]
|
||||
glob = "0.2"
|
||||
3
third_party/ZoKrates/zokrates_pest_ast/README.md
vendored
Normal file
3
third_party/ZoKrates/zokrates_pest_ast/README.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# zokrates_pest_ast
|
||||
|
||||
ZoKrates AST generation based on pest output.
|
||||
1191
third_party/ZoKrates/zokrates_pest_ast/src/lib.rs
vendored
Normal file
1191
third_party/ZoKrates/zokrates_pest_ast/src/lib.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user