initialise
This commit is contained in:
commit
ef8ef3fc61
714
Cargo.lock
generated
Normal file
714
Cargo.lock
generated
Normal file
@ -0,0 +1,714 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bellman_ce"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7e1a2edf80a8ed042463f8888946f70fcd901f1615711bb253b7dc32b9c9fe73"
|
||||||
|
dependencies = [
|
||||||
|
"bit-vec",
|
||||||
|
"byteorder",
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam",
|
||||||
|
"futures",
|
||||||
|
"num_cpus",
|
||||||
|
"pairing_ce",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-vec"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4523a10839ffae575fb08aa3423026c8cb4687eef43952afb956229d4f246f7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap-v3"
|
||||||
|
version = "3.0.0-beta.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfac055d61c39ace5061621530f7f55651a261a4fba296ce1bad06d41a8de65e"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term",
|
||||||
|
"atty",
|
||||||
|
"bitflags",
|
||||||
|
"clap_derive-v3",
|
||||||
|
"indexmap",
|
||||||
|
"lazy_static",
|
||||||
|
"strsim",
|
||||||
|
"textwrap",
|
||||||
|
"unicode-width",
|
||||||
|
"vec_map",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive-v3"
|
||||||
|
version = "3.0.0-beta.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6dd675567eb3e35787bd2583d129e85fabc7503b0a093d08c51198a307e2091"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-channel",
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-queue",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-channel"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
"maybe-uninit",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"maybe-uninit",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"lazy_static",
|
||||||
|
"maybe-uninit",
|
||||||
|
"memoffset",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-queue"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"cfg-if",
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "exitcode"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ff_ce"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "40ced6646e4e98a53da162e38ffe9c865edbd7a2f9ff197067b0a8bf1114bf8a"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"ff_derive_ce",
|
||||||
|
"hex",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ff_derive_ce"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50c052fa6d4c2f12305ec364bfb8ef884836f3f61ea015b202372ff996d1ac4b"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fuchsia-cprng"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-executor",
|
||||||
|
"futures-io",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-channel"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-executor"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"futures-util",
|
||||||
|
"num_cpus",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-io"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-sink"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"futures-sink",
|
||||||
|
"futures-task",
|
||||||
|
"memchr",
|
||||||
|
"pin-utils",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex-literal"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0"
|
||||||
|
dependencies = [
|
||||||
|
"hex-literal-impl",
|
||||||
|
"proc-macro-hack",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex-literal-impl"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d4c5c844e2fee0bf673d54c2c177f1713b3d2af2ff6e666b49cb7572e6cf42d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-hack",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.67"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "maybe-uninit"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
|
||||||
|
dependencies = [
|
||||||
|
"rustc_version",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pairing_ce"
|
||||||
|
version = "0.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f55ca3bd80245b5d43dd4467bc9ab5daf869bd76c6cd3ca54c4499b41923657d"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"ff_ce",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-utils"
|
||||||
|
version = "0.1.0-alpha.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "0.4.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7959c6467d962050d639361f7703b2051c43036d03493c36f01d440fdd3138a"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "0.4.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e4002d9f55991d5e019fb940a90e1a95eb80c24e77cb2462dd4dc869604d543a"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"syn-mid",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-hack"
|
||||||
|
version = "0.5.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
|
||||||
|
dependencies = [
|
||||||
|
"fuchsia-cprng",
|
||||||
|
"libc",
|
||||||
|
"rand_core 0.3.1",
|
||||||
|
"rdrand",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.4.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rdrand"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.3.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||||
|
dependencies = [
|
||||||
|
"semver-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver-parser"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.104"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.104"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.48"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn-mid"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vec_map"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||||
|
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-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zkutil"
|
||||||
|
version = "0.5.0"
|
||||||
|
dependencies = [
|
||||||
|
"bellman_ce",
|
||||||
|
"byteorder",
|
||||||
|
"cfg-if",
|
||||||
|
"clap-v3",
|
||||||
|
"exitcode",
|
||||||
|
"hex-literal",
|
||||||
|
"itertools",
|
||||||
|
"num-bigint",
|
||||||
|
"num-traits",
|
||||||
|
"rand",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
69
Cargo.toml
Normal file
69
Cargo.toml
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||||
|
#
|
||||||
|
# When uploading crates to the registry Cargo will automatically
|
||||||
|
# "normalize" Cargo.toml files for maximal compatibility
|
||||||
|
# with all versions of Cargo and also rewrite `path` dependencies
|
||||||
|
# to registry (e.g., crates.io) dependencies.
|
||||||
|
#
|
||||||
|
# If you are reading this file be aware that the original Cargo.toml
|
||||||
|
# will likely look very different (and much more reasonable).
|
||||||
|
# See Cargo.toml.orig for the original contents.
|
||||||
|
|
||||||
|
[package]
|
||||||
|
edition = "2018"
|
||||||
|
name = "zkutil"
|
||||||
|
version = "0.5.0"
|
||||||
|
authors = ["Roman Semenov <semenov.roma@gmail.com>"]
|
||||||
|
description = "Library for working with circom circuits"
|
||||||
|
homepage = "https://github.com/poma/zkutil"
|
||||||
|
documentation = "https://docs.rs/zkutil"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/poma/zkutil"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "lib"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "zkutil"
|
||||||
|
path = "src/main.rs"
|
||||||
|
[dependencies.bellman_ce]
|
||||||
|
version = "0.3.4"
|
||||||
|
default-features = false
|
||||||
|
|
||||||
|
[dependencies.byteorder]
|
||||||
|
version = "1"
|
||||||
|
|
||||||
|
[dependencies.cfg-if]
|
||||||
|
version = "0.1.10"
|
||||||
|
|
||||||
|
[dependencies.clap]
|
||||||
|
version = "3.0.0-beta.1"
|
||||||
|
package = "clap-v3"
|
||||||
|
|
||||||
|
[dependencies.exitcode]
|
||||||
|
version = "1.1.2"
|
||||||
|
|
||||||
|
[dependencies.hex-literal]
|
||||||
|
version = "0.2.1"
|
||||||
|
|
||||||
|
[dependencies.itertools]
|
||||||
|
version = "0.8.1"
|
||||||
|
|
||||||
|
[dependencies.num-bigint]
|
||||||
|
version = "0.2.3"
|
||||||
|
|
||||||
|
[dependencies.num-traits]
|
||||||
|
version = "0.2.8"
|
||||||
|
|
||||||
|
[dependencies.rand]
|
||||||
|
version = "0.4"
|
||||||
|
|
||||||
|
[dependencies.serde]
|
||||||
|
version = "1.0"
|
||||||
|
features = ["derive"]
|
||||||
|
|
||||||
|
[dependencies.serde_json]
|
||||||
|
version = "1.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["bellman_ce/multicore"]
|
34
Cargo.toml.orig
Normal file
34
Cargo.toml.orig
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[package]
|
||||||
|
name = "zkutil"
|
||||||
|
version = "0.5.0"
|
||||||
|
authors = ["Roman Semenov <semenov.roma@gmail.com>"]
|
||||||
|
description = "Library for working with circom circuits"
|
||||||
|
documentation = "https://docs.rs/zkutil"
|
||||||
|
homepage = "https://github.com/poma/zkutil"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/poma/zkutil"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "lib"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "zkutil"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rand = "0.4"
|
||||||
|
byteorder = "1"
|
||||||
|
exitcode = "1.1.2"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
num-bigint = "0.2.3"
|
||||||
|
num-traits = "0.2.8"
|
||||||
|
itertools = "0.8.1"
|
||||||
|
cfg-if = "0.1.10"
|
||||||
|
hex-literal = "0.2.1"
|
||||||
|
clap = { package = "clap-v3", version = "3.0.0-beta.1" } # todo: replace with official v3 when it's released to crates.io
|
||||||
|
bellman_ce = { version = "0.3.4", default-features = false } # active features depend on build type
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["bellman_ce/multicore"]
|
23
LICENSE.md
Normal file
23
LICENSE.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Permission is hereby granted, free of charge, to any
|
||||||
|
person obtaining a copy of this software and associated
|
||||||
|
documentation files (the "Software"), to deal in the
|
||||||
|
Software without restriction, including without
|
||||||
|
limitation the rights to use, copy, modify, merge,
|
||||||
|
publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software
|
||||||
|
is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice
|
||||||
|
shall be included in all copies or substantial portions
|
||||||
|
of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||||
|
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
124
README.md
Normal file
124
README.md
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
# zkUtil ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/poma/zkutil/Rust) [![Crates.io](https://img.shields.io/crates/v/zkutil.svg)](https://crates.io/crates/zkutil)
|
||||||
|
|
||||||
|
A tool to work with zkSNARK circuits generated by circom compiler. Based on circom import code by @kobigurk
|
||||||
|
|
||||||
|
**The generated keys are currently incompatible with upstream Websnark and require using a custom fork**
|
||||||
|
|
||||||
|
## Usage examples:
|
||||||
|
|
||||||
|
```shell script
|
||||||
|
# Getting help
|
||||||
|
> zkutil --help
|
||||||
|
zkutil
|
||||||
|
A tool to work with SNARK circuits generated by circom
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
zkutil <SUBCOMMAND>
|
||||||
|
|
||||||
|
FLAGS:
|
||||||
|
-h, --help Prints help information
|
||||||
|
-V, --version Prints version information
|
||||||
|
|
||||||
|
SUBCOMMANDS:
|
||||||
|
export-keys Export proving and verifying keys compatible with snarkjs/websnark
|
||||||
|
generate-verifier Generate verifier smart contract
|
||||||
|
help Prints this message or the help of the given subcommand(s)
|
||||||
|
prove Generate a SNARK proof
|
||||||
|
setup Generate trusted setup parameters
|
||||||
|
verify Verify a SNARK proof
|
||||||
|
|
||||||
|
# Getting help for a subcommand
|
||||||
|
> zkutil prove --help
|
||||||
|
zkutil-prove
|
||||||
|
Generate a SNARK proof
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
zkutil prove [OPTIONS]
|
||||||
|
|
||||||
|
FLAGS:
|
||||||
|
-h, --help Prints help information
|
||||||
|
-V, --version Prints version information
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-c, --circuit <circuit> Circuit R1CS or JSON file [default: circuit.r1cs]
|
||||||
|
-p, --params <params> Snark trusted setup parameters file [default: params.bin]
|
||||||
|
-r, --proof <proof> Output file for proof JSON [default: proof.json]
|
||||||
|
-i, --public <public> Output file for public inputs JSON [default: public.json]
|
||||||
|
-w, --witness <witness> Witness JSON file [default: witness.json]
|
||||||
|
|
||||||
|
# Suppose we have circuit file and a sample inputs
|
||||||
|
> ls
|
||||||
|
circuit.circom input.json
|
||||||
|
|
||||||
|
# Compile the circuit
|
||||||
|
> circom -rw circuit.circom
|
||||||
|
Constraints: 10000
|
||||||
|
Constraints: 20000
|
||||||
|
Constraints: 30000
|
||||||
|
Constraints: 40000
|
||||||
|
Constraints: 50000
|
||||||
|
|
||||||
|
# Generate a local trusted setup
|
||||||
|
> zkutil setup
|
||||||
|
Loading circuit...
|
||||||
|
Generating trusted setup parameters...
|
||||||
|
Has generated 28296 points
|
||||||
|
Writing to file...
|
||||||
|
Done!
|
||||||
|
|
||||||
|
# Calculate witness from the input.json
|
||||||
|
# At the moment we still need to calculate witness using snarkjs
|
||||||
|
> snarkjs calculatewitness
|
||||||
|
|
||||||
|
# Generate a snark proof
|
||||||
|
> zkutil prove
|
||||||
|
Loading circuit...
|
||||||
|
Proving...
|
||||||
|
Saved proof.json and public.json
|
||||||
|
|
||||||
|
# Verify the proof
|
||||||
|
> zkutil verify
|
||||||
|
Proof is correct
|
||||||
|
|
||||||
|
# Generate a solidity verifier contract
|
||||||
|
> zkutil generate-verifier
|
||||||
|
Created verifier.sol
|
||||||
|
|
||||||
|
# Export keys to snarkjs/websnark compatible format
|
||||||
|
> zkutil export-keys
|
||||||
|
Exporting params.bin...
|
||||||
|
Created proving_key.json and verification_key.json
|
||||||
|
|
||||||
|
# Verify the same proof with snarkjs
|
||||||
|
> snarkjs verify
|
||||||
|
OK
|
||||||
|
|
||||||
|
# Here's a list of files that we have after this
|
||||||
|
> ls
|
||||||
|
circuit.circom circuit.r1cs circuit.wasm input.json params.bin proof.json public.json Verifier.sol proving_key.json verifying_key.json witness.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Also see `test.sh` for example
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
|
||||||
|
Install Rust
|
||||||
|
|
||||||
|
```shell script
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Install zkutil globally
|
||||||
|
|
||||||
|
```shell script
|
||||||
|
cargo install zkutil
|
||||||
|
# Make sure `~/.cargo/bin` is in $PATH (should be added automatically during Rust installation)
|
||||||
|
```
|
||||||
|
|
||||||
|
Or alternatively you can compile and run it instead:
|
||||||
|
|
||||||
|
```shell script
|
||||||
|
git clone https://github.com/poma/zkutil
|
||||||
|
cd zkutil
|
||||||
|
cargo run --release -- prove --help
|
||||||
|
```
|
15
circuit.circom
Normal file
15
circuit.circom
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
template Num2Bits(n) {
|
||||||
|
signal input in;
|
||||||
|
signal output out[n];
|
||||||
|
var lc1=0;
|
||||||
|
|
||||||
|
for (var i = 0; i<n; i++) {
|
||||||
|
out[i] <-- (in >> i) & 1;
|
||||||
|
out[i] * (out[i] -1 ) === 0;
|
||||||
|
lc1 += out[i] * 2**i;
|
||||||
|
}
|
||||||
|
|
||||||
|
lc1 === in;
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Num2Bits(8);
|
572
src/circom_circuit.rs
Normal file
572
src/circom_circuit.rs
Normal file
@ -0,0 +1,572 @@
|
|||||||
|
#![allow(clippy::needless_range_loop)]
|
||||||
|
extern crate bellman_ce;
|
||||||
|
extern crate rand;
|
||||||
|
|
||||||
|
use std::str;
|
||||||
|
use std::fs::{self, OpenOptions, File};
|
||||||
|
use std::io::{BufReader, Read, Seek};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::iter::repeat;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use rand::{Rng, OsRng};
|
||||||
|
|
||||||
|
use bellman_ce::{
|
||||||
|
Circuit,
|
||||||
|
SynthesisError,
|
||||||
|
Variable,
|
||||||
|
Index,
|
||||||
|
ConstraintSystem,
|
||||||
|
LinearCombination,
|
||||||
|
source::QueryDensity,
|
||||||
|
groth16::{
|
||||||
|
Parameters,
|
||||||
|
Proof,
|
||||||
|
generate_random_parameters as generate_random_parameters2,
|
||||||
|
prepare_verifying_key,
|
||||||
|
create_random_proof,
|
||||||
|
verify_proof,
|
||||||
|
prepare_prover,
|
||||||
|
},
|
||||||
|
pairing::{
|
||||||
|
Engine,
|
||||||
|
CurveAffine,
|
||||||
|
ff::PrimeField,
|
||||||
|
ff::ScalarEngine,
|
||||||
|
bn256::{
|
||||||
|
Bn256,
|
||||||
|
Fq,
|
||||||
|
Fq2,
|
||||||
|
G1Affine,
|
||||||
|
G2Affine,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::utils::{
|
||||||
|
repr_to_big,
|
||||||
|
proof_to_hex,
|
||||||
|
p1_to_vec,
|
||||||
|
p2_to_vec,
|
||||||
|
pairing_to_vec,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct CircuitJson {
|
||||||
|
pub constraints: Vec<Vec<BTreeMap<String, String>>>,
|
||||||
|
#[serde(rename = "nPubInputs")]
|
||||||
|
pub num_inputs: usize,
|
||||||
|
#[serde(rename = "nOutputs")]
|
||||||
|
pub num_outputs: usize,
|
||||||
|
#[serde(rename = "nVars")]
|
||||||
|
pub num_variables: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct ProofJson {
|
||||||
|
pub protocol: String,
|
||||||
|
pub proof: Option<String>,
|
||||||
|
pub pi_a: Vec<String>,
|
||||||
|
pub pi_b: Vec<Vec<String>>,
|
||||||
|
pub pi_c: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct ProvingKeyJson {
|
||||||
|
#[serde(rename = "polsA")]
|
||||||
|
pub pols_a: Vec<BTreeMap<String, String>>,
|
||||||
|
#[serde(rename = "polsB")]
|
||||||
|
pub pols_b: Vec<BTreeMap<String, String>>,
|
||||||
|
#[serde(rename = "polsC")]
|
||||||
|
pub pols_c: Vec<BTreeMap<String, String>>,
|
||||||
|
#[serde(rename = "A")]
|
||||||
|
pub a: Vec<Vec<String>>,
|
||||||
|
#[serde(rename = "B1")]
|
||||||
|
pub b1: Vec<Vec<String>>,
|
||||||
|
#[serde(rename = "B2")]
|
||||||
|
pub b2: Vec<Vec<Vec<String>>>,
|
||||||
|
#[serde(rename = "C")]
|
||||||
|
pub c: Vec<Option<Vec<String>>>,
|
||||||
|
pub vk_alfa_1: Vec<String>,
|
||||||
|
pub vk_beta_1: Vec<String>,
|
||||||
|
pub vk_delta_1: Vec<String>,
|
||||||
|
pub vk_beta_2: Vec<Vec<String>>,
|
||||||
|
pub vk_delta_2: Vec<Vec<String>>,
|
||||||
|
#[serde(rename = "hExps")]
|
||||||
|
pub h: Vec<Vec<String>>,
|
||||||
|
pub protocol: String,
|
||||||
|
#[serde(rename = "nPublic")]
|
||||||
|
pub n_public: usize,
|
||||||
|
#[serde(rename = "nVars")]
|
||||||
|
pub n_vars: usize,
|
||||||
|
#[serde(rename = "domainBits")]
|
||||||
|
pub domain_bits: usize,
|
||||||
|
#[serde(rename = "domainSize")]
|
||||||
|
pub domain_size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct VerifyingKeyJson {
|
||||||
|
#[serde(rename = "IC")]
|
||||||
|
pub ic: Vec<Vec<String>>,
|
||||||
|
pub vk_alfa_1: Vec<String>,
|
||||||
|
pub vk_alpha_1: Vec<String>,
|
||||||
|
pub vk_beta_2: Vec<Vec<String>>,
|
||||||
|
pub vk_gamma_2: Vec<Vec<String>>,
|
||||||
|
pub vk_delta_2: Vec<Vec<String>>,
|
||||||
|
pub vk_alfabeta_12: Vec<Vec<Vec<String>>>,
|
||||||
|
pub vk_alphabeta_12: Vec<Vec<Vec<String>>>,
|
||||||
|
pub curve: String,
|
||||||
|
pub protocol: String,
|
||||||
|
#[serde(rename = "nPublic")]
|
||||||
|
pub inputs_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Constraint<E> = (
|
||||||
|
Vec<(usize, <E as ScalarEngine>::Fr)>,
|
||||||
|
Vec<(usize, <E as ScalarEngine>::Fr)>,
|
||||||
|
Vec<(usize, <E as ScalarEngine>::Fr)>,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct R1CS<E: Engine> {
|
||||||
|
pub num_inputs: usize,
|
||||||
|
pub num_aux: usize,
|
||||||
|
pub num_variables: usize,
|
||||||
|
pub constraints: Vec<Constraint<E>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct CircomCircuit<E: Engine> {
|
||||||
|
pub r1cs: R1CS<E>,
|
||||||
|
pub witness: Option<Vec<E::Fr>>,
|
||||||
|
pub wire_mapping: Option<Vec<usize>>,
|
||||||
|
// debug symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Engine> CircomCircuit<E> {
|
||||||
|
pub fn get_public_inputs(&self) -> Option<Vec<E::Fr>> {
|
||||||
|
match &self.witness {
|
||||||
|
None => None,
|
||||||
|
Some(w) => match &self.wire_mapping {
|
||||||
|
None => Some(w[1..self.r1cs.num_inputs].to_vec()),
|
||||||
|
Some(m) => Some(m[1..self.r1cs.num_inputs].iter().map(|i| w[*i]).collect_vec()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_public_inputs_json(&self) -> String {
|
||||||
|
let inputs = self.get_public_inputs();
|
||||||
|
let inputs = match inputs {
|
||||||
|
None => return String::from("[]"),
|
||||||
|
Some(inp) => inp.iter().map(|x| repr_to_big(x.into_repr())).collect_vec(),
|
||||||
|
};
|
||||||
|
serde_json::to_string_pretty(&inputs).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Our demo circuit implements this `Circuit` trait which
|
||||||
|
/// is used during paramgen and proving in order to
|
||||||
|
/// synthesize the constraint system.
|
||||||
|
impl<'a, E: Engine> Circuit<E> for CircomCircuit<E> {
|
||||||
|
//noinspection RsBorrowChecker
|
||||||
|
fn synthesize<CS: ConstraintSystem<E>>(
|
||||||
|
self,
|
||||||
|
cs: &mut CS
|
||||||
|
) -> Result<(), SynthesisError>
|
||||||
|
{
|
||||||
|
let witness = &self.witness;
|
||||||
|
let wire_mapping = &self.wire_mapping;
|
||||||
|
for i in 1..self.r1cs.num_inputs {
|
||||||
|
cs.alloc_input(
|
||||||
|
|| format!("variable {}", i),
|
||||||
|
|| {
|
||||||
|
Ok(match witness {
|
||||||
|
None => E::Fr::from_str("1").unwrap(),
|
||||||
|
Some(w) => match wire_mapping {
|
||||||
|
None => w[i],
|
||||||
|
Some(m) => w[m[i]],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..self.r1cs.num_aux {
|
||||||
|
cs.alloc(
|
||||||
|
|| format!("aux {}", i),
|
||||||
|
|| {
|
||||||
|
Ok(match witness {
|
||||||
|
None => E::Fr::from_str("1").unwrap(),
|
||||||
|
Some(w) => match wire_mapping {
|
||||||
|
None => w[i + self.r1cs.num_inputs],
|
||||||
|
Some(m) => w[m[i + self.r1cs.num_inputs]],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let make_index = |index|
|
||||||
|
if index < self.r1cs.num_inputs {
|
||||||
|
Index::Input(index)
|
||||||
|
} else {
|
||||||
|
Index::Aux(index - self.r1cs.num_inputs)
|
||||||
|
};
|
||||||
|
let make_lc = |lc_data: Vec<(usize, E::Fr)>|
|
||||||
|
lc_data.iter().fold(
|
||||||
|
LinearCombination::<E>::zero(),
|
||||||
|
|lc: LinearCombination<E>, (index, coeff)| lc + (*coeff, Variable::new_unchecked(make_index(*index)))
|
||||||
|
);
|
||||||
|
for (i, constraint) in self.r1cs.constraints.iter().enumerate() {
|
||||||
|
cs.enforce(|| format!("constraint {}", i),
|
||||||
|
|_| make_lc(constraint.0.clone()),
|
||||||
|
|_| make_lc(constraint.1.clone()),
|
||||||
|
|_| make_lc(constraint.2.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prove<E: Engine, R: Rng>(circuit: CircomCircuit<E>, params: &Parameters<E>, mut rng: R) -> Result<Proof<E>, SynthesisError> {
|
||||||
|
let mut params2 = params.clone();
|
||||||
|
filter_params(&mut params2);
|
||||||
|
create_random_proof(circuit, ¶ms2, &mut rng)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_random_parameters<E: Engine, R: Rng>(circuit: CircomCircuit<E>, mut rng: R) -> Result<Parameters<E>, SynthesisError> {
|
||||||
|
generate_random_parameters2(circuit, &mut rng)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify_circuit<E: Engine>(circuit: &CircomCircuit<E>, params: &Parameters<E>, proof: &Proof<E>) -> Result<bool, SynthesisError> {
|
||||||
|
let inputs = match circuit.get_public_inputs() {
|
||||||
|
None => return Err(SynthesisError::AssignmentMissing),
|
||||||
|
Some(inp) => inp,
|
||||||
|
};
|
||||||
|
verify_proof(&prepare_verifying_key(¶ms.vk), proof, &inputs)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify<E: Engine>(params: &Parameters<E>, proof: &Proof<E>, inputs: &[E::Fr]) -> Result<bool, SynthesisError> {
|
||||||
|
verify_proof(&prepare_verifying_key(¶ms.vk), proof, &inputs)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_verifier_sol(params: &Parameters<Bn256>) -> String {
|
||||||
|
// TODO: use a simple template engine
|
||||||
|
let bytes = include_bytes!("verifier_groth.sol");
|
||||||
|
let template = String::from_utf8_lossy(bytes);
|
||||||
|
|
||||||
|
let p1_to_str = |p: &<Bn256 as Engine>::G1Affine| {
|
||||||
|
if p.is_zero() {
|
||||||
|
// todo: throw instead
|
||||||
|
return String::from("<POINT_AT_INFINITY>");
|
||||||
|
}
|
||||||
|
let xy = p.into_xy_unchecked();
|
||||||
|
let x = repr_to_big(xy.0.into_repr());
|
||||||
|
let y = repr_to_big(xy.1.into_repr());
|
||||||
|
format!("uint256({}), uint256({})", x, y)
|
||||||
|
};
|
||||||
|
let p2_to_str = |p: &<Bn256 as Engine>::G2Affine| {
|
||||||
|
if p.is_zero() {
|
||||||
|
// todo: throw instead
|
||||||
|
return String::from("<POINT_AT_INFINITY>");
|
||||||
|
}
|
||||||
|
let xy = p.into_xy_unchecked();
|
||||||
|
let x_c0 = repr_to_big(xy.0.c0.into_repr());
|
||||||
|
let x_c1 = repr_to_big(xy.0.c1.into_repr());
|
||||||
|
let y_c0 = repr_to_big(xy.1.c0.into_repr());
|
||||||
|
let y_c1 = repr_to_big(xy.1.c1.into_repr());
|
||||||
|
format!("[uint256({}), uint256({})], [uint256({}), uint256({})]", x_c1, x_c0, y_c1, y_c0)
|
||||||
|
};
|
||||||
|
|
||||||
|
let template = template.replace("<%vk_alfa1%>", &*p1_to_str(¶ms.vk.alpha_g1));
|
||||||
|
let template = template.replace("<%vk_beta2%>", &*p2_to_str(¶ms.vk.beta_g2));
|
||||||
|
let template = template.replace("<%vk_gamma2%>", &*p2_to_str(¶ms.vk.gamma_g2));
|
||||||
|
let template = template.replace("<%vk_delta2%>", &*p2_to_str(¶ms.vk.delta_g2));
|
||||||
|
|
||||||
|
let template = template.replace("<%vk_ic_length%>", &*params.vk.ic.len().to_string());
|
||||||
|
let template = template.replace("<%vk_input_length%>", &*(params.vk.ic.len() - 1).to_string());
|
||||||
|
|
||||||
|
let mut vi = String::from("");
|
||||||
|
for i in 0..params.vk.ic.len() {
|
||||||
|
vi = format!("{}{}vk.IC[{}] = Pairing.G1Point({});\n", vi, if vi.is_empty() { "" } else { " " }, i, &*p1_to_str(¶ms.vk.ic[i]));
|
||||||
|
}
|
||||||
|
template.replace("<%vk_ic_pts%>", &*vi)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_verifier_sol_file(params: &Parameters<Bn256>, filename: &str) -> std::io::Result<()> {
|
||||||
|
fs::write(filename, create_verifier_sol(params).as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proof_to_json(proof: &Proof<Bn256>) -> Result<String, serde_json::error::Error> {
|
||||||
|
serde_json::to_string_pretty(&ProofJson {
|
||||||
|
protocol: "groth".to_string(),
|
||||||
|
proof: Some(proof_to_hex(&proof)),
|
||||||
|
pi_a: p1_to_vec(&proof.a),
|
||||||
|
pi_b: p2_to_vec(&proof.b),
|
||||||
|
pi_c: p1_to_vec(&proof.c),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proof_to_json_file(proof: &Proof<Bn256>, filename: &str) -> std::io::Result<()> {
|
||||||
|
let str = proof_to_json(proof).unwrap(); // TODO: proper error handling
|
||||||
|
fs::write(filename, str.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_params_file(filename: &str) -> Parameters<Bn256> {
|
||||||
|
let reader = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(filename)
|
||||||
|
.expect("unable to open.");
|
||||||
|
load_params(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_params<R: Read>(reader: R) -> Parameters<Bn256> {
|
||||||
|
Parameters::read(reader, true).expect("unable to read params")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_inputs_json_file<E: Engine>(filename: &str) -> Vec<E::Fr> {
|
||||||
|
let reader = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(filename)
|
||||||
|
.expect("unable to open.");
|
||||||
|
load_inputs_json::<E, BufReader<File>>(BufReader::new(reader))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_inputs_json<E: Engine, R: Read>(reader: R) -> Vec<E::Fr> {
|
||||||
|
let inputs: Vec<String> = serde_json::from_reader(reader).unwrap();
|
||||||
|
inputs.into_iter().map(|x| E::Fr::from_str(&x).unwrap()).collect::<Vec<E::Fr>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_proof_json_file<E: Engine>(filename: &str) -> Proof<Bn256> {
|
||||||
|
let reader = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(filename)
|
||||||
|
.expect("unable to open.");
|
||||||
|
load_proof_json(BufReader::new(reader))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_proof_json<R: Read>(reader: R) -> Proof<Bn256> {
|
||||||
|
let proof: ProofJson = serde_json::from_reader(reader).unwrap();
|
||||||
|
Proof {
|
||||||
|
a: G1Affine::from_xy_checked(
|
||||||
|
Fq::from_str(&proof.pi_a[0]).unwrap(),
|
||||||
|
Fq::from_str(&proof.pi_a[1]).unwrap(),
|
||||||
|
).unwrap(),
|
||||||
|
b: G2Affine::from_xy_checked(
|
||||||
|
Fq2 {
|
||||||
|
c0: Fq::from_str(&proof.pi_b[0][0]).unwrap(),
|
||||||
|
c1: Fq::from_str(&proof.pi_b[0][1]).unwrap(),
|
||||||
|
},
|
||||||
|
Fq2 {
|
||||||
|
c0: Fq::from_str(&proof.pi_b[1][0]).unwrap(),
|
||||||
|
c1: Fq::from_str(&proof.pi_b[1][1]).unwrap(),
|
||||||
|
},
|
||||||
|
).unwrap(),
|
||||||
|
c: G1Affine::from_xy_checked(
|
||||||
|
Fq::from_str(&proof.pi_c[0]).unwrap(),
|
||||||
|
Fq::from_str(&proof.pi_c[1]).unwrap(),
|
||||||
|
).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn filter_params<E: Engine>(params: &mut Parameters<E>) {
|
||||||
|
params.vk.ic = params.vk.ic.clone().into_iter().filter(|x| !x.is_zero()).collect::<Vec<_>>();
|
||||||
|
params.h = Arc::new((*params.h).clone().into_iter().filter(|x| !x.is_zero()).collect::<Vec<_>>());
|
||||||
|
params.a = Arc::new((*params.a).clone().into_iter().filter(|x| !x.is_zero()).collect::<Vec<_>>());
|
||||||
|
params.b_g1 = Arc::new((*params.b_g1).clone().into_iter().filter(|x| !x.is_zero()).collect::<Vec<_>>());
|
||||||
|
params.b_g2 = Arc::new((*params.b_g2).clone().into_iter().filter(|x| !x.is_zero()).collect::<Vec<_>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proving_key_json(params: &Parameters<Bn256>, circuit: CircomCircuit<Bn256>) -> Result<String, serde_json::error::Error> {
|
||||||
|
let mut pols_a: Vec<BTreeMap<String, String>> = vec![];
|
||||||
|
let mut pols_b: Vec<BTreeMap<String, String>> = vec![];
|
||||||
|
let mut pols_c: Vec<BTreeMap<String, String>> = vec![];
|
||||||
|
for _ in 0..circuit.r1cs.num_aux + circuit.r1cs.num_inputs {
|
||||||
|
pols_a.push(BTreeMap::new());
|
||||||
|
pols_b.push(BTreeMap::new());
|
||||||
|
pols_c.push(BTreeMap::new());
|
||||||
|
}
|
||||||
|
for c in 0..circuit.r1cs.constraints.len() {
|
||||||
|
for item in circuit.r1cs.constraints[c].0.iter() {
|
||||||
|
pols_a[item.0].insert(c.to_string(), repr_to_big(item.1.into_repr()));
|
||||||
|
}
|
||||||
|
for item in circuit.r1cs.constraints[c].1.iter() {
|
||||||
|
pols_b[item.0].insert(c.to_string(), repr_to_big(item.1.into_repr()));
|
||||||
|
}
|
||||||
|
for item in circuit.r1cs.constraints[c].2.iter() {
|
||||||
|
pols_c[item.0].insert(c.to_string(), repr_to_big(item.1.into_repr()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..circuit.r1cs.num_inputs {
|
||||||
|
pols_a[i].insert((circuit.r1cs.constraints.len() + i).to_string(), String::from("1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let domain_bits = log2_floor(circuit.r1cs.constraints.len() + circuit.r1cs.num_inputs) + 1;
|
||||||
|
let n_public = circuit.r1cs.num_inputs - 1;
|
||||||
|
let n_vars = circuit.r1cs.num_variables;
|
||||||
|
|
||||||
|
let p = prepare_prover(circuit).unwrap().assignment;
|
||||||
|
let mut a_iter = params.a.iter();
|
||||||
|
let mut b1_iter = params.b_g1.iter();
|
||||||
|
let mut b2_iter = params.b_g2.iter();
|
||||||
|
let zero1 = G1Affine::zero();
|
||||||
|
let zero2 = G2Affine::zero();
|
||||||
|
let a = repeat(true).take(params.vk.ic.len())
|
||||||
|
.chain(p.a_aux_density.iter())
|
||||||
|
.map(|item| if item { a_iter.next().unwrap() } else { &zero1 })
|
||||||
|
.map(|e| p1_to_vec(e))
|
||||||
|
.collect_vec();
|
||||||
|
let b1 = p.b_input_density.iter()
|
||||||
|
.chain(p.b_aux_density.iter())
|
||||||
|
.map(|item| if item { b1_iter.next().unwrap() } else { &zero1 })
|
||||||
|
.map(|e| p1_to_vec(e))
|
||||||
|
.collect_vec();
|
||||||
|
let b2 = p.b_input_density.iter()
|
||||||
|
.chain(p.b_aux_density.iter())
|
||||||
|
.map(|item| if item { b2_iter.next().unwrap() } else { &zero2 })
|
||||||
|
.map(|e| p2_to_vec(e))
|
||||||
|
.collect_vec();
|
||||||
|
let c = repeat(None).take(params.vk.ic.len())
|
||||||
|
.chain(params.l.iter().map(|e| Some(p1_to_vec(e))))
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
let proving_key = ProvingKeyJson {
|
||||||
|
pols_a,
|
||||||
|
pols_b,
|
||||||
|
pols_c,
|
||||||
|
a,
|
||||||
|
b1,
|
||||||
|
b2,
|
||||||
|
c,
|
||||||
|
vk_alfa_1: p1_to_vec(¶ms.vk.alpha_g1),
|
||||||
|
vk_beta_1: p1_to_vec(¶ms.vk.beta_g1),
|
||||||
|
vk_delta_1: p1_to_vec(¶ms.vk.delta_g1),
|
||||||
|
vk_beta_2: p2_to_vec(¶ms.vk.beta_g2),
|
||||||
|
vk_delta_2: p2_to_vec(¶ms.vk.delta_g2),
|
||||||
|
h: params.h.iter().map(|e| p1_to_vec(e)).collect_vec(),
|
||||||
|
protocol: String::from("groth"),
|
||||||
|
n_public,
|
||||||
|
n_vars,
|
||||||
|
domain_bits,
|
||||||
|
domain_size: 1 << domain_bits,
|
||||||
|
};
|
||||||
|
|
||||||
|
serde_json::to_string(&proving_key)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log2_floor(num: usize) -> usize {
|
||||||
|
assert!(num > 0);
|
||||||
|
let mut pow = 0;
|
||||||
|
while (1 << (pow + 1)) <= num {
|
||||||
|
pow += 1;
|
||||||
|
}
|
||||||
|
pow
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proving_key_json_file(params: &Parameters<Bn256>, circuit: CircomCircuit<Bn256>, filename: &str) -> std::io::Result<()> {
|
||||||
|
let str = proving_key_json(params, circuit).unwrap(); // TODO: proper error handling
|
||||||
|
fs::write(filename, str.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verification_key_json(params: &Parameters<Bn256>) -> Result<String, serde_json::error::Error> {
|
||||||
|
let verification_key = VerifyingKeyJson {
|
||||||
|
ic: params.vk.ic.iter().map(|e| p1_to_vec(e)).collect_vec(),
|
||||||
|
vk_alfa_1: p1_to_vec(¶ms.vk.alpha_g1),
|
||||||
|
vk_alpha_1: p1_to_vec(¶ms.vk.alpha_g1),
|
||||||
|
vk_beta_2: p2_to_vec(¶ms.vk.beta_g2),
|
||||||
|
vk_gamma_2: p2_to_vec(¶ms.vk.gamma_g2),
|
||||||
|
vk_delta_2: p2_to_vec(¶ms.vk.delta_g2),
|
||||||
|
vk_alfabeta_12: pairing_to_vec(&Bn256::pairing(params.vk.alpha_g1, params.vk.beta_g2)),
|
||||||
|
vk_alphabeta_12: pairing_to_vec(&Bn256::pairing(params.vk.alpha_g1, params.vk.beta_g2)),
|
||||||
|
inputs_count: params.vk.ic.len() - 1,
|
||||||
|
curve: String::from("BN254"),
|
||||||
|
protocol: String::from("groth"),
|
||||||
|
};
|
||||||
|
serde_json::to_string_pretty(&verification_key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verification_key_json_file(params: &Parameters<Bn256>, filename: &str) -> std::io::Result<()> {
|
||||||
|
let str = verification_key_json(params).unwrap(); // TODO: proper error handling
|
||||||
|
fs::write(filename, str.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn witness_from_json_file<E: Engine>(filename: &str) -> Vec<E::Fr> {
|
||||||
|
let reader = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(filename)
|
||||||
|
.expect("unable to open.");
|
||||||
|
witness_from_json::<E, BufReader<File>>(BufReader::new(reader))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn witness_from_json<E: Engine, R: Read>(reader: R) -> Vec<E::Fr> {
|
||||||
|
let witness: Vec<String> = serde_json::from_reader(reader).unwrap();
|
||||||
|
witness.into_iter().map(|x| E::Fr::from_str(&x).unwrap()).collect::<Vec<E::Fr>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn witness_from_bin_file<E: Engine>(filename: &str) -> Result<Vec<E::Fr>, std::io::Error> {
|
||||||
|
let reader = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(filename)
|
||||||
|
.expect("unable to open.");
|
||||||
|
witness_from_bin::<E, BufReader<File>>(BufReader::new(reader))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn witness_from_bin<E: Engine, R: Read>(reader: R) -> Result<Vec<E::Fr>, std::io::Error> {
|
||||||
|
let file = crate::wtns_reader::read::<E, R>(reader)?;
|
||||||
|
Ok(file.witness)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn r1cs_from_json_file<E: Engine>(filename: &str) -> R1CS<E> {
|
||||||
|
let reader = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(filename)
|
||||||
|
.expect("unable to open.");
|
||||||
|
r1cs_from_json(BufReader::new(reader))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn r1cs_from_json<E: Engine, R: Read>(reader: R) -> R1CS<E> {
|
||||||
|
let circuit_json: CircuitJson = serde_json::from_reader(reader).unwrap();
|
||||||
|
|
||||||
|
let num_inputs = circuit_json.num_inputs + circuit_json.num_outputs + 1;
|
||||||
|
let num_aux = circuit_json.num_variables - num_inputs;
|
||||||
|
|
||||||
|
let convert_constraint = |lc: &BTreeMap<String, String>| {
|
||||||
|
lc.iter().map(|(index, coeff)| (index.parse().unwrap(), E::Fr::from_str(coeff).unwrap())).collect_vec()
|
||||||
|
};
|
||||||
|
|
||||||
|
let constraints = circuit_json.constraints.iter().map(
|
||||||
|
|c| (convert_constraint(&c[0]), convert_constraint(&c[1]), convert_constraint(&c[2]))
|
||||||
|
).collect_vec();
|
||||||
|
|
||||||
|
R1CS {
|
||||||
|
num_inputs,
|
||||||
|
num_aux,
|
||||||
|
num_variables: circuit_json.num_variables,
|
||||||
|
constraints,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn r1cs_from_bin<R: Read + Seek>(reader: R) -> Result<(R1CS<Bn256>, Vec<usize>), std::io::Error> {
|
||||||
|
let file = crate::r1cs_reader::read(reader)?;
|
||||||
|
let num_inputs = (1 + file.header.n_pub_in + file.header.n_pub_out) as usize;
|
||||||
|
let num_variables = file.header.n_wires as usize;
|
||||||
|
let num_aux = num_variables - num_inputs;
|
||||||
|
Ok((
|
||||||
|
R1CS { num_aux, num_inputs, num_variables, constraints: file.constraints, },
|
||||||
|
file.wire_mapping.iter().map(|e| *e as usize).collect_vec()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn r1cs_from_bin_file(filename: &str) -> Result<(R1CS<Bn256>, Vec<usize>), std::io::Error> {
|
||||||
|
let reader = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(filename)
|
||||||
|
.expect("unable to open.");
|
||||||
|
r1cs_from_bin(BufReader::new(reader))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_rng() -> Box<dyn Rng> {
|
||||||
|
Box::new(OsRng::new().unwrap())
|
||||||
|
}
|
15
src/lib.rs
Normal file
15
src/lib.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate serde;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate hex_literal;
|
||||||
|
extern crate bellman_ce;
|
||||||
|
extern crate rand;
|
||||||
|
extern crate itertools;
|
||||||
|
extern crate byteorder;
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_traits;
|
||||||
|
|
||||||
|
pub mod utils;
|
||||||
|
pub mod circom_circuit;
|
||||||
|
pub mod r1cs_reader;
|
||||||
|
pub mod wtns_reader;
|
253
src/main.rs
Normal file
253
src/main.rs
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
extern crate clap;
|
||||||
|
extern crate bellman_ce;
|
||||||
|
extern crate zkutil;
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::path::Path;
|
||||||
|
use clap::Clap;
|
||||||
|
use bellman_ce::pairing::{
|
||||||
|
Engine,
|
||||||
|
bn256::Bn256
|
||||||
|
};
|
||||||
|
use zkutil::circom_circuit::{
|
||||||
|
prove as prove2,
|
||||||
|
verify as verify2,
|
||||||
|
create_rng,
|
||||||
|
load_params_file,
|
||||||
|
proof_to_json_file,
|
||||||
|
r1cs_from_json_file,
|
||||||
|
r1cs_from_bin_file,
|
||||||
|
witness_from_json_file,
|
||||||
|
witness_from_bin_file,
|
||||||
|
load_proof_json_file,
|
||||||
|
load_inputs_json_file,
|
||||||
|
create_verifier_sol_file,
|
||||||
|
proving_key_json_file,
|
||||||
|
verification_key_json_file,
|
||||||
|
generate_random_parameters,
|
||||||
|
CircomCircuit,
|
||||||
|
R1CS,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A tool to work with SNARK circuits generated by circom
|
||||||
|
#[derive(Clap)]
|
||||||
|
struct Opts {
|
||||||
|
#[clap(subcommand)]
|
||||||
|
command: SubCommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clap)]
|
||||||
|
enum SubCommand {
|
||||||
|
/// Generate a SNARK proof
|
||||||
|
Prove(ProveOpts),
|
||||||
|
/// Verify a SNARK proof
|
||||||
|
Verify(VerifyOpts),
|
||||||
|
/// Generate trusted setup parameters
|
||||||
|
Setup(SetupOpts),
|
||||||
|
/// Generate verifier smart contract
|
||||||
|
GenerateVerifier(GenerateVerifierOpts),
|
||||||
|
/// Export proving and verifying keys compatible with snarkjs/websnark
|
||||||
|
ExportKeys(ExportKeysOpts),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A subcommand for generating a SNARK proof
|
||||||
|
#[derive(Clap)]
|
||||||
|
struct ProveOpts {
|
||||||
|
/// Snark trusted setup parameters file
|
||||||
|
#[clap(short = "p", long = "params", default_value = "params.bin")]
|
||||||
|
params: String,
|
||||||
|
/// Circuit R1CS or JSON file [default: circuit.r1cs|circuit.json]
|
||||||
|
#[clap(short = "c", long = "circuit")]
|
||||||
|
circuit: Option<String>,
|
||||||
|
/// Witness JSON file [default: witness.wtns|witness.json]
|
||||||
|
#[clap(short = "w", long = "witness")]
|
||||||
|
witness: Option<String>,
|
||||||
|
/// Output file for proof JSON
|
||||||
|
#[clap(short = "r", long = "proof", default_value = "proof.json")]
|
||||||
|
proof: String,
|
||||||
|
/// Output file for public inputs JSON
|
||||||
|
#[clap(short = "o", long = "public", default_value = "public.json")]
|
||||||
|
public: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A subcommand for verifying a SNARK proof
|
||||||
|
#[derive(Clap)]
|
||||||
|
struct VerifyOpts {
|
||||||
|
/// Snark trusted setup parameters file
|
||||||
|
#[clap(short = "p", long = "params", default_value = "params.bin")]
|
||||||
|
params: String,
|
||||||
|
/// Proof JSON file
|
||||||
|
#[clap(short = "r", long = "proof", default_value = "proof.json")]
|
||||||
|
proof: String,
|
||||||
|
/// Public inputs JSON file
|
||||||
|
#[clap(short = "i", long = "public", default_value = "public.json")]
|
||||||
|
public: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A subcommand for generating a trusted setup parameters
|
||||||
|
#[derive(Clap)]
|
||||||
|
struct SetupOpts {
|
||||||
|
/// Snark trusted setup parameters file
|
||||||
|
#[clap(short = "p", long = "params", default_value = "params.bin")]
|
||||||
|
params: String,
|
||||||
|
/// Circuit R1CS or JSON file [default: circuit.r1cs|circuit.json]
|
||||||
|
#[clap(short = "c", long = "circuit")]
|
||||||
|
circuit: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A subcommand for generating a Solidity verifier smart contract
|
||||||
|
#[derive(Clap)]
|
||||||
|
struct GenerateVerifierOpts {
|
||||||
|
/// Snark trusted setup parameters file
|
||||||
|
#[clap(short = "p", long = "params", default_value = "params.bin")]
|
||||||
|
params: String,
|
||||||
|
/// Output smart contract name
|
||||||
|
#[clap(short = "v", long = "verifier", default_value = "Verifier.sol")]
|
||||||
|
verifier: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A subcommand for exporting proving and verifying keys compatible with snarkjs/websnark
|
||||||
|
#[derive(Clap)]
|
||||||
|
struct ExportKeysOpts {
|
||||||
|
/// Snark trusted setup parameters file
|
||||||
|
#[clap(short = "p", long = "params", default_value = "params.bin")]
|
||||||
|
params: String,
|
||||||
|
/// Circuit R1CS or JSON file [default: circuit.r1cs|circuit.json]
|
||||||
|
#[clap(short = "c", long = "circuit")]
|
||||||
|
circuit: Option<String>,
|
||||||
|
/// Output proving key file
|
||||||
|
#[clap(short = "r", long = "pk", default_value = "proving_key.json")]
|
||||||
|
pk: String,
|
||||||
|
/// Output verifying key file
|
||||||
|
#[clap(short = "v", long = "vk", default_value = "verification_key.json")]
|
||||||
|
vk: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let opts: Opts = Opts::parse();
|
||||||
|
match opts.command {
|
||||||
|
SubCommand::Prove(o) => {
|
||||||
|
prove(o);
|
||||||
|
}
|
||||||
|
SubCommand::Verify(o) => {
|
||||||
|
verify(o);
|
||||||
|
}
|
||||||
|
SubCommand::Setup(o) => {
|
||||||
|
setup(o);
|
||||||
|
}
|
||||||
|
SubCommand::GenerateVerifier(o) => {
|
||||||
|
generate_verifier(o);
|
||||||
|
}
|
||||||
|
SubCommand::ExportKeys(o) => {
|
||||||
|
export_keys(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_r1cs(filename: &str) -> R1CS<Bn256> {
|
||||||
|
if filename.ends_with("json") {
|
||||||
|
r1cs_from_json_file(filename)
|
||||||
|
} else {
|
||||||
|
let (r1cs, _wire_mapping) = r1cs_from_bin_file(filename).unwrap();
|
||||||
|
r1cs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_circuit_file(filename: Option<String>) -> String {
|
||||||
|
match filename {
|
||||||
|
Some(s) => s,
|
||||||
|
None => if Path::new("circuit.r1cs").exists() || !Path::new("circuit.json").exists() {
|
||||||
|
"circuit.r1cs".to_string()
|
||||||
|
} else {
|
||||||
|
"circuit.json".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_witness<E: Engine>(filename: &str) -> Vec<E::Fr> {
|
||||||
|
if filename.ends_with("json") {
|
||||||
|
witness_from_json_file::<E>(filename)
|
||||||
|
} else {
|
||||||
|
witness_from_bin_file::<E>(filename).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_witness_file(filename: Option<String>) -> String {
|
||||||
|
match filename {
|
||||||
|
Some(s) => s,
|
||||||
|
None => if Path::new("witness.wtns").exists() || !Path::new("witness.json").exists() {
|
||||||
|
"witness.wtns".to_string()
|
||||||
|
} else {
|
||||||
|
"witness.json".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prove(opts: ProveOpts) {
|
||||||
|
let rng = create_rng();
|
||||||
|
let params = load_params_file(&opts.params);
|
||||||
|
let circuit_file = resolve_circuit_file(opts.circuit);
|
||||||
|
let witness_file = resolve_witness_file(opts.witness);
|
||||||
|
println!("Loading circuit from {}...", circuit_file);
|
||||||
|
let circuit = CircomCircuit {
|
||||||
|
r1cs: load_r1cs(&circuit_file),
|
||||||
|
witness: Some(load_witness::<Bn256>(&witness_file)),
|
||||||
|
wire_mapping: None,
|
||||||
|
};
|
||||||
|
println!("Proving...");
|
||||||
|
let proof = prove2(circuit.clone(), ¶ms, rng).unwrap();
|
||||||
|
proof_to_json_file(&proof, &opts.proof).unwrap();
|
||||||
|
fs::write(&opts.public, circuit.get_public_inputs_json().as_bytes()).unwrap();
|
||||||
|
println!("Saved {} and {}", opts.proof, opts.public);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify(opts: VerifyOpts) {
|
||||||
|
let params = load_params_file(&opts.params);
|
||||||
|
let proof = load_proof_json_file::<Bn256>(&opts.proof);
|
||||||
|
let inputs = load_inputs_json_file::<Bn256>(&opts.public);
|
||||||
|
let correct = verify2(¶ms, &proof, &inputs).unwrap();
|
||||||
|
if correct {
|
||||||
|
println!("Proof is correct");
|
||||||
|
} else {
|
||||||
|
println!("Proof is invalid!");
|
||||||
|
std::process::exit(400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(opts: SetupOpts) {
|
||||||
|
let circuit_file = resolve_circuit_file(opts.circuit);
|
||||||
|
println!("Loading circuit from {}...", circuit_file);
|
||||||
|
let rng = create_rng();
|
||||||
|
let circuit = CircomCircuit {
|
||||||
|
r1cs: load_r1cs(&circuit_file),
|
||||||
|
witness: None,
|
||||||
|
wire_mapping: None,
|
||||||
|
};
|
||||||
|
println!("Generating trusted setup parameters...");
|
||||||
|
let params = generate_random_parameters(circuit, rng).unwrap();
|
||||||
|
println!("Writing to file...");
|
||||||
|
let writer = File::create(&opts.params).unwrap();
|
||||||
|
params.write(writer).unwrap();
|
||||||
|
println!("Saved parameters to {}", opts.params);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_verifier(opts: GenerateVerifierOpts) {
|
||||||
|
let params = load_params_file(&opts.params);
|
||||||
|
create_verifier_sol_file(¶ms, &opts.verifier).unwrap();
|
||||||
|
println!("Created {}", opts.verifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn export_keys(opts: ExportKeysOpts) {
|
||||||
|
println!("Exporting {}...", opts.params);
|
||||||
|
let params = load_params_file(&opts.params);
|
||||||
|
let circuit_file = resolve_circuit_file(opts.circuit);
|
||||||
|
let circuit = CircomCircuit {
|
||||||
|
r1cs: load_r1cs(&circuit_file),
|
||||||
|
witness: None,
|
||||||
|
wire_mapping: None,
|
||||||
|
};
|
||||||
|
proving_key_json_file(¶ms, circuit, &opts.pk).unwrap();
|
||||||
|
verification_key_json_file(¶ms, &opts.vk).unwrap();
|
||||||
|
println!("Created {} and {}.", opts.pk, opts.vk);
|
||||||
|
}
|
227
src/r1cs_reader.rs
Normal file
227
src/r1cs_reader.rs
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
#![allow(unused_variables, dead_code)]
|
||||||
|
use byteorder::{ReadBytesExt, LittleEndian};
|
||||||
|
use std::{collections::HashMap, io::{Error, ErrorKind, Read, Result, Seek, SeekFrom}};
|
||||||
|
use bellman_ce::pairing::{
|
||||||
|
Engine,
|
||||||
|
bn256::Bn256,
|
||||||
|
ff::{
|
||||||
|
Field, PrimeField, PrimeFieldRepr,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
use crate::circom_circuit::Constraint;
|
||||||
|
#[cfg(test)]
|
||||||
|
use std::io::{BufReader, Cursor};
|
||||||
|
|
||||||
|
pub struct Header {
|
||||||
|
pub field_size: u32,
|
||||||
|
pub prime_size: Vec<u8>,
|
||||||
|
pub n_wires: u32,
|
||||||
|
pub n_pub_out: u32,
|
||||||
|
pub n_pub_in: u32,
|
||||||
|
pub n_prv_in: u32,
|
||||||
|
pub n_labels: u64,
|
||||||
|
pub n_constraints: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct R1CSFile<E: Engine> {
|
||||||
|
pub version: u32,
|
||||||
|
pub header: Header,
|
||||||
|
pub constraints: Vec<Constraint<E>>,
|
||||||
|
pub wire_mapping: Vec<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_field<R: Read, E: Engine>(mut reader: R) -> Result<E::Fr> {
|
||||||
|
let mut repr = E::Fr::zero().into_repr();
|
||||||
|
repr.read_le(&mut reader)?;
|
||||||
|
let fr = E::Fr::from_repr(repr)
|
||||||
|
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
|
||||||
|
Ok(fr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_header<R: Read>(mut reader: R, size: u64) -> Result<Header> {
|
||||||
|
let field_size = reader.read_u32::<LittleEndian>()?;
|
||||||
|
let mut prime_size = vec![0u8; field_size as usize];
|
||||||
|
reader.read_exact(&mut prime_size)?;
|
||||||
|
if size != 32 + field_size as u64 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "Invalid header section size"))
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Header {
|
||||||
|
field_size,
|
||||||
|
prime_size,
|
||||||
|
n_wires: reader.read_u32::<LittleEndian>()?,
|
||||||
|
n_pub_out: reader.read_u32::<LittleEndian>()?,
|
||||||
|
n_pub_in: reader.read_u32::<LittleEndian>()?,
|
||||||
|
n_prv_in: reader.read_u32::<LittleEndian>()?,
|
||||||
|
n_labels: reader.read_u64::<LittleEndian>()?,
|
||||||
|
n_constraints: reader.read_u32::<LittleEndian>()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_constraint_vec<R: Read, E:Engine>(mut reader: R, header: &Header) -> Result<Vec<(usize, E::Fr)>> {
|
||||||
|
let n_vec = reader.read_u32::<LittleEndian>()? as usize;
|
||||||
|
let mut vec = Vec::with_capacity(n_vec);
|
||||||
|
for _ in 0..n_vec {
|
||||||
|
vec.push((
|
||||||
|
reader.read_u32::<LittleEndian>()? as usize,
|
||||||
|
read_field::<&mut R, E>(&mut reader)?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_constraints<R: Read, E: Engine>(mut reader: R, size: u64, header: &Header) -> Result<Vec<Constraint<E>>> {
|
||||||
|
// todo check section size
|
||||||
|
let mut vec = Vec::with_capacity(header.n_constraints as usize);
|
||||||
|
for _ in 0..header.n_constraints {
|
||||||
|
vec.push((
|
||||||
|
read_constraint_vec::<&mut R, E>(&mut reader, &header)?,
|
||||||
|
read_constraint_vec::<&mut R, E>(&mut reader, &header)?,
|
||||||
|
read_constraint_vec::<&mut R, E>(&mut reader, &header)?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_map<R: Read>(mut reader: R, size: u64, header: &Header) -> Result<Vec<u64>> {
|
||||||
|
if size != header.n_wires as u64 * 8 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "Invalid map section size"))
|
||||||
|
}
|
||||||
|
let mut vec = Vec::with_capacity(header.n_wires as usize);
|
||||||
|
for _ in 0..header.n_wires {
|
||||||
|
vec.push(reader.read_u64::<LittleEndian>()?);
|
||||||
|
}
|
||||||
|
if vec[0] != 0 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "Wire 0 should always be mapped to 0"))
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<R: Read + Seek>(mut reader: R) -> Result<R1CSFile<Bn256>> {
|
||||||
|
let mut magic = [0u8; 4];
|
||||||
|
reader.read_exact(&mut magic)?;
|
||||||
|
if magic != [0x72, 0x31, 0x63, 0x73] { // magic = "r1cs"
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "Invalid magic number"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let version = reader.read_u32::<LittleEndian>()?;
|
||||||
|
if version != 1 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "Unsupported version"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let num_sections = reader.read_u32::<LittleEndian>()?;
|
||||||
|
|
||||||
|
// section type -> file offset
|
||||||
|
let mut sec_offsets = HashMap::<u32, u64>::new();
|
||||||
|
let mut sec_sizes = HashMap::<u32, u64>::new();
|
||||||
|
|
||||||
|
// get file offset of each section
|
||||||
|
for _ in 0..num_sections {
|
||||||
|
let sec_type = reader.read_u32::<LittleEndian>()?;
|
||||||
|
let sec_size = reader.read_u64::<LittleEndian>()?;
|
||||||
|
let offset = reader.seek(SeekFrom::Current(0))?;
|
||||||
|
sec_offsets.insert(sec_type, offset);
|
||||||
|
sec_sizes.insert(sec_type, sec_size);
|
||||||
|
reader.seek(SeekFrom::Current(sec_size as i64))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let header_type = 1;
|
||||||
|
let constraint_type = 2;
|
||||||
|
let wire2label_type = 3;
|
||||||
|
|
||||||
|
reader.seek(SeekFrom::Start(*sec_offsets.get(&header_type).unwrap()))?;
|
||||||
|
let header = read_header(&mut reader, *sec_sizes.get(&header_type).unwrap())?;
|
||||||
|
if header.field_size != 32 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "This parser only supports 32-byte fields"))
|
||||||
|
}
|
||||||
|
if header.prime_size != hex!("010000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430") {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "This parser only supports bn256"))
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.seek(SeekFrom::Start(*sec_offsets.get(&constraint_type).unwrap()))?;
|
||||||
|
let constraints = read_constraints::<&mut R, Bn256>(&mut reader, *sec_sizes.get(&constraint_type).unwrap(), &header)?;
|
||||||
|
|
||||||
|
reader.seek(SeekFrom::Start(*sec_offsets.get(&wire2label_type).unwrap()))?;
|
||||||
|
let wire_mapping = read_map(&mut reader, *sec_sizes.get(&wire2label_type).unwrap(), &header)?;
|
||||||
|
|
||||||
|
|
||||||
|
Ok(R1CSFile { version, header, constraints, wire_mapping })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample() {
|
||||||
|
let data = hex!("
|
||||||
|
72316373
|
||||||
|
01000000
|
||||||
|
03000000
|
||||||
|
01000000 40000000 00000000
|
||||||
|
20000000
|
||||||
|
010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430
|
||||||
|
07000000
|
||||||
|
01000000
|
||||||
|
02000000
|
||||||
|
03000000
|
||||||
|
e8030000 00000000
|
||||||
|
03000000
|
||||||
|
02000000 88020000 00000000
|
||||||
|
02000000
|
||||||
|
05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
06000000 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
03000000
|
||||||
|
00000000 02000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
02000000 14000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
03000000 0C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
02000000
|
||||||
|
00000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
02000000 07000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
03000000
|
||||||
|
01000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
04000000 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
02000000
|
||||||
|
03000000 2C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
06000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
00000000
|
||||||
|
01000000
|
||||||
|
06000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
03000000
|
||||||
|
00000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
02000000 0B000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
03000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
01000000
|
||||||
|
06000000 58020000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|
||||||
|
03000000 38000000 00000000
|
||||||
|
00000000 00000000
|
||||||
|
03000000 00000000
|
||||||
|
0a000000 00000000
|
||||||
|
0b000000 00000000
|
||||||
|
0c000000 00000000
|
||||||
|
0f000000 00000000
|
||||||
|
44010000 00000000
|
||||||
|
");
|
||||||
|
|
||||||
|
use bellman_ce::pairing::ff;
|
||||||
|
let reader = BufReader::new(Cursor::new(&data[..]));
|
||||||
|
let file = read(reader).unwrap();
|
||||||
|
assert_eq!(file.version, 1);
|
||||||
|
|
||||||
|
assert_eq!(file.header.field_size, 32);
|
||||||
|
assert_eq!(file.header.prime_size, &hex!("010000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430"));
|
||||||
|
assert_eq!(file.header.n_wires, 7);
|
||||||
|
assert_eq!(file.header.n_pub_out, 1);
|
||||||
|
assert_eq!(file.header.n_pub_in, 2);
|
||||||
|
assert_eq!(file.header.n_prv_in, 3);
|
||||||
|
assert_eq!(file.header.n_labels, 0x03e8);
|
||||||
|
assert_eq!(file.header.n_constraints, 3);
|
||||||
|
|
||||||
|
assert_eq!(file.constraints.len(), 3);
|
||||||
|
assert_eq!(file.constraints[0].0.len(), 2);
|
||||||
|
assert_eq!(file.constraints[0].0[0].0, 5);
|
||||||
|
assert_eq!(file.constraints[0].0[0].1, ff::from_hex("0x03").unwrap());
|
||||||
|
assert_eq!(file.constraints[2].1[0].0, 0);
|
||||||
|
assert_eq!(file.constraints[2].1[0].1, ff::from_hex("0x06").unwrap());
|
||||||
|
assert_eq!(file.constraints[1].2.len(), 0);
|
||||||
|
|
||||||
|
assert_eq!(file.wire_mapping.len(), 7);
|
||||||
|
assert_eq!(file.wire_mapping[1], 3);
|
||||||
|
}
|
102
src/utils.rs
Normal file
102
src/utils.rs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
extern crate bellman_ce;
|
||||||
|
extern crate rand;
|
||||||
|
extern crate byteorder;
|
||||||
|
extern crate num_bigint;
|
||||||
|
extern crate num_traits;
|
||||||
|
|
||||||
|
use std::fmt::Display;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use num_bigint::BigUint;
|
||||||
|
use num_traits::Num;
|
||||||
|
use bellman_ce::{
|
||||||
|
groth16::Proof,
|
||||||
|
pairing::{
|
||||||
|
ff::PrimeField,
|
||||||
|
CurveAffine,
|
||||||
|
bn256::{
|
||||||
|
G1Affine,
|
||||||
|
G2Affine,
|
||||||
|
Fq12,
|
||||||
|
Bn256,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn repr_to_big<T: Display>(r: T) -> String {
|
||||||
|
BigUint::from_str_radix(&format!("{}", r)[2..], 16).unwrap().to_str_radix(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn repr_to_hex<T: Display>(r: T) -> String {
|
||||||
|
format!("{}", r)[2..].to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proof_to_hex(proof: &Proof<Bn256>) -> String {
|
||||||
|
let a = proof.a.into_xy_unchecked();
|
||||||
|
let b = proof.b.into_xy_unchecked();
|
||||||
|
let c = proof.c.into_xy_unchecked();
|
||||||
|
[a.0, a.1, b.0.c1, b.0.c0, b.1.c1, b.1.c0, c.0, c.1]
|
||||||
|
.iter()
|
||||||
|
.map(|e| repr_to_hex(e.into_repr()))
|
||||||
|
.join("")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn p1_to_vec(p: &G1Affine) -> Vec<String> {
|
||||||
|
let xy = p.into_xy_unchecked();
|
||||||
|
vec![
|
||||||
|
repr_to_big(xy.0.into_repr()),
|
||||||
|
repr_to_big(xy.1.into_repr()),
|
||||||
|
if p.is_zero() { "0".to_string() } else { "1".to_string() }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn p2_to_vec(p: &G2Affine) -> Vec<Vec<String>> {
|
||||||
|
let xy = p.into_xy_unchecked();
|
||||||
|
vec![
|
||||||
|
vec![
|
||||||
|
repr_to_big(xy.0.c0.into_repr()),
|
||||||
|
repr_to_big(xy.0.c1.into_repr()),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
repr_to_big(xy.1.c0.into_repr()),
|
||||||
|
repr_to_big(xy.1.c1.into_repr()),
|
||||||
|
],
|
||||||
|
if p.is_zero() {
|
||||||
|
vec!["0".to_string(), "0".to_string()]
|
||||||
|
} else {
|
||||||
|
vec!["1".to_string(), "0".to_string()]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pairing_to_vec(p: &Fq12) -> Vec<Vec<Vec<String>>> {
|
||||||
|
vec![
|
||||||
|
vec![
|
||||||
|
vec![
|
||||||
|
repr_to_big(p.c0.c0.c0.into_repr()),
|
||||||
|
repr_to_big(p.c0.c0.c1.into_repr()),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
repr_to_big(p.c0.c1.c0.into_repr()),
|
||||||
|
repr_to_big(p.c0.c1.c1.into_repr()),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
repr_to_big(p.c0.c2.c0.into_repr()),
|
||||||
|
repr_to_big(p.c0.c2.c1.into_repr()),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
vec![
|
||||||
|
repr_to_big(p.c1.c0.c0.into_repr()),
|
||||||
|
repr_to_big(p.c1.c0.c1.into_repr()),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
repr_to_big(p.c1.c1.c0.into_repr()),
|
||||||
|
repr_to_big(p.c1.c1.c1.into_repr()),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
repr_to_big(p.c1.c2.c0.into_repr()),
|
||||||
|
repr_to_big(p.c1.c2.c1.into_repr()),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
}
|
168
src/verifier_groth.sol
Normal file
168
src/verifier_groth.sol
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
pragma solidity ^0.6.0;
|
||||||
|
|
||||||
|
library Pairing {
|
||||||
|
uint256 constant PRIME_Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||||
|
|
||||||
|
struct G1Point {
|
||||||
|
uint256 X;
|
||||||
|
uint256 Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encoding of field elements is: X[0] * z + X[1]
|
||||||
|
struct G2Point {
|
||||||
|
uint256[2] X;
|
||||||
|
uint256[2] Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return The negation of p, i.e. p.plus(p.negate()) should be zero
|
||||||
|
*/
|
||||||
|
function negate(G1Point memory p) internal pure returns (G1Point memory) {
|
||||||
|
// The prime q in the base field F_q for G1
|
||||||
|
if (p.X == 0 && p.Y == 0) {
|
||||||
|
return G1Point(0, 0);
|
||||||
|
} else {
|
||||||
|
return G1Point(p.X, PRIME_Q - (p.Y % PRIME_Q));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return r the sum of two points of G1
|
||||||
|
*/
|
||||||
|
function plus(
|
||||||
|
G1Point memory p1,
|
||||||
|
G1Point memory p2
|
||||||
|
) internal view returns (G1Point memory r) {
|
||||||
|
uint256[4] memory input = [
|
||||||
|
p1.X, p1.Y,
|
||||||
|
p2.X, p2.Y
|
||||||
|
];
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
// solium-disable-next-line security/no-inline-assembly
|
||||||
|
assembly {
|
||||||
|
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||||
|
// Use "invalid" to make gas estimation work
|
||||||
|
switch success case 0 { invalid() }
|
||||||
|
}
|
||||||
|
|
||||||
|
require(success, "pairing-add-failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @return r the product of a point on G1 and a scalar, i.e.
|
||||||
|
* p == p.scalarMul(1) and p.plus(p) == p.scalarMul(2) for all
|
||||||
|
* points p.
|
||||||
|
*/
|
||||||
|
function scalarMul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
|
||||||
|
uint256[3] memory input = [p.X, p.Y, s];
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
// solium-disable-next-line security/no-inline-assembly
|
||||||
|
assembly {
|
||||||
|
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||||
|
// Use "invalid" to make gas estimation work
|
||||||
|
switch success case 0 { invalid() }
|
||||||
|
}
|
||||||
|
|
||||||
|
require(success, "pairing-mul-failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @return The result of computing the pairing check
|
||||||
|
* e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||||
|
* For example,
|
||||||
|
* pairing([P1(), P1().negate()], [P2(), P2()]) should return true.
|
||||||
|
*/
|
||||||
|
function pairing(
|
||||||
|
G1Point memory a1,
|
||||||
|
G2Point memory a2,
|
||||||
|
G1Point memory b1,
|
||||||
|
G2Point memory b2,
|
||||||
|
G1Point memory c1,
|
||||||
|
G2Point memory c2,
|
||||||
|
G1Point memory d1,
|
||||||
|
G2Point memory d2
|
||||||
|
) internal view returns (bool) {
|
||||||
|
uint256[24] memory input = [
|
||||||
|
a1.X, a1.Y, a2.X[0], a2.X[1], a2.Y[0], a2.Y[1],
|
||||||
|
b1.X, b1.Y, b2.X[0], b2.X[1], b2.Y[0], b2.Y[1],
|
||||||
|
c1.X, c1.Y, c2.X[0], c2.X[1], c2.Y[0], c2.Y[1],
|
||||||
|
d1.X, d1.Y, d2.X[0], d2.X[1], d2.Y[0], d2.Y[1]
|
||||||
|
];
|
||||||
|
uint256[1] memory out;
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
// solium-disable-next-line security/no-inline-assembly
|
||||||
|
assembly {
|
||||||
|
success := staticcall(sub(gas(), 2000), 8, input, mul(24, 0x20), out, 0x20)
|
||||||
|
// Use "invalid" to make gas estimation work
|
||||||
|
switch success case 0 { invalid() }
|
||||||
|
}
|
||||||
|
|
||||||
|
require(success, "pairing-opcode-failed");
|
||||||
|
return out[0] != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Verifier {
|
||||||
|
uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
|
||||||
|
uint256 constant PRIME_Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
|
||||||
|
using Pairing for *;
|
||||||
|
|
||||||
|
struct VerifyingKey {
|
||||||
|
Pairing.G1Point alfa1;
|
||||||
|
Pairing.G2Point beta2;
|
||||||
|
Pairing.G2Point gamma2;
|
||||||
|
Pairing.G2Point delta2;
|
||||||
|
Pairing.G1Point[<%vk_ic_length%>] IC;
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||||
|
vk.alfa1 = Pairing.G1Point(<%vk_alfa1%>);
|
||||||
|
vk.beta2 = Pairing.G2Point(<%vk_beta2%>);
|
||||||
|
vk.gamma2 = Pairing.G2Point(<%vk_gamma2%>);
|
||||||
|
vk.delta2 = Pairing.G2Point(<%vk_delta2%>);
|
||||||
|
<%vk_ic_pts%>
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @returns Whether the proof is valid given the hardcoded verifying key
|
||||||
|
* above and the public inputs
|
||||||
|
*/
|
||||||
|
function verifyProof(
|
||||||
|
bytes memory proof,
|
||||||
|
uint256[<%vk_input_length%>] memory input
|
||||||
|
) public view returns (bool) {
|
||||||
|
uint256[8] memory p = abi.decode(proof, (uint256[8]));
|
||||||
|
for (uint8 i = 0; i < p.length; i++) {
|
||||||
|
// Make sure that each element in the proof is less than the prime q
|
||||||
|
require(p[i] < PRIME_Q, "verifier-proof-element-gte-prime-q");
|
||||||
|
}
|
||||||
|
Pairing.G1Point memory proofA = Pairing.G1Point(p[0], p[1]);
|
||||||
|
Pairing.G2Point memory proofB = Pairing.G2Point([p[2], p[3]], [p[4], p[5]]);
|
||||||
|
Pairing.G1Point memory proofC = Pairing.G1Point(p[6], p[7]);
|
||||||
|
|
||||||
|
VerifyingKey memory vk = verifyingKey();
|
||||||
|
// Compute the linear combination vkX
|
||||||
|
Pairing.G1Point memory vkX = vk.IC[0];
|
||||||
|
for (uint256 i = 0; i < input.length; i++) {
|
||||||
|
// Make sure that every input is less than the snark scalar field
|
||||||
|
require(input[i] < SNARK_SCALAR_FIELD, "verifier-input-gte-snark-scalar-field");
|
||||||
|
vkX = Pairing.plus(vkX, Pairing.scalarMul(vk.IC[i + 1], input[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pairing.pairing(
|
||||||
|
Pairing.negate(proofA),
|
||||||
|
proofB,
|
||||||
|
vk.alfa1,
|
||||||
|
vk.beta2,
|
||||||
|
vkX,
|
||||||
|
vk.gamma2,
|
||||||
|
proofC,
|
||||||
|
vk.delta2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
94
src/wtns_reader.rs
Normal file
94
src/wtns_reader.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use byteorder::{ReadBytesExt, LittleEndian};
|
||||||
|
use std::io::{Read, Result, ErrorKind, Error};
|
||||||
|
use bellman_ce::pairing::{
|
||||||
|
Engine,
|
||||||
|
ff::{
|
||||||
|
Field, PrimeField, PrimeFieldRepr,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Header {
|
||||||
|
pub field_size: u32,
|
||||||
|
pub prime_size: Vec<u8>,
|
||||||
|
pub witness_len: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WTNSFile<E: Engine> {
|
||||||
|
pub version: u32,
|
||||||
|
pub header: Header,
|
||||||
|
pub witness: Vec<E::Fr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_field<R: Read, E: Engine>(mut reader: R) -> Result<E::Fr> {
|
||||||
|
let mut repr = E::Fr::zero().into_repr();
|
||||||
|
repr.read_le(&mut reader)?;
|
||||||
|
let fr = E::Fr::from_repr(repr)
|
||||||
|
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
|
||||||
|
Ok(fr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_header<R: Read>(mut reader: R, size: u64) -> Result<Header> {
|
||||||
|
let field_size = reader.read_u32::<LittleEndian>()?;
|
||||||
|
let mut prime_size = vec![0u8; field_size as usize];
|
||||||
|
reader.read_exact(&mut prime_size)?;
|
||||||
|
//if size != 32 + field_size as u64 {
|
||||||
|
if size != 4 + 32 + 4 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "Invalid header section size"))
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Header {
|
||||||
|
field_size,
|
||||||
|
prime_size,
|
||||||
|
witness_len: reader.read_u32::<LittleEndian>()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_witness<R: Read, E:Engine>(mut reader: R, size: u64, header: &Header) -> Result<Vec<E::Fr>> {
|
||||||
|
if size != (header.witness_len * header.field_size) as u64 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "Invalid witness section size"));
|
||||||
|
}
|
||||||
|
let mut result = Vec::with_capacity(header.witness_len as usize);
|
||||||
|
for _ in 0..header.witness_len {
|
||||||
|
result.push(read_field::<&mut R, E>(&mut reader)?);
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<E: Engine, R: Read>(mut reader: R) -> Result<WTNSFile<E>> {
|
||||||
|
let mut magic = [0u8; 4];
|
||||||
|
reader.read_exact(&mut magic)?;
|
||||||
|
if magic != [119, 116, 110, 115] { // magic = "wtns"
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "Invalid magic number"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let version = reader.read_u32::<LittleEndian>()?;
|
||||||
|
if version > 2 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "Unsupported version"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let _num_sections = reader.read_u32::<LittleEndian>()?;
|
||||||
|
|
||||||
|
// todo: rewrite this to support different section order and unknown sections
|
||||||
|
// todo: handle sec_size correctly
|
||||||
|
let sec_type = reader.read_u32::<LittleEndian>()?;
|
||||||
|
if sec_type != 1 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "Invalid section type"));
|
||||||
|
}
|
||||||
|
let sec_size = reader.read_u64::<LittleEndian>()?;
|
||||||
|
let header = read_header(&mut reader, sec_size)?;
|
||||||
|
if header.field_size != 32 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "This parser only supports 32-byte fields"))
|
||||||
|
}
|
||||||
|
if header.prime_size != hex!("010000f093f5e1439170b97948e833285d588181b64550b829a031e1724e6430") {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "This parser only supports bn256"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let sec_type = reader.read_u32::<LittleEndian>()?;
|
||||||
|
if sec_type != 2 {
|
||||||
|
return Err(Error::new(ErrorKind::InvalidData, "Invalid section type"));
|
||||||
|
}
|
||||||
|
let sec_size = reader.read_u64::<LittleEndian>()?;
|
||||||
|
let witness = read_witness::<&mut R, E>(&mut reader, sec_size, &header)?;
|
||||||
|
|
||||||
|
Ok(WTNSFile { version, header, witness })
|
||||||
|
}
|
22
test.sh
Normal file
22
test.sh
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Compile the circuit
|
||||||
|
npx circom -rw
|
||||||
|
|
||||||
|
# Do a local trusted setup, generate params.bin
|
||||||
|
cargo run --release setup
|
||||||
|
|
||||||
|
# Export proving and verifying keys compatible with snarkjs and websnark
|
||||||
|
cargo run --release export-keys
|
||||||
|
|
||||||
|
# generate solidity verifier
|
||||||
|
cargo run --release generate-verifier
|
||||||
|
|
||||||
|
# generate and verify proof
|
||||||
|
npx snarkjs calculatewitness # witness is still generated by snarkjs
|
||||||
|
cargo run --release prove
|
||||||
|
cargo run --release verify
|
||||||
|
|
||||||
|
# Double check by verifying the same proof with snarkjs
|
||||||
|
npx snarkjs verify
|
Loading…
Reference in New Issue
Block a user