diff --git a/Cargo.lock b/Cargo.lock index c905d983..8a68d592 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,15 +48,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "approx" version = "0.5.1" @@ -257,6 +248,7 @@ dependencies = [ "bincode", "bls12_381", "circ_fields", + "circ_opt", "curve25519-dalek", "env_logger", "ff", @@ -275,6 +267,7 @@ dependencies = [ "logos", "lp-solvers", "merlin", + "once_cell", "pairing", "paste", "pest", @@ -290,7 +283,6 @@ dependencies = [ "serde_bytes", "serde_json", "spartan", - "structopt", "thiserror", "typed-arena", "zokrates_parser", @@ -313,18 +305,47 @@ dependencies = [ ] [[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +name = "circ_opt" +version = "0.1.0" +dependencies = [ + "clap", +] + +[[package]] +name = "clap" +version = "4.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" dependencies = [ - "ansi_term", "atty", "bitflags", + "clap_derive", + "clap_lex", + "once_cell", "strsim", - "textwrap", - "unicode-width", - "vec_map", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2 1.0.49", + "quote 1.0.18", + "syn 1.0.95", +] + +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", ] [[package]] @@ -491,7 +512,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", "quote 1.0.18", "syn 1.0.95", "synstructure", @@ -532,7 +553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e715451ab983be06481e927a275ec12372103ad426c7cb82cebfe14698ed4cf4" dependencies = [ "num-traits", - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", "quote 1.0.18", "syn 1.0.95", ] @@ -548,7 +569,7 @@ dependencies = [ "num-bigint", "num-integer", "num-traits", - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", "quote 1.0.18", "syn 1.0.95", ] @@ -700,12 +721,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" @@ -835,7 +853,7 @@ checksum = "56a7d287fd2ac3f75b11f19a1c8a874a7d55744bd91f7a1b3e7cf87d4343c36d" dependencies = [ "beef", "fnv", - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", "quote 1.0.18", "regex-syntax", "syn 1.0.95", @@ -954,9 +972,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.11.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b10983b38c53aebdf33f542c6275b0f58a238129d00c4ae0e6fb59738d783ca" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "opaque-debug" @@ -964,6 +982,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +[[package]] +name = "os_str_bytes" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" + [[package]] name = "pairing" version = "0.22.0" @@ -1020,7 +1044,7 @@ checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", "quote 1.0.18", "syn 1.0.95", ] @@ -1059,7 +1083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", "quote 1.0.18", "syn 1.0.95", "version_check", @@ -1071,7 +1095,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", "quote 1.0.18", "version_check", ] @@ -1087,9 +1111,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] @@ -1111,7 +1135,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b22a693222d716a9587786f37ac3f6b4faedb5b80c23914e7303ff5a1d8016e9" dependencies = [ - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", "quote 1.0.18", "syn 1.0.95", ] @@ -1131,7 +1155,7 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", ] [[package]] @@ -1342,7 +1366,7 @@ version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", "quote 1.0.18", "syn 1.0.95", ] @@ -1427,33 +1451,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "structopt" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" -dependencies = [ - "clap", - "lazy_static", - "structopt-derive", -] - -[[package]] -name = "structopt-derive" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2 1.0.39", - "quote 1.0.18", - "syn 1.0.95", -] +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" @@ -1478,7 +1478,7 @@ version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" dependencies = [ - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", "quote 1.0.18", "unicode-ident", ] @@ -1489,7 +1489,7 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", "quote 1.0.18", "syn 1.0.95", "unicode-xid 0.2.3", @@ -1524,15 +1524,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "thiserror" version = "1.0.31" @@ -1548,7 +1539,7 @@ version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", "quote 1.0.18", "syn 1.0.95", ] @@ -1577,18 +1568,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" -[[package]] -name = "unicode-segmentation" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - [[package]] name = "unicode-xid" version = "0.1.0" @@ -1607,12 +1586,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.4" @@ -1698,7 +1671,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" dependencies = [ - "proc-macro2 1.0.39", + "proc-macro2 1.0.49", "quote 1.0.18", "syn 1.0.95", "synstructure", diff --git a/Cargo.toml b/Cargo.toml index 62728543..de805c87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" [dependencies] circ_fields = { path = "circ_fields" } +circ_opt = { path = "circ_opt" } #hashconsing = "1.3" hashconsing = { git = "https://github.com/alex-ozdemir/hashconsing.git", branch = "phash"} rug = { version = "1.11", features = ["serde"] } @@ -46,21 +47,17 @@ merlin = { version = "3.0.0", optional = true } curve25519-dalek = {version = "3.2.0", features = ["serde"], optional = true} paste = "1.0" im = "15" +once_cell = "1" [dev-dependencies] quickcheck = "1" quickcheck_macros = "1" env_logger = "0.8" bls12_381 = "0.7" -structopt = "0.3" approx = "0.5.0" [features] -default = ["bls12381", "ff_dfl"] -bls12381 = [] -bn254 = [] -ristretto255 = [] -ff_dfl = [] +default = [] c = ["lang-c"] lp = ["good_lp", "lp-solvers"] r1cs = ["bellman", "spartan", "merlin", "curve25519-dalek"] diff --git a/circ_opt/.gitignore b/circ_opt/.gitignore new file mode 100644 index 00000000..eb5a316c --- /dev/null +++ b/circ_opt/.gitignore @@ -0,0 +1 @@ +target diff --git a/circ_opt/Cargo.lock b/circ_opt/Cargo.lock new file mode 100644 index 00000000..6484747c --- /dev/null +++ b/circ_opt/Cargo.lock @@ -0,0 +1,790 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytes" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" + +[[package]] +name = "cc" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "circ_opt" +version = "0.1.0" +dependencies = [ + "clap", + "heck", + "trycmd", +] + +[[package]] +name = "clap" +version = "4.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "656ad1e55e23d287773f7d8192c300dc715c3eeded93b3da651d11c42cfd74d2" +dependencies = [ + "bitflags", + "clap_derive", + "clap_lex", + "is-terminal", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concolor" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "318d6c16e73b3a900eb212ad6a82fc7d298c5ab8184c7a9998646455bc474a16" +dependencies = [ + "bitflags", + "concolor-query", + "is-terminal", +] + +[[package]] +name = "concolor-query" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a90734b3d5dcf656e7624cca6bce9c3a90ee11f900e80141a7427ccfb3d317" + +[[package]] +name = "content_inspector" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" +dependencies = [ + "memchr", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "dunce" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "escargot" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5584ba17d7ab26a8a7284f13e5bd196294dd2f2d79773cff29b9e9edef601a6" +dependencies = [ + "log", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + +[[package]] +name = "filetime" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "humantime-serde" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" +dependencies = [ + "humantime", + "serde", +] + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "is-terminal" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +dependencies = [ + "hermit-abi", + "io-lifetimes", + "rustix", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "libc" +version = "0.2.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" + +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "os_pipe" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6a252f1f8c11e84b3ab59d7a488e48e4478a93937e027076638c49536204639" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "os_str_bytes" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rustix" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "similar" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" + +[[package]] +name = "snapbox" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbd7b250c7243273b5aec4ca366fced84ad716d110bb7baae4814678952ebde" +dependencies = [ + "concolor", + "content_inspector", + "dunce", + "filetime", + "libc", + "normalize-line-endings", + "os_pipe", + "similar", + "snapbox-macros", + "tempfile", + "wait-timeout", + "walkdir", + "windows-sys", + "yansi", +] + +[[package]] +name = "snapbox-macros" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "485e65c1203eb37244465e857d15a26d3a85a5410648ccb53b18bd44cb3a7336" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "toml_datetime" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808b51e57d0ef8f71115d8f3a01e7d3750d01c79cac4b3eda910f4389fdf92fd" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1541ba70885967e662f69d31ab3aeca7b1aaecfcd58679590b893e9239c3646" +dependencies = [ + "combine", + "indexmap", + "itertools", + "serde", + "toml_datetime", +] + +[[package]] +name = "trycmd" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e381af441e13a3635303d26769620a9454aef05ec3303711efc3f1dd785a33af" +dependencies = [ + "escargot", + "glob", + "humantime", + "humantime-serde", + "rayon", + "serde", + "shlex", + "snapbox", + "toml_edit", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +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 = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/circ_opt/Cargo.toml b/circ_opt/Cargo.toml new file mode 100644 index 00000000..d66ecdac --- /dev/null +++ b/circ_opt/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "circ_opt" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4", features = ["derive", "env"] } + +[dev-dependencies] +trycmd = { version = "0.14", features = ["examples"] } +heck = "0.4" diff --git a/circ_opt/README.md b/circ_opt/README.md new file mode 100644 index 00000000..37e69361 --- /dev/null +++ b/circ_opt/README.md @@ -0,0 +1,491 @@ +Basic option system for CirC. + +## Tests ([`trycmd`](https://docs.rs/trycmd/latest/trycmd/index.html)) + +These tests are based on the example binary in `examples/parser.rs`. +It contains a `clap::Parser` that simply includes `CircOpt`: +```rust +use clap::Parser; +use circ_opt::CircOpt; + +#[derive(Parser, Debug)] +struct BinaryOpt { + #[command(flatten)] + pub circ: CircOpt, +} + +fn main() { + let opt = BinaryOpt::parse(); + println!("{:#?}", opt); +} +``` + +### Help Messages +```console +$ parser --help +? 0 +Options that configure CirC + +Usage: parser [OPTIONS] + +Options: + --r1cs-verified + Use the verified field-blaster + + [env: R1CS_VERIFIED=] + [default: false] + [possible values: true, false] + + --r1cs-div-by-zero + Which field division-by-zero semantics to encode in R1cs + + [env: R1CS_DIV_BY_ZERO=] + [default: incomplete] + + Possible values: + - incomplete: Division-by-zero renders the circuit incomplete + - zero: Division-by-zero gives zero + - non-det: Division-by-zero gives a per-division unspecified result + + --r1cs-lc-elim-thresh + linear combination constraints up to this size will be eliminated + + [env: R1CS_LC_ELIM_THRESH=] + [default: 50] + + --field-builtin + Which field to use + + [env: FIELD_BUILTIN=] + [default: bls12381] + + Possible values: + - bls12381: BLS12-381 scalar field + - bn254: BN-254 scalar field + + --field-custom-modulus + Which modulus to use (overrides [FieldOpt::builtin]) + + [env: FIELD_CUSTOM_MODULUS=] + [default: ] + + --zsharp-isolate-asserts + In Z#, "isolate" assertions. That is, assertions in if/then/else expressions only take effect if that branch is active. + + See `--branch-isolation` in [ZoKrates](https://zokrates.github.io/language/control_flow.html). + + [env: ZSHARP_ISOLATE_ASSERTS=] + [default: false] + [possible values: true, false] + + --datalog-rec-limit + How many recursions to allow + + [env: DATALOG_REC_LIMIT=] + [default: 5] + + --datalog-lint-prim-rec + Lint recursions that are allegedly primitive recursive + + [env: DATALOG_LINT_PRIM_REC=] + [default: false] + [possible values: true, false] + + -h, --help + Print help information (use `-h` for a summary) + +``` +```console +$ parser -h +? 0 +Options that configure CirC + +Usage: parser [OPTIONS] + +Options: + --r1cs-verified + Use the verified field-blaster [env: R1CS_VERIFIED=] [default: false] [possible values: true, false] + --r1cs-div-by-zero + Which field division-by-zero semantics to encode in R1cs [env: R1CS_DIV_BY_ZERO=] [default: incomplete] [possible values: incomplete, zero, non-det] + --r1cs-lc-elim-thresh + linear combination constraints up to this size will be eliminated [env: R1CS_LC_ELIM_THRESH=] [default: 50] + --field-builtin + Which field to use [env: FIELD_BUILTIN=] [default: bls12381] [possible values: bls12381, bn254] + --field-custom-modulus + Which modulus to use (overrides [FieldOpt::builtin]) [env: FIELD_CUSTOM_MODULUS=] [default: ] + --zsharp-isolate-asserts + In Z#, "isolate" assertions. That is, assertions in if/then/else expressions only take effect if that branch is active [env: ZSHARP_ISOLATE_ASSERTS=] [default: false] [possible values: true, false] + --datalog-rec-limit + How many recursions to allow [env: DATALOG_REC_LIMIT=] [default: 5] + --datalog-lint-prim-rec + Lint recursions that are allegedly primitive recursive [env: DATALOG_LINT_PRIM_REC=] [default: false] [possible values: true, false] + -h, --help + Print help information (use `--help` for more detail) + +``` + +### Defaults +```console +$ parser +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: false, + div_by_zero: Incomplete, + lc_elim_thresh: 50, + }, + field: FieldOpt { + builtin: Bls12381, + custom_modulus: "", + }, + zsharp: ZsharpOpt { + isolate_asserts: false, + }, + datalog: DatalogOpt { + rec_limit: 5, + lint_prim_rec: false, + }, + }, +} + +``` + +### R1CS Options +```console +$ parser --r1cs-verified true +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: true, + div_by_zero: Incomplete, + lc_elim_thresh: 50, + }, + field: FieldOpt { + builtin: Bls12381, + custom_modulus: "", + }, + zsharp: ZsharpOpt { + isolate_asserts: false, + }, + datalog: DatalogOpt { + rec_limit: 5, + lint_prim_rec: false, + }, + }, +} + +``` +```console +$ parser --r1cs-verified false +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: false, + div_by_zero: Incomplete, + lc_elim_thresh: 50, + }, + field: FieldOpt { + builtin: Bls12381, + custom_modulus: "", + }, + zsharp: ZsharpOpt { + isolate_asserts: false, + }, + datalog: DatalogOpt { + rec_limit: 5, + lint_prim_rec: false, + }, + }, +} + +``` +```console +$ parser --r1cs-div-by-zero non-det +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: false, + div_by_zero: NonDet, + lc_elim_thresh: 50, + }, + field: FieldOpt { + builtin: Bls12381, + custom_modulus: "", + }, + zsharp: ZsharpOpt { + isolate_asserts: false, + }, + datalog: DatalogOpt { + rec_limit: 5, + lint_prim_rec: false, + }, + }, +} + +``` +```console +$ parser --r1cs-div-by-zero incomplete +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: false, + div_by_zero: Incomplete, + lc_elim_thresh: 50, + }, + field: FieldOpt { + builtin: Bls12381, + custom_modulus: "", + }, + zsharp: ZsharpOpt { + isolate_asserts: false, + }, + datalog: DatalogOpt { + rec_limit: 5, + lint_prim_rec: false, + }, + }, +} + +``` +```console +$ parser --r1cs-div-by-zero zero +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: false, + div_by_zero: Zero, + lc_elim_thresh: 50, + }, + field: FieldOpt { + builtin: Bls12381, + custom_modulus: "", + }, + zsharp: ZsharpOpt { + isolate_asserts: false, + }, + datalog: DatalogOpt { + rec_limit: 5, + lint_prim_rec: false, + }, + }, +} + +``` +```console +$ R1CS_DIV_BY_ZERO=non-det parser --r1cs-lc-elim-thresh 11 +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: false, + div_by_zero: NonDet, + lc_elim_thresh: 11, + }, + field: FieldOpt { + builtin: Bls12381, + custom_modulus: "", + }, + zsharp: ZsharpOpt { + isolate_asserts: false, + }, + datalog: DatalogOpt { + rec_limit: 5, + lint_prim_rec: false, + }, + }, +} + +``` +```console +$ R1CS_VERIFIED=true R1CS_LC_ELIM_THRESH=10 parser +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: true, + div_by_zero: Incomplete, + lc_elim_thresh: 10, + }, + field: FieldOpt { + builtin: Bls12381, + custom_modulus: "", + }, + zsharp: ZsharpOpt { + isolate_asserts: false, + }, + datalog: DatalogOpt { + rec_limit: 5, + lint_prim_rec: false, + }, + }, +} + +``` + +### Field Options + +```console +$ FIELD_CUSTOM_MODULUS=7 parser --field-builtin bn254 +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: false, + div_by_zero: Incomplete, + lc_elim_thresh: 50, + }, + field: FieldOpt { + builtin: Bn254, + custom_modulus: "7", + }, + zsharp: ZsharpOpt { + isolate_asserts: false, + }, + datalog: DatalogOpt { + rec_limit: 5, + lint_prim_rec: false, + }, + }, +} + +``` + +```console +$ FIELD_BUILTIN=bn254 parser --field-custom-modulus 7 +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: false, + div_by_zero: Incomplete, + lc_elim_thresh: 50, + }, + field: FieldOpt { + builtin: Bn254, + custom_modulus: "7", + }, + zsharp: ZsharpOpt { + isolate_asserts: false, + }, + datalog: DatalogOpt { + rec_limit: 5, + lint_prim_rec: false, + }, + }, +} + +``` + +### Z# Options + +```console +$ ZSHARP_ISOLATE_ASSERTS=true parser +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: false, + div_by_zero: Incomplete, + lc_elim_thresh: 50, + }, + field: FieldOpt { + builtin: Bls12381, + custom_modulus: "", + }, + zsharp: ZsharpOpt { + isolate_asserts: true, + }, + datalog: DatalogOpt { + rec_limit: 5, + lint_prim_rec: false, + }, + }, +} + +``` + +```console +$ parser --zsharp-isolate-asserts true +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: false, + div_by_zero: Incomplete, + lc_elim_thresh: 50, + }, + field: FieldOpt { + builtin: Bls12381, + custom_modulus: "", + }, + zsharp: ZsharpOpt { + isolate_asserts: true, + }, + datalog: DatalogOpt { + rec_limit: 5, + lint_prim_rec: false, + }, + }, +} + +``` + +### Datalog Options + +```console +$ DATALOG_LINT_PRIM_REC=true parser --datalog-rec-limit 10 +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: false, + div_by_zero: Incomplete, + lc_elim_thresh: 50, + }, + field: FieldOpt { + builtin: Bls12381, + custom_modulus: "", + }, + zsharp: ZsharpOpt { + isolate_asserts: false, + }, + datalog: DatalogOpt { + rec_limit: 10, + lint_prim_rec: true, + }, + }, +} + +``` + +```console +$ DATALOG_REC_LIMIT=15 parser --datalog-lint-prim-rec true +? 0 +BinaryOpt { + circ: CircOpt { + r1cs: R1csOpt { + verified: false, + div_by_zero: Incomplete, + lc_elim_thresh: 50, + }, + field: FieldOpt { + builtin: Bls12381, + custom_modulus: "", + }, + zsharp: ZsharpOpt { + isolate_asserts: false, + }, + datalog: DatalogOpt { + rec_limit: 15, + lint_prim_rec: true, + }, + }, +} + +``` diff --git a/circ_opt/examples/parser.rs b/circ_opt/examples/parser.rs new file mode 100644 index 00000000..45eb4e9e --- /dev/null +++ b/circ_opt/examples/parser.rs @@ -0,0 +1,13 @@ +use circ_opt::CircOpt; +use clap::Parser; + +#[derive(Parser, Debug)] +struct BinaryOpt { + #[command(flatten)] + pub circ: CircOpt, +} + +fn main() { + let opt = BinaryOpt::parse(); + println!("{:#?}", opt); +} diff --git a/circ_opt/src/lib.rs b/circ_opt/src/lib.rs new file mode 100644 index 00000000..5fc4e5bc --- /dev/null +++ b/circ_opt/src/lib.rs @@ -0,0 +1,244 @@ +//! Options for CirC. +//! +//! ## Contents +//! +//! * A type for circ options [CircOpt] containing fields for module options: +//! * `r1cs`: [R1csOpt] +//! * `datalog`: [DatalogOpt] +//! * `zsharp`: [ZsharpOpt] +//! * `field`: [FieldOpt] +//! * all options types implement: +//! * std's [Default] +//! * clap's [Args]; all options are settable by +//! * environmental variable (SHOUTY_SNEK_CASE), e.g., `"R1CS_LC_ELIM_THRESH"` +//! * long option (kebab-case), e.g., `"--r1cs-lc-elim-thresh"` +//! * these a guaranteed to agree (and we test this) +//! +//! ## Constructing custom options in a compiler +//! +//! We recommend that compilers construct custom options using [`clap`][clap]. +//! Simply use our (rexported) version of clap in your compiler ([crate::clap]) +//! and include [CircOpt] in your [clap::Parser]. +//! +//! ```rust +//! use circ_opt::{CircOpt, clap::Parser}; +//! +//! #[derive(Parser, Debug)] +//! struct BinaryOpt { +//! #[command(flatten)] +//! pub circ: CircOpt, +//! } +//! +//! fn main() { +//! let opt = BinaryOpt::parse(); +//! } +//! ``` +//! +//! [clap]: https://crates.io/crates/clap + +use clap::{ArgAction, Args, ValueEnum}; + +use std::default::Default; + +/// Re-export our version of clap. +pub use clap; + +#[derive(Args, Debug, Clone, Default, PartialEq, Eq)] +/// Options that configure CirC +pub struct CircOpt { + /// Options for the R1cs backend + #[command(flatten)] + pub r1cs: R1csOpt, + /// Options for the prime field used + #[command(flatten)] + pub field: FieldOpt, + /// Options for the Z# frontend + #[command(flatten)] + pub zsharp: ZsharpOpt, + /// Options for the datalog frontend + #[command(flatten)] + pub datalog: DatalogOpt, +} + +/// Options for the R1cs backend +#[derive(Args, Debug, Clone, PartialEq, Eq)] +pub struct R1csOpt { + /// Use the verified field-blaster + #[arg(long = "r1cs-verified", env = "R1CS_VERIFIED", action = ArgAction::Set, default_value = "false")] + pub verified: bool, + + /// Which field division-by-zero semantics to encode in R1cs + #[arg( + long = "r1cs-div-by-zero", + env = "R1CS_DIV_BY_ZERO", + value_enum, + default_value = "incomplete" + )] + pub div_by_zero: FieldDivByZero, + + #[arg( + long = "r1cs-lc-elim-thresh", + env = "R1CS_LC_ELIM_THRESH", + default_value = "50" + )] + /// linear combination constraints up to this size will be eliminated + pub lc_elim_thresh: usize, +} + +impl Default for R1csOpt { + fn default() -> Self { + Self { + verified: false, + div_by_zero: FieldDivByZero::Incomplete, + lc_elim_thresh: 50, + } + } +} + +#[derive(ValueEnum, Debug, PartialEq, Eq, Clone, Copy)] +/// Which field division-by-zero semantics to encode in R1cs +pub enum FieldDivByZero { + /// Division-by-zero renders the circuit incomplete + Incomplete, + /// Division-by-zero gives zero + Zero, + /// Division-by-zero gives a per-division unspecified result + NonDet, +} + +impl Default for FieldDivByZero { + fn default() -> Self { + FieldDivByZero::Incomplete + } +} + +/// Options for the prime field used +#[derive(Args, Debug, Default, Clone, PartialEq, Eq)] +pub struct FieldOpt { + /// Which field to use + #[arg( + long = "field-builtin", + env = "FIELD_BUILTIN", + value_enum, + default_value = "bls12381" + )] + pub builtin: BuiltinField, + + /// Which modulus to use (overrides [FieldOpt::builtin]) + #[arg( + long = "field-custom-modulus", + env = "FIELD_CUSTOM_MODULUS", + default_value = "" + )] + pub custom_modulus: String, +} + +#[derive(ValueEnum, Debug, PartialEq, Eq, Clone, Copy)] +/// Which field to use +pub enum BuiltinField { + /// BLS12-381 scalar field + Bls12381, + /// BN-254 scalar field + Bn254, +} + +impl Default for BuiltinField { + fn default() -> Self { + BuiltinField::Bls12381 + } +} + +/// Options for the datalog frontend +#[derive(Args, Debug, Default, Clone, PartialEq, Eq)] +pub struct ZsharpOpt { + /// In Z#, "isolate" assertions. That is, assertions in if/then/else expressions only take + /// effect if that branch is active. + /// + /// See `--branch-isolation` in + /// [ZoKrates](https://zokrates.github.io/language/control_flow.html). + #[arg(long = "zsharp-isolate-asserts", env = "ZSHARP_ISOLATE_ASSERTS", action = ArgAction::Set, default_value = "false")] + pub isolate_asserts: bool, +} + +/// Options for the datalog frontend +#[derive(Args, Debug, Clone, PartialEq, Eq)] +pub struct DatalogOpt { + /// How many recursions to allow + #[arg( + long = "datalog-rec-limit", + env = "DATALOG_REC_LIMIT", + name = "N", + default_value = "5" + )] + pub rec_limit: usize, + + /// Lint recursions that are allegedly primitive recursive + #[arg(long = "datalog-lint-prim-rec", env = "DATALOG_LINT_PRIM_REC", action = ArgAction::Set, default_value = "false")] + pub lint_prim_rec: bool, +} + +impl Default for DatalogOpt { + fn default() -> Self { + Self { + rec_limit: 5, + lint_prim_rec: false, + } + } +} + +#[cfg(test)] +mod test { + + use super::*; + + use clap::{CommandFactory, Parser}; + use heck::{ToKebabCase, ToShoutySnekCase}; + + #[derive(Parser, Debug)] + struct BinaryOpt { + #[command(flatten)] + pub circ: CircOpt, + } + + #[test] + fn std_and_clap_defaults_agree() { + let std_default: CircOpt = Default::default(); + let clap_default: CircOpt = BinaryOpt::parse_from::<_, &str>(std::iter::empty()).circ; + assert_eq!(std_default, clap_default); + } + + #[test] + fn long_and_env_names_agree() { + for arg in BinaryOpt::command().get_arguments() { + if let Some(long_name) = arg.get_long() { + if let Some(env_name) = arg.get_env() { + let env_name = env_name.to_str().unwrap(); + assert_eq!( + env_name, + long_name.TO_SHOUTY_SNEK_CASE(), + "The long name\n '{}'\ndoes not match the envvar name\n '{}'\n", + long_name, + env_name, + ); + assert_eq!( + env_name, + env_name.TO_SHOUTY_SNEK_CASE(), + "The envvar name '{}' is not in SHOUTY_SNEK_CASE", + env_name, + ); + assert_eq!( + long_name, + long_name.to_kebab_case(), + "The long name '{}' is not in kebab-case", + long_name, + ); + } else { + panic!("Long option '{}' has no envvar", long_name); + } + } else if let Some(env_name) = arg.get_env() { + let env_name = env_name.to_str().unwrap(); + panic!("Envar option '{}' has no long_name", env_name); + } + } + } +} diff --git a/circ_opt/tests/trycmd.rs b/circ_opt/tests/trycmd.rs new file mode 100644 index 00000000..3c584424 --- /dev/null +++ b/circ_opt/tests/trycmd.rs @@ -0,0 +1,6 @@ +#[test] +fn trycmd() { + trycmd::TestCases::new() + .register_bins(trycmd::cargo::compile_examples([]).unwrap()) + .case("README.md"); +} diff --git a/driver.py b/driver.py index d5d02911..7df7d4fb 100755 --- a/driver.py +++ b/driver.py @@ -7,6 +7,16 @@ import sys from util import * +def log_run_check(cmd): + s = ( + " ".join(f"'{tok}'" if " " in tok else tok for tok in cmd) + if type(cmd) == list + else cmd + ) + print(f"Running: {s}") + return subprocess.run(cmd, check=True) + + def install(features): """ Used for installing third party libraries @@ -16,7 +26,7 @@ def install(features): features : set of str set of features required """ - + def verify_path_empty(path) -> bool: return not os.path.isdir(path) or (os.path.isdir(path) and not os.listdir(path)) @@ -24,7 +34,8 @@ def install(features): if f == "aby": if verify_path_empty(ABY_SOURCE): subprocess.run( - ["git", "clone", "https://github.com/edwjchen/ABY.git", ABY_SOURCE]) + ["git", "clone", "https://github.com/edwjchen/ABY.git", ABY_SOURCE] + ) subprocess.run(["./scripts/build_aby.zsh"]) # install python requirements @@ -45,8 +56,9 @@ def check(features): cargo_features = filter_cargo_features(features) if cargo_features: cmd = cmd + ["--features"] + cargo_features - if "ristretto255" in features: cmd = cmd + ["--no-default-features"] - subprocess.run(cmd, check=True) + if "ristretto255" in features: + cmd = cmd + ["--no-default-features"] + log_run_check(cmd) def build(features): @@ -65,7 +77,7 @@ def build(features): cmd = ["cargo", "build"] if mode: - cmd += ["--"+mode] + cmd += ["--" + mode] else: # default to release mode cmd += ["--release"] @@ -74,18 +86,17 @@ def build(features): cargo_features = filter_cargo_features(features) if cargo_features: cmd = cmd + ["--features"] + cargo_features - if "ristretto255" in features: cmd = cmd + ["--no-default-features"] + if "ristretto255" in features: + cmd = cmd + ["--no-default-features"] - print(cmd) - subprocess.run(cmd, check=True) + log_run_check(cmd) if "aby" in features: if "c" in features: - subprocess.run(["./scripts/build_mpc_c_test.zsh"], check=True) + log_run_check(["./scripts/build_mpc_c_test.zsh"]) if "smt" in features and "zok" in features: - subprocess.run( - ["./scripts/build_mpc_zokrates_test.zsh"], check=True) - subprocess.run(["./scripts/build_aby.zsh"], check=True) + log_run_check(["./scripts/build_mpc_zokrates_test.zsh"]) + log_run_check(["./scripts/build_aby.zsh"]) def test(features, extra_args): @@ -113,34 +124,33 @@ def test(features, extra_args): test_cmd += ["--no-default-features"] test_cmd_release += ["--no-default-features"] if len(extra_args) > 0: - test_cmd += ["--"] + extra_args - test_cmd_release += ["--"] + extra_args + test_cmd += extra_args + test_cmd_release += extra_args - subprocess.run(test_cmd, check=True) + log_run_check(test_cmd) if load_mode() == "release": - subprocess.run(test_cmd_release, check=True) + log_run_check(test_cmd_release) if "r1cs" in features and "smt" in features: - subprocess.run(["./scripts/test_datalog.zsh"], check=True) + log_run_check(["./scripts/test_datalog.zsh"]) if "zok" in features and "smt" in features: if "aby" in features: - subprocess.run( - ["python3", "./scripts/aby_tests/zokrates_test_aby.py"], check=True) + log_run_check(["python3", "./scripts/aby_tests/zokrates_test_aby.py"]) if "lp" in features: - subprocess.run(["./scripts/test_zok_to_ilp.zsh"], check=True) + log_run_check(["./scripts/test_zok_to_ilp.zsh"]) if "r1cs" in features: - if "ristretto255" in features: # spartan field - subprocess.run(["./scripts/spartan_zok_test.zsh"], check=True) - else: # bellman field - subprocess.run(["./scripts/zokrates_test.zsh"], check=True) + if "ristretto255" in features: # spartan field + log_run_check(["./scripts/spartan_zok_test.zsh"]) + else: # bellman field + log_run_check(["./scripts/zokrates_test.zsh"]) if "lp" in features and "r1cs" in features: - subprocess.run(["./scripts/test_zok_to_ilp_pf.zsh"], check=True) + log_run_check(["./scripts/test_zok_to_ilp_pf.zsh"]) if "c" in features: if "aby" in features: - subprocess.run( - ["python3", "./scripts/aby_tests/c_test_aby.py"], check=True) + log_run_check(["python3", "./scripts/aby_tests/c_test_aby.py"]) + def benchmark(features): mode = load_mode() @@ -150,7 +160,7 @@ def benchmark(features): cmd = ["cargo", "build"] if mode: - cmd += ["--"+mode] + cmd += ["--" + mode] else: # default to release mode cmd += ["--release"] @@ -159,13 +169,14 @@ def benchmark(features): cargo_features = filter_cargo_features(features) if cargo_features: cmd = cmd + ["--features"] + cargo_features - if "ristretto255" in features: cmd = cmd + ["--no-default-features"] - subprocess.run(cmd, check=True) + if "ristretto255" in features: + cmd = cmd + ["--no-default-features"] + log_run_check(cmd) def format(): print("formatting!") - subprocess.run(["cargo", "fmt", "--all"], check=True) + log_run_check(["cargo", "fmt", "--all"]) def lint(): @@ -183,8 +194,9 @@ def lint(): cargo_features = filter_cargo_features(features) if cargo_features: cmd = cmd + ["--features"] + cargo_features - if "ristretto255" in features: cmd = cmd + ["--no-default-features"] - subprocess.run(cmd, check=True) + if "ristretto255" in features: + cmd = cmd + ["--no-default-features"] + log_run_check(cmd) def flamegraph(features, extra): @@ -192,26 +204,29 @@ def flamegraph(features, extra): cargo_features = filter_cargo_features(features) if cargo_features: cmd = cmd + ["--features"] + cargo_features - if "ristretto255" in features: cmd = cmd + ["--no-default-features"] + if "ristretto255" in features: + cmd = cmd + ["--no-default-features"] cmd += extra print("running:", " ".join(cmd)) - subprocess.run(cmd, check=True) + log_run_check(cmd) def clean(features): print("cleaning!") if "aby" in features: - subprocess.run(["./scripts/clean_aby.zsh"]) - subprocess.run(["rm", "-rf", "scripts/aby_tests/__pycache__"]) - subprocess.run(["rm", "-rf", "P", "V", "pi", - "perf.data perf.data.old flamegraph.svg"]) + log_run_check(["./scripts/clean_aby.zsh"]) + log_run_check(["rm", "-rf", "scripts/aby_tests/__pycache__"]) + log_run_check( + ["rm", "-rf", "P", "V", "pi", "perf.data perf.data.old flamegraph.svg"] + ) + log_run_check(["cargo", "clean"]) def set_mode(mode): def verify_mode(mode): if mode not in ("debug", "release"): - raise RuntimeError( - f"Unknown mode: {mode}, --mode ") + raise RuntimeError(f"Unknown mode: {mode}, --mode ") + verify_mode(mode) save_mode(mode) @@ -233,6 +248,7 @@ def set_features(features): if f in valid_features | {"ristretto255"}: return True return False + features = set(sorted([f for f in features if verify_feature(f)])) save_features(features) print("Feature set:", sorted(list(features))) @@ -246,48 +262,83 @@ def format_sub_process_cmd(r: subprocess.CalledProcessError) -> str: if __name__ == "__main__": try: parser = argparse.ArgumentParser() - parser.add_argument("-i", "--install", action="store_true", - help="install all dependencies from the feature set") parser.add_argument( - "-c", "--check", action="store_true", help="run `cargo check`") - parser.add_argument("-b", "--build", action="store_true", - help="run `cargo build` and build all dependencies from the feature set") - parser.add_argument("-t", "--test", action="store_true", - help="build and test all dependencies from the feature set") + "-i", + "--install", + action="store_true", + help="install all dependencies from the feature set", + ) parser.add_argument( - "-f", "--format", action="store_true", help="run `cargo fmt --all`") + "-c", "--check", action="store_true", help="run `cargo check`" + ) parser.add_argument( - "-l", "--lint", action="store_true", help="run `cargo clippy`") - parser.add_argument("--flamegraph", action="store_true", - help="run `cargo flamegraph`") - parser.add_argument("-C", "--clean", action="store_true", - help="remove all generated files") - parser.add_argument("-m", "--mode", type=str, - help="set `debug` or `release` mode") - parser.add_argument("-A", "--all_features", - action="store_true", help="set all features on") - parser.add_argument("-L", "--list_features", - action="store_true", help="print active features") - parser.add_argument("-F", "--features", nargs="+", - help="set features on , reset features with -F none") + "-b", + "--build", + action="store_true", + help="run `cargo build` and build all dependencies from the feature set", + ) parser.add_argument( - "--benchmark", action="store_true", help="build benchmarks") - parser.add_argument("extra", metavar="PASS_THROUGH_ARGS", nargs=argparse.REMAINDER, - help="Extra arguments for --flamegraph. Prefix with --") + "-t", + "--test", + action="store_true", + help="build and test all dependencies from the feature set", + ) + parser.add_argument( + "-f", "--format", action="store_true", help="run `cargo fmt --all`" + ) + parser.add_argument( + "-l", "--lint", action="store_true", help="run `cargo clippy`" + ) + parser.add_argument( + "--flamegraph", action="store_true", help="run `cargo flamegraph`" + ) + parser.add_argument( + "-C", "--clean", action="store_true", help="remove all generated files" + ) + parser.add_argument( + "-m", "--mode", type=str, help="set `debug` or `release` mode" + ) + parser.add_argument( + "-A", "--all_features", action="store_true", help="set all features on" + ) + parser.add_argument( + "-L", "--list_features", action="store_true", help="print active features" + ) + parser.add_argument( + "-F", + "--features", + nargs="+", + help="set features on , reset features with -F none", + ) + parser.add_argument("--benchmark", action="store_true", help="build benchmarks") + parser.add_argument( + "extra", + metavar="PASS_THROUGH_ARGS", + nargs=argparse.REMAINDER, + help="Extra arguments for --flamegraph. Prefix with --", + ) args = parser.parse_args() def verify_single_action(args: argparse.Namespace): - actions = [k for k, v in vars(args).items() if ( - type(v) is bool or k in ["features", "mode"]) and bool(v)] + actions = [ + k + for k, v in vars(args).items() + if (type(v) is bool or k in ["features", "mode"]) and bool(v) + ] if len(actions) != 1: parser.error( - "parser error: only one action can be specified. got: " + " ".join(actions)) + "parser error: only one action can be specified. got: " + + " ".join(actions) + ) + verify_single_action(args) def verify_extra_implies_flamegraph_or_test(args: argparse.Namespace): if (not args.flamegraph and not args.test) and len(args.extra) > 0: parser.error( - "parser error: no --flamegraph or --test action, and extra arguments") + "parser error: no --flamegraph or --test action, and extra arguments" + ) + verify_extra_implies_flamegraph_or_test(args) features = load_features() diff --git a/examples/circ.rs b/examples/circ.rs index 2c3eae52..4068bbe1 100644 --- a/examples/circ.rs +++ b/examples/circ.rs @@ -9,6 +9,11 @@ use bellman::groth16::{ #[cfg(feature = "r1cs")] use bellman::Circuit; use bls12_381::{Bls12, Scalar}; +use circ::cfg::{ + cfg, + clap::{self, Args, Parser, Subcommand, ValueEnum}, + CircOpt, +}; #[cfg(feature = "c")] use circ::front::c::{self, C}; use circ::front::datalog::{self, Datalog}; @@ -35,7 +40,6 @@ use circ::target::r1cs::spartan::write_data; use circ::target::r1cs::trans::to_r1cs; #[cfg(feature = "smt")] use circ::target::smt::find_model; -use circ::util::field::DFL_T; use circ_fields::FieldT; use fxhash::FxHashMap as HashMap; #[cfg(feature = "lp")] @@ -44,87 +48,69 @@ use std::fs::File; use std::io::Read; use std::io::Write; use std::path::{Path, PathBuf}; -use structopt::clap::arg_enum; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] -#[structopt(name = "circ", about = "CirC: the circuit compiler")] +#[derive(Debug, Parser)] +#[command(name = "circ", about = "CirC: the circuit compiler")] struct Options { /// Input file - #[structopt(parse(from_os_str), name = "PATH")] + #[arg(name = "PATH")] path: PathBuf, - #[structopt(flatten)] + #[command(flatten)] frontend: FrontendOptions, + #[command(flatten)] + circ: CircOpt, + /// Number of parties for an MPC. - #[structopt(long, default_value = "2", name = "PARTIES")] + #[arg(long, default_value = "2", name = "PARTIES")] parties: u8, #[structopt(subcommand)] backend: Backend, } -#[derive(Debug, StructOpt)] +#[derive(Debug, Args)] struct FrontendOptions { /// Input language - #[structopt(long, default_value = "auto", name = "LANG")] + #[arg(long, default_value = "auto", name = "LANG")] language: Language, /// Value threshold - #[structopt(long)] + #[arg(long)] value_threshold: Option, - - /// How many recursions to allow (datalog) - #[structopt(short, long, name = "N", default_value = "5")] - rec_limit: usize, - - /// Lint recursions that are allegedly primitive recursive (datalog) - #[structopt(long)] - lint_prim_rec: bool, - - #[cfg(feature = "zok")] - /// In Z#, "isolate" assertions. That is, assertions in if/then/else expressions only take - /// effect if that branch is active. - /// - /// See `--branch-isolation` in - /// [ZoKrates](https://zokrates.github.io/language/control_flow.html). - #[structopt(long)] - z_isolate_asserts: bool, } -#[derive(Debug, StructOpt)] +#[derive(Debug, Subcommand)] enum Backend { #[allow(dead_code)] R1cs { - #[structopt(long, default_value = "P", parse(from_os_str))] + #[arg(long, default_value = "P")] prover_key: PathBuf, - #[structopt(long, default_value = "V", parse(from_os_str))] + #[arg(long, default_value = "V")] verifier_key: PathBuf, - #[structopt(long, default_value = "50")] + #[arg(long, default_value = "50")] /// linear combination constraints up to this size will be eliminated lc_elimination_thresh: usize, - #[structopt(long, default_value = "count")] + #[arg(long, default_value = "count")] action: ProofAction, }, Smt {}, Ilp {}, Mpc { - #[structopt(long, default_value = "hycc", name = "cost_model")] + #[arg(long, default_value = "hycc", name = "cost_model")] cost_model: String, - #[structopt(long, default_value = "lp", name = "selection_scheme")] + #[arg(long, default_value = "lp", name = "selection_scheme")] selection_scheme: String, }, } -arg_enum! { - #[derive(PartialEq, Eq, Debug)] - enum Language { - Zsharp, - Datalog, - C, - Auto, - } +#[derive(PartialEq, Eq, Debug, Clone, ValueEnum)] +enum Language { + Zsharp, + Datalog, + C, + Auto, } #[derive(PartialEq, Eq, Debug)] @@ -140,13 +126,11 @@ pub enum CostModelType { Hycc, } -arg_enum! { - #[derive(PartialEq, Eq, Debug)] - enum ProofAction { - Count, - Setup, - SpartanSetup, - } +#[derive(PartialEq, Eq, Debug, Clone, ValueEnum)] +enum ProofAction { + Count, + Setup, + SpartanSetup, } fn determine_language(l: &Language, input_path: &Path) -> DeterminedLanguage { @@ -175,7 +159,8 @@ fn main() { .format_level(false) .format_timestamp(None) .init(); - let options = Options::from_args(); + let options = Options::parse(); + circ::cfg::set(&options.circ); let path_buf = options.path.clone(); println!("{:?}", options); let mode = match options.backend { @@ -194,7 +179,6 @@ fn main() { let inputs = zsharp::Inputs { file: options.path, mode, - isolate_asserts: options.frontend.z_isolate_asserts, }; ZSharpFE::gen(inputs) } @@ -203,11 +187,7 @@ fn main() { panic!("Missing feature: smt,zok"); } DeterminedLanguage::Datalog => { - let inputs = datalog::Inputs { - file: options.path, - rec_limit: options.frontend.rec_limit, - lint_prim_rec: options.frontend.lint_prim_rec, - }; + let inputs = datalog::Inputs { file: options.path }; Datalog::gen(inputs) } #[cfg(feature = "c")] @@ -285,15 +265,13 @@ fn main() { action, prover_key, verifier_key, - lc_elimination_thresh, .. } => { println!("Converting to r1cs"); - let (r1cs, mut prover_data, verifier_data) = - to_r1cs(cs.get("main").clone(), FieldT::from(DFL_T.modulus())); + let (r1cs, mut prover_data, verifier_data) = to_r1cs(cs.get("main").clone(), cfg()); println!("Pre-opt R1cs size: {}", r1cs.constraints().len()); - let r1cs = reduce_linearities(r1cs, Some(lc_elimination_thresh)); + let r1cs = reduce_linearities(r1cs, cfg()); println!("Final R1cs size: {}", r1cs.constraints().len()); // save the optimized r1cs: the prover needs it to synthesize. @@ -363,7 +341,7 @@ fn main() { } #[cfg(feature = "smt")] Backend::Smt { .. } => { - if options.frontend.lint_prim_rec { + if options.circ.datalog.lint_prim_rec { let main_comp = cs.get("main").clone(); assert_eq!(main_comp.outputs.len(), 1); match find_model(&main_comp.outputs[0]) { diff --git a/examples/opa_bench.rs b/examples/opa_bench.rs index 7e2009d0..f01611f8 100644 --- a/examples/opa_bench.rs +++ b/examples/opa_bench.rs @@ -1,16 +1,16 @@ +use circ::cfg::clap::{self, Parser}; use circ::ir::term::*; use circ::target::aby::assignment::ilp; use circ::term; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] -#[structopt( +#[derive(Debug, Parser)] +#[command( name = "opa_bench", about = "Optimal Protocol Assignment via ILP benchmarker" )] struct Options { /// Number of parties for an MPC. If missing, generates a proof circuit. - #[structopt(name = "MULTS")] + #[arg(name = "MULTS")] n_mults: u32, } @@ -19,7 +19,7 @@ fn main() { .format_level(false) .format_timestamp(None) .init(); - let options = Options::from_args(); + let options = Options::parse(); let v = leaf_term(Op::Var("a".to_owned(), Sort::BitVector(32))); let mut t = v.clone(); for _i in 0..options.n_mults { diff --git a/examples/zk.rs b/examples/zk.rs index 22b44f67..5f6ccef5 100644 --- a/examples/zk.rs +++ b/examples/zk.rs @@ -1,39 +1,36 @@ use bls12_381::Bls12; +use circ::cfg::clap::{self, Parser, ValueEnum}; use circ::ir::term::text::parse_value_map; use circ::target::r1cs::bellman; use circ::target::r1cs::spartan; use std::path::PathBuf; -use structopt::clap::arg_enum; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] -#[structopt(name = "circ", about = "CirC: the circuit compiler")] +#[derive(Debug, Parser)] +#[command(name = "zk", about = "The CirC ZKP runner")] struct Options { - #[structopt(long, default_value = "P", parse(from_os_str))] + #[arg(long, default_value = "P")] prover_key: PathBuf, - #[structopt(long, default_value = "V", parse(from_os_str))] + #[arg(long, default_value = "V")] verifier_key: PathBuf, - #[structopt(long, default_value = "pi", parse(from_os_str))] + #[arg(long, default_value = "pi")] proof: PathBuf, - #[structopt(long, default_value = "in", parse(from_os_str))] + #[arg(long, default_value = "in")] inputs: PathBuf, - #[structopt(long, default_value = "pin", parse(from_os_str))] + #[arg(long, default_value = "pin")] pin: PathBuf, - #[structopt(long, default_value = "vin", parse(from_os_str))] + #[arg(long, default_value = "vin")] vin: PathBuf, - #[structopt(long)] + #[arg(long)] action: ProofAction, } -arg_enum! { - #[derive(PartialEq, Debug)] - /// `Prove`/`Verify` execute proving/verifying in bellman separately - /// `Spartan` executes both proving/verifying in spartan - enum ProofAction { - Prove, - Verify, - Spartan, - } +#[derive(PartialEq, Debug, Clone, ValueEnum)] +/// `Prove`/`Verify` execute proving/verifying in bellman separately +/// `Spartan` executes both proving/verifying in spartan +enum ProofAction { + Prove, + Verify, + Spartan, } fn main() { @@ -41,7 +38,7 @@ fn main() { .format_level(false) .format_timestamp(None) .init(); - let opts = Options::from_args(); + let opts = Options::parse(); match opts.action { ProofAction::Prove => { let input_map = parse_value_map(&std::fs::read(opts.inputs).unwrap()); diff --git a/examples/zxc.rs b/examples/zxc.rs index a3582bc9..09a227e0 100644 --- a/examples/zxc.rs +++ b/examples/zxc.rs @@ -10,74 +10,71 @@ use bls12_381::{Bls12, Scalar}; use circ::front::zsharp::{self, ZSharpFE}; use circ::front::{FrontEnd, Mode}; use circ::ir::opt::{opt, Opt}; -use circ_fields::FieldT; /* use circ::target::r1cs::bellman::parse_instance; */ use circ::target::r1cs::opt::reduce_linearities; use circ::target::r1cs::trans::to_r1cs; -use circ::util::field::DFL_T; /* use std::fs::File; use std::io::Read; use std::io::Write; */ +use circ::cfg::{ + cfg, + clap::{self, Parser, ValueEnum}, + CircOpt, +}; use std::path::PathBuf; -use structopt::clap::arg_enum; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] -#[structopt(name = "zxc", about = "CirC: the circuit compiler")] +#[derive(Debug, Parser)] +#[command(name = "zxc", about = "CirC: the circuit compiler")] struct Options { /// Input file - #[structopt(parse(from_os_str), name = "PATH")] + #[arg(name = "PATH")] path: PathBuf, /* - #[structopt(long, default_value = "P", parse(from_os_str))] + #[arg(long, default_value = "P", parse(from_os_str))] prover_key: PathBuf, - #[structopt(long, default_value = "V", parse(from_os_str))] + #[arg(long, default_value = "V", parse(from_os_str))] verifier_key: PathBuf, - #[structopt(long, default_value = "pi", parse(from_os_str))] + #[arg(long, default_value = "pi", parse(from_os_str))] proof: PathBuf, - #[structopt(long, default_value = "x", parse(from_os_str))] + #[arg(long, default_value = "x", parse(from_os_str))] instance: PathBuf, */ - #[structopt(short = "L")] + #[arg(short = 'L')] /// skip linearity reduction entirely skip_linred: bool, - #[structopt(long, default_value = "50")] - /// linear combination constraints up to this size will be eliminated (if the pass is enabled) - lc_elimination_thresh: usize, + #[command(flatten)] + /// CirC options + circ: CircOpt, - #[structopt(long, default_value = "count")] + #[arg(long, default_value = "count")] action: ProofAction, - #[structopt(short = "q")] + #[arg(short = 'q')] /// quiet mode: don't print R1CS at the end quiet: bool, } -arg_enum! { - #[derive(PartialEq, Debug)] - enum ProofAction { - Count, - Prove, - Setup, - Verify, - } +#[derive(PartialEq, Eq, Debug, Clone, ValueEnum)] +enum ProofAction { + Count, + Setup, + Prove, + Verify, } -arg_enum! { - #[derive(PartialEq, Debug)] - enum ProofOption { - Count, - Prove, - } +#[derive(PartialEq, Debug, Clone, ValueEnum)] +enum ProofOption { + Count, + Prove, } fn main() { @@ -85,14 +82,14 @@ fn main() { .format_level(false) .format_timestamp(None) .init(); - let options = Options::from_args(); + let options = Options::parse(); + circ::cfg::set(&options.circ); println!("{:?}", options); let cs = { let inputs = zsharp::Inputs { file: options.path, mode: Mode::Proof, - isolate_asserts: false, }; ZSharpFE::gen(inputs) }; @@ -132,7 +129,7 @@ fn main() { */ println!("Converting to r1cs"); - let (r1cs, _, _) = to_r1cs(cs.get("main").clone(), FieldT::from(DFL_T.modulus())); + let (r1cs, _, _) = to_r1cs(cs.get("main").clone(), cfg()); let r1cs = if options.skip_linred { println!("Skipping linearity reduction, as requested."); r1cs @@ -141,7 +138,7 @@ fn main() { "R1cs size before linearity reduction: {}", r1cs.constraints().len() ); - reduce_linearities(r1cs, Some(options.lc_elimination_thresh)) + reduce_linearities(r1cs, cfg()) }; println!("Final R1cs size: {}", r1cs.constraints().len()); match action { diff --git a/examples/zxi.rs b/examples/zxi.rs index 209e565f..3502fc1b 100644 --- a/examples/zxi.rs +++ b/examples/zxi.rs @@ -1,23 +1,22 @@ use circ::front::zsharp::{Inputs, ZSharpFE}; +use circ::cfg::{ + clap::{self, Parser}, + CircOpt, +}; use circ::front::Mode; use std::path::PathBuf; -use structopt::StructOpt; -#[derive(Debug, StructOpt)] -#[structopt(name = "circ", about = "CirC: the circuit compiler")] +#[derive(Debug, Parser)] +#[command(name = "zxi", about = "The Z# interpreter")] struct Options { /// Input file - #[structopt(parse(from_os_str))] + #[arg()] zsharp_path: PathBuf, - /// Number of parties for an MPC. If missing, generates a proof circuit. - #[structopt(short, long, name = "PARTIES")] - parties: Option, - - /// Whether to maximize the output - #[structopt(short, long)] - maximize: bool, + #[command(flatten)] + /// CirC options + circ: CircOpt, } fn main() { @@ -25,20 +24,11 @@ fn main() { .format_level(false) .format_timestamp(None) .init(); - let options = Options::from_args(); - //println!("{:?}", options); - let mode = if options.maximize { - Mode::Opt - } else { - match options.parties { - Some(p) => Mode::Mpc(p), - None => Mode::Proof, - } - }; + let options = Options::parse(); + circ::cfg::set(&options.circ); let inputs = Inputs { file: options.zsharp_path, - mode, - isolate_asserts: false, + mode: Mode::Proof, }; let cs = ZSharpFE::interpret(inputs); cs.pretty(&mut std::io::stdout().lock()) diff --git a/scripts/test_datalog.zsh b/scripts/test_datalog.zsh index 780381ea..1db6b37e 100755 --- a/scripts/test_datalog.zsh +++ b/scripts/test_datalog.zsh @@ -11,18 +11,18 @@ $BIN --language datalog ./examples/datalog/inv.pl r1cs --action count || true $BIN --language datalog ./examples/datalog/call.pl r1cs --action count || true $BIN --language datalog ./examples/datalog/arr.pl r1cs --action count || true # Small R1cs b/c too little recursion. -size=$(($BIN --language datalog ./examples/datalog/dumb_hash.pl -r 4 r1cs --action count || true) | egrep "Final R1cs size:" | egrep -o "\\b[0-9]+") +size=$(($BIN --language datalog ./examples/datalog/dumb_hash.pl --datalog-rec-limit 4 r1cs --action count || true) | egrep "Final R1cs size:" | egrep -o "\\b[0-9]+") [ "$size" -lt 10 ] # Big R1cs b/c enough recursion -size=$(($BIN --language datalog ./examples/datalog/dumb_hash.pl -r 5 r1cs --action count || true) | egrep "Final R1cs size:" | egrep -o "\\b[0-9]+") +size=$(($BIN --language datalog ./examples/datalog/dumb_hash.pl --datalog-rec-limit 5 r1cs --action count || true) | egrep "Final R1cs size:" | egrep -o "\\b[0-9]+") [ "$size" -gt 250 ] -size=$(($BIN --language datalog ./examples/datalog/dumb_hash.pl -r 10 r1cs --action count || true) | egrep "Final R1cs size:" | egrep -o "\\b[0-9]+") +size=$(($BIN --language datalog ./examples/datalog/dumb_hash.pl --datalog-rec-limit 10 r1cs --action count || true) | egrep "Final R1cs size:" | egrep -o "\\b[0-9]+") [ "$size" -gt 250 ] -size=$(($BIN --language datalog ./examples/datalog/dec.pl -r 2 r1cs --action count || true) | egrep "Final R1cs size:" | egrep -o "\\b[0-9]+") +size=$(($BIN --language datalog ./examples/datalog/dec.pl --datalog-rec-limit 2 r1cs --action count || true) | egrep "Final R1cs size:" | egrep -o "\\b[0-9]+") [ "$size" -gt 250 ] # Test prim-rec test -$BIN --language datalog ./examples/datalog/dec.pl --lint-prim-rec smt +$BIN --language datalog ./examples/datalog/dec.pl --datalog-lint-prim-rec true smt -($BIN --language datalog ./examples/datalog/not_dec.pl --lint-prim-rec smt || true) | egrep 'Not prim' +($BIN --language datalog ./examples/datalog/not_dec.pl --datalog-lint-prim-rec true smt || true) | egrep 'Not prim' diff --git a/scripts/zokrates_test.zsh b/scripts/zokrates_test.zsh index 0ae8c8ec..e21c22f1 100755 --- a/scripts/zokrates_test.zsh +++ b/scripts/zokrates_test.zsh @@ -45,7 +45,7 @@ function pf_test { # Test prove workflow with --z-isolate-asserts, given an example name function pf_test_isolate { ex_name=$1 - $BIN --z-isolate-asserts examples/ZoKrates/pf/$ex_name.zok r1cs --action setup + $BIN --zsharp-isolate-asserts true examples/ZoKrates/pf/$ex_name.zok r1cs --action setup $ZK_BIN --inputs examples/ZoKrates/pf/$ex_name.zok.pin --action prove $ZK_BIN --inputs examples/ZoKrates/pf/$ex_name.zok.vin --action verify rm -rf P V pi diff --git a/src/cfg.rs b/src/cfg.rs new file mode 100644 index 00000000..2312a89f --- /dev/null +++ b/src/cfg.rs @@ -0,0 +1,109 @@ +//! CirC Configuration +//! +//! This module contains two components: +//! * A type [CircCfg] for configuration information. +//! * Static configuration storage +//! * set with [set] and [set_cfg] +//! * read with [cfg] +//! * it can only be set once per process +//! * if you want to unit-test your component, we recommend that it **should not** use [cfg]. + +use circ_fields::FieldT; + +use once_cell::sync::OnceCell; +use rug::Integer; + +use std::convert::From; +use std::default::Default; + +/// Re-export our clap version +pub use circ_opt::clap; +/// Re-export our clap [clap::Args] +pub use circ_opt::CircOpt; + +/// A Circ configuration. Contructible [From::from] [CircOpt]. +#[derive(Clone, Debug)] +pub struct CircCfg { + opt: CircOpt, + field: FieldT, +} + +/// Set the CirC configuration from a [CircOpt]. +/// +/// If you want to build the CirC configuration [CircCfg] object yourself, +/// you can set it with [set_cfg]. +/// +/// [CircOpt] implements [clap::Args], so it can be build from your command line or envvars. See +/// its documentation. +pub fn set(o: &CircOpt) { + set_cfg(From::from(o.clone())) +} + +/// Set the CirC configuration to its defaults. +/// See [set] to customize +pub fn set_default() { + set_cfg(Default::default()) +} + +/// Set the CirC configuration from a [CircCfg]. +/// +/// We recommends using [set], which takes a [CircOpt] instead. +pub fn set_cfg(c: CircCfg) { + CFG.set(c).unwrap_or_else(|c| { + panic!( + "Tried to set the CirC configuration, but it had already been set.\nNew cfg:\n{:#?}", + c + ) + }) +} + +/// Get the configuration +pub fn cfg() -> &'static CircCfg { + CFG.get().expect("A component tried to read the CirC configuration, but it was not yet set. Did the top-level application call `circ::cfg::set`?") +} + +static CFG: OnceCell = OnceCell::new(); + +impl From for CircCfg { + fn from(opt: CircOpt) -> Self { + let field = if !opt.field.custom_modulus.is_empty() { + let error = + |r: &str| panic!("The field modulus '{}' is {}", &opt.field.custom_modulus, r); + let i = Integer::from_str_radix(&opt.field.custom_modulus, 10) + .unwrap_or_else(|_| error("not an integer")); + if i.is_probably_prime(30) == rug::integer::IsPrime::No { + error("not a prime"); + } + FieldT::from(i) + } else { + match opt.field.builtin { + circ_opt::BuiltinField::Bls12381 => FieldT::FBls12381, + circ_opt::BuiltinField::Bn254 => FieldT::FBn254, + } + }; + Self { opt, field } + } +} + +impl Default for CircCfg { + fn default() -> Self { + Self::from(CircOpt::default()) + } +} + +/// Used to expose all fields of [CircOpt]. +impl std::ops::Deref for CircCfg { + type Target = CircOpt; + + fn deref(&self) -> &Self::Target { + &self.opt + } +} + +/// Additional functionality +impl CircCfg { + /// The default field + pub fn field(&self) -> &FieldT { + &self.field + } +} diff --git a/src/front/datalog/mod.rs b/src/front/datalog/mod.rs index 3712b95f..607c9e60 100644 --- a/src/front/datalog/mod.rs +++ b/src/front/datalog/mod.rs @@ -9,6 +9,7 @@ use fxhash::FxHashMap; use log::debug; use rug::Integer; +use crate::cfg::cfg; use crate::circify::{Circify, Loc, Val}; use crate::front::{PROVER_VIS, PUBLIC_VIS}; use crate::ir::opt::cfold::fold; @@ -29,10 +30,6 @@ use parser::ast; pub struct Inputs { /// The file to look for `main` in. pub file: PathBuf, - /// How many recursions to tolerate - pub rec_limit: usize, - /// Should we lint primitive recursions? - pub lint_prim_rec: bool, } struct Gen<'ast> { @@ -381,7 +378,7 @@ pub struct Datalog; impl FrontEnd for Datalog { type Inputs = Inputs; fn gen(i: Inputs) -> Computations { - let mut f = File::open(&i.file).unwrap(); + let mut f = File::open(i.file).unwrap(); let mut buffer = String::new(); f.read_to_string(&mut buffer).unwrap(); let ast = parser::parse(&buffer); @@ -392,9 +389,9 @@ impl FrontEnd for Datalog { panic!("parse error!") } }; - let mut g = Gen::new(i.rec_limit); + let mut g = Gen::new(cfg().datalog.rec_limit); g.register_rules(&ast); - let r = if i.lint_prim_rec { + let r = if cfg().datalog.lint_prim_rec { g.lint_rules() } else { g.entry_rule("main") diff --git a/src/front/datalog/term.rs b/src/front/datalog/term.rs index a0a6fa3e..6f772670 100644 --- a/src/front/datalog/term.rs +++ b/src/front/datalog/term.rs @@ -7,9 +7,9 @@ use rug::Integer; use super::error::ErrorKind; use super::ty::Ty; +use crate::cfg::cfg; use crate::circify::{CirCtx, Embeddable, Typed}; use crate::ir::term::*; -use crate::util::field::DFL_T; /// A term #[derive(Debug, Clone)] @@ -63,7 +63,7 @@ pub fn pf_ir_lit(i: I) -> Term where Integer: From, { - leaf_term(Op::Const(Value::Field(DFL_T.new_v(i)))) + leaf_term(Op::Const(Value::Field(cfg().field().new_v(i)))) } /// Initialize a boolean literal @@ -81,10 +81,12 @@ impl Ty { match self { Self::Bool => Sort::Bool, Self::Uint(w) => Sort::BitVector(*w as usize), - Self::Field => Sort::Field(DFL_T.clone()), - Self::Array(n, b) => { - Sort::Array(Box::new(Sort::Field(DFL_T.clone())), Box::new(b.sort()), *n) - } + Self::Field => Sort::Field(cfg().field().clone()), + Self::Array(n, b) => Sort::Array( + Box::new(Sort::Field(cfg().field().clone())), + Box::new(b.sort()), + *n, + ), } } fn default_ir_term(&self) -> Term { @@ -316,7 +318,7 @@ pub fn or(s: &T, t: &T) -> Result { pub fn uint_to_field(s: &T) -> Result { match &s.ty { Ty::Uint(_) => Ok(T::new( - term![Op::UbvToPf(DFL_T.clone()); s.ir.clone()], + term![Op::UbvToPf(cfg().field().clone()); s.ir.clone()], Ty::Field, )), _ => Err(ErrorKind::InvalidUnOp("to_field".into(), s.clone())), @@ -393,7 +395,3 @@ impl Datalog { Self } } - -// fn idx_name(struct_name: &str, idx: usize) -> String { -// format!("{}.{}", struct_name, idx) -// } diff --git a/src/front/zsharp/mod.rs b/src/front/zsharp/mod.rs index afc98137..ee0f56af 100644 --- a/src/front/zsharp/mod.rs +++ b/src/front/zsharp/mod.rs @@ -5,11 +5,11 @@ mod term; pub mod zvisit; use super::{FrontEnd, Mode}; +use crate::cfg::cfg; use crate::circify::{CircError, Circify, Loc, Val}; use crate::front::{PROVER_VIS, PUBLIC_VIS}; use crate::ir::proof::ConstraintMetadata; use crate::ir::term::*; -use crate::util::field::DFL_T; use log::{debug, warn}; use rug::Integer; @@ -32,10 +32,6 @@ pub struct Inputs { pub file: PathBuf, /// The mode to generate for (MPC or proof). Effects visibility. pub mode: Mode, - /// Whether to isolate assertions. - /// - /// That is, whether assertions in in-active if/then/else branches are disabled. - pub isolate_asserts: bool, } /// The Z# front-end. Implements [FrontEnd]. @@ -46,11 +42,11 @@ impl FrontEnd for ZSharpFE { fn gen(i: Inputs) -> Computations { debug!( "Starting Z# front-end, field: {}", - Sort::Field(DFL_T.clone()) + Sort::Field(cfg().field().clone()) ); let loader = parser::ZLoad::new(); let asts = loader.load(&i.file); - let mut g = ZGen::new(asts, i.mode, loader.stdlib(), i.isolate_asserts); + let mut g = ZGen::new(asts, i.mode, loader.stdlib(), cfg().zsharp.isolate_asserts); g.visit_files(); g.file_stack_push(i.file); g.generics_stack_push(HashMap::new()); @@ -72,7 +68,7 @@ impl ZSharpFE { pub fn interpret(i: Inputs) -> T { let loader = parser::ZLoad::new(); let asts = loader.load(&i.file); - let mut g = ZGen::new(asts, i.mode, loader.stdlib(), i.isolate_asserts); + let mut g = ZGen::new(asts, i.mode, loader.stdlib(), cfg().zsharp.isolate_asserts); g.visit_files(); g.file_stack_push(i.file); g.generics_stack_push(HashMap::new()); @@ -330,7 +326,7 @@ impl<'ast> ZGen<'ast> { generics.len() )) } else { - Ok(uint_lit(DFL_T.modulus().significant_bits(), 32)) + Ok(uint_lit(cfg().field().modulus().significant_bits(), 32)) } } _ => Err(format!("Unknown or unimplemented builtin '{}'", f_name)), diff --git a/src/front/zsharp/term.rs b/src/front/zsharp/term.rs index f589186c..99c7c398 100644 --- a/src/front/zsharp/term.rs +++ b/src/front/zsharp/term.rs @@ -4,11 +4,11 @@ use std::fmt::{self, Display, Formatter}; use rug::Integer; +use crate::cfg::cfg; use crate::circify::{CirCtx, Embeddable, Typed}; use crate::front::field_list::FieldList; use crate::ir::opt::cfold::fold as constant_fold; use crate::ir::term::*; -use crate::util::field::DFL_T; #[derive(Clone, PartialEq, Eq)] pub enum Ty { @@ -57,10 +57,12 @@ impl Ty { match self { Self::Bool => Sort::Bool, Self::Uint(w) => Sort::BitVector(*w), - Self::Field => Sort::Field(DFL_T.clone()), - Self::Array(n, b) => { - Sort::Array(Box::new(Sort::Field(DFL_T.clone())), Box::new(b.sort()), *n) - } + Self::Field => Sort::Field(cfg().field().clone()), + Self::Array(n, b) => Sort::Array( + Box::new(Sort::Field(cfg().field().clone())), + Box::new(b.sort()), + *n, + ), Self::Struct(_name, fs) => { Sort::Tuple(fs.fields().map(|(_f_name, f_ty)| f_ty.sort()).collect()) } @@ -360,10 +362,10 @@ pub fn div(a: T, b: T) -> Result { } fn rem_field(a: Term, b: Term) -> Term { - let len = DFL_T.modulus().significant_bits() as usize; + let len = cfg().field().modulus().significant_bits() as usize; let a_bv = term![Op::PfToBv(len); a]; let b_bv = term![Op::PfToBv(len); b]; - term![Op::UbvToPf(DFL_T.clone()); term![Op::BvBinOp(BvBinOp::Urem); a_bv, b_bv]] + term![Op::UbvToPf(cfg().field().clone()); term![Op::BvBinOp(BvBinOp::Urem); a_bv, b_bv]] } fn rem_uint(a: Term, b: Term) -> Term { @@ -441,7 +443,7 @@ fn ult_uint(a: Term, b: Term) -> Term { // XXX(constr_opt) see TODO file - only need to expand to MIN of two bit-lengths if done right // XXX(constr_opt) do this using subtraction instead? fn field_comp(a: Term, b: Term, op: BvBinPred) -> Term { - let len = DFL_T.modulus().significant_bits() as usize; + let len = cfg().field().modulus().significant_bits() as usize; let a_bv = term![Op::PfToBv(len); a]; let b_bv = term![Op::PfToBv(len); b]; term![Op::BvBinPred(op); a_bv, b_bv] @@ -634,7 +636,7 @@ fn pf_val(i: I) -> Value where Integer: From, { - Value::Field(DFL_T.new_v(i)) + Value::Field(cfg().field().new_v(i)) } pub fn field_lit(i: I) -> T @@ -711,7 +713,7 @@ pub fn array_select(array: T, idx: T) -> Result { match array.ty { Ty::Array(_, elem_ty) if matches!(idx.ty, Ty::Uint(_) | Ty::Field) => { let iterm = if matches!(idx.ty, Ty::Uint(_)) { - term![Op::UbvToPf(DFL_T.clone()); idx.term] + term![Op::UbvToPf(cfg().field().clone()); idx.term] } else { idx.term }; @@ -725,7 +727,7 @@ pub fn array_store(array: T, idx: T, val: T) -> Result { if matches!(&array.ty, Ty::Array(_, _)) && matches!(&idx.ty, Ty::Uint(_) | Ty::Field) { // XXX(q) typecheck here? let iterm = if matches!(idx.ty, Ty::Uint(_)) { - term![Op::UbvToPf(DFL_T.clone()); idx.term] + term![Op::UbvToPf(cfg().field().clone()); idx.term] } else { idx.term }; @@ -756,7 +758,7 @@ fn ir_array>(sort: Sort, elems: I) -> Term { .collect::>(); let len = values.len() + to_insert.len(); let arr = leaf_term(Op::Const(Value::Array(Array::new( - Sort::Field(DFL_T.clone()), + Sort::Field(cfg().field().clone()), Box::new(sort.default_value()), values.into_iter().collect::>(), len, @@ -786,7 +788,10 @@ pub fn array>(elems: I) -> Result { pub fn uint_to_field(u: T) -> Result { match &u.ty { - Ty::Uint(_) => Ok(T::new(Ty::Field, term![Op::UbvToPf(DFL_T.clone()); u.term])), + Ty::Uint(_) => Ok(T::new( + Ty::Field, + term![Op::UbvToPf(cfg().field().clone()); u.term], + )), u => Err(format!("Cannot do uint-to-field on {}", u)), } } @@ -925,7 +930,7 @@ impl Embeddable for ZSharp { Ty::Field, ctx.cs.borrow_mut().new_var( &name, - Sort::Field(DFL_T.clone()), + Sort::Field(cfg().field().clone()), visibility, precompute.map(|p| p.term), ), diff --git a/src/ir/term/dist.rs b/src/ir/term/dist.rs index 3da10cc2..a75ab6cc 100644 --- a/src/ir/term/dist.rs +++ b/src/ir/term/dist.rs @@ -316,8 +316,6 @@ impl rand::distributions::Distribution for FixedSizeDist { pub mod test { use super::*; - use crate::util::field::DFL_T; - use fxhash::FxHashMap as HashMap; use quickcheck::{Arbitrary, Gen}; use rand::distributions::Distribution; @@ -337,7 +335,7 @@ pub mod test { let mut rng = rand::rngs::StdRng::seed_from_u64(u64::arbitrary(g)); let d = FixedSizeDist { bv_width: Some(8), - pf_t: Some(DFL_T.clone()), + pf_t: Some(FieldT::FBls12381), tuples: true, size: g.size(), sort: Sort::Bool, diff --git a/src/lib.rs b/src/lib.rs index 224f8fe9..161fc29c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ #[macro_use] pub mod ir; +pub mod cfg; pub mod circify; pub mod front; pub mod target; diff --git a/src/target/r1cs/mod.rs b/src/target/r1cs/mod.rs index eec6ca85..a4134c25 100644 --- a/src/target/r1cs/mod.rs +++ b/src/target/r1cs/mod.rs @@ -2,7 +2,6 @@ use circ_fields::{FieldT, FieldV}; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; -use lazy_static::lazy_static; use log::debug; use paste::paste; use rug::Integer; @@ -20,37 +19,6 @@ pub mod opt; pub mod spartan; pub mod trans; -/// Guarantees for the IR->R1cs transform -/// -/// Relevant to division by zero (in the field). -pub enum Relaxation { - /// May introduce incompleteness - Incomplete, - /// May introduce non-determinism - NonDet, - /// Deterministic - Det, -} - -lazy_static! { - static ref RELAXATION: Relaxation = { - match std::env::var("CIRC_RELAXATION") - .map(|s| s.to_lowercase()) - .as_ref() - .map(|s| s.as_str()) - { - Ok("incomplete") => Relaxation::Incomplete, - Ok("nondet") => Relaxation::NonDet, - Ok("det") => Relaxation::Det, - Ok(s) => panic!( - "Invalid CIRC_RELAXATION {}. Should be: incomplete, nondet or det", - s - ), - Err(_) => Relaxation::Incomplete, - } - }; -} - #[derive(Debug, Clone, Serialize, Deserialize)] /// A Rank 1 Constraint System. pub struct R1cs { diff --git a/src/target/r1cs/opt.rs b/src/target/r1cs/opt.rs index de708142..916693bf 100644 --- a/src/target/r1cs/opt.rs +++ b/src/target/r1cs/opt.rs @@ -1,5 +1,6 @@ //! Optimizations over R1CS use super::*; +use crate::cfg::CircCfg; use crate::util::once::OnceQueue; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use log::debug; @@ -183,11 +184,8 @@ fn constantly_true((a, b, c): &(Lc, Lc, Lc)) -> bool { /// /// * `lc_size_thresh`: the maximum size LC (number of non-constant monomials) that will be used /// for propagation. `None` means no size limit. -pub fn reduce_linearities( - r1cs: R1cs, - lc_size_thresh: Option, -) -> R1cs { - LinReducer::new(r1cs, lc_size_thresh.unwrap_or(usize::MAX)).run() +pub fn reduce_linearities(r1cs: R1cs, cfg: &CircCfg) -> R1cs { + LinReducer::new(r1cs, cfg.r1cs.lc_elim_thresh).run() } #[cfg(test)] @@ -256,7 +254,7 @@ mod test { #[quickcheck] fn random(SatR1cs(r1cs, values): SatR1cs) { - let r1cs2 = reduce_linearities(r1cs, None); + let r1cs2 = reduce_linearities(r1cs, &CircCfg::default()); r1cs2.check_all(&values); } } diff --git a/src/target/r1cs/trans.rs b/src/target/r1cs/trans.rs index eb2daba3..9042d0fb 100644 --- a/src/target/r1cs/trans.rs +++ b/src/target/r1cs/trans.rs @@ -3,6 +3,7 @@ //! [Ben Braun's //! thesis](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.683.6940&rep=rep1&type=pdf) //! is a good intro to how this process works. +use crate::cfg::CircCfg; use crate::ir::term::extras::Letified; use crate::ir::term::precomp::PreComp; use crate::ir::term::*; @@ -10,6 +11,7 @@ use crate::target::bitsize; use crate::target::r1cs::*; use circ_fields::FieldT; +use circ_opt::FieldDivByZero; use fxhash::FxHashSet; use log::debug; use rug::ops::Pow; @@ -35,7 +37,7 @@ enum EmbeddedTerm { Tuple(Vec), } -struct ToR1cs { +struct ToR1cs<'cfg> { r1cs: R1cs, cache: TermMap, wit_ext: PreComp, @@ -43,11 +45,13 @@ struct ToR1cs { next_idx: usize, zero: TermLc, one: TermLc, + cfg: &'cfg CircCfg, field: FieldT, } -impl ToR1cs { - fn new(field: FieldT, public_inputs: FxHashSet) -> Self { +impl<'cfg> ToR1cs<'cfg> { + fn new(cfg: &'cfg CircCfg, public_inputs: FxHashSet) -> Self { + let field = cfg.field().clone(); debug!("Starting R1CS back-end, field: {}", field); let r1cs = R1cs::new(field.clone()); let zero = TermLc(pf_lit(field.new_v(0u8)), r1cs.zero()); @@ -61,6 +65,7 @@ impl ToR1cs { zero, one, field, + cfg, } } @@ -870,8 +875,8 @@ impl ToR1cs { } Op::UbvToPf(_) => self.get_bv_uint(&c.cs[0]), Op::PfUnOp(PfUnOp::Neg) => -self.get_pf(&c.cs[0]).clone(), - Op::PfUnOp(PfUnOp::Recip) => match *super::RELAXATION { - Relaxation::Incomplete => { + Op::PfUnOp(PfUnOp::Recip) => match self.cfg.r1cs.div_by_zero { + FieldDivByZero::Incomplete => { // ix = 1 let x = self.get_pf(&c.cs[0]).clone(); let inv_x = self.fresh_var("recip", term![PF_RECIP; x.0.clone()], false); @@ -879,7 +884,7 @@ impl ToR1cs { .constraint(x.1, inv_x.1.clone(), self.r1cs.zero() + 1); inv_x } - Relaxation::NonDet => { + FieldDivByZero::NonDet => { // ixx = x let x = self.get_pf(&c.cs[0]).clone(); let x2 = self.mul(x.clone(), x.clone()); @@ -887,7 +892,7 @@ impl ToR1cs { self.r1cs.constraint(x2.1, inv_x.1.clone(), x.1); inv_x } - Relaxation::Det => { + FieldDivByZero::Zero => { // ix = 1 - z // zx = 0 // zi = 0 @@ -933,7 +938,7 @@ impl ToR1cs { /// ## Returns /// /// * The R1CS instance -pub fn to_r1cs(mut cs: Computation, modulus: FieldT) -> (R1cs, ProverData, VerifierData) { +pub fn to_r1cs(mut cs: Computation, cfg: &CircCfg) -> (R1cs, ProverData, VerifierData) { let assertions = cs.outputs.clone(); let metadata = cs.metadata.clone(); let public_inputs = metadata @@ -941,7 +946,7 @@ pub fn to_r1cs(mut cs: Computation, modulus: FieldT) -> (R1cs, ProverDat .map(ToOwned::to_owned) .collect(); debug!("public inputs: {:?}", public_inputs); - let mut converter = ToR1cs::new(modulus, public_inputs); + let mut converter = ToR1cs::new(cfg, public_inputs); debug!( "Term count: {}", assertions @@ -969,20 +974,28 @@ pub fn to_r1cs(mut cs: Computation, modulus: FieldT) -> (R1cs, ProverDat #[cfg(test)] pub mod test { use super::*; - use crate::util::field::DFL_T; use crate::ir::proof::Constraints; use crate::ir::term::dist::test::*; use crate::ir::term::dist::*; use crate::target::r1cs::opt::reduce_linearities; - use circ_fields::FieldT; use fxhash::FxHashMap; use quickcheck::{Arbitrary, Gen}; use quickcheck_macros::quickcheck; use rand::distributions::Distribution; use rand::SeedableRng; + fn to_r1cs_dflt(cs: Computation) -> (R1cs, ProverData, VerifierData) { + to_r1cs(cs, &CircCfg::default()) + } + + fn to_r1cs_mod17(cs: Computation) -> (R1cs, ProverData, VerifierData) { + let mut opt = crate::cfg::CircOpt::default(); + opt.field.custom_modulus = "17".into(); + to_r1cs(cs, &CircCfg::from(opt)) + } + fn init() { let _ = env_logger::builder().is_test(true).try_init(); } @@ -1006,7 +1019,7 @@ pub mod test { leaf_term(Op::Var("b".to_owned(), Sort::Bool)), ], ); - let (r1cs, pd, _) = to_r1cs(cs, FieldT::from(Integer::from(17))); + let (r1cs, pd, _) = to_r1cs_mod17(cs); let precomp = pd.precompute; let extended_values = precomp.eval(&values); r1cs.check_all(&extended_values); @@ -1050,7 +1063,7 @@ pub mod test { term![Op::Not; t] }; let cs = Computation::from_constraint_system_parts(vec![t], Vec::new()); - let (r1cs, pd, _) = to_r1cs(cs, DFL_T.clone()); + let (r1cs, pd, _) = to_r1cs_dflt(cs); let precomp = pd.precompute; let extended_values = precomp.eval(&values); r1cs.check_all(&extended_values); @@ -1063,7 +1076,8 @@ pub mod test { let mut cs = Computation::from_constraint_system_parts(vec![t], Vec::new()); crate::ir::opt::scalarize_vars::scalarize_inputs(&mut cs); crate::ir::opt::tuple::eliminate_tuples(&mut cs); - let (r1cs, pd, _) = to_r1cs(cs, DFL_T.clone()); + let cfg = CircCfg::default(); + let (r1cs, pd, _) = to_r1cs(cs, &cfg); let precomp = pd.precompute; let extended_values = precomp.eval(&values); r1cs.check_all(&extended_values); @@ -1074,11 +1088,12 @@ pub mod test { let v = eval(&t, &values); let t = term![Op::Eq; t, leaf_term(Op::Const(v))]; let cs = Computation::from_constraint_system_parts(vec![t], Vec::new()); - let (r1cs, pd, _) = to_r1cs(cs, DFL_T.clone()); + let cfg = CircCfg::default(); + let (r1cs, pd, _) = to_r1cs(cs, &cfg); let precomp = pd.precompute; let extended_values = precomp.eval(&values); r1cs.check_all(&extended_values); - let r1cs2 = reduce_linearities(r1cs, None); + let r1cs2 = reduce_linearities(r1cs, &cfg); r1cs2.check_all(&extended_values); } @@ -1089,11 +1104,12 @@ pub mod test { let mut cs = Computation::from_constraint_system_parts(vec![t], Vec::new()); crate::ir::opt::scalarize_vars::scalarize_inputs(&mut cs); crate::ir::opt::tuple::eliminate_tuples(&mut cs); - let (r1cs, pd, _) = to_r1cs(cs, DFL_T.clone()); + let cfg = CircCfg::default(); + let (r1cs, pd, _) = to_r1cs(cs, &cfg); let precomp = pd.precompute; let extended_values = precomp.eval(&values); r1cs.check_all(&extended_values); - let r1cs2 = reduce_linearities(r1cs, None); + let r1cs2 = reduce_linearities(r1cs, &cfg); r1cs2.check_all(&extended_values); } @@ -1111,7 +1127,7 @@ pub mod test { term![Op::BvUnOp(BvUnOp::Neg); leaf_term(Op::Var("b".to_owned(), Sort::BitVector(8)))]]]], vec![leaf_term(Op::Var("b".to_owned(), Sort::BitVector(8)))], ); - let (r1cs, pd, _) = to_r1cs(cs, DFL_T.clone()); + let (r1cs, pd, _) = to_r1cs_dflt(cs); let precomp = pd.precompute; let extended_values = precomp.eval(&values); r1cs.check_all(&extended_values); @@ -1127,11 +1143,12 @@ pub mod test { let v = eval(&t, &values); let t = term![Op::Eq; t, leaf_term(Op::Const(v))]; let cs = Computation::from_constraint_system_parts(vec![t], vec![]); - let (r1cs, pd, _) = to_r1cs(cs, DFL_T.clone()); + let cfg = CircCfg::default(); + let (r1cs, pd, _) = to_r1cs(cs, &cfg); let precomp = pd.precompute; let extended_values = precomp.eval(&values); r1cs.check_all(&extended_values); - let r1cs2 = reduce_linearities(r1cs, None); + let r1cs2 = reduce_linearities(r1cs, &cfg); r1cs2.check_all(&extended_values); } @@ -1143,14 +1160,14 @@ pub mod test { )))) } - fn pf(i: isize) -> Term { - leaf_term(Op::Const(Value::Field(DFL_T.new_v(i)))) + fn pf_dflt(i: isize) -> Term { + leaf_term(Op::Const(Value::Field(CircCfg::default().field().new_v(i)))) } fn const_test(term: Term) { let mut cs = Computation::new(); cs.assert(term); - let (r1cs, pd, _) = to_r1cs(cs, DFL_T.clone()); + let (r1cs, pd, _) = to_r1cs_dflt(cs); let precomp = pd.precompute; let extended_values = precomp.eval(&Default::default()); r1cs.check_all(&extended_values); @@ -1240,17 +1257,17 @@ pub mod test { fn pf2bv() { const_test(term![ Op::Eq; - term![Op::PfToBv(4); pf(8)], + term![Op::PfToBv(4); pf_dflt(8)], bv(0b1000, 4) ]); const_test(term![ Op::Eq; - term![Op::PfToBv(4); pf(15)], + term![Op::PfToBv(4); pf_dflt(15)], bv(0b1111, 4) ]); const_test(term![ Op::Eq; - term![Op::PfToBv(8); pf(15)], + term![Op::PfToBv(8); pf_dflt(15)], bv(0b1111, 8) ]); } @@ -1274,7 +1291,7 @@ pub mod test { ], ); crate::ir::opt::tuple::eliminate_tuples(&mut cs); - let (r1cs, pd, _) = to_r1cs(cs, FieldT::from(Integer::from(17))); + let (r1cs, pd, _) = to_r1cs_mod17(cs); let precomp = pd.precompute; let extended_values = precomp.eval(&values); r1cs.check_all(&extended_values); diff --git a/src/util/field.rs b/src/util/field.rs deleted file mode 100644 index 116c3821..00000000 --- a/src/util/field.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! Field type defaults -// -// NOTE: when we eventually break CirC into separate crates, -// each crate may want its own field type default - -#[cfg(all(not(feature = "ff_dfl"), not(feature = "ristretto255")))] -use circ_fields::moduli::*; -use circ_fields::FieldT; -#[cfg(not(feature = "ff_dfl"))] -use lazy_static::lazy_static; -#[cfg(feature = "ristretto255")] -use rug::Integer; - -#[cfg(all( - feature = "bls12381", - not(feature = "bn254"), - not(feature = "ristretto255"), - feature = "ff_dfl" -))] -/// Default field -pub const DFL_T: FieldT = FieldT::FBls12381; -#[cfg(all( - feature = "bls12381", - not(feature = "bn254"), - not(feature = "ristretto255"), - not(feature = "ff_dfl") -))] -lazy_static! { - /// Default field - pub static ref DFL_T: FieldT = FieldT::IntField(F_BLS12381_FMOD_ARC.clone()); -} - -#[cfg(all( - not(feature = "bls12381"), - feature = "bn254", - not(feature = "ristretto255"), - feature = "ff_dfl" -))] -/// Default field -pub const DFL_T: FieldT = FieldT::FBn254; -#[cfg(all( - not(feature = "bls12381"), - feature = "bn254", - not(feature = "ristretto255"), - not(feature = "ff_dfl") -))] -lazy_static! { - /// Default field - pub static ref DFL_T: FieldT = FieldT::IntField(F_BN254_FMOD_ARC.clone()); -} - -#[cfg(all( - not(feature = "bls12381"), - not(feature = "bn254"), - feature = "ristretto255" -))] -lazy_static! { - /// Spartan modulus - pub static ref RISTRETTO255_MOD: Integer = Integer::from_str_radix( - "7237005577332262213973186563042994240857116359379907606001950938285454250989", - 10 - ).unwrap(); -} -#[cfg(all( - not(feature = "bls12381"), - not(feature = "bn254"), - feature = "ristretto255" -))] -lazy_static! { - /// Default field - pub static ref DFL_T: FieldT = FieldT::from(RISTRETTO255_MOD.clone()); -} diff --git a/src/util/mod.rs b/src/util/mod.rs index 3b7c6030..b5abce48 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,6 +1,5 @@ //! Various data structures, etc. -pub mod field; pub mod hc; pub mod once;