diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8bffb3984..a1c92ed16 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -42,26 +42,10 @@ jobs: run: cargo fmt --check # Build and run the tests - name: Build and run tests - run: cargo test --verbose --release - # Run our non-interactive examples and assert the complete without error - - name: Verify examples (amm) - run: cargo run --release --bin amm - - name: Verify examples (bigint) - run: cargo run --release --bin bigint - - name: Verify examples (chi_sq) - run: cargo run --release --bin chi_sq - - name: Verify examples (dot_prod) - run: cargo run --release --bin dot_prod - - name: Verify examples (mean_variance) - run: cargo run --release --bin mean_variance - - name: Verify examples (ordering_zkp) - run: cargo run --release --bin ordering_zkp - - name: Verify examples (pir) - run: cargo run --release --bin pir - - name: Verify examples (simple_multiply) - run: cargo run --release --bin simple_multiply - - name: Verify examples (sudoku_zkp) - run: cargo run --release --bin sudoku_zkp + run: cargo test --workspace --verbose --release + - name: Verify examples outside of workspace (allowlist_zkp) + run: cargo test --workspace --verbose + working-directory: ./examples/allowlist_zkp - name: Build sunscreen and bincode run: cargo build --release --package sunscreen --package bincode - name: Build mdBook diff --git a/Cargo.lock b/Cargo.lock index b2267f399..05303f7b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2084,6 +2084,13 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "polynomial_zkp" +version = "0.1.0" +dependencies = [ + "sunscreen", +] + [[package]] name = "ppv-lite86" version = "0.2.17" diff --git a/Cargo.toml b/Cargo.toml index efb7952e3..1301834de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,11 +19,8 @@ members = [ "sunscreen_compiler_common", "sunscreen_zkp_backend", ] -exclude = [ - "mdBook", - "rust-playground" -] +exclude = ["mdBook", "rust-playground", "examples/allowlist_zkp"] [profile.release] -split-debuginfo="packed" -debug=true +split-debuginfo = "packed" +debug = true diff --git a/benchmarks/bfv_zkp/src/bfv.rs b/benchmarks/bfv_zkp/src/bfv.rs index f1ee4c755..a5c01c874 100644 --- a/benchmarks/bfv_zkp/src/bfv.rs +++ b/benchmarks/bfv_zkp/src/bfv.rs @@ -358,7 +358,7 @@ pub fn prove_public_encryption( encryption_data: &(Ciphertext, Noise, Poly), public_key: &PublicKey, ) -> Proof { - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let prog = app.get_zkp_program(prove_enc).unwrap(); @@ -377,7 +377,7 @@ pub fn prove_public_encryption( let const_args = public_bfv_proof_params(&ciphertext, public_key); runtime - .prove(prog, const_args, vec![], private_args) + .prove(prog, private_args, vec![], const_args) .unwrap() } @@ -387,13 +387,13 @@ pub fn verify_public_encryption( ciphertext: &Ciphertext, public_key: &PublicKey, ) { - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let const_args = public_bfv_proof_params(ciphertext, public_key); let program = app.get_zkp_program(prove_enc).unwrap(); - runtime.verify(program, proof, const_args, vec![]).unwrap(); + runtime.verify(program, proof, vec![], const_args).unwrap(); } #[test] diff --git a/examples/allowlist_zkp/.gitignore b/examples/allowlist_zkp/.gitignore new file mode 100644 index 000000000..ea8c4bf7f --- /dev/null +++ b/examples/allowlist_zkp/.gitignore @@ -0,0 +1 @@ +/target diff --git a/examples/allowlist_zkp/Cargo.lock b/examples/allowlist_zkp/Cargo.lock new file mode 100644 index 000000000..c207446fb --- /dev/null +++ b/examples/allowlist_zkp/Cargo.lock @@ -0,0 +1,1969 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bindgen" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a022e58a142a46fea340d68012b9201c094e93ec3d033a944a24f8fd4a4f09a" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 1.0.109", + "which", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clear_on_drop" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38508a63f4979f0048febc9966fadbd48e5dab31fd0ec6a3f151bbf4a74f7423" +dependencies = [ + "cc", +] + +[[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "emsdk" +version = "0.1.1" +dependencies = [ + "fs_extra", + "reqwest", +] + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-io", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "h2" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.2", + "libc", + "windows-sys", +] + +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + +[[package]] +name = "itoa" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" +dependencies = [ + "cc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core", + "zeroize", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.2", + "libc", +] + +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl" +version = "0.10.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "paste" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "petgraph" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +dependencies = [ + "fixedbitset", + "indexmap", + "serde", + "serde_derive", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prover" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "sunscreen", + "zkp", +] + +[[package]] +name = "quote" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89089e897c013b3deb627116ae56a6955a72b8bed395c9526af31c9fe528b484" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa250384981ea14565685dea16a9ccc4d1c541a13f82b9c168572264d1df8c56" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" + +[[package]] +name = "reqwest" +version = "0.11.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustix" +version = "0.37.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" + +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "seal_fhe" +version = "0.7.0" +dependencies = [ + "bindgen", + "cmake", + "emsdk", + "link-cplusplus", + "serde", + "static_assertions", + "thiserror", +] + +[[package]] +name = "security-framework" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "serde" +version = "1.0.167" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7daf513456463b42aa1d94cff7e0c24d682b429f020b9afa4f5ba5c40a22b237" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.167" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b69b106b68bc8054f0e974e70d19984040f8a5cf9215ca82626ea4853f82c4b9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + +[[package]] +name = "serde_json" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer", + "digest", + "keccak", + "opaque-debug", +] + +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "subtle-ng" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" + +[[package]] +name = "sunscreen" +version = "0.7.0" +dependencies = [ + "bumpalo", + "crypto-bigint", + "log", + "num", + "paste", + "petgraph", + "seal_fhe", + "serde", + "static_assertions", + "subtle", + "sunscreen_backend", + "sunscreen_compiler_common", + "sunscreen_compiler_macros", + "sunscreen_fhe_program", + "sunscreen_runtime", + "sunscreen_zkp_backend", + "thiserror", +] + +[[package]] +name = "sunscreen_backend" +version = "0.7.0" +dependencies = [ + "crossbeam", + "env_logger", + "log", + "num", + "petgraph", + "seal_fhe", + "sunscreen_compiler_common", + "sunscreen_fhe_program", + "sunscreen_runtime", +] + +[[package]] +name = "sunscreen_bulletproofs" +version = "4.0.0" +dependencies = [ + "byteorder", + "clear_on_drop", + "digest", + "merlin", + "rand", + "rand_core", + "serde", + "serde_derive", + "sha3", + "subtle-ng", + "sunscreen_curve25519", + "thiserror", +] + +[[package]] +name = "sunscreen_compiler_common" +version = "0.1.0" +dependencies = [ + "petgraph", + "proc-macro2", + "quote", + "semver", + "serde", + "static_assertions", + "syn 2.0.23", + "thiserror", +] + +[[package]] +name = "sunscreen_compiler_macros" +version = "0.7.0" +dependencies = [ + "proc-macro2", + "quote", + "sunscreen_compiler_common", + "syn 2.0.23", + "thiserror", +] + +[[package]] +name = "sunscreen_curve25519" +version = "4.1.1" +dependencies = [ + "byteorder", + "digest", + "rand_core", + "serde", + "subtle-ng", + "zeroize", +] + +[[package]] +name = "sunscreen_fhe_program" +version = "0.7.0" +dependencies = [ + "petgraph", + "seal_fhe", + "serde", + "static_assertions", + "sunscreen_compiler_common", + "thiserror", +] + +[[package]] +name = "sunscreen_runtime" +version = "0.7.0" +dependencies = [ + "bincode", + "crossbeam", + "log", + "num_cpus", + "petgraph", + "rayon", + "rlp", + "seal_fhe", + "semver", + "serde", + "static_assertions", + "sunscreen_compiler_common", + "sunscreen_fhe_program", + "sunscreen_zkp_backend", + "thiserror", +] + +[[package]] +name = "sunscreen_zkp_backend" +version = "0.1.0" +dependencies = [ + "bumpalo", + "crypto-bigint", + "log", + "merlin", + "petgraph", + "serde", + "static_assertions", + "sunscreen_bulletproofs", + "sunscreen_compiler_common", + "sunscreen_curve25519", + "thiserror", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +dependencies = [ + "autocfg", + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +dependencies = [ + "autocfg", + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "windows-sys", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "verifier" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "sunscreen", + "zkp", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.23", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + +[[package]] +name = "zkp" +version = "0.1.0" +dependencies = [ + "sunscreen", +] diff --git a/examples/allowlist_zkp/Cargo.toml b/examples/allowlist_zkp/Cargo.toml new file mode 100644 index 000000000..8b0419318 --- /dev/null +++ b/examples/allowlist_zkp/Cargo.toml @@ -0,0 +1,7 @@ +[workspace] +members = ["zkp", "prover", "verifier"] + +[workspace.dependencies] +anyhow = "1.0" +bincode = "1.3.3" +sunscreen = { path = "../../sunscreen", features = ["bulletproofs"] } diff --git a/examples/allowlist_zkp/README.md b/examples/allowlist_zkp/README.md new file mode 100644 index 000000000..7fe28c6d5 --- /dev/null +++ b/examples/allowlist_zkp/README.md @@ -0,0 +1,18 @@ +# allowlist + +This example shows a possible project layout using cargo workspaces. The +`prover` and `verifier` are separate crates and refer to the common `zkp` crate +for the ZKP program definition. + +When the prover and verifier live on different machines, they'll probably +communicate by sending the serialized proof over a network call. However, we can +demonstrate a similar scenario by having them communicate as separate processes, +piping a serialized proof from `prover` stdout to `verifier` stdin. + +In this allowlist zkp, the verifier verifies that the prover has an entry on its +public allowlist, without revealing which entry. The allowlist is hardcoded to +the numbers 100 to 199 inclusive. + +```shell +cargo run -p prover -- 101 | cargo run -p verifier +``` diff --git a/examples/allowlist_zkp/prover/Cargo.toml b/examples/allowlist_zkp/prover/Cargo.toml new file mode 100644 index 000000000..eda94178d --- /dev/null +++ b/examples/allowlist_zkp/prover/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "prover" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = { workspace = true } +bincode = { workspace = true } +sunscreen = { workspace = true } +zkp = { path = "../zkp" } diff --git a/examples/allowlist_zkp/prover/src/main.rs b/examples/allowlist_zkp/prover/src/main.rs new file mode 100644 index 000000000..50454be8c --- /dev/null +++ b/examples/allowlist_zkp/prover/src/main.rs @@ -0,0 +1,30 @@ +use std::io; + +use anyhow::Result; +use sunscreen::{ + bulletproofs::BulletproofsBackend, types::zkp::BulletproofsField, ZkpProgramFnExt, +}; + +use zkp::{default_list, allowlist}; + +fn main() -> Result<()> { + let prog = allowlist.compile::()?; + let runtime = allowlist.runtime::()?; + + let entry: BulletproofsField = get_first_arg()?.unwrap_or(101).into(); + let list: [BulletproofsField; 100] = default_list(); + + let proof = runtime + .proof_builder(&prog) + .private_input(entry) + .public_input(list) + .prove()?; + + bincode::serialize_into(io::stdout(), &proof)?; + Ok(()) +} + +fn get_first_arg() -> Result> { + let arg = std::env::args().nth(1).map(|s| s.parse()).transpose()?; + Ok(arg) +} diff --git a/examples/allowlist_zkp/verifier/Cargo.toml b/examples/allowlist_zkp/verifier/Cargo.toml new file mode 100644 index 000000000..e036c2315 --- /dev/null +++ b/examples/allowlist_zkp/verifier/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "verifier" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = { workspace = true } +bincode = { workspace = true } +sunscreen = { workspace = true } +zkp = { path = "../zkp" } diff --git a/examples/allowlist_zkp/verifier/src/main.rs b/examples/allowlist_zkp/verifier/src/main.rs new file mode 100644 index 000000000..e64c79a68 --- /dev/null +++ b/examples/allowlist_zkp/verifier/src/main.rs @@ -0,0 +1,54 @@ +use std::io; + +use anyhow::Result; +use sunscreen::{ + bulletproofs::BulletproofsBackend, types::zkp::BulletproofsField, Proof, ZkpProgramFnExt, +}; + +use zkp::{default_list, allowlist}; + +fn main() -> Result<()> { + let prog = allowlist.compile::()?; + let runtime = allowlist.runtime::()?; + + let proof: Proof = bincode::deserialize_from(io::stdin())?; + + let list: [BulletproofsField; 100] = default_list(); + + runtime + .verification_builder(&prog) + .proof(&proof) + .public_input(list) + .verify()?; + + println!("Verified proof successfully!"); + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn main_works() -> Result<()> { + let prog = allowlist.compile::()?; + let runtime = allowlist.runtime::()?; + + let entry: BulletproofsField = 101.into(); + let list: [BulletproofsField; 100] = default_list(); + + let proof = runtime + .proof_builder(&prog) + .private_input(entry) + .public_input(list) + .prove()?; + + runtime + .verification_builder(&prog) + .proof(&proof) + .public_input(list) + .verify()?; + + Ok(()) + } +} diff --git a/examples/allowlist_zkp/zkp/Cargo.toml b/examples/allowlist_zkp/zkp/Cargo.toml new file mode 100644 index 000000000..ec994ba25 --- /dev/null +++ b/examples/allowlist_zkp/zkp/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "zkp" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +sunscreen = { workspace = true } diff --git a/examples/allowlist_zkp/zkp/src/lib.rs b/examples/allowlist_zkp/zkp/src/lib.rs new file mode 100644 index 000000000..2f9a9c1bf --- /dev/null +++ b/examples/allowlist_zkp/zkp/src/lib.rs @@ -0,0 +1,20 @@ +use std::array; + +use sunscreen::{types::zkp::Field, zkp_program, zkp_var, FieldSpec}; + +/// A ZKP proving a private entry is equal to one of the values in a list. +#[zkp_program] +pub fn allowlist(entry: Field, #[public] list: [Field; 100]) { + let zero = zkp_var!(0); + let one = zkp_var!(1); + let mut poly = one; + for x in list { + poly = poly * (x - entry); + } + poly.constrain_eq(zero); +} + +/// A default list for the prover and verifier to use: [100, 199] +pub fn default_list() -> [Field; 100] { + array::from_fn(|i| Field::from(100 + i as u32)) +} diff --git a/examples/amm/src/main.rs b/examples/amm/src/main.rs index 4c3afdc0c..a734802dc 100644 --- a/examples/amm/src/main.rs +++ b/examples/amm/src/main.rs @@ -106,3 +106,13 @@ fn main() -> Result<(), Error> { Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn main_works() -> Result<(), Error> { + main() + } +} diff --git a/examples/bigint/src/main.rs b/examples/bigint/src/main.rs index 81657391d..596b2474c 100644 --- a/examples/bigint/src/main.rs +++ b/examples/bigint/src/main.rs @@ -89,3 +89,13 @@ fn main() -> Result<(), Error> { Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn main_works() -> Result<(), Error> { + main() + } +} diff --git a/examples/chi_sq/src/main.rs b/examples/chi_sq/src/main.rs index 9f5bc2c44..642858e46 100644 --- a/examples/chi_sq/src/main.rs +++ b/examples/chi_sq/src/main.rs @@ -289,3 +289,13 @@ fn main() -> Result<(), Error> { Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn main_works() -> Result<(), Error> { + main() + } +} diff --git a/examples/dot_prod/src/main.rs b/examples/dot_prod/src/main.rs index cf48f3ba3..96d66bbac 100644 --- a/examples/dot_prod/src/main.rs +++ b/examples/dot_prod/src/main.rs @@ -5,7 +5,7 @@ use sunscreen::{ fhe_program, types::{bfv::Batched, Cipher, LaneCount, SwapRows}, - Compiler, FheProgramInput, FheRuntime, PlainModulusConstraint, + Compiler, Error, FheProgramInput, FheRuntime, PlainModulusConstraint, }; use std::ops::*; @@ -112,7 +112,7 @@ fn is_power_of_2(value: usize) -> bool { * Creates a math vector and returns it represented as both a [`Vec`] and a * [`Batched`] type. */ -fn make_vector() -> Result<(Vec, Batched), sunscreen::Error> { +fn make_vector() -> Result<(Vec, Batched), Error> { if !is_power_of_2(LENDIV2) { panic!("Vector length not a power of 2"); } @@ -129,7 +129,7 @@ fn make_vector() -> Result<(Vec, Batched), s Ok((a, batched)) } -fn main() -> Result<(), sunscreen::Error> { +fn main() -> Result<(), Error> { let (a_vec, a_batched) = make_vector::()?; // Run our naive implementation of dot product we know to be correct. @@ -186,3 +186,13 @@ fn main() -> Result<(), sunscreen::Error> { Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn main_works() -> Result<(), Error> { + main() + } +} diff --git a/examples/mean_variance/src/main.rs b/examples/mean_variance/src/main.rs index b88ee36a5..33e451a6b 100644 --- a/examples/mean_variance/src/main.rs +++ b/examples/mean_variance/src/main.rs @@ -201,3 +201,13 @@ fn main() -> Result<(), Error> { Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn main_works() -> Result<(), Error> { + main() + } +} diff --git a/examples/ordering_zkp/src/main.rs b/examples/ordering_zkp/src/main.rs index 86392887e..119f1cbb3 100644 --- a/examples/ordering_zkp/src/main.rs +++ b/examples/ordering_zkp/src/main.rs @@ -1,15 +1,14 @@ use sunscreen::{ - types::zkp::{ConstrainCmp, Field}, - zkp_program, BulletproofsBackend, Compiler, Error, FieldSpec, ZkpBackend, ZkpRuntime, + bulletproofs::BulletproofsBackend, + types::zkp::{BulletproofsField, ConstrainCmp, Field}, + zkp_program, Compiler, Error, FieldSpec, ZkpRuntime, }; #[zkp_program] -fn greater_than(a: Field, #[constant] b: Field) { +fn greater_than(a: Field, #[public] b: Field) { a.constrain_gt_bounded(b, 32) } -type BPField = Field<::Field>; - fn main() -> Result<(), Error> { let app = Compiler::new() .zkp_backend::() @@ -18,14 +17,14 @@ fn main() -> Result<(), Error> { let greater_than_zkp = app.get_zkp_program(greater_than).unwrap(); - let runtime = ZkpRuntime::new(&BulletproofsBackend::new())?; + let runtime = ZkpRuntime::new(BulletproofsBackend::new())?; - let amount = BPField::from(232); - let threshold = BPField::from(64); + let amount = BulletproofsField::from(232); + let threshold = BulletproofsField::from(64); // Prove that amount > threshold - let proof = runtime.prove(greater_than_zkp, vec![threshold], vec![], vec![amount])?; + let proof = runtime.prove(greater_than_zkp, vec![amount], vec![threshold], vec![])?; runtime.verify(greater_than_zkp, &proof, vec![threshold], vec![])?; @@ -36,15 +35,20 @@ fn main() -> Result<(), Error> { mod tests { use super::*; - fn run_test(amount: BPField, threshold: BPField, should_succeed: bool) { + #[test] + fn main_works() -> Result<(), Error> { + main() + } + + fn run_test(amount: BulletproofsField, threshold: BulletproofsField, should_succeed: bool) { let app = Compiler::new() .zkp_backend::() .zkp_program(greater_than) .compile() .unwrap(); let gt_zkp = app.get_zkp_program(greater_than).unwrap(); - let runtime = ZkpRuntime::new(&BulletproofsBackend::new()).unwrap(); - let proof = runtime.prove(gt_zkp, vec![threshold], vec![], vec![amount]); + let runtime = ZkpRuntime::new(BulletproofsBackend::new()).unwrap(); + let proof = runtime.prove(gt_zkp, vec![amount], vec![threshold], vec![]); if !should_succeed { assert!(proof.is_err()); } else { diff --git a/examples/pir/src/main.rs b/examples/pir/src/main.rs index 626fd0222..53800b0af 100644 --- a/examples/pir/src/main.rs +++ b/examples/pir/src/main.rs @@ -159,3 +159,13 @@ fn main() -> Result<(), Error> { Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn main_works() -> Result<(), Error> { + main() + } +} diff --git a/examples/polynomial_zkp/Cargo.toml b/examples/polynomial_zkp/Cargo.toml new file mode 100644 index 000000000..f52489190 --- /dev/null +++ b/examples/polynomial_zkp/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "polynomial_zkp" +version = "0.1.0" +edition = "2021" + +[dependencies] +sunscreen = { path = "../../sunscreen", features = ["bulletproofs"] } diff --git a/examples/polynomial_zkp/src/main.rs b/examples/polynomial_zkp/src/main.rs new file mode 100644 index 000000000..db7f882be --- /dev/null +++ b/examples/polynomial_zkp/src/main.rs @@ -0,0 +1,354 @@ +use std::array; + +use sunscreen::{ + bulletproofs::BulletproofsBackend, + types::zkp::{ + AddVar, BigInt, BulletproofsField, Coerce, Field, MulVar, NumFieldElements, ProgramNode, + SubVar, ToNativeFields, + }, + with_zkp_ctx, zkp_program, zkp_var, Compiler, Error, FieldSpec, TypeName, ZkpBackend, + ZkpContextOps, ZkpRuntime, +}; + +/// A quotient polynomial over native field elements. +/// +/// This is a polynomial over the quotient ring `Z[x]/(x^N + 1)`. Polynomial quotient rings are +/// very common in the lattice cryptography undergirding FHE, so this is a structure we're +/// particularly interested in. +/// +/// The quotient ring is actually quite simple. Polynomials `p(x)` behave just like they do +/// in`Z[x]`, but they are reduced modulo `x^N + 1`. This is similar to modular arithmetic, where +/// numbers in `Z_q` behave just like those in `Z`, but you reduce numbers `n` greater than `q` to +/// `n mod q`. The only difference is here, instead of taking the remainder of `n` divided by `q`, +/// you take the remainder of `p(x)` divided by `x^N + 1`. Long division with polynomials is +/// typically rather tedious, but lucky for us, the divisor polynomial `x^N + 1` has a _really_ +/// nice property. All you have to do is replace every factor of `x^N` with `-1` in `p(x)`! +/// +/// Let's try an example. Suppose `p(x) = (x^4 - 4)` and `q(x) = (x^2 - 3)` are polynomials in +/// `Z[x]/(x^5 + 1)`. Then +/// +/// ```ignore +/// p(x) * q(x) = (x^4 - 4) * (x^2 - 3) +/// = x^6 - 3x^4 - 4x^2 + 12 +/// = -x - 3x^4 - 4x^2 + 12 +/// = -3x^4 - 4x^2 - x + 12 +/// ``` +/// +/// Pretty easy, right? +/// +/// We represent the polynomial here as an array of coefficients, ordered from least significant to +/// most significant. +#[derive(Debug, Copy, Clone, TypeName)] +pub struct Polynomial { + coefficients: [Field; N], +} + +// To use our `Polynomial` in ZKP programs, we have to satisfy the `Polynomial: ZkpType` +// constraint. This is equivalent to providing impls for `TypeName`, `NumFieldElements`, and +// `ToNativeFields`. The first we are able to #[derive()]. + +// The second one is trivial. +impl NumFieldElements for Polynomial { + const NUM_NATIVE_FIELD_ELEMENTS: usize = N; +} + +// The last one is also fairly trivial! We just need to package up our representation into an +// ordered list of the `BigInt`s underlying the `Field`. +impl ToNativeFields for Polynomial { + fn to_native_fields(&self) -> Vec { + self.coefficients.map(|x| x.val).into_iter().collect() + } +} + +// However, if you try to use the polynomial now, you'll find it is not incredibly useful. We need +// to implement some arithmetic traits to be able to add, subtract, and multiply elements of this +// type. + +// Addition is quite simple, we just add the corresponding coefficients together. +impl AddVar for Polynomial { + fn add(lhs: ProgramNode, rhs: ProgramNode) -> ProgramNode { + let mut coeff_node_indices = vec![]; + + with_zkp_ctx(|ctx| { + for (left, right) in lhs.ids.iter().zip(rhs.ids) { + coeff_node_indices.push(ctx.add_addition(*left, *right)); + } + }); + + Self::coerce(&coeff_node_indices) + } +} + +// Similarly for subtraction. +impl SubVar for Polynomial { + fn sub(lhs: ProgramNode, rhs: ProgramNode) -> ProgramNode { + let mut coeff_node_indices = vec![]; + + with_zkp_ctx(|ctx| { + for (left, right) in lhs.ids.iter().zip(rhs.ids) { + coeff_node_indices.push(ctx.add_subtraction(*left, *right)); + } + }); + + Self::coerce(&coeff_node_indices) + } +} + +// Multiplication is a little more involved, but generally we just follow the logic described in +// the quotient ring above. +impl MulVar for Polynomial { + fn mul(lhs: ProgramNode, rhs: ProgramNode) -> ProgramNode { + let mut output_coeffs = vec![]; + + with_zkp_ctx(|ctx| { + // We'll start with the zero polynomial, and add to each coefficient as we go + output_coeffs = vec![ctx.add_constant(&BigInt::ZERO); N]; + + // When multiplying (a_i x^i) * (b_j x^j), we get a (a_i * b_j) addend for the + // `x^{i+j}` coefficient + for i in 0..N { + for j in 0..N { + // But! Recall we reduce any x^{i+j} to x^{(i+j) % N} in the quotient ring + let coeff_index = (i + j) % N; + + // Next let's multiply (a_i * b_j) + let coeffs_mul = ctx.add_multiplication(lhs.ids[i], rhs.ids[j]); + + // If (i + j) >= N, we have to add the -1 factor + let coeff_addend = if i + j >= N { + ctx.add_negate(coeffs_mul) + } else { + coeffs_mul + }; + + // Finally, let's add it to our running total for that coefficient + output_coeffs[coeff_index] = + ctx.add_addition(output_coeffs[coeff_index], coeff_addend); + } + } + }); + + Self::coerce(&output_coeffs) + } +} + +// Next we'll add a few convenient methods for constructing polynomials within ZKP programs + +impl Polynomial { + /// Create the zero polynomial. + pub fn zero() -> ProgramNode { + let zero = with_zkp_ctx(|ctx| ctx.add_constant(&BigInt::ZERO)); + ProgramNode::new(&[zero; N]) + } + + /// Create the polynomial `1`, i.e. the polynomial with zero coefficients everywhere except + /// for the coefficient `1` at `x^0`. + pub fn one() -> ProgramNode { + let mut poly_ids: [_; N] = Self::zero().ids.try_into().unwrap(); + let one = with_zkp_ctx(|ctx| ctx.add_constant(&BigInt::ONE)); + poly_ids[0] = one; + ProgramNode::new(&poly_ids) + } + + /// Create the polynomial `x`, i.e. the polynomial with zero coefficients everywhere except + /// for the coefficient `1` at `x^1`. + pub fn x() -> ProgramNode { + let mut poly_ids: [_; N] = Self::zero().ids.try_into().unwrap(); + let one = with_zkp_ctx(|ctx| ctx.add_constant(&BigInt::ONE)); + poly_ids[1] = one; + ProgramNode::new(&poly_ids) + } + + /// Make a scalar polynomial, i.e. the polynomial with zero coefficients everywhere except for + /// the coefficient `scalar` at `x^0`. + pub fn scalar(scalar: S) -> ProgramNode + where + S: Into>>, + { + let mut poly_ids: [_; N] = Self::zero().ids.try_into().unwrap(); + poly_ids[0] = scalar.into().ids[0]; + ProgramNode::new(&poly_ids) + } + + /// Make a root polynomial `(x - root)` + pub fn root(root: S) -> ProgramNode + where + S: Into>>, + { + let x = Self::x(); + let r = Self::scalar(root); + x - r + } +} +// One last thing that will be nice for users is an easy way to construct `Polynomial` inputs +// to ZKP programs + +/// Create a `Polynomial` from an array of coefficients beloning to a particular ZKP backend. +pub fn from_coefficients( + coeffs: [I; N], +) -> Polynomial +where + Field: From, +{ + Polynomial { + coefficients: coeffs.map(Field::from), + } +} + +// Notice we want to define the evaluate function not on the `Polynomial` itself, but rather the +// `ProgramNode`. + +pub trait Evaluate { + fn evaluate(&self, point: S) -> ProgramNode> + where + S: Into>>; +} + +impl Evaluate for ProgramNode> { + /// Evaluate the polynomial at `point` + fn evaluate(&self, point: S) -> ProgramNode> + where + S: Into>>, + { + let point = point.into().ids[0]; + let node_index = with_zkp_ctx(|ctx| { + let mut result = ctx.add_constant(&BigInt::ZERO); + let mut pow = ctx.add_constant(&BigInt::ONE); + for coeff in self.ids { + let addend = ctx.add_multiplication(pow, *coeff); + result = ctx.add_addition(result, addend); + pow = ctx.add_multiplication(pow, point); + } + result + }); + + ProgramNode::new(&[node_index]) + } +} + +// Finally, let's use our polynomial! + +#[zkp_program] +pub fn one_of(x: Field, #[public] list: [Field; 5]) { + // Let's build up a polynomial by roots + // Note we want to allow degree 5, so we want a ring modulo x^{6} + let mut poly = Polynomial::::one(); + for elem in list { + poly = poly * Polynomial::root(elem); + } + + // If x is in the list, then it is a root of the polynomial + poly.evaluate(x).constrain_eq(zkp_var!(0)); +} + +// We can also use polynomials as arguments + +#[zkp_program] +pub fn private_eval( + eval: Field, + point: Field, + #[public] poly: Polynomial, +) { + poly.evaluate(point).constrain_eq(eval); +} + +fn main() -> Result<(), Error> { + let app = Compiler::new() + .zkp_backend::() + .zkp_program(one_of) + .zkp_program(private_eval) + .compile()?; + let runtime = ZkpRuntime::new(BulletproofsBackend::new())?; + + // Let's test our `one_of` ZKP works as expected + + let one_of_zkp = app.get_zkp_program(one_of).unwrap(); + + let x = BulletproofsField::from(12345); + let list: [_; 5] = array::from_fn(|i| BulletproofsField::from(12343 + i as u32)); + + let proof = runtime + .proof_builder(one_of_zkp) + .private_input(x) + .public_input(list) + .prove()?; + runtime + .verification_builder(one_of_zkp) + .proof(&proof) + .public_input(list) + .verify()?; + + // Next let's try out `private_eval` + + let private_eval_zkp = app.get_zkp_program(private_eval).unwrap(); + + let poly = from_coefficients::([1, 42, 0, 0, 0, 3, 0, 0, 0, 0]); + let point = BulletproofsField::from(2); + // At point 2, the poly should be equal to 1 + 42 * 2 + 3 * 32 = 181 + let eval = BulletproofsField::from(1 + 42 * 2 + 3 * 32); + + let proof = runtime + .proof_builder(private_eval_zkp) + .private_input(eval) + .private_input(point) + .public_input(poly) + .prove()?; + runtime + .verification_builder(private_eval_zkp) + .proof(&proof) + .public_input(poly) + .verify()?; + + Ok(()) +} + +#[cfg(test)] +mod tests { + use sunscreen::ZkpProgramFnExt; + + use super::*; + + #[test] + fn main_works() -> Result<(), Error> { + main() + } + + #[test] + fn one_of_failure() -> Result<(), Error> { + let one_of_zkp = one_of.compile::()?; + let runtime = one_of.runtime::()?; + + let x = BulletproofsField::from(12345); + let list: [_; 5] = array::from_fn(|i| BulletproofsField::from(12346 + i as u32)); + + let proof = runtime + .proof_builder(&one_of_zkp) + .private_input(x) + .public_input(list) + .prove(); + + assert!(proof.is_err()); + Ok(()) + } + + #[test] + fn eval_poly_failure() -> Result<(), Error> { + let private_eval_zkp = private_eval.compile::()?; + let runtime = private_eval.runtime::()?; + + let poly = from_coefficients::([1, 42, 0, 0, 0, 3, 0, 0, 0, 0]); + // Eval point 3 instead of point 2 + let point = BulletproofsField::from(3); + let eval = BulletproofsField::from(1 + 42 * 2 + 3 * 32); + + let proof = runtime + .proof_builder(&private_eval_zkp) + .private_input(eval) + .private_input(point) + .public_input(poly) + .prove(); + + assert!(proof.is_err()); + Ok(()) + } +} diff --git a/examples/simple_multiply/src/main.rs b/examples/simple_multiply/src/main.rs index 1a4d95060..73bf2f130 100644 --- a/examples/simple_multiply/src/main.rs +++ b/examples/simple_multiply/src/main.rs @@ -81,3 +81,13 @@ fn main() -> Result<(), Error> { Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn main_works() -> Result<(), Error> { + main() + } +} diff --git a/examples/sudoku_zkp/src/main.rs b/examples/sudoku_zkp/src/main.rs index 53d7b9ac2..ad2dfd328 100644 --- a/examples/sudoku_zkp/src/main.rs +++ b/examples/sudoku_zkp/src/main.rs @@ -1,60 +1,11 @@ use sunscreen::{ - types::zkp::Field, zkp_program, zkp_var, BulletproofsBackend, Compiler, Error, FieldSpec, - ZkpBackend, ZkpProgramInput, ZkpRuntime, + bulletproofs::BulletproofsBackend, + types::zkp::{BulletproofsField, Field}, + zkp_program, zkp_var, Error, FieldSpec, ZkpProgramFnExt, }; -type BPField = Field<::Field>; - -fn main() -> Result<(), Error> { - let app = Compiler::new() - .zkp_backend::() - .zkp_program(sudoku_proof) - .compile()?; - - let prog = app.get_zkp_program(sudoku_proof).unwrap(); - - let runtime = ZkpRuntime::new(&BulletproofsBackend::new())?; - - let ex_puzzle = [ - [0, 7, 0, 0, 2, 0, 0, 4, 6], - [0, 6, 0, 0, 0, 0, 8, 9, 0], - [2, 0, 0, 8, 0, 0, 7, 1, 5], - [0, 8, 4, 0, 9, 7, 0, 0, 0], - [7, 1, 0, 0, 0, 0, 0, 5, 9], - [0, 0, 0, 1, 3, 0, 4, 8, 0], - [6, 9, 7, 0, 0, 2, 0, 0, 8], - [0, 5, 8, 0, 0, 0, 0, 6, 0], - [4, 3, 0, 0, 8, 0, 0, 7, 0], - ]; - - let ex_sol = [ - [8, 7, 5, 9, 2, 1, 3, 4, 6], - [3, 6, 1, 7, 5, 4, 8, 9, 2], - [2, 4, 9, 8, 6, 3, 7, 1, 5], - [5, 8, 4, 6, 9, 7, 1, 2, 3], - [7, 1, 3, 2, 4, 8, 6, 5, 9], - [9, 2, 6, 1, 3, 5, 4, 8, 7], - [6, 9, 7, 4, 1, 2, 5, 3, 8], - [1, 5, 8, 3, 7, 9, 2, 6, 4], - [4, 3, 2, 5, 8, 6, 9, 7, 1], - ]; - - let board: Vec = vec![ex_sol.map(|a| a.map(BPField::from)).into()]; - - let cons: Vec = vec![ex_puzzle.map(|a| a.map(BPField::from)).into()]; - - let proof = runtime.prove(prog, cons.clone(), vec![], board)?; - - runtime.verify(prog, &proof, cons, vec![])?; - - Ok(()) -} - #[zkp_program] -fn sudoku_proof( - #[constant] constraints: [[Field; 9]; 9], - board: [[Field; 9]; 9], -) { +fn sudoku_proof(solution: [[Field; 9]; 9], #[public] board: [[Field; 9]; 9]) { let zero = zkp_var!(0); let assert_unique_numbers = |squares| { @@ -67,31 +18,21 @@ fn sudoku_proof( } }; - // Proves that the board matches up with the puzzle where applicable - - for i in 0..9 { - for j in 0..9 { - let square = board[i][j]; - let constraint = constraints[i][j]; - (constraint * (constraint - square)).constrain_eq(zero); - } - } - // Checks rows contain every number from 1 to 9 - for row in board { + for row in solution { assert_unique_numbers(row); } // Checks columns contain each number from 1 to 9 for col in 0..9 { - let column = board.map(|r| r[col]); + let column = solution.map(|r| r[col]); assert_unique_numbers(column); } // Checks squares contain each number from 1 to 9 for i in 0..3 { for j in 0..3 { - let rows = &board[(i * 3)..(i * 3 + 3)]; + let rows = &solution[(i * 3)..(i * 3 + 3)]; let square = rows.iter().map(|s| &s[(j * 3)..(j * 3 + 3)]); @@ -105,6 +46,54 @@ fn sudoku_proof( assert_unique_numbers(flattened_sq); } } + + // Proves that the solution matches up with the puzzle where applicable + for i in 0..9 { + for j in 0..9 { + let square = solution[i][j]; + let constraint = board[i][j]; + (constraint * (constraint - square)).constrain_eq(zero); + } + } +} + +fn main() -> Result<(), Error> { + let prog = sudoku_proof.compile::()?; + let runtime = sudoku_proof.runtime::()?; + + let ex_board = [ + [0, 7, 0, 0, 2, 0, 0, 4, 6], + [0, 6, 0, 0, 0, 0, 8, 9, 0], + [2, 0, 0, 8, 0, 0, 7, 1, 5], + [0, 8, 4, 0, 9, 7, 0, 0, 0], + [7, 1, 0, 0, 0, 0, 0, 5, 9], + [0, 0, 0, 1, 3, 0, 4, 8, 0], + [6, 9, 7, 0, 0, 2, 0, 0, 8], + [0, 5, 8, 0, 0, 0, 0, 6, 0], + [4, 3, 0, 0, 8, 0, 0, 7, 0], + ]; + + let ex_sol = [ + [8, 7, 5, 9, 2, 1, 3, 4, 6], + [3, 6, 1, 7, 5, 4, 8, 9, 2], + [2, 4, 9, 8, 6, 3, 7, 1, 5], + [5, 8, 4, 6, 9, 7, 1, 2, 3], + [7, 1, 3, 2, 4, 8, 6, 5, 9], + [9, 2, 6, 1, 3, 5, 4, 8, 7], + [6, 9, 7, 4, 1, 2, 5, 3, 8], + [1, 5, 8, 3, 7, 9, 2, 6, 4], + [4, 3, 2, 5, 8, 6, 9, 7, 1], + ]; + + let solution = ex_sol.map(|a| a.map(BulletproofsField::from)); + + let board = ex_board.map(|a| a.map(BulletproofsField::from)); + + let proof = runtime.prove(&prog, vec![solution], vec![board], vec![])?; + + runtime.verify(&prog, &proof, vec![board], vec![])?; + + Ok(()) } #[cfg(test)] @@ -112,18 +101,16 @@ mod tests { use super::*; #[test] - fn valid_example() { - let app = Compiler::new() - .zkp_backend::() - .zkp_program(sudoku_proof) - .compile() - .unwrap(); - - let prog = app.get_zkp_program(sudoku_proof).unwrap(); + fn main_works() -> Result<(), Error> { + main() + } - let runtime = ZkpRuntime::new(&BulletproofsBackend::new()).unwrap(); + #[test] + fn valid_example() { + let prog = sudoku_proof.compile::().unwrap(); + let runtime = sudoku_proof.runtime::().unwrap(); - let ex_puzzle = [ + let ex_board = [ [0, 7, 0, 0, 2, 0, 0, 4, 6], [0, 6, 0, 0, 0, 0, 8, 9, 0], [2, 0, 0, 8, 0, 0, 7, 1, 5], @@ -147,30 +134,24 @@ mod tests { [4, 3, 2, 5, 8, 6, 9, 7, 1], ]; - let board: Vec = vec![ex_sol.map(|a| a.map(BPField::from)).into()]; + let solution = ex_sol.map(|a| a.map(BulletproofsField::from)); + let board = ex_board.map(|a| a.map(BulletproofsField::from)); - let cons: Vec = vec![ex_puzzle.map(|a| a.map(BPField::from)).into()]; - - let proof = runtime.prove(prog, cons.clone(), vec![], board).unwrap(); + let proof = runtime + .prove(&prog, vec![solution], vec![board], vec![]) + .unwrap(); - let verify = runtime.verify(prog, &proof, cons, vec![]); + let verify = runtime.verify(&prog, &proof, vec![board], vec![]); assert!(verify.is_ok()); } #[test] fn bad_solution() { - let app = Compiler::new() - .zkp_backend::() - .zkp_program(sudoku_proof) - .compile() - .unwrap(); + let prog = sudoku_proof.compile::().unwrap(); + let runtime = sudoku_proof.runtime::().unwrap(); - let prog = app.get_zkp_program(sudoku_proof).unwrap(); - - let runtime = ZkpRuntime::new(&BulletproofsBackend::new()).unwrap(); - - let ex_puzzle = [ + let ex_board = [ [0, 7, 0, 0, 2, 0, 0, 4, 6], [0, 6, 0, 0, 0, 0, 8, 9, 0], [2, 0, 0, 8, 0, 0, 7, 1, 5], @@ -194,28 +175,21 @@ mod tests { [4, 3, 2, 5, 8, 6, 9, 7, 1], ]; - let board: Vec = vec![ex_sol.map(|a| a.map(BPField::from)).into()]; + let solution = ex_sol.map(|a| a.map(BulletproofsField::from)); - let cons: Vec = vec![ex_puzzle.map(|a| a.map(BPField::from)).into()]; + let board = ex_board.map(|a| a.map(BulletproofsField::from)); - let proof = runtime.prove(prog, cons, vec![], board); + let proof = runtime.prove(&prog, vec![solution], vec![board], vec![]); assert!(proof.is_err()); } #[test] fn out_of_bounds_input() { - let app = Compiler::new() - .zkp_backend::() - .zkp_program(sudoku_proof) - .compile() - .unwrap(); - - let prog = app.get_zkp_program(sudoku_proof).unwrap(); - - let runtime = ZkpRuntime::new(&BulletproofsBackend::new()).unwrap(); + let prog = sudoku_proof.compile::().unwrap(); + let runtime = sudoku_proof.runtime::().unwrap(); - let ex_puzzle = [[0; 9]; 9]; + let ex_board = [[0; 9]; 9]; let ex_sol = [ [8, 7, 5, 9, 2, 1, 3, 4, 10], @@ -229,11 +203,11 @@ mod tests { [4, 3, 2, 5, 8, 6, 9, 7, 1], ]; - let board: Vec = vec![ex_sol.map(|a| a.map(BPField::from)).into()]; + let solution = ex_sol.map(|a| a.map(BulletproofsField::from)); - let cons: Vec = vec![ex_puzzle.map(|a| a.map(BPField::from)).into()]; + let board = ex_board.map(|a| a.map(BulletproofsField::from)); - let proof = runtime.prove(prog, cons, vec![], board); + let proof = runtime.prove(&prog, vec![solution], vec![board], vec![]); assert!(proof.is_err()); } diff --git a/sunscreen/benches/fractional_range_proof.rs b/sunscreen/benches/fractional_range_proof.rs index d09a47074..2df3ac32c 100644 --- a/sunscreen/benches/fractional_range_proof.rs +++ b/sunscreen/benches/fractional_range_proof.rs @@ -105,7 +105,7 @@ fn unshield_tx_fractional_range_proof(_c: &mut Criterion) { // 3 * 1 + 2 * 2 = 7 let balance = make_fractional_value(&[3, 2]); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let prover_time = Instant::now(); @@ -193,7 +193,7 @@ fn private_tx_fractional_range_proof(_c: &mut Criterion) { // 1 * 1 + 1 * 2 + 1 * 4 = 7 let c = make_fractional_value(&[1, 1, 1]); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let prover_time = Instant::now(); @@ -256,7 +256,7 @@ fn mean_variance_fractional_range_proof(_c: &mut Criterion) { // 4 * 1 + 16 * 2 = 36 let b = make_fractional_value(&[4, 16]); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let prover_time = Instant::now(); @@ -333,7 +333,7 @@ fn chi_sq_fractional_range_proof(_c: &mut Criterion) { let priv_inputs: Vec = vec![a_0.into(), a_1.into(), a_2.into()]; let const_inputs: Vec = vec![n.into()]; - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let prover_time = Instant::now(); diff --git a/sunscreen/src/compiler.rs b/sunscreen/src/compiler.rs index d866a61ee..136529b18 100644 --- a/sunscreen/src/compiler.rs +++ b/sunscreen/src/compiler.rs @@ -7,7 +7,7 @@ use crate::{ use std::collections::{HashMap, HashSet}; use std::marker::PhantomData; use sunscreen_fhe_program::FheProgramTrait; -use sunscreen_runtime::{marker, CompiledFheProgram, Fhe, FheZkp, Zkp}; +use sunscreen_runtime::{marker, CompiledFheProgram, Fhe, FheRuntime, FheZkp, Zkp}; use sunscreen_zkp_backend::{CompiledZkpProgram, FieldSpec, ZkpBackend}; #[derive(Debug, Clone)] @@ -26,7 +26,9 @@ pub trait FheProgramFn { fn signature(&self) -> CallSignature; /** - * Compile the `#[fhe_program]`. + * Build the `#[fhe_program]` into a compiled frontend. + * + * You should not have to call this function directly. */ fn build(&self, params: &Params) -> Result; @@ -46,6 +48,91 @@ pub trait FheProgramFn { fn chain_count(&self) -> usize; } +/// An extension of [`FheProgramFn`], providing helpers and convenience methods. +pub trait FheProgramFnExt: FheProgramFn { + /// Compile the `#[fhe_program]` into a [runnable][sunscreen_runtime::GenericRuntime::run] + /// [`CompiledFheProgram`]. + /// + /// This is a convenient way to compile just a single FHE program. + /// ```rust + /// use sunscreen::{fhe_program, types::{bfv::Signed, Cipher}, FheProgramFnExt}; + /// + /// #[fhe_program(scheme = "bfv")] + /// fn multiply(a: Cipher, b: Cipher) -> Cipher { + /// a * b + /// } + /// # fn main() -> Result<(), sunscreen::Error> { + /// let multiply_prog = multiply.compile()?; + /// # Ok(()) + /// # } + /// ``` + /// + /// It is shorthand for: + /// ```rust + /// use sunscreen::{fhe_program, types::{bfv::Signed, Cipher}, Compiler}; + /// + /// #[fhe_program(scheme = "bfv")] + /// fn multiply(a: Cipher, b: Cipher) -> Cipher { + /// a * b + /// } + /// # fn main() -> Result<(), sunscreen::Error> { + /// let app = Compiler::new().fhe_program(multiply).compile()?; + /// let multiply_prog = app.get_fhe_program(multiply).unwrap(); + /// # Ok(()) + /// # } + /// ``` + fn compile(&self) -> Result + where + Self: AsRef + Sized + Clone + 'static, + { + Ok(Compiler::new() + .fhe_program(self.clone()) + .compile()? + .take_fhe_program(self) + .unwrap()) + } + + /// Make a new [`FheRuntime`] with parameters suitable to run this `#[fhe_program]`. + /// + /// This is a convenient way to run a single FHE program. + /// ```rust + /// use sunscreen::{fhe_program, types::{bfv::Signed, Cipher}, FheProgramFnExt}; + /// + /// #[fhe_program(scheme = "bfv")] + /// fn multiply(a: Cipher, b: Cipher) -> Cipher { + /// a * b + /// } + /// # fn main() -> Result<(), sunscreen::Error> { + /// let runtime = multiply.runtime()?; + /// # Ok(()) + /// # } + /// ``` + /// + /// It is shorthand for: + /// ```rust + /// use sunscreen::{fhe_program, types::{bfv::Signed, Cipher}, Compiler, FheRuntime}; + /// + /// #[fhe_program(scheme = "bfv")] + /// fn multiply(a: Cipher, b: Cipher) -> Cipher { + /// a * b + /// } + /// # fn main() -> Result<(), sunscreen::Error> { + /// let app = Compiler::new().fhe_program(multiply).compile()?; + /// let runtime = FheRuntime::new(app.params()); + /// # Ok(()) + /// # } + /// ``` + fn runtime(&self) -> Result + where + Self: AsRef + Sized + Clone + 'static, + { + let app = Compiler::new().fhe_program(self.clone()).compile()?; + Ok(FheRuntime::new(app.params())?) + } +} + +impl FheProgramFnExt for T where T: FheProgramFn {} + struct FheCompilerData { fhe_program_fns: Vec>, params_mode: ParamsMode, @@ -78,7 +165,7 @@ impl Default for ZkpCompilerData { struct ZkpCompilerData { // In practice, B should always be BoxZkpFn> where - // F: BackendField. + // F: FieldSpec. zkp_program_fns: Vec, } diff --git a/sunscreen/src/lib.rs b/sunscreen/src/lib.rs index c26896f02..c6e76a7b3 100644 --- a/sunscreen/src/lib.rs +++ b/sunscreen/src/lib.rs @@ -7,33 +7,31 @@ //! # Examples //! This example is further annotated in `examples/simple_multiply`. //! ``` -//! # use sunscreen::{fhe_program, Compiler, types::{bfv::Signed, Cipher}, PlainModulusConstraint, Params, FheRuntime}; -//! +//! # use sunscreen::{fhe_program, types::{bfv::Signed, Cipher}, FheProgramFnExt, Result}; //! #[fhe_program(scheme = "bfv")] //! fn simple_multiply(a: Cipher, b: Cipher) -> Cipher { //! a * b //! } //! -//! fn main() { -//! let app = Compiler::new() -//! .fhe_program(simple_multiply) -//! .plain_modulus_constraint(PlainModulusConstraint::Raw(600)) -//! .additional_noise_budget(5) -//! .compile() -//! .unwrap(); -//! -//! let runtime = FheRuntime::new(app.params()).unwrap(); +//! fn main() -> Result<()> { +//! let multiply_program = simple_multiply.compile()?; +//! let runtime = simple_multiply.runtime()?; //! -//! let (public_key, private_key) = runtime.generate_keys().unwrap(); +//! let (public_key, private_key) = runtime.generate_keys()?; //! -//! let a = runtime.encrypt(Signed::from(15), &public_key).unwrap(); -//! let b = runtime.encrypt(Signed::from(5), &public_key).unwrap(); +//! let a = runtime.encrypt(Signed::from(15), &public_key)?; +//! let b = runtime.encrypt(Signed::from(5), &public_key)?; //! -//! let results = runtime.run(app.get_fhe_program(simple_multiply).unwrap(), vec![a, b], &public_key).unwrap(); +//! let results = runtime.run( +//! &multiply_program, +//! vec![a, b], +//! &public_key +//! )?; //! -//! let c: Signed = runtime.decrypt(&results[0], &private_key).unwrap(); +//! let c: Signed = runtime.decrypt(&results[0], &private_key)?; //! -//! assert_eq!(c, 75.into()); +//! assert_eq!(c, 75.into()); +//! Ok(()) //! } //! ``` //! @@ -73,7 +71,7 @@ use std::cell::RefCell; use std::collections::HashMap; use std::marker::PhantomData; -pub use compiler::{Compiler, FheProgramFn, GenericCompiler}; +pub use compiler::{Compiler, FheProgramFn, FheProgramFnExt, GenericCompiler}; pub use error::{Error, Result}; pub use params::PlainModulusConstraint; pub use seal_fhe::Plaintext as SealPlaintext; @@ -82,17 +80,19 @@ pub use sunscreen_fhe_program::{SchemeType, SecurityLevel}; pub use sunscreen_runtime::{ CallSignature, Ciphertext, CompiledFheProgram, Error as RuntimeError, FheProgramInput, FheProgramInputTrait, FheProgramMetadata, FheRuntime, FheZkpRuntime, InnerCiphertext, - InnerPlaintext, Params, Plaintext, PrivateKey, PublicKey, RequiredKeys, Runtime, WithContext, - ZkpProgramInput, ZkpRuntime, + InnerPlaintext, Params, Plaintext, PrivateKey, ProofBuilder, PublicKey, RequiredKeys, Runtime, + VerificationBuilder, WithContext, ZkpProgramInput, ZkpRuntime, }; #[cfg(feature = "bulletproofs")] -pub use sunscreen_zkp_backend::bulletproofs::{BulletproofsBackend, BulletproofsR1CSProof}; -pub use sunscreen_zkp_backend::{Error as ZkpError, FieldSpec, Result as ZkpResult, ZkpBackend}; -pub use zkp::ZkpProgramFn; +pub use sunscreen_zkp_backend::bulletproofs; +pub use sunscreen_zkp_backend::{ + Error as ZkpError, FieldSpec, Proof, Result as ZkpResult, ZkpBackend, +}; pub use zkp::{ invoke_gadget, with_zkp_ctx, ZkpContext, ZkpContextOps, ZkpData, ZkpFrontendCompilation, CURRENT_ZKP_CTX, }; +pub use zkp::{ZkpProgramFn, ZkpProgramFnExt}; #[derive(Clone)] /** @@ -142,7 +142,7 @@ where * These parameters were chosen during compilation. * * # Remarks - * If no [`fhe_program`] was specified, this function returns [`None`]. + * If no [`fhe_program`] was specified, this function panics. */ pub fn params(&self) -> &Params { &self.fhe_programs.values().next().unwrap().metadata.params @@ -186,6 +186,18 @@ where pub fn get_fhe_programs(&self) -> impl Iterator { self.fhe_programs.iter() } + + /// Take ownership of a compiled program with the given name, removing it from this + /// `Application`. + /// + /// You probably don't need this function, since runtimes can operate on borrowed + /// programs. See [`Self::get_fhe_program`] instead. + fn take_fhe_program(&mut self, name: N) -> Option + where + N: AsRef, + { + self.fhe_programs.remove(name.as_ref()) + } } impl Application @@ -209,6 +221,18 @@ where pub fn get_zkp_programs(&self) -> impl Iterator { self.zkp_programs.iter() } + + /// Take ownership of a compiled program with the given name, removing it from this + /// `Application`. + /// + /// You probably don't need this function, since runtimes can operate on borrowed + /// programs. See [`Self::get_zkp_program`] instead. + fn take_zkp_program(&mut self, name: N) -> Option + where + N: AsRef, + { + self.zkp_programs.remove(name.as_ref()) + } } #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] diff --git a/sunscreen/src/types/mod.rs b/sunscreen/src/types/mod.rs index dc98acb5f..0082b3616 100644 --- a/sunscreen/src/types/mod.rs +++ b/sunscreen/src/types/mod.rs @@ -136,8 +136,9 @@ where } } -/// Creates new FHE variables from literals. Note that literals can be used directly in -/// arithmetic operations with ciphertexts: +/// Creates new FHE variables from literals. +/// +/// Note that literals can be used directly in arithmetic operations with ciphertexts: /// /// ``` /// # use sunscreen::{fhe_program, types::{Cipher, bfv::Signed}}; diff --git a/sunscreen/src/types/zkp/field.rs b/sunscreen/src/types/zkp/field.rs index 3ad5dab02..94bab2e78 100644 --- a/sunscreen/src/types/zkp/field.rs +++ b/sunscreen/src/types/zkp/field.rs @@ -2,7 +2,6 @@ use std::marker::PhantomData; use subtle::{Choice, ConditionallySelectable}; use sunscreen_compiler_macros::TypeName; -use sunscreen_runtime::ZkpProgramInputTrait; use sunscreen_zkp_backend::{BigInt, FieldSpec}; use crate::{ @@ -37,6 +36,14 @@ pub struct Field { _phantom: PhantomData, } +#[cfg(feature = "bulletproofs")] +/// A convenient type alias for the `Field` of the bulletproofs backend. +/// +/// This is equivalent to `Field::::Field`, or +/// [`Field::`]. +pub type BulletproofsField = + Field<::Field>; + // Can't #[derive()] due to PhantomData. impl Copy for Field {} @@ -148,9 +155,6 @@ impl ToNativeFields for Field { } } -impl ZkpType for Field {} -impl ZkpProgramInputTrait for Field {} - impl AddVar for Field { fn add(lhs: ProgramNode, rhs: ProgramNode) -> ProgramNode { with_zkp_ctx(|ctx| { @@ -444,7 +448,7 @@ mod tests { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let program = app.get_zkp_program(le).unwrap(); @@ -453,9 +457,9 @@ mod tests { let result = runtime.prove( program, + vec![BpField::from(x), BpField::from(y)], vec![], vec![], - vec![BpField::from(x), BpField::from(y)], ); let proof = if expect_pass { @@ -493,7 +497,7 @@ mod tests { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let program = app.get_zkp_program(le).unwrap(); @@ -502,9 +506,9 @@ mod tests { let result = runtime.prove( program, + vec![BpField::from(x), BpField::from(y)], vec![], vec![], - vec![BpField::from(x), BpField::from(y)], ); let proof = if expect_pass { @@ -542,7 +546,7 @@ mod tests { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let program = app.get_zkp_program(le).unwrap(); @@ -551,9 +555,9 @@ mod tests { let result = runtime.prove( program, + vec![BpField::from(x), BpField::from(y)], vec![], vec![], - vec![BpField::from(x), BpField::from(y)], ); let proof = if expect_pass { @@ -591,7 +595,7 @@ mod tests { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let program = app.get_zkp_program(le).unwrap(); @@ -600,9 +604,9 @@ mod tests { let result = runtime.prove( program, + vec![BpField::from(x), BpField::from(y)], vec![], vec![], - vec![BpField::from(x), BpField::from(y)], ); let proof = if expect_pass { diff --git a/sunscreen/src/types/zkp/gadgets/arithmetic.rs b/sunscreen/src/types/zkp/gadgets/arithmetic.rs index 1736b5fc3..ad631f241 100644 --- a/sunscreen/src/types/zkp/gadgets/arithmetic.rs +++ b/sunscreen/src/types/zkp/gadgets/arithmetic.rs @@ -82,7 +82,7 @@ impl Gadget for SignedModulus { 2 } - fn compute_inputs( + fn compute_hidden_inputs( &self, gadget_inputs: &[sunscreen_zkp_backend::BigInt], ) -> ZkpResult> { @@ -144,7 +144,7 @@ impl Inverse { } impl Gadget for Inverse { - fn compute_inputs(&self, gadget_inputs: &[BigInt]) -> ZkpResult> { + fn compute_hidden_inputs(&self, gadget_inputs: &[BigInt]) -> ZkpResult> { let x = gadget_inputs[0]; if x == BigInt::ZERO { @@ -193,14 +193,14 @@ mod tests { use super::*; #[test] - fn compute_inputs_is_correct() { + fn compute_hidden_inputs_is_correct() { let m = BigInt::from(22u32); let field_modulus = ::Field::FIELD_MODULUS; let gadget = SignedModulus::new(field_modulus, 16); let test_case = |x: BigInt| { - let outputs = gadget.compute_inputs(&[x, m]).unwrap(); + let outputs = gadget.compute_hidden_inputs(&[x, m]).unwrap(); let q = outputs[0]; let r = outputs[1]; @@ -250,7 +250,7 @@ mod tests { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let prog = app.get_zkp_program(div_rem).unwrap(); @@ -259,14 +259,14 @@ mod tests { let test_case = |x: i64, m: i64, expected_q: i64, expected_r: i64, expect_success: bool| { let result = runtime.prove( prog, - vec![], - vec![], vec![ BpField::from(x), BpField::from(m), BpField::from(expected_q), BpField::from(expected_r), ], + vec![], + vec![], ); let proof = if expect_success { diff --git a/sunscreen/src/types/zkp/gadgets/binary.rs b/sunscreen/src/types/zkp/gadgets/binary.rs index e38723b70..cf70fee7d 100644 --- a/sunscreen/src/types/zkp/gadgets/binary.rs +++ b/sunscreen/src/types/zkp/gadgets/binary.rs @@ -26,7 +26,7 @@ impl ToUInt { } impl Gadget for ToUInt { - fn compute_inputs(&self, gadget_inputs: &[BigInt]) -> ZkpResult> { + fn compute_hidden_inputs(&self, gadget_inputs: &[BigInt]) -> ZkpResult> { let val = gadget_inputs[0]; if self.n == 0 { @@ -112,7 +112,7 @@ impl Gadget for ToUInt { pub struct AssertBinary; impl Gadget for AssertBinary { - fn compute_inputs(&self, gadget_inputs: &[BigInt]) -> ZkpResult> { + fn compute_hidden_inputs(&self, gadget_inputs: &[BigInt]) -> ZkpResult> { let val = gadget_inputs[0]; if val != BigInt::ONE && val != BigInt::ZERO { @@ -177,14 +177,14 @@ mod tests { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let prog = app.get_zkp_program(test).unwrap(); type BPField = Field<::Field>; let test_proof = |x: u8, expect_pass: bool| { - let result = runtime.prove(prog, vec![], vec![], vec![BPField::from(x)]); + let result = runtime.prove(prog, vec![BPField::from(x)], vec![], vec![]); let proof = if expect_pass { result.unwrap() @@ -221,14 +221,14 @@ mod tests { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let prog = app.get_zkp_program(test).unwrap(); type BPField = Field<::Field>; let proof = runtime - .prove(prog, vec![], vec![], vec![BPField::from(42u8)]) + .prove(prog, vec![BPField::from(42u8)], vec![], vec![]) .unwrap(); runtime diff --git a/sunscreen/src/types/zkp/mod.rs b/sunscreen/src/types/zkp/mod.rs index 1a2b71f5d..67c339369 100644 --- a/sunscreen/src/types/zkp/mod.rs +++ b/sunscreen/src/types/zkp/mod.rs @@ -4,10 +4,14 @@ mod program_node; mod rns_polynomial; pub use field::*; -use petgraph::stable_graph::NodeIndex; +// N.B. `NodeIndex` is actually common to both FHE and ZKP, but it's really only leaked as an +// implementation detail on the ZKP side (via gadgets). So I think it makes sense to export under +// sunscreen::types::zkp. +pub use petgraph::stable_graph::NodeIndex; pub use program_node::*; pub use rns_polynomial::*; use sunscreen_compiler_common::TypeName; +pub use sunscreen_zkp_backend::{BigInt, Gadget}; pub use sunscreen_runtime::{ToNativeFields, ZkpProgramInputTrait}; @@ -192,6 +196,8 @@ pub trait NumFieldElements { */ pub trait ZkpType: NumFieldElements + Sized + TypeName + ToNativeFields {} +impl ZkpType for T {} + /** * Methods for coercing ZKP data types. */ @@ -214,8 +220,6 @@ where const NUM_NATIVE_FIELD_ELEMENTS: usize = T::NUM_NATIVE_FIELD_ELEMENTS * N; } -impl ZkpType for [T; N] where T: ZkpType {} - impl Coerce for T where T: ZkpType, diff --git a/sunscreen/src/types/zkp/program_node.rs b/sunscreen/src/types/zkp/program_node.rs index a3df03f1f..f7032505e 100644 --- a/sunscreen/src/types/zkp/program_node.rs +++ b/sunscreen/src/types/zkp/program_node.rs @@ -276,7 +276,7 @@ where */ pub trait ConstrainCmp { /** - * Constrain that this value is less than or equal than the RHS. + * Constrain that this value is less than or equal to the RHS. * * # Remarks * The number of bits is the maximum number of bits required to @@ -290,7 +290,7 @@ pub trait ConstrainCmp { fn constrain_le_bounded(self, rhs: Rhs, bits: usize); /** - * Constrain that this value is less than or equal than the RHS. + * Constrain that this value is less than the RHS. * * # Remarks * The number of bits is the maximum number of bits required to @@ -304,7 +304,7 @@ pub trait ConstrainCmp { fn constrain_lt_bounded(self, rhs: Rhs, bits: usize); /** - * Constrain that this value is less than or equal than the RHS. + * Constrain that this value is greater than or equal to the RHS. * * # Remarks * The number of bits is the maximum number of bits required to @@ -318,7 +318,7 @@ pub trait ConstrainCmp { fn constrain_ge_bounded(self, rhs: Rhs, bits: usize); /** - * Constrain that this value is less than or equal than the RHS. + * Constrain that this value is greater than the RHS. * * # Remarks * The number of bits is the maximum number of bits required to diff --git a/sunscreen/src/types/zkp/rns_polynomial.rs b/sunscreen/src/types/zkp/rns_polynomial.rs index 9b8143bd7..a301671b4 100644 --- a/sunscreen/src/types/zkp/rns_polynomial.rs +++ b/sunscreen/src/types/zkp/rns_polynomial.rs @@ -1,6 +1,5 @@ use petgraph::stable_graph::NodeIndex; use sunscreen_compiler_macros::TypeName; -use sunscreen_runtime::ZkpProgramInputTrait; use sunscreen_zkp_backend::{BigInt, FieldSpec}; use crate::{ @@ -9,7 +8,7 @@ use crate::{ zkp::ZkpContextOps, }; -use super::{AddVar, Field, Mod, MulVar, NumFieldElements, ToNativeFields, ZkpType}; +use super::{AddVar, Field, Mod, MulVar, NumFieldElements, ToNativeFields}; use crate as sunscreen; @@ -51,8 +50,6 @@ impl ToNativeFields for RnsRingPol } } -impl ZkpType for RnsRingPolynomial {} - /** * Returns the RNS residues for each coefficient. The coefficient index * is the leading dimension for efficient NTT transforms. @@ -95,11 +92,6 @@ impl AddVar for RnsRingPolynomial< } } -impl ZkpProgramInputTrait - for RnsRingPolynomial -{ -} - impl MulVar for RnsRingPolynomial { fn mul(lhs: ProgramNode, rhs: ProgramNode) -> ProgramNode { let left = lhs.residues(); @@ -224,7 +216,7 @@ mod tests { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let program = app.get_zkp_program(add_poly).unwrap(); @@ -237,11 +229,11 @@ mod tests { ]); let proof = runtime - .prove(program, vec![a.clone(), a.clone()], vec![], vec![]) + .prove(program, vec![], vec![], vec![a.clone(), a.clone()]) .unwrap(); runtime - .verify(program, &proof, vec![a.clone(), a.clone()], vec![]) + .verify(program, &proof, vec![], vec![a.clone(), a.clone()]) .unwrap(); let b = @@ -281,7 +273,7 @@ mod tests { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let program = app.get_zkp_program(add_poly).unwrap(); @@ -291,11 +283,11 @@ mod tests { let a = BpPoly::from([[1u8, 2, 3, 4, 5, 6, 7, 8], [9, 10, 11, 12, 13, 14, 15, 16]]); let proof = runtime - .prove(program, vec![a.clone(), a.clone()], vec![], vec![]) + .prove(program, vec![], vec![], vec![a.clone(), a.clone()]) .unwrap(); runtime - .verify(program, &proof, vec![a.clone(), a.clone()], vec![]) + .verify(program, &proof, vec![], vec![a.clone(), a.clone()]) .unwrap(); let b = BpPoly::from([[0u8, 2, 3, 4, 5, 6, 7, 8], [9, 10, 11, 12, 13, 14, 15, 16]]); @@ -334,7 +326,7 @@ mod tests { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let program = app.get_zkp_program(scale_poly).unwrap(); @@ -353,9 +345,9 @@ mod tests { let const_args: Vec = vec![a.into(), b.into()]; let proof = runtime - .prove(program, const_args.clone(), vec![], vec![]) + .prove(program, vec![], vec![], const_args.clone()) .unwrap(); - runtime.verify(program, &proof, const_args, vec![]).unwrap(); + runtime.verify(program, &proof, vec![], const_args).unwrap(); } } diff --git a/sunscreen/src/zkp/mod.rs b/sunscreen/src/zkp/mod.rs index 38d9cb756..e638b853b 100644 --- a/sunscreen/src/zkp/mod.rs +++ b/sunscreen/src/zkp/mod.rs @@ -1,10 +1,10 @@ use petgraph::Graph; -use sunscreen_runtime::CallSignature; +use sunscreen_runtime::{CallSignature, ZkpRuntime}; use sunscreen_zkp_backend::{ - BigInt, CompiledZkpProgram, FieldSpec, Gadget, Operation as JitOperation, + BigInt, CompiledZkpProgram, FieldSpec, Gadget, Operation as JitOperation, ZkpBackend, }; -use crate::Result; +use crate::{Compiler, Result}; use std::collections::HashMap; use std::hash::Hash; @@ -32,6 +32,139 @@ pub trait ZkpProgramFn { fn name(&self) -> &str; } +/// An extension of [`ZkpProgramFn`], providing helpers and convenience methods. +pub trait ZkpProgramFnExt { + /// Compile this `#[zkp_program]`. + /// + /// This is a convenient way to compile just a single ZKP program. + /// ```rust + /// use sunscreen::{ + /// bulletproofs::BulletproofsBackend, + /// zkp_program, types::zkp::{BulletproofsField, Field}, + /// FieldSpec, ZkpRuntime, ZkpProgramFnExt + /// }; + /// + /// #[zkp_program] + /// fn is_eq(a: Field, b: Field) { + /// a.constrain_eq(b) + /// } + /// # fn main() -> Result<(), sunscreen::Error> { + /// let is_eq_prog = is_eq.compile::()?; + /// let a = BulletproofsField::from(64); + /// let b = BulletproofsField::from(64); + /// let runtime = ZkpRuntime::new(BulletproofsBackend::new())?; + /// runtime.prove(&is_eq_prog, vec![a, b], vec![], vec![])?; + /// # Ok(()) + /// # } + /// ``` + /// + /// It is shorthand for: + /// ```rust + /// use sunscreen::{ + /// bulletproofs::BulletproofsBackend, + /// types::zkp::{BulletproofsField, Field}, + /// zkp_program, zkp_var, FieldSpec, Compiler, Error, ZkpRuntime, + /// }; + /// + /// #[zkp_program] + /// fn is_eq(a: Field, b: Field) { + /// a.constrain_eq(b) + /// } + /// # fn main() -> Result<(), sunscreen::Error> { + /// let app = Compiler::new() + /// .zkp_backend::() + /// .zkp_program(is_eq) + /// .compile()?; + /// let is_eq_prog = app.get_zkp_program(is_eq).unwrap(); + /// let a = BulletproofsField::from(64); + /// let b = BulletproofsField::from(64); + /// let runtime = ZkpRuntime::new(BulletproofsBackend::new())?; + /// runtime.prove(&is_eq_prog, vec![a, b], vec![], vec![])?; + /// # Ok(()) + /// # } + /// ``` + fn compile(&self) -> Result + where + Self: ZkpProgramFn, + Self: Sized + Clone + AsRef + 'static, + { + Ok(Compiler::new() + .zkp_backend::() + .zkp_program(self.clone()) + .compile()? + .take_zkp_program(self) + .unwrap()) + } + + /// Create a new `ZkpRuntime` with the given backend. + /// + /// This is identical to [`ZkpRuntime::new`], but is offered in this extension trait for + /// convenience. + /// + /// ```rust + /// use sunscreen::{ + /// bulletproofs::BulletproofsBackend, + /// zkp_program, types::zkp::{BulletproofsField, Field}, + /// FieldSpec, ZkpProgramFnExt + /// }; + /// + /// #[zkp_program] + /// fn is_eq(a: Field, b: Field) { + /// a.constrain_eq(b) + /// } + /// # fn main() -> Result<(), sunscreen::Error> { + /// let is_eq_prog = is_eq.compile::()?; + /// let runtime = is_eq.runtime_with(BulletproofsBackend::new())?; + /// let a = BulletproofsField::from(64); + /// let b = BulletproofsField::from(64); + /// runtime.prove(&is_eq_prog, vec![a, b], vec![], vec![])?; + /// # Ok(()) + /// # } + /// ``` + fn runtime_with(&self, backend: B) -> Result> + where + B: 'static, + Self: ZkpProgramFn, + Self: Sized + Clone + AsRef + 'static, + { + Ok(ZkpRuntime::new(backend)?) + } + + /// Create a new `ZkpRuntime`, with backend specified by type. + /// + /// This is similar to [`ZkpRuntime::new`], but always creates the backend value + /// via the [`Default`] impl. + /// + /// ```rust + /// use sunscreen::{ + /// bulletproofs::BulletproofsBackend, + /// zkp_program, types::zkp::{BulletproofsField, Field}, + /// FieldSpec, ZkpProgramFnExt + /// }; + /// + /// #[zkp_program] + /// fn is_eq(a: Field, b: Field) { + /// a.constrain_eq(b) + /// } + /// # fn main() -> Result<(), sunscreen::Error> { + /// let is_eq_prog = is_eq.compile::()?; + /// let runtime = is_eq.runtime::()?; + /// let a = BulletproofsField::from(64); + /// let b = BulletproofsField::from(64); + /// runtime.prove(&is_eq_prog, vec![a, b], vec![], vec![])?; + /// # Ok(()) + /// # } + /// ``` + fn runtime(&self) -> Result> + where + B: 'static, + Self: ZkpProgramFn, + Self: Sized + Clone + AsRef + 'static, + { + self.runtime_with(B::default()) + } +} + use std::fmt::Debug; use petgraph::stable_graph::NodeIndex; diff --git a/sunscreen/tests/zkp_program_tests.rs b/sunscreen/tests/zkp_program_tests.rs index aa5521cee..d392eefd3 100644 --- a/sunscreen/tests/zkp_program_tests.rs +++ b/sunscreen/tests/zkp_program_tests.rs @@ -19,16 +19,16 @@ fn can_add_and_mul_native_fields() { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let program = app.get_zkp_program(add_mul).unwrap(); let proof = runtime .prove( program, + vec![BPField::from(10u8), BPField::from(4u8), BPField::from(2u8)], vec![], vec![], - vec![BPField::from(10u8), BPField::from(4u8), BPField::from(2u8)], ) .unwrap(); @@ -53,11 +53,11 @@ fn get_input_mismatch_on_incorrect_args() { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let program = app.get_zkp_program(add_mul).unwrap(); - let result = runtime.prove(program, vec![], vec![], vec![BPField::from(0u8)]); + let result = runtime.prove(program, vec![BPField::from(0u8)], vec![], vec![]); assert!(matches!( result, @@ -68,7 +68,7 @@ fn get_input_mismatch_on_incorrect_args() { #[test] fn can_use_public_inputs() { #[zkp_program] - fn add_mul(#[public] a: Field, b: Field, c: Field) { + fn add_mul(b: Field, c: Field, #[public] a: Field) { let x = a * b + c; x.constrain_eq(Field::from(42u32)) @@ -80,28 +80,28 @@ fn can_use_public_inputs() { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let program = app.get_zkp_program(add_mul).unwrap(); let proof = runtime .prove( program, - vec![], - vec![BPField::from(10u8)], vec![BPField::from(4u8), BPField::from(2u8)], + vec![BPField::from(10u8)], + vec![], ) .unwrap(); runtime - .verify(program, &proof, vec![], vec![BPField::from(10u8)]) + .verify(program, &proof, vec![BPField::from(10u8)], vec![]) .unwrap(); } #[test] fn can_use_constant_inputs() { #[zkp_program] - fn add_mul(#[constant] a: Field, b: Field, c: Field) { + fn add_mul(b: Field, c: Field, #[constant] a: Field) { let x = a * b + c; x.constrain_eq(Field::from(42u32)) @@ -113,21 +113,21 @@ fn can_use_constant_inputs() { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let program = app.get_zkp_program(add_mul).unwrap(); let proof = runtime .prove( program, - vec![BPField::from(10u8)], - vec![], vec![BPField::from(4u8), BPField::from(2u8)], + vec![], + vec![BPField::from(10u8)], ) .unwrap(); runtime - .verify(program, &proof, vec![BPField::from(10u8)], vec![]) + .verify(program, &proof, vec![], vec![BPField::from(10u8)]) .unwrap(); } @@ -148,7 +148,7 @@ fn can_declare_array_inputs() { .compile() .unwrap(); - let runtime = Runtime::new_zkp(&BulletproofsBackend::new()).unwrap(); + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); let program = app.get_zkp_program(in_range).unwrap(); @@ -156,9 +156,57 @@ fn can_declare_array_inputs() { .flat_map(|i| (0..9u64).map(|j| BPField::from(i + j)).collect::>()) .collect::>(); - let proof = runtime.prove(program, vec![], vec![], inputs).unwrap(); + let proof = runtime.prove(program, inputs, vec![], vec![]).unwrap(); runtime .verify(program, &proof, Vec::::new(), vec![]) .unwrap(); } + +#[test] +fn builder_methods_work() { + #[zkp_program] + fn arbitrary( + x: Field, + ys: [Field; 9], + #[constant] zss: [[Field; 9]; 64], + ) { + for y in ys { + x.constrain_eq(y); + } + for zs in zss { + for (y, z) in ys.iter().zip(zs) { + y.constrain_eq(z); + } + } + } + + let app = Compiler::new() + .zkp_backend::() + .zkp_program(arbitrary) + .compile() + .unwrap(); + + let runtime = Runtime::new_zkp(BulletproofsBackend::new()).unwrap(); + + let program = app.get_zkp_program(arbitrary).unwrap(); + + let x = BPField::from(0); + let ys = [BPField::from(0); 9]; + let zss = [[BPField::from(0); 9]; 64]; + + let proof = runtime + .proof_builder(program) + .constant_input(zss) + .private_input(x) + .private_input(ys) + .prove() + .unwrap(); + + runtime + .verification_builder(program) + .proof(&proof) + .constant_input(zss) + .verify() + .unwrap(); +} diff --git a/sunscreen_compiler_common/src/graph.rs b/sunscreen_compiler_common/src/graph.rs index 0834b8f05..75db761d1 100644 --- a/sunscreen_compiler_common/src/graph.rs +++ b/sunscreen_compiler_common/src/graph.rs @@ -386,32 +386,24 @@ where return Err(GraphQueryError::IncorrectBinaryOperandEdges); } - let left = parent_edges - .iter() - .filter_map(|e| { - if matches!(e.weight(), EdgeInfo::Left) { - Some(e.source()) - } else { - None - } - }) - .next(); + let left = parent_edges.iter().find_map(|e| { + if matches!(e.weight(), EdgeInfo::Left) { + Some(e.source()) + } else { + None + } + }); - let right = parent_edges - .iter() - .filter_map(|e| { - if matches!(e.weight(), EdgeInfo::Right) { - Some(e.source()) - } else { - None - } - }) - .next(); + let right = parent_edges.iter().find_map(|e| { + if matches!(e.weight(), EdgeInfo::Right) { + Some(e.source()) + } else { + None + } + }); - Ok(( - left.ok_or(GraphQueryError::IncorrectBinaryOperandEdges)?, - right.ok_or(GraphQueryError::IncorrectBinaryOperandEdges)?, - )) + left.zip(right) + .ok_or(GraphQueryError::IncorrectBinaryOperandEdges) } /** diff --git a/sunscreen_compiler_macros/src/zkp_program.rs b/sunscreen_compiler_macros/src/zkp_program.rs index a23ec61a7..0a1e69493 100644 --- a/sunscreen_compiler_macros/src/zkp_program.rs +++ b/sunscreen_compiler_macros/src/zkp_program.rs @@ -106,27 +106,55 @@ fn parse_inner(_attr_params: ZkpProgramAttrs, input_fn: ItemFn) -> Result { args.iter().map(|a| { let mut arg_kind = ArgumentKind::Private; - match a.0.len() { - 0 => {}, - 1 => { - let ident = a.0[0].path().get_ident(); + match &a.0[..] { + [] => { + if public_seen || constant_seen { + return Err(Error::compile_error(a.2.span(), + "private arguments must be specified before #[public] and #[constant] arguments" + )); + } + }, + [attr] => { + let ident = attr.path().get_ident(); match ident.map(|x| x.to_string()).as_deref() { - Some("private") => {}, - Some("public") => arg_kind = ArgumentKind::Public, - Some("constant") => arg_kind = ArgumentKind::Constant, + Some("private") => { + if public_seen || constant_seen { + return Err(Error::compile_error(attr.path().span(), + "#[private] arguments must be specified before #[public] and #[constant] arguments" + )); + } + }, + Some("public") => { + if constant_seen { + return Err(Error::compile_error(attr.path().span(), + "#[public] arguments must be specified before #[constant] arguments " + )); + } + arg_kind = ArgumentKind::Public; + public_seen = true; + }, + Some("constant") => { + arg_kind = ArgumentKind::Constant; + constant_seen = true; + }, _ => { - return Err(Error::compile_error(a.0[0].path().span(), &format!("Expected #[private], #[public] or #[constant], found {}", a.0[0].path().to_token_stream()))); + return Err(Error::compile_error(attr.path().span(), &format!( + "Expected #[private], #[public] or #[constant], found {}", + attr.path().to_token_stream() + ))); } } }, - _ => { - return Err(Error::compile_error(a.1.span(), "ZKP program arguments may only have one attribute (#[public] or #[constant]).")); + [_, attr, ..] => { + return Err(Error::compile_error(attr.span(), "ZKP program arguments may only have one attribute (#[private], #[public] or #[constant]).")); } }; @@ -224,6 +252,8 @@ fn parse_inner(_attr_params: ZkpProgramAttrs, input_fn: ItemFn) -> Result), } const_assert!(std::mem::size_of::() <= 24); @@ -147,6 +153,13 @@ impl Error { Self::FheTypeError(Box::new(msg.to_owned())) } + /** + * Create an [`Error::ZkpBuilderError`]. + */ + pub fn zkp_builder_error(msg: &str) -> Self { + Self::ZkpBuilderError(Box::new(msg.to_owned())) + } + fn unwrap_argument_mismatch_data(&self) -> &(Vec, Vec) { match self { Self::ArgumentMismatch(d) => d, diff --git a/sunscreen_runtime/src/lib.rs b/sunscreen_runtime/src/lib.rs index d256bdf03..74ac438b3 100644 --- a/sunscreen_runtime/src/lib.rs +++ b/sunscreen_runtime/src/lib.rs @@ -1,8 +1,7 @@ #![deny(missing_docs)] #![deny(rustdoc::broken_intra_doc_links)] -//! This crate contains the types and functions for executing a Sunscreen FHE program -//! (i.e. an [`FheProgram`](sunscreen_fhe_program::FheProgram)). +//! This crate contains the types and functions for executing a Sunscreen FHE or ZKP program. mod array; mod error; @@ -205,7 +204,7 @@ pub enum FheProgramInput { */ pub trait ZkpProgramInputTrait: ToNativeFields + TypeNameInstance {} -impl ZkpProgramInputTrait for [T; N] where T: ZkpProgramInputTrait + TypeName {} +impl ZkpProgramInputTrait for T {} #[derive(Clone)] /** diff --git a/sunscreen_runtime/src/runtime.rs b/sunscreen_runtime/src/runtime.rs index 554f793e6..861ff011b 100644 --- a/sunscreen_runtime/src/runtime.rs +++ b/sunscreen_runtime/src/runtime.rs @@ -439,14 +439,14 @@ where pub fn prove( &self, program: &CompiledZkpProgram, - constant_inputs: Vec, - public_inputs: Vec, private_inputs: Vec, + public_inputs: Vec, + constant_inputs: Vec, ) -> Result where I: Into, { - let constant_inputs = constant_inputs + let private_inputs = private_inputs .into_iter() .flat_map(|x| I::into(x).0.to_native_fields()) .collect::>(); @@ -454,7 +454,7 @@ where .into_iter() .flat_map(|x| I::into(x).0.to_native_fields()) .collect::>(); - let private_inputs = private_inputs + let constant_inputs = constant_inputs .into_iter() .flat_map(|x| I::into(x).0.to_native_fields()) .collect::>(); @@ -477,6 +477,28 @@ where Ok(backend.prove(&prog, &inputs)?) } + /// Create a proof builder. + /// + /// This provides a wrapper around calling [`Self::prove`], and can be convenient when you + /// have ZKP program arguments of different types. Instead of casting them all to + /// `ZkpProgramInput`, you can add them one by one: + /// + /// ```rust,ignore + /// let runtime = ZkpRuntime::new(&backend)?; + /// let x = NativeField::from(1); + /// let ys = [NativeField::from(2), NativeField::from(3)]; + /// let proof = runtime.proof_builder(&program) + /// .private_input(x) + /// .private_input(ys) + /// .prove()?; + /// ``` + pub fn proof_builder<'r, 'p>( + &'r self, + program: &'p CompiledZkpProgram, + ) -> ProofBuilder<'r, 'p, T, B> { + ProofBuilder::new(self, program) + } + /** * Verify that the given `proof` satisfies the given `program`. */ @@ -484,8 +506,8 @@ where &self, program: &CompiledZkpProgram, proof: &Proof, - constant_inputs: Vec, public_inputs: Vec, + constant_inputs: Vec, ) -> Result<()> where I: Into, @@ -512,6 +534,29 @@ where Ok(backend.verify(&prog, proof)?) } + + /// Create a verification builder. + /// + /// This provides a wrapper around calling [`Self::verify`], and can be convenient when you + /// have ZKP program arguments of different types. Instead of casting them all to + /// `ZkpProgramInput`, you can add them one by one: + /// + /// ```rust,ignore + /// let runtime = ZkpRuntime::new(&backend)?; + /// let x = NativeField::from(1); + /// let ys = [NativeField::from(2), NativeField::from(3)]; + /// runtime.verification_builder(&program) + /// .proof(&proof) + /// .constant_input(x) + /// .public_input(ys) + /// .verify()?; + /// ``` + pub fn verification_builder<'r, 'p>( + &'r self, + program: &'p CompiledZkpProgram, + ) -> VerificationBuilder<'r, 'p, '_, T, B> { + VerificationBuilder::new(self, program) + } } impl GenericRuntime<(), ()> { @@ -569,14 +614,14 @@ impl GenericRuntime<(), ()> { /** * Creates a new Runtime supporting only ZKP operations */ - pub fn new_zkp(backend: &B) -> Result> + pub fn new_zkp(backend: B) -> Result> where - B: ZkpBackend + Clone + 'static, + B: ZkpBackend + 'static, { Ok(GenericRuntime { runtime_data: RuntimeData::Zkp(Self::make_zkp_runtime_data()), _phantom_t: PhantomData, - zkp_backend: backend.clone(), + zkp_backend: backend, }) } @@ -640,9 +685,9 @@ impl ZkpRuntime { /** * Create a new [`ZkpRuntime`]. */ - pub fn new(backend: &B) -> Result + pub fn new(backend: B) -> Result where - B: ZkpBackend + Clone + 'static, + B: ZkpBackend + 'static, { Runtime::new_zkp(backend) } @@ -660,3 +705,186 @@ impl ZkpRuntime { * can do both. */ pub type Runtime = GenericRuntime<(), ()>; + +/// A builder for creating a proof. +/// +/// This is offered as a convenience for building the arguments necessary for the +/// [`prove`][GenericRuntime::prove] function. +pub struct ProofBuilder<'r, 'p, T: marker::Zkp, B: ZkpBackend> { + runtime: &'r GenericRuntime, + program: &'p CompiledZkpProgram, + constant_inputs: Vec, + public_inputs: Vec, + private_inputs: Vec, +} + +impl<'r, 'p, T: marker::Zkp, B: ZkpBackend> ProofBuilder<'r, 'p, T, B> { + /// Create a new `ProofBuilder`. It's typically more convenient to create a proof builder + /// via [`runtime.proof_builder()`][GenericRuntime::proof_builder]. + pub fn new(runtime: &'r GenericRuntime, program: &'p CompiledZkpProgram) -> Self + where + T: marker::Zkp, + B: ZkpBackend, + { + Self { + runtime, + program, + constant_inputs: vec![], + public_inputs: vec![], + private_inputs: vec![], + } + } + + /// Add a constant input to the proof builder. + pub fn constant_input(mut self, input: impl Into) -> Self { + self.constant_inputs.push(input.into()); + self + } + + /// Add multiple constant inputs to the proof builder. + pub fn constant_inputs(mut self, inputs: I) -> Self + where + I: IntoIterator, + ZkpProgramInput: From, + { + self.constant_inputs + .extend(inputs.into_iter().map(ZkpProgramInput::from)); + self + } + + /// Add a public input to the proof builder. + pub fn public_input(mut self, input: impl Into) -> Self { + self.public_inputs.push(input.into()); + self + } + + /// Add multiple public inputs to the proof builder. + pub fn public_inputs(mut self, inputs: I) -> Self + where + I: IntoIterator, + ZkpProgramInput: From, + { + self.public_inputs + .extend(inputs.into_iter().map(ZkpProgramInput::from)); + self + } + + /// Add a private input to the proof builder. + pub fn private_input(mut self, input: impl Into) -> Self { + self.private_inputs.push(input.into()); + self + } + + /// Add multiple private inputs to the proof builder. + pub fn private_inputs(mut self, inputs: I) -> Self + where + I: IntoIterator, + ZkpProgramInput: From, + { + self.private_inputs + .extend(inputs.into_iter().map(ZkpProgramInput::from)); + self + } + + /// Generate a proof; see [`runtime.prove()`][GenericRuntime::prove]. + pub fn prove(self) -> Result { + self.runtime.prove( + self.program, + self.private_inputs, + self.public_inputs, + self.constant_inputs, + ) + } +} + +/// A builder for verifying a proof. +/// +/// This is offered as a convenience for building the arguments necessary for the +/// [`verify`][GenericRuntime::verify] function. +pub struct VerificationBuilder<'r, 'p, 'a, T: marker::Zkp, B: ZkpBackend> { + runtime: &'r GenericRuntime, + program: &'p CompiledZkpProgram, + proof: Option<&'a Proof>, + constant_inputs: Vec, + public_inputs: Vec, +} + +impl<'r, 'p, 'a, T: marker::Zkp, B: ZkpBackend> VerificationBuilder<'r, 'p, 'a, T, B> { + /// Create a new `VerificationBuilder`. It's typically more convenient to create a + /// verification builder via + /// [`runtime.verification_builder()`][GenericRuntime::verification_builder]. + pub fn new(runtime: &'r GenericRuntime, program: &'p CompiledZkpProgram) -> Self + where + T: marker::Zkp, + B: ZkpBackend, + { + Self { + runtime, + program, + proof: None, + public_inputs: vec![], + constant_inputs: vec![], + } + } + + /// Add the proof to verify. + pub fn proof(mut self, proof: &'a Proof) -> Self { + self.proof = Some(proof); + self + } + + /// Add a constant input to the verification builder. + pub fn constant_input(mut self, input: impl Into) -> Self { + self.constant_inputs.push(input.into()); + self + } + + /// Add multiple constant inputs to the verification builder. + pub fn constant_inputs(mut self, inputs: I) -> Self + where + I: IntoIterator, + ZkpProgramInput: From, + { + self.constant_inputs + .extend(inputs.into_iter().map(ZkpProgramInput::from)); + self + } + + /// Add a public input to the verification builder. + pub fn public_input(mut self, input: impl Into) -> Self { + self.public_inputs.push(input.into()); + self + } + + /// Add multiple public inputs to the verification builder. + pub fn public_inputs(mut self, inputs: I) -> Self + where + I: IntoIterator, + ZkpProgramInput: From, + { + self.public_inputs + .extend(inputs.into_iter().map(ZkpProgramInput::from)); + self + } + + /// Verify that `self.proof` satisfies `self.program`; see + /// [`runtime.verify()`][GenericRuntime::verify]. + /// + /// # Remarks + /// Will error if the underlying `verify` call errors, or if a proof has not yet been + /// supplied to the builder. That is, you must call [`Self::proof`] before calling this + /// function. + pub fn verify(self) -> Result<()> { + let proof = self.proof.ok_or_else(|| { + Error::zkp_builder_error( + "You must supply a proof to the verification builder before calling `verify`", + ) + })?; + self.runtime.verify( + self.program, + proof, + self.public_inputs, + self.constant_inputs, + ) + } +} diff --git a/sunscreen_zkp_backend/src/bulletproofs.rs b/sunscreen_zkp_backend/src/bulletproofs.rs index 33258bdb8..fc1122fbf 100644 --- a/sunscreen_zkp_backend/src/bulletproofs.rs +++ b/sunscreen_zkp_backend/src/bulletproofs.rs @@ -314,7 +314,7 @@ impl BulletproofsCircuit { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] /** * A Bulletproofs backend. */ @@ -526,7 +526,7 @@ fn try_uint_to_scalar(x: &UInt) -> Result { scalar.ok_or_else(|| Error::out_of_range(&x.to_string())) } -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone)] /// The specification for a field in the Bulletproofs proof system. pub struct BulletproofsFieldSpec {} diff --git a/sunscreen_zkp_backend/src/jit.rs b/sunscreen_zkp_backend/src/jit.rs index f5682cd39..df8c89b62 100644 --- a/sunscreen_zkp_backend/src/jit.rs +++ b/sunscreen_zkp_backend/src/jit.rs @@ -348,7 +348,7 @@ where .map(|x| node_outputs[x].clone().zkp_into()) .collect::>(); - let hidden_inputs = g.compute_inputs(&args)?; + let hidden_inputs = g.compute_hidden_inputs(&args)?; let mut next_nodes = query .edges_directed(id, Direction::Outgoing) diff --git a/sunscreen_zkp_backend/src/lib.rs b/sunscreen_zkp_backend/src/lib.rs index 27230b325..efe62ba84 100644 --- a/sunscreen_zkp_backend/src/lib.rs +++ b/sunscreen_zkp_backend/src/lib.rs @@ -66,7 +66,7 @@ compile_error!("This crate currently requires a little endian target architectur * * We instead ask the prover to simply provide the binary decomposition * and prove that it's correct. To do this, we create a gadget. Its - * [`compute_inputs`](Gadget::compute_inputs) method directly computes the + * [`compute_hidden_inputs`](Gadget::compute_hidden_inputs) method directly computes the * decomposition with shifting and masking. Then, the * [`gen_circuit`](Gadget::gen_circuit) method defined a circuit that proves * the following: @@ -106,7 +106,7 @@ pub trait Gadget: Any + Send + Sync { * * Implementors should ensure this function runs in constant time. */ - fn compute_inputs(&self, gadget_inputs: &[BigInt]) -> Result>; + fn compute_hidden_inputs(&self, gadget_inputs: &[BigInt]) -> Result>; /** * Returns the expected number of gadget inputs. @@ -393,9 +393,9 @@ pub trait ZkpBackend { fn jit_prover( &self, prog: &CompiledZkpProgram, - constant_inputs: &[BigInt], - public_inputs: &[BigInt], private_inputs: &[BigInt], + public_inputs: &[BigInt], + constant_inputs: &[BigInt], ) -> Result; /** @@ -410,8 +410,8 @@ pub trait ZkpBackend { fn jit_verifier( &self, prog: &CompiledZkpProgram, - constant_inputs: &[BigInt], public_inputs: &[BigInt], + constant_inputs: &[BigInt], ) -> Result; }