├── .gitignore ├── .tool-versions ├── chess ├── .gitignore ├── Cargo.toml ├── rust-toolchain ├── methods │ ├── Cargo.toml │ ├── guest │ │ ├── Cargo.toml │ │ └── src │ │ │ └── bin │ │ │ └── checkmate.rs │ ├── src │ │ └── lib.rs │ └── build.rs ├── core │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── host │ ├── Cargo.toml │ └── src │ │ └── main.rs └── README.md ├── json ├── .gitignore ├── Cargo.toml ├── rust-toolchain ├── core │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── methods │ ├── Cargo.toml │ ├── guest │ │ ├── Cargo.toml │ │ └── src │ │ │ └── bin │ │ │ └── search_json.rs │ ├── src │ │ └── lib.rs │ └── build.rs ├── host │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── res │ └── example.json └── README.md ├── sha ├── .gitignore ├── Cargo.toml ├── rust-toolchain ├── methods │ ├── Cargo.toml │ ├── guest │ │ ├── Cargo.toml │ │ └── src │ │ │ └── bin │ │ │ └── hash.rs │ ├── src │ │ └── lib.rs │ └── build.rs ├── host │ ├── Cargo.toml │ └── src │ │ └── main.rs └── README.md ├── factors ├── .gitignore ├── Cargo.toml ├── rust-toolchain ├── factors │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── methods │ ├── Cargo.toml │ ├── guest │ │ ├── Cargo.toml │ │ └── src │ │ │ └── bin │ │ │ └── multiply.rs │ ├── src │ │ └── lib.rs │ └── build.rs └── README.md ├── rustfmt.toml ├── waldo ├── waldo.webp ├── waldo_mask.png ├── rust-toolchain.toml ├── .gitignore ├── methods │ ├── Cargo.toml │ ├── src │ │ └── lib.rs │ ├── guest │ │ ├── Cargo.toml │ │ └── src │ │ │ └── bin │ │ │ └── image_crop.rs │ └── build.rs ├── host │ ├── Cargo.toml │ └── src │ │ └── bin │ │ ├── verify.rs │ │ └── prove.rs ├── Cargo.toml ├── core │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ ├── image.rs │ │ └── merkle.rs └── README.md ├── password-checker ├── Cargo.toml ├── rust-toolchain ├── core │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── cli │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── methods │ ├── Cargo.toml │ ├── guest │ │ ├── Cargo.toml │ │ └── src │ │ │ └── bin │ │ │ └── pw_checker.rs │ ├── src │ │ └── lib.rs │ └── build.rs └── README.md ├── voting-machine ├── Cargo.toml ├── rust-toolchain ├── core │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── methods │ ├── Cargo.toml │ ├── guest │ │ ├── Cargo.toml │ │ └── src │ │ │ └── bin │ │ │ ├── init.rs │ │ │ ├── freeze.rs │ │ │ └── submit.rs │ ├── src │ │ └── lib.rs │ └── build.rs ├── host │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── README.md ├── wordle ├── Cargo.toml ├── rust-toolchain ├── core │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── methods │ ├── Cargo.toml │ ├── guest │ │ ├── Cargo.toml │ │ └── src │ │ │ └── bin │ │ │ └── wordle.rs │ ├── src │ │ └── lib.rs │ └── build.rs ├── host │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── wordlist.rs └── README.md ├── digital-signature ├── Cargo.toml ├── rust-toolchain ├── core │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── methods │ ├── Cargo.toml │ ├── guest │ │ ├── Cargo.toml │ │ └── src │ │ │ └── bin │ │ │ └── sign.rs │ ├── src │ │ └── lib.rs │ └── build.rs ├── cli │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── lib.rs └── README.md ├── README.md ├── .licenserc.json ├── .github └── workflows │ └── main.yml └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | target -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | nodejs lts 2 | -------------------------------------------------------------------------------- /chess/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | target/ 3 | -------------------------------------------------------------------------------- /json/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | target/ 3 | -------------------------------------------------------------------------------- /sha/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | target/ 3 | -------------------------------------------------------------------------------- /factors/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Cargo.lock 3 | methods/guest/Cargo.lock 4 | target/ 5 | -------------------------------------------------------------------------------- /json/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "host", 4 | "methods", 5 | ] 6 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | group_imports = "StdExternalCrate" 2 | imports_granularity = "Module" 3 | -------------------------------------------------------------------------------- /sha/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "host", 4 | "methods", 5 | ] 6 | -------------------------------------------------------------------------------- /chess/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "host", 4 | "methods", 5 | ] 6 | -------------------------------------------------------------------------------- /waldo/waldo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/risc0/risc0-rust-examples/HEAD/waldo/waldo.webp -------------------------------------------------------------------------------- /factors/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "factors", 4 | "methods", 5 | ] 6 | -------------------------------------------------------------------------------- /password-checker/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "cli" 4 | , 5 | "methods"] 6 | -------------------------------------------------------------------------------- /waldo/waldo_mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/risc0/risc0-rust-examples/HEAD/waldo/waldo_mask.png -------------------------------------------------------------------------------- /voting-machine/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "core", 4 | "host", 5 | "methods", 6 | ] 7 | -------------------------------------------------------------------------------- /wordle/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "core", 4 | "host", 5 | "methods", 6 | ] 7 | -------------------------------------------------------------------------------- /chess/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2022-10-28" 3 | components = [ "rustfmt", "rust-src" ] 4 | profile = "minimal" 5 | -------------------------------------------------------------------------------- /json/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2022-10-28" 3 | components = [ "rustfmt", "rust-src" ] 4 | profile = "minimal" 5 | -------------------------------------------------------------------------------- /sha/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2022-10-28" 3 | components = [ "rustfmt", "rust-src" ] 4 | profile = "minimal" 5 | -------------------------------------------------------------------------------- /factors/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2022-10-28" 3 | components = [ "rustfmt", "rust-src" ] 4 | profile = "minimal" 5 | -------------------------------------------------------------------------------- /waldo/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2022-10-28" 3 | components = [ "rustfmt", "rust-src" ] 4 | profile = "minimal" 5 | -------------------------------------------------------------------------------- /wordle/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2022-10-28" 3 | components = [ "rustfmt", "rust-src" ] 4 | profile = "minimal" 5 | -------------------------------------------------------------------------------- /digital-signature/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "cli", 4 | "core", 5 | "methods", 6 | ] 7 | 8 | default-members = ["cli"] 9 | -------------------------------------------------------------------------------- /voting-machine/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2022-10-28" 3 | components = [ "rustfmt", "rust-src" ] 4 | profile = "minimal" 5 | -------------------------------------------------------------------------------- /digital-signature/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2022-10-28" 3 | components = [ "rustfmt", "rust-src" ] 4 | profile = "minimal" 5 | -------------------------------------------------------------------------------- /password-checker/rust-toolchain: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2022-10-28" 3 | components = [ "rustfmt", "rust-src" ] 4 | profile = "minimal" 5 | -------------------------------------------------------------------------------- /password-checker/core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "password-checker-core" 3 | version = "0.12.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | serde = "1.0" 8 | -------------------------------------------------------------------------------- /waldo/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Cargo.lock 3 | methods/guest/Cargo.lock 4 | target/ 5 | 6 | # waldo specific files to ignore 7 | waldo_cutout.png 8 | receipt.bin 9 | -------------------------------------------------------------------------------- /json/core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "json-core" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | risc0-zkp = { version = "0.12", default-features = false } 8 | serde = "1.0" 9 | -------------------------------------------------------------------------------- /wordle/core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wordle-core" 3 | version = "1.0.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | risc0-zkp = { version = "0.12", default-features = false } 8 | serde = "1.0" 9 | -------------------------------------------------------------------------------- /factors/factors/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "starter" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | methods = { path = "../methods" } 8 | risc0-zkvm = "0.12" 9 | serde = "1.0" 10 | -------------------------------------------------------------------------------- /chess/methods/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "methods" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [build-dependencies] 7 | risc0-build = "0.12" 8 | 9 | [package.metadata.risc0] 10 | methods = ["guest"] 11 | -------------------------------------------------------------------------------- /factors/methods/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "methods" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [build-dependencies] 7 | risc0-build = "0.12" 8 | 9 | [package.metadata.risc0] 10 | methods = ["guest"] 11 | -------------------------------------------------------------------------------- /json/methods/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "methods" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [build-dependencies] 7 | risc0-build = "0.12" 8 | 9 | [package.metadata.risc0] 10 | methods = ["guest"] 11 | -------------------------------------------------------------------------------- /sha/methods/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "methods" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [build-dependencies] 7 | risc0-build = "0.12" 8 | 9 | [package.metadata.risc0] 10 | methods = ["guest"] 11 | -------------------------------------------------------------------------------- /wordle/methods/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "methods" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [build-dependencies] 7 | risc0-build = "0.12" 8 | 9 | [package.metadata.risc0] 10 | methods = ["guest"] 11 | -------------------------------------------------------------------------------- /waldo/methods/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "waldo-methods" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [build-dependencies] 7 | risc0-build = "0.12" 8 | 9 | [package.metadata.risc0] 10 | methods = ["guest"] 11 | -------------------------------------------------------------------------------- /chess/core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chess-core" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | risc0-zkp = { version = "0.12", default-features = false } 8 | serde = { version = "1.0", default-features = false } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust examples for RISC Zero 2 | 3 | _(This repository has been deprecated. These examples now live in the [examples directory](https://github.com/risc0/risc0/tree/main/examples) of the [main RISC Zero repository](https://github.com/risc0/risc0).)_ 4 | -------------------------------------------------------------------------------- /voting-machine/core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "voting-machine-core" 3 | version = "0.12.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | risc0-zkp = { version = "0.12", default-features = false } 8 | serde = { version = "1.0", default-features = false } 9 | -------------------------------------------------------------------------------- /digital-signature/core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "digital-signature-core" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | risc0-zkp = { version = "0.12", default-features = false } 8 | serde = { version = "1.0", default-features = false } 9 | -------------------------------------------------------------------------------- /factors/methods/guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "methods-guest" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [workspace] 7 | 8 | [build-dependencies] 9 | risc0-build = "0.12" 10 | 11 | [dependencies] 12 | risc0-zkvm = { version = "0.12", default-features = false } 13 | -------------------------------------------------------------------------------- /chess/host/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chess-host" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | chess-core = { path = "../core" } 8 | clap = "4.0" 9 | methods = { path = "../methods" } 10 | risc0-zkvm = "0.12" 11 | serde = "1.0" 12 | shakmaty = "0.22" 13 | -------------------------------------------------------------------------------- /json/host/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "json-example" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | json = "0.12" 8 | json-core = { path = "../core" } 9 | methods = { path = "../methods" } 10 | risc0-zkp = "0.12" 11 | risc0-zkvm = "0.12" 12 | serde = "1.0" 13 | -------------------------------------------------------------------------------- /wordle/host/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "starter" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | methods = { path = "../methods" } 8 | rand = "0.8.5" 9 | risc0-zkp = "0.12" 10 | risc0-zkvm = "0.12" 11 | serde = "1.0" 12 | wordle-core = { path = "../core" } 13 | -------------------------------------------------------------------------------- /json/res/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "boolean_field": true, 3 | "critical_data": 47, 4 | "obj_field": { 5 | "string_subfield": "hello world", 6 | "array_subfield": [ 7 | "more", 8 | "example", 9 | "text" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /sha/host/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sha-example" 3 | version = "0.12.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | clap = "4.0" 8 | methods = { path = "../methods" } 9 | risc0-zkp = "0.12" 10 | risc0-zkvm = "0.12" 11 | serde = "1.0" 12 | 13 | [dev-dependencies] 14 | hex = "0.4" 15 | -------------------------------------------------------------------------------- /sha/methods/guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "methods-guest" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [workspace] 7 | 8 | [build-dependencies] 9 | risc0-build = "0.12" 10 | 11 | [dependencies] 12 | risc0-zkvm = { version = "0.12", default-features = false, features = ["std"] } 13 | -------------------------------------------------------------------------------- /voting-machine/methods/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "voting-machine-methods" 3 | version = "0.12.0" 4 | edition = "2021" 5 | 6 | [package.metadata.risc0] 7 | methods = ["guest"] 8 | 9 | [profile.release] 10 | lto = true 11 | opt-level = "z" 12 | 13 | [build-dependencies] 14 | risc0-build = "0.12" 15 | -------------------------------------------------------------------------------- /digital-signature/methods/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "digital-signature-methods" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [package.metadata.risc0] 7 | methods = ["guest"] 8 | 9 | [profile.release] 10 | lto = true 11 | opt-level = "z" 12 | 13 | [build-dependencies] 14 | risc0-build = "0.12" 15 | -------------------------------------------------------------------------------- /password-checker/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "password-checker" 3 | version = "0.12.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | password-checker-core = { path = "../core" } 8 | password-checker-methods = { path = "../methods" } 9 | rand = "0.8" 10 | risc0-zkp = "0.12" 11 | risc0-zkvm = "0.12" 12 | -------------------------------------------------------------------------------- /password-checker/methods/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "password-checker-methods" 3 | version = "0.12.0" 4 | edition = "2021" 5 | 6 | [package.metadata.risc0] 7 | methods = ["guest"] 8 | 9 | [profile.release] 10 | lto = true 11 | opt-level = "z" 12 | 13 | [build-dependencies] 14 | risc0-build = "0.12" 15 | -------------------------------------------------------------------------------- /wordle/methods/guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "methods-guest" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [workspace] 7 | 8 | [build-dependencies] 9 | risc0-build = "0.12" 10 | 11 | [dependencies] 12 | risc0-zkvm = { version = "0.12", default-features = false, features = ["std"] } 13 | wordle-core = { path = "../../core" } 14 | -------------------------------------------------------------------------------- /voting-machine/host/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "voting-machine" 3 | version = "0.12.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | clap = "3.1.18" 8 | ctor = "0.1" 9 | env_logger = "0.9.0" 10 | log = "0.4.17" 11 | risc0-zkvm = "0.12" 12 | voting-machine-core = { path = "../core" } 13 | voting-machine-methods = { path = "../methods" } 14 | -------------------------------------------------------------------------------- /json/methods/guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "guest" 3 | version = "0.12.0" 4 | edition = "2021" 5 | 6 | [workspace] 7 | 8 | [build-dependencies] 9 | risc0-build = "0.12" 10 | 11 | [dependencies] 12 | json-core = { path = "../../core" } 13 | risc0-zkvm = { version = "0.12", default-features = false, features = [ "std" ] } 14 | json = "0.12" 15 | -------------------------------------------------------------------------------- /chess/methods/guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "methods-guest" 3 | version = "0.12.0" 4 | edition = "2021" 5 | 6 | [workspace] 7 | 8 | [build-dependencies] 9 | risc0-build = "0.12" 10 | 11 | [dependencies] 12 | # chess = "3.2" 13 | shakmaty = "0.22" 14 | risc0-zkvm = { version = "0.12", default-features = false, features = ["std"]} 15 | chess-core = { path = "../../core" } 16 | -------------------------------------------------------------------------------- /waldo/host/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "waldo-host" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | bincode = "1.3" 8 | clap = { version = "4.0", features = ["derive"] } 9 | env_logger = "0.10" 10 | image = "0.24.5" 11 | risc0-zkp = "0.12" 12 | risc0-zkvm = "0.12" 13 | serde = "1.0" 14 | viuer = "0.6" 15 | waldo-core = { path = "../core" } 16 | waldo-methods = { path = "../methods" } 17 | -------------------------------------------------------------------------------- /voting-machine/methods/guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | [package] 4 | name = "voting-machine-methods-guest" 5 | version = "0.12.0" 6 | edition = "2021" 7 | 8 | [dependencies] 9 | voting-machine-core = { path = "../../core" } 10 | risc0-zkvm = { version = "0.12", default-features = false } 11 | 12 | [profile.release] 13 | lto = true 14 | opt-level = "z" 15 | 16 | [build-dependencies] 17 | risc0-build = "0.12" 18 | -------------------------------------------------------------------------------- /digital-signature/methods/guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | [package] 4 | name = "digital-signature-methods-guest" 5 | version = "0.1.0" 6 | edition = "2021" 7 | 8 | [dependencies] 9 | digital-signature-core = { path = "../../core" } 10 | risc0-zkvm = { version = "0.12", default_features = false} 11 | 12 | [profile.release] 13 | lto = true 14 | opt-level = "z" 15 | 16 | [build-dependencies] 17 | risc0-build = "0.12" 18 | -------------------------------------------------------------------------------- /digital-signature/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "digital-signature" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | clap = "3.1" 8 | digital-signature-core = { path = "../core" } 9 | digital-signature-methods = { path = "../methods" } 10 | env_logger = "0.9" 11 | log = "0.4" 12 | risc0-zkp = "0.12" 13 | risc0-zkvm = "0.12" 14 | serde = "1.0" 15 | sha2 = "0.10" 16 | 17 | [dev-dependencies] 18 | ctor = "0.1" 19 | -------------------------------------------------------------------------------- /password-checker/methods/guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "password-checker-guest" 3 | version = "0.12.0" 4 | edition = "2021" 5 | 6 | [workspace] 7 | 8 | [dependencies] 9 | password-checker-core = { path = "../../core" } 10 | risc0-zkvm = { version = "0.12", default-features = false, features = [ "std" ] } 11 | 12 | [profile.release] 13 | lto = true 14 | opt-level = "z" 15 | 16 | [build-dependencies] 17 | risc0-build = "0.12" 18 | -------------------------------------------------------------------------------- /json/README.md: -------------------------------------------------------------------------------- 1 | # JSON Example 2 | 3 | This code demonstrates how to prove that a JSON file contains a specific field and value using the RISC Zero zkVM. The JSON file is identified by SHA-256 hash, allowing users to commit to a specific JSON file and then prove some of its contents without revealing the full file. 4 | 5 | ## Video Tutorial 6 | 7 | For a walk-through of this example, check out this [excerpt from our workshop at ZK HACK III](https://www.youtube.com/watch?v=6vIgBHx61vc&list=PLcPzhUaCxlCgig7ofeARMPwQ8vbuD6hC5&index=7). 8 | -------------------------------------------------------------------------------- /waldo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "core", 4 | "host", 5 | "methods", 6 | ] 7 | 8 | [profile.release] 9 | opt-level = 3 10 | 11 | [patch.crates-io] 12 | # TODO(victor): Remove these patch definitions when 8bd948b is included in a release. 13 | risc0-zkp = { git = "https://github.com/risc0/risc0", rev = "8bd948be64d6084d1f01b37d60073f920c9beaed" } 14 | risc0-zkvm = { git = "https://github.com/risc0/risc0", rev = "8bd948be64d6084d1f01b37d60073f920c9beaed" } 15 | risc0-build = { git = "https://github.com/risc0/risc0", rev = "8bd948be64d6084d1f01b37d60073f920c9beaed" } 16 | -------------------------------------------------------------------------------- /waldo/core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "waldo-core" 3 | version = "0.1.0" 4 | edition = "2021" 5 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 6 | 7 | [dependencies] 8 | bincode = "1.3" 9 | bytemuck = "1.12" 10 | divrem = "1.0.0" 11 | elsa = "1.7" 12 | image = { version = "0.24.5", default-features = false } 13 | merkle_light = "0.4" 14 | merkle_light_derive = "0.4" 15 | risc0-zkp = { version = "0.12", default-features = false } 16 | risc0-zkvm = { version = "0.12", default-features = false, features = ["std"] } 17 | serde = "1.0" 18 | 19 | [dev-dependencies] 20 | hex = "0.4.3" 21 | rand = "0.8.5" 22 | sha2 = "0.10.6" 23 | -------------------------------------------------------------------------------- /json/methods/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | include!(concat!(env!("OUT_DIR"), "/methods.rs")); 16 | -------------------------------------------------------------------------------- /sha/methods/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | include!(concat!(env!("OUT_DIR"), "/methods.rs")); 16 | -------------------------------------------------------------------------------- /chess/methods/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | include!(concat!(env!("OUT_DIR"), "/methods.rs")); 16 | -------------------------------------------------------------------------------- /factors/methods/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | include!(concat!(env!("OUT_DIR"), "/methods.rs")); 16 | -------------------------------------------------------------------------------- /json/methods/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | fn main() { 16 | risc0_build::embed_methods(); 17 | } 18 | -------------------------------------------------------------------------------- /sha/methods/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | fn main() { 16 | risc0_build::embed_methods(); 17 | } 18 | -------------------------------------------------------------------------------- /waldo/methods/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | include!(concat!(env!("OUT_DIR"), "/methods.rs")); 16 | -------------------------------------------------------------------------------- /wordle/methods/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | include!(concat!(env!("OUT_DIR"), "/methods.rs")); 16 | -------------------------------------------------------------------------------- /chess/methods/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | fn main() { 16 | risc0_build::embed_methods(); 17 | } 18 | -------------------------------------------------------------------------------- /factors/methods/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | fn main() { 16 | risc0_build::embed_methods(); 17 | } 18 | -------------------------------------------------------------------------------- /voting-machine/methods/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | include!(concat!(env!("OUT_DIR"), "/methods.rs")); 16 | -------------------------------------------------------------------------------- /wordle/methods/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | fn main() { 16 | risc0_build::embed_methods(); 17 | } 18 | -------------------------------------------------------------------------------- /digital-signature/methods/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | include!(concat!(env!("OUT_DIR"), "/methods.rs")); 16 | -------------------------------------------------------------------------------- /password-checker/methods/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | include!(concat!(env!("OUT_DIR"), "/methods.rs")); 16 | -------------------------------------------------------------------------------- /voting-machine/methods/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | fn main() { 16 | risc0_build::embed_methods(); 17 | } 18 | -------------------------------------------------------------------------------- /digital-signature/methods/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | fn main() { 16 | risc0_build::embed_methods(); 17 | } 18 | -------------------------------------------------------------------------------- /password-checker/methods/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | fn main() { 16 | risc0_build::embed_methods(); 17 | } 18 | -------------------------------------------------------------------------------- /sha/README.md: -------------------------------------------------------------------------------- 1 | # SHA Example 2 | 3 | This code demonstrates how to provably compute the SHA-256 hash of a string using RISC Zero. 4 | 5 | Notable details: 6 | * We use `risc0_zkvm_guest::sha` rather than general-purpose SHA code. This is because the RISC Zero zkVM includes SHA-specific accelerator code, and we therefore get _much_ better performance by using the native SHA code. 7 | * We could have passed the guest a `String` rather than a string literal for the same result. 8 | * Interpretting the output on the host side as a `risc0_zkp::core::sha::Digest` is useful for quality of life. We could also directly read the bytes written in the journal, but then we need to be careful about endianness, printing the bytes (`Digest` implements the `Display` trait), etc. 9 | -------------------------------------------------------------------------------- /.licenserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "**/*.{cpp,h,rs}": [ 3 | "// Copyright 2023 RISC Zero, Inc.", 4 | "//", 5 | "// Licensed under the Apache License, Version 2.0 (the \"License\");", 6 | "// you may not use this file except in compliance with the License.", 7 | "// You may obtain a copy of the License at", 8 | "//", 9 | "// http://www.apache.org/licenses/LICENSE-2.0", 10 | "//", 11 | "// Unless required by applicable law or agreed to in writing, software", 12 | "// distributed under the License is distributed on an \"AS IS\" BASIS,", 13 | "// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.", 14 | "// See the License for the specific language governing permissions and", 15 | "// limitations under the License." 16 | ], 17 | "ignore": [ 18 | "target/", 19 | "tmp/" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /chess/core/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use serde::{Deserialize, Serialize}; 16 | 17 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 18 | pub struct Inputs { 19 | pub board: String, 20 | pub mv: String, 21 | } 22 | -------------------------------------------------------------------------------- /password-checker/core/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use serde::{Deserialize, Serialize}; 16 | 17 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 18 | pub struct PasswordRequest { 19 | pub password: String, 20 | pub salt: [u8; 32], 21 | } 22 | -------------------------------------------------------------------------------- /json/core/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use risc0_zkp::core::sha::Digest; 16 | use serde::{Deserialize, Serialize}; 17 | 18 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 19 | pub struct Outputs { 20 | pub data: u32, 21 | pub hash: Digest, 22 | } 23 | -------------------------------------------------------------------------------- /waldo/methods/guest/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "waldo-methods-guest" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [workspace] 7 | 8 | [build-dependencies] 9 | risc0-build = "0.12" 10 | 11 | [dependencies] 12 | image = { version = "0.24.5", default-features = false } 13 | risc0-zkvm = { version = "0.12", default-features = false, features = ["std"] } 14 | waldo-core = { path = "../../core" } 15 | 16 | [profile.release] 17 | lto = true 18 | opt-level = 3 19 | 20 | [patch.crates-io] 21 | # TODO(victor): Remove these patch definitions when 8bd948b is included in a release. 22 | risc0-zkp = { git = "https://github.com/risc0/risc0", rev = "8bd948be64d6084d1f01b37d60073f920c9beaed" } 23 | risc0-zkvm = { git = "https://github.com/risc0/risc0", rev = "8bd948be64d6084d1f01b37d60073f920c9beaed" } 24 | risc0-build = { git = "https://github.com/risc0/risc0", rev = "8bd948be64d6084d1f01b37d60073f920c9beaed" } 25 | -------------------------------------------------------------------------------- /sha/methods/guest/src/bin/hash.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![no_main] 16 | 17 | use risc0_zkvm::guest::env; 18 | use risc0_zkvm::sha::{sha, Sha}; 19 | 20 | risc0_zkvm::guest::entry!(main); 21 | 22 | pub fn main() { 23 | let data: String = env::read(); 24 | let sha = sha().hash_bytes(&data.as_bytes()); 25 | env::commit(&*sha); 26 | } 27 | -------------------------------------------------------------------------------- /waldo/methods/build.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::collections::hash_map::HashMap; 16 | 17 | use risc0_build::GuestOptions; 18 | 19 | fn main() { 20 | risc0_build::embed_methods_with_options(HashMap::from([( 21 | "waldo-methods-guest", 22 | GuestOptions { 23 | features: vec![], 24 | std: true, 25 | }, 26 | )])); 27 | } 28 | -------------------------------------------------------------------------------- /digital-signature/methods/guest/src/bin/sign.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![no_main] 16 | #![no_std] 17 | 18 | use risc0_zkvm::guest::{env, sha}; 19 | use digital_signature_core::{SignMessageCommit, SigningRequest}; 20 | 21 | risc0_zkvm::guest::entry!(main); 22 | 23 | pub fn main() { 24 | let request: SigningRequest = env::read(); 25 | env::commit(&SignMessageCommit { 26 | identity: *sha::digest(&request.passphrase.pass), 27 | msg: request.msg, 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /voting-machine/methods/guest/src/bin/init.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![no_main] 16 | #![no_std] 17 | 18 | use risc0_zkvm::guest::{env, sha}; 19 | 20 | use voting_machine_core::{InitializeVotingMachineCommit, VotingMachineState}; 21 | 22 | risc0_zkvm::guest::entry!(main); 23 | 24 | pub fn main() { 25 | let state: VotingMachineState = env::read(); 26 | env::commit(&InitializeVotingMachineCommit { 27 | polls_open: state.polls_open, 28 | voter_bitfield: state.voter_bitfield, 29 | state: *sha::digest(&state), 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /json/methods/guest/src/bin/search_json.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![no_main] 16 | 17 | use json::parse; 18 | use json_core::Outputs; 19 | use risc0_zkvm::guest::{env, sha}; 20 | 21 | risc0_zkvm::guest::entry!(main); 22 | 23 | pub fn main() { 24 | let data: String = env::read(); 25 | let sha = sha::digest(&data.as_bytes()); 26 | let data = parse(&data).unwrap(); 27 | let proven_val = data["critical_data"].as_u32().unwrap(); 28 | let out = Outputs { 29 | data: proven_val, 30 | hash: *sha, 31 | }; 32 | env::commit(&out); 33 | } 34 | -------------------------------------------------------------------------------- /wordle/core/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use risc0_zkp::core::sha::Digest; 16 | use serde::{Deserialize, Serialize}; 17 | 18 | pub const WORD_LENGTH: usize = 5; 19 | 20 | #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] 21 | pub enum LetterFeedback { 22 | LetterCorrect, 23 | LetterPresent, 24 | #[default] 25 | LetterMiss, 26 | } 27 | 28 | pub type WordFeedback = [LetterFeedback; WORD_LENGTH]; 29 | 30 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 31 | pub struct GameState { 32 | pub correct_word_hash: Digest, 33 | pub feedback: WordFeedback, 34 | } 35 | -------------------------------------------------------------------------------- /factors/methods/guest/src/bin/multiply.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![no_main] 16 | #![no_std] 17 | 18 | use risc0_zkvm::guest::env; 19 | 20 | risc0_zkvm::guest::entry!(main); 21 | 22 | pub fn main() { 23 | // Load the first number from the host 24 | let a: u64 = env::read(); 25 | // Load the second number from the host 26 | let b: u64 = env::read(); 27 | // Verify that neither of them are 1 (i.e. nontrivial factors) 28 | if a == 1 || b == 1 { 29 | panic!("Trivial factors") 30 | } 31 | // Compute the product while being careful with integer overflow 32 | let product = a.checked_mul(b).expect("Integer overflow"); 33 | env::commit(&product); 34 | } 35 | -------------------------------------------------------------------------------- /chess/methods/guest/src/bin/checkmate.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![no_main] 16 | 17 | use chess_core::Inputs; 18 | use risc0_zkvm::guest::env; 19 | use shakmaty::fen::Fen; 20 | use shakmaty::san::San; 21 | use shakmaty::{CastlingMode, Chess, FromSetup, Move, Position, Setup}; 22 | 23 | risc0_zkvm::guest::entry!(main); 24 | 25 | pub fn main() { 26 | let inputs: Inputs = env::read(); 27 | let mv: String = inputs.mv; 28 | let initial_state: String = inputs.board; 29 | env::commit(&initial_state); 30 | 31 | let setup = Setup::from(Fen::from_ascii(initial_state.as_bytes()).unwrap()); 32 | let pos = Chess::from_setup(setup, CastlingMode::Standard).unwrap(); 33 | 34 | let mv: Move = mv.parse::().unwrap().to_move(&pos).unwrap(); 35 | let pos = pos.play(&mv).unwrap(); 36 | assert!(pos.is_checkmate()); 37 | } 38 | -------------------------------------------------------------------------------- /voting-machine/methods/guest/src/bin/freeze.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![no_main] 16 | #![no_std] 17 | 18 | use risc0_zkvm::guest::{env, sha}; 19 | 20 | use voting_machine_core::{FreezeVotingMachineCommit, FreezeVotingMachineParams}; 21 | 22 | risc0_zkvm::guest::entry!(main); 23 | 24 | pub fn main() { 25 | let params: FreezeVotingMachineParams = env::read(); 26 | let result = params.process(); 27 | env::write(&result); 28 | let polls_open = result.state.polls_open; 29 | let voter_bitfield = result.state.voter_bitfield; 30 | let count = result.state.count; 31 | env::commit(&FreezeVotingMachineCommit { 32 | old_state: *sha::digest(¶ms.state), 33 | new_state: *sha::digest(&result.state), 34 | polls_open: polls_open, 35 | voter_bitfield: voter_bitfield, 36 | count: count, 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /voting-machine/methods/guest/src/bin/submit.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![no_main] 16 | #![no_std] 17 | 18 | use risc0_zkvm::guest::{env, sha}; 19 | 20 | use voting_machine_core::{SubmitBallotCommit, SubmitBallotParams}; 21 | 22 | risc0_zkvm::guest::entry!(main); 23 | 24 | pub fn main() { 25 | let params: SubmitBallotParams = env::read(); 26 | let result = params.process(); 27 | env::write(&result); 28 | let polls_open = result.state.polls_open; 29 | let voter_bitfield = result.state.voter_bitfield; 30 | let voter = params.ballot.voter; 31 | let vote_yes = params.ballot.vote_yes; 32 | let vote_counted = result.vote_counted; 33 | env::commit(&SubmitBallotCommit { 34 | old_state: *sha::digest(¶ms.state), 35 | new_state: *sha::digest(&result.state), 36 | polls_open: polls_open, 37 | voter_bitfield: voter_bitfield, 38 | voter: voter, 39 | vote_yes: vote_yes, 40 | vote_counted: vote_counted, 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /factors/README.md: -------------------------------------------------------------------------------- 1 | # Factors 2 | 3 | The _factors_ example is a minimalistic RISC Zero zkVM proof. The prover demonstrates that they know two nontrivial factors (i.e. both greater than 1) of a number, without revealing what those factors are. Thus, the prover demonstrates that a number is composite -- and that they know the factors -- without revealing any further information about the number. 4 | 5 | This example was chosen because it is very straightforward. Implementing the verified multiplication and reporting the result in the receipt involves no complexity beyond what is necessary to run the zkVM at all. We therefore hope this example is a good place to look to see all the steps necessary to use the RISC Zero zkVM without any superfluous problem-specific details. 6 | 7 | Choosing a simple example necessarily excludes all of the more complex use cases -- so if you are looking for anything beyond the basics, we recommend looking at other examples in this repository! 8 | 9 | ## Run this example 10 | 11 | First, make sure [rustup](https://rustup.rs) is installed. This project uses a [nightly](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) version of [Rust](https://doc.rust-lang.org/book/ch01-01-installation.html). The [`rust-toolchain`](rust-toolchain) file will be used by `cargo` to automatically install the correct version. 12 | 13 | To build all methods and execute the method within the zkVM, run the following command: 14 | 15 | ``` 16 | cargo run 17 | ``` 18 | 19 | ## Video Tutorial 20 | 21 | For a walk-through of this example, check out this [excerpt from our workshop at ZK HACK III](https://www.youtube.com/watch?v=nWxL21hKV9s&list=PLcPzhUaCxlCgig7ofeARMPwQ8vbuD6hC5&index=3). 22 | -------------------------------------------------------------------------------- /chess/README.md: -------------------------------------------------------------------------------- 1 | # ZK Checkmate 2 | 3 | Proves that a chess position has a checkmate without revealing what that checkmate is. 4 | 5 | Takes a move that is kept private and an initial board state that is published to the [journal](https://www.risczero.com/docs/explainers/zkvm/). There are default values for these, but you can also pass in an alternative move and/or board state as command line arguments. The move is in SAN format and the board state is in FEN format. 6 | 7 | ## Quick Start 8 | 9 | First, make sure [rustup](https://rustup.rs) is installed. This project uses a [nightly](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) version of [Rust](https://doc.rust-lang.org/book/ch01-01-installation.html). The [`rust-toolchain`](rust-toolchain) file will be used by `cargo` to automatically install the correct version. 10 | 11 | To build all methods and create a zero-knowledge proof that the position defined [here](https://github.com/risc0/risc0-rust-examples/blob/main/chess/host/src/main.rs) includes a mate-in-one, run the following command: 12 | 13 | ``` 14 | cargo run 15 | ``` 16 | 17 | ## About the code 18 | The [guest code](https://github.com/risc0/risc0-rust-examples/blob/main/chess/methods/guest/src/bin/checkmate.rs) generates the `pos` that results from a given `move` on a given `board`, and then checks that `pos` is checkmate. 19 | The [host code](https://github.com/risc0/risc0-rust-examples/blob/main/chess/host/src/main.rs) supplies the `move` and the `board`. 20 | 21 | ## Video Tutorial 22 | 23 | For a walk-through of this example, check out this [excerpt from our workshop at ZK HACK III](https://www.youtube.com/watch?v=vxqxRiTXGBI&list=PLcPzhUaCxlCgig7ofeARMPwQ8vbuD6hC5&index=9). 24 | -------------------------------------------------------------------------------- /digital-signature/README.md: -------------------------------------------------------------------------------- 1 | # Simple digital signature 2 | 3 | A simple digital signature scheme built on the RISC Zero platform. 4 | 5 | ## Summary 6 | 7 | From [Wikipedia](https://en.wikipedia.org/wiki/Digital_signature): 8 | > A digital signature is a mathematical scheme for verifying the authenticity of 9 | digital messages or documents. A valid digital signature, where the 10 | prerequisites are satisfied, gives a recipient very high confidence that the 11 | message was created by a known sender (authenticity), and that the message was 12 | not altered in transit (integrity). 13 | 14 | This example shows how to build a simple digital signature scheme on the Risc0 15 | platform. In this scheme, the sender possesses a passphrase which they use to 16 | sign messages. Their identity is simply the SHA-256d hash of their passphrase. 17 | 18 | In our scheme, we would send the message, the commitment (message and 19 | identity), and the receipt. This allows the recipient to know that we have the 20 | passphrase (authenticity) and used it to sign the message in question 21 | (integrity). 22 | 23 | Specifically, the sender uses the zkVM to run `sign(message, passphrase)`. This 24 | returns a data structure that includes the important components: commitment and 25 | receipt. The commitment shows the message and the signer's identity, and the 26 | receipt proves that the identity was computed by taking the SHA-256d of 27 | the signer's passphrase (i.e. not just copied). Thus the signer must possess the 28 | passphrase. Sending those along with the message covers the full scope of a 29 | typical digital signature scheme. 30 | 31 | ## Run the example 32 | 33 | ```bash 34 | cargo run --release -- "This is a signed message" --passphrase="passw0rd" 35 | ``` 36 | -------------------------------------------------------------------------------- /wordle/methods/guest/src/bin/wordle.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![no_main] 16 | 17 | use risc0_zkvm::guest::{env, sha}; 18 | use wordle_core::{WORD_LENGTH, WordFeedback, LetterFeedback, GameState}; 19 | 20 | risc0_zkvm::guest::entry!(main); 21 | 22 | pub fn main() { 23 | let word: String = env::read(); 24 | let guess: String = env::read(); 25 | 26 | if word.chars().count() != WORD_LENGTH { 27 | panic!("secret word must have length 5!") 28 | } 29 | 30 | if guess.chars().count() != WORD_LENGTH { 31 | panic!("guess must have length 5!") 32 | } 33 | 34 | let correct_word_hash = sha::digest(&word.as_bytes()).to_owned(); 35 | env::commit(&correct_word_hash); 36 | 37 | let mut score: WordFeedback = WordFeedback::default(); 38 | for i in 0..WORD_LENGTH { 39 | score[i] = if word.as_bytes()[i] == guess.as_bytes()[i] { 40 | LetterFeedback::LetterCorrect 41 | } else if word.as_bytes().contains(&guess.as_bytes()[i]) { 42 | LetterFeedback::LetterPresent 43 | } else { 44 | LetterFeedback::LetterMiss 45 | } 46 | } 47 | let game_state = GameState { 48 | correct_word_hash: correct_word_hash, 49 | feedback: score, 50 | }; 51 | env::commit(&game_state); 52 | } 53 | -------------------------------------------------------------------------------- /digital-signature/core/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![cfg_attr(not(test), no_std)] 16 | 17 | use core::fmt::{Debug, Display, Formatter}; 18 | 19 | use risc0_zkp::core::sha::Digest; 20 | use serde::{Deserialize, Serialize}; 21 | 22 | #[derive(Clone, Deserialize, Eq, PartialEq, Serialize)] 23 | pub struct Message { 24 | pub msg: [u8; 32], 25 | } 26 | 27 | impl Display for Message { 28 | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { 29 | for word in self.msg { 30 | core::write!(f, "{:02x?}", word)?; 31 | } 32 | Ok(()) 33 | } 34 | } 35 | 36 | impl Debug for Message { 37 | fn fmt(&self, f: &mut Formatter) -> core::fmt::Result { 38 | for word in self.msg { 39 | core::write!(f, "{:02x?}", word)?; 40 | } 41 | Ok(()) 42 | } 43 | } 44 | 45 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 46 | pub struct Passphrase { 47 | pub pass: [u8; 32], 48 | } 49 | 50 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 51 | pub struct SigningRequest { 52 | pub passphrase: Passphrase, 53 | pub msg: Message, 54 | } 55 | 56 | #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)] 57 | pub struct SignMessageCommit { 58 | pub identity: Digest, 59 | pub msg: Message, 60 | } 61 | -------------------------------------------------------------------------------- /json/host/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::io::prelude::*; 16 | 17 | use json_core::Outputs; 18 | use methods::{SEARCH_JSON_ELF, SEARCH_JSON_ID}; 19 | use risc0_zkvm::serde::{from_slice, to_vec}; 20 | use risc0_zkvm::Prover; 21 | 22 | fn main() { 23 | let mut file = 24 | std::fs::File::open("res/example.json").expect("Example file should be accessible"); 25 | let mut data = String::new(); 26 | file.read_to_string(&mut data) 27 | .expect("Should not have I/O errors"); 28 | 29 | // Make the prover. 30 | let mut prover = Prover::new(SEARCH_JSON_ELF, SEARCH_JSON_ID) 31 | .expect("Prover should be constructed from matching method code & ID"); 32 | 33 | prover.add_input_u32_slice(&to_vec(&data).expect("should be serializable")); 34 | 35 | // Run prover & generate receipt 36 | let receipt = prover.run().expect("Code should be provable"); 37 | 38 | receipt 39 | .verify(SEARCH_JSON_ID) 40 | .expect("Proven code should verify"); 41 | 42 | let journal = &receipt.journal; 43 | let outputs: Outputs = from_slice(&journal).expect("Journal should contain an Outputs object"); 44 | 45 | println!("\nThe JSON file with hash\n {}\nprovably contains a field 'critical_data' with value {}\n", outputs.hash, outputs.data); 46 | } 47 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | # Allows running this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | jobs: 13 | check: 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | project: 18 | - chess 19 | - digital-signature 20 | - factors 21 | - json 22 | - password-checker 23 | - sha 24 | - voting-machine 25 | - wordle 26 | - waldo 27 | os: [Linux, macOS] 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v3 31 | with: 32 | # Fetch the merge commit and origin/HEAD. 33 | fetch-depth: 2 34 | - uses: risc0/actions-rs-toolchain@v1 35 | with: 36 | toolchain: stable 37 | - name: Install cargo-sort 38 | uses: risc0/cargo-install@v1 39 | with: 40 | crate: cargo-sort 41 | version: "1.0" 42 | - run: cargo fmt --all -- --check 43 | working-directory: ${{ matrix.project }} 44 | - run: cargo sort --workspace --check 45 | working-directory: ${{ matrix.project }} 46 | - run: npx @kt3k/license-checker 47 | 48 | test: 49 | strategy: 50 | fail-fast: false 51 | matrix: 52 | project: 53 | - chess 54 | - digital-signature 55 | - factors 56 | - json 57 | - password-checker 58 | - sha 59 | - voting-machine 60 | - wordle 61 | - waldo 62 | os: [Linux, macOS] 63 | runs-on: [self-hosted, "${{ matrix.os }}"] 64 | steps: 65 | - uses: actions/checkout@v2 66 | - uses: actions-rs/toolchain@v1 67 | with: 68 | toolchain: stable 69 | - run: cargo test --release 70 | working-directory: ${{ matrix.project }} 71 | -------------------------------------------------------------------------------- /password-checker/cli/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::fs; 16 | 17 | use password_checker_core::PasswordRequest; 18 | use password_checker_methods::{PW_CHECKER_ELF, PW_CHECKER_ID}; 19 | use rand::prelude::*; 20 | use risc0_zkp::core::sha::Digest; 21 | use risc0_zkvm::serde::{from_slice, to_vec}; 22 | use risc0_zkvm::Prover; 23 | 24 | fn main() { 25 | let mut rng = StdRng::from_entropy(); 26 | let mut salt = [0u8; 32]; 27 | rng.fill_bytes(&mut salt); 28 | 29 | let request = PasswordRequest { 30 | password: "S00perSecr1t!!!".into(), 31 | salt, 32 | }; 33 | 34 | // a new prover is created to run the pw_checker method 35 | let mut prover = Prover::new(PW_CHECKER_ELF, PW_CHECKER_ID).unwrap(); 36 | 37 | // Adding input to the prover makes it readable by the guest 38 | let vec = to_vec(&request).unwrap(); 39 | prover.add_input_u32_slice(&vec); 40 | 41 | let receipt = prover.run().unwrap(); 42 | let password_hash: Digest = from_slice(&receipt.journal).unwrap(); 43 | println!("Password hash is: {}", &password_hash); 44 | 45 | // In most scenarios, we would serialize and send the receipt to a verifier here 46 | // The verifier checks the receipt with the following call, which panics if the receipt is wrong 47 | receipt.verify(PW_CHECKER_ID).unwrap(); 48 | } 49 | -------------------------------------------------------------------------------- /wordle/README.md: -------------------------------------------------------------------------------- 1 | # Wordle in the zkVM 2 | 3 | ## Quick Start 4 | 5 | First, make sure [rustup](https://rustup.rs) is installed. This project uses a [nightly](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) version of [Rust](https://doc.rust-lang.org/book/ch01-01-installation.html). The [`rust-toolchain`](rust-toolchain) file will be used by `cargo` to automatically install the correct version. 6 | 7 | To build all methods and play Wordle within the zkVM, run the following command: 8 | 9 | ``` 10 | cargo run 11 | ``` 12 | 13 | Then, start guessing 5 letter words! 14 | 15 | ## About the game 16 | 17 | The [game](https://github.com/risc0/risc0-rust-examples/blob/main/wordle/host/src/main.rs) consists of two agents: a player and a server. 18 | The zkVM enforces that the server plays fairly. 19 | 20 | The game begins with the server choosing a secret word from the [wordlist](https://github.com/risc0/risc0-rust-examples/blob/main/wordle/host/src/wordlist.rs), and sending the player the hash of the secret word. 21 | 22 | The player then submits guesses. After each guess, the server returns which letters from the guess match the letters in the secret word. 23 | In addition, the server returns a [receipt](https://www.risczero.com/docs/explainers/proof-system/) that attests to the logic of the letter-checking and [includes the hash](https://github.com/risc0/risc0-rust-examples/blob/main/wordle/methods/guest/src/bin/wordle.rs) of the secret word. 24 | 25 | ## Ensuring fair play 26 | 27 | The player ensures that server isn't cheating using the [`check_receipt` function](https://github.com/risc0/risc0-rust-examples/blob/main/wordle/host/src/main.rs). 28 | This function first runs `receipt.verify(WORDLE_ID)` which ensures that the receipt is valid and was generated by the correct binary file. 29 | Then, the `check_receipt` function checks that the hash in the [journal contents](https://www.risczero.com/docs/explainers/zkvm/) match the hash of the secret word provided at the start of the game. 30 | -------------------------------------------------------------------------------- /waldo/core/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #[macro_use] 16 | extern crate merkle_light_derive; 17 | extern crate merkle_light; 18 | 19 | pub mod image; 20 | pub mod merkle; 21 | 22 | use serde::{Deserialize, Serialize}; 23 | 24 | /// Private input values to the image crop method. 25 | #[derive(Debug, Serialize, Deserialize)] 26 | pub struct PrivateInput { 27 | /// Merkle tree root committing to the full Where's Waldo image. 28 | pub root: merkle::Node, 29 | 30 | /// Width and height of the committed image. 31 | pub image_dimensions: (u32, u32), 32 | 33 | /// X and y location for the top left corner of the crop. 34 | pub crop_location: (u32, u32), 35 | 36 | /// Width and height of the cropped image. 37 | pub crop_dimensions: (u32, u32), 38 | 39 | /// Optional mask to apply to the image to filter out additional pixels from the crop area. 40 | pub mask: Option>, 41 | } 42 | 43 | /// Public journal values that will be committed by the image crop method. 44 | #[derive(Debug, Serialize, Deserialize)] 45 | pub struct Journal { 46 | pub subimage: Vec, 47 | 48 | /// Width and height of the resulting subimage. 49 | pub subimage_dimensions: (u32, u32), 50 | 51 | /// Merkle tree root of the committed image. 52 | /// Must be checked against the root of the image that was expected to be cropped. 53 | pub root: merkle::Node, 54 | 55 | /// Width and height of the committed image. 56 | /// Must be checked against the dimensions of the image that was expected to be cropped. 57 | pub image_dimensions: (u32, u32), 58 | } 59 | -------------------------------------------------------------------------------- /password-checker/README.md: -------------------------------------------------------------------------------- 1 | # password_checker 2 | 3 | This simple password checker is implemented in Rust. The program is implemented in two parts: a policy checker (that runs in the zkVM) and a host driver (an ordinary command-line program that uses the zkVM to run the policy checker). 4 | 5 | The policy checker accepts a password string and a salt from the host driver and checks the validity of the password. A password validity-checking function then examines the password and panics if criteria are not met. If the password meets validity criteria, execution proceeds and the zkVM appends a hash of the salted password to the journal. The journal is a readable record of all values committed by code in the zkVM; it is attached to the receipt (a record of correct execution). 6 | 7 | # Why use zkVM to run this? 8 | 9 | Our goal is to run our own password check locally without having to share our password directly with a recipient, preferring instead to share only a SHA-256 password hash. Because the validity-checking and hashing functionality runs on the zkVM, it generates a receipt that identifies which binary was executed (via the method ID), associates shared results with this particular execution (via the journal), and confirms its own integrity (via the cryptographic seal). 10 | 11 | # Project organization 12 | 13 | The main program that calls a method in the guest ZKVM is in [cli/src/main.rs](cli/src/main.rs). The code that runs inside the ZKVM is in [methods/guest/src/bin/pw_checker.rs](methods/guest/src/bin/pw_checker.rs). The rest of the project is build support. 14 | 15 | For the main RISC Zero project, see [here](https://github.com/risc0/risc0) 16 | 17 | # Run this example 18 | 19 | To build and run this example, use: 20 | 21 | ``` 22 | cargo run --release 23 | ``` 24 | 25 | # And now, some fine print 26 | 27 | This repository contains example code meant to illustrate the fundamentals of programming with the zkVM. The password policy (and broader protocol) implemented here is intended for educational purposes only. 28 | 29 | 30 | ## Video Tutorial 31 | 32 | For a walk-through of the fundamentals of this example, check out this [excerpt from our workshop at ZK HACK III](https://www.youtube.com/watch?v=vxqxRiTXGBI&list=PLcPzhUaCxlCgig7ofeARMPwQ8vbuD6hC5&index=5). 33 | -------------------------------------------------------------------------------- /factors/factors/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use methods::{MULTIPLY_ELF, MULTIPLY_ID}; 16 | use risc0_zkvm::serde::{from_slice, to_vec}; 17 | use risc0_zkvm::Prover; 18 | 19 | fn main() { 20 | // Pick two numbers 21 | let a: u64 = 17; 22 | let b: u64 = 23; 23 | 24 | // Multiply them inside the ZKP 25 | // First, we make the prover, loading the 'multiply' method 26 | let mut prover = Prover::new(MULTIPLY_ELF, MULTIPLY_ID).expect( 27 | "Prover should be constructed from valid method source code and corresponding method ID", 28 | ); 29 | 30 | // Next we send a & b to the guest 31 | prover.add_input_u32_slice(&to_vec(&a).expect("should be serializable")); 32 | prover.add_input_u32_slice(&to_vec(&b).expect("should be serializable")); 33 | // Run prover & generate receipt 34 | let receipt = prover.run() 35 | .expect("Valid code should be provable if it doesn't overflow the cycle limit. See `embed_methods_with_options` for information on adjusting maximum cycle count."); 36 | 37 | // Extract journal of receipt (i.e. output c, where c = a * b) 38 | let c: u64 = from_slice(&receipt.journal).expect( 39 | "Journal output should deserialize into the same types (& order) that it was written", 40 | ); 41 | 42 | // Print an assertion 43 | println!("I know the factors of {}, and I can prove it!", c); 44 | 45 | // Here is where one would send 'receipt' over the network... 46 | 47 | // Verify receipt, panic if it's wrong 48 | receipt.verify(MULTIPLY_ID).expect( 49 | "Code you have proven should successfully verify; did you specify the correct method ID?", 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /digital-signature/cli/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use clap::{Arg, Command}; 16 | use digital_signature::sign; 17 | use log::LevelFilter; 18 | use sha2::{Digest, Sha256}; 19 | 20 | fn main() { 21 | env_logger::builder().filter_level(LevelFilter::Info).init(); 22 | 23 | let matches = Command::new("sign") 24 | .version("0.1.0") 25 | .author("Risc0, Inc.") 26 | .about("Digital signatures with Risc0") 27 | .arg(Arg::new("message").required(true)) 28 | .arg( 29 | Arg::new("passphrase") 30 | .long("passphrase") 31 | .required(true) 32 | .takes_value(true), 33 | ) 34 | .get_matches(); 35 | 36 | let message = matches.value_of("message").unwrap(); 37 | let passphrase = matches.value_of("passphrase").unwrap(); 38 | let signing_receipt = sign(&passphrase, &message).unwrap(); 39 | 40 | log::info!("Inputs"); 41 | log::info!("\tmessage: {:?}", &message); 42 | log::info!("Commitment:"); 43 | log::info!("\tmessage: {:?}", &signing_receipt.get_message().unwrap()); 44 | log::info!("\tidentity: {:?}", &signing_receipt.get_identity().unwrap()); 45 | log::info!("Integrity Checks:"); 46 | let message_hash = &signing_receipt.get_message().unwrap().msg; 47 | let expected_message_hash = Sha256::digest(message); 48 | if message_hash != expected_message_hash.as_slice() { 49 | log::error!("Message commitment does not match given message!"); 50 | std::process::exit(1); 51 | } 52 | log::info!("\tmessage: valid"); 53 | if signing_receipt.verify().is_err() { 54 | log::error!("Receipt is invalid!"); 55 | log::error!("{}", signing_receipt.verify().unwrap_err()); 56 | std::process::exit(1); 57 | } 58 | log::info!("\treceipt: valid"); 59 | } 60 | -------------------------------------------------------------------------------- /waldo/methods/guest/src/bin/image_crop.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![no_main] 16 | // #![no_std] 17 | 18 | use image::{imageops, GenericImageView}; 19 | use risc0_zkvm::guest::env; 20 | use waldo_core::image::{ImageMask, ImageOracle, IMAGE_CHUNK_SIZE}; 21 | use waldo_core::{Journal, PrivateInput}; 22 | 23 | risc0_zkvm::guest::entry!(main); 24 | 25 | pub fn main() { 26 | // Read a Merkle proof from the host. 27 | let input: PrivateInput = env::read(); 28 | 29 | // Initialize a Merkle tree based vector oracle, supporting verified access to a vector of data 30 | // on the host. Use the oracle to access a range of elements from the host. 31 | let oracle = ImageOracle::<{ IMAGE_CHUNK_SIZE }>::new( 32 | input.root, 33 | input.image_dimensions.0, 34 | input.image_dimensions.1, 35 | ); 36 | 37 | let subimage = imageops::crop_imm( 38 | &oracle, 39 | input.crop_location.0, 40 | input.crop_location.1, 41 | input.crop_dimensions.0, 42 | input.crop_dimensions.1, 43 | ) 44 | .to_image(); 45 | 46 | // If a mask is provided, apply it to reveal less about the image. 47 | let subimage_masked = match input.mask { 48 | Some(mask_raw) => { 49 | let mask = 50 | ImageMask::from_raw(input.crop_dimensions.0, input.crop_dimensions.1, mask_raw) 51 | .unwrap(); 52 | mask.apply(subimage) 53 | } 54 | None => subimage, 55 | }; 56 | 57 | // Collect the verified public information into the journal. 58 | let journal = Journal { 59 | root: *oracle.root(), 60 | image_dimensions: oracle.dimensions(), 61 | subimage_dimensions: subimage_masked.dimensions(), 62 | subimage: subimage_masked.into_raw(), 63 | }; 64 | env::commit(&journal); 65 | } 66 | -------------------------------------------------------------------------------- /chess/host/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use chess_core::Inputs; 16 | use clap::{Arg, Command}; 17 | use methods::{CHECKMATE_ELF, CHECKMATE_ID}; 18 | use risc0_zkvm::serde::{from_slice, to_vec}; 19 | use risc0_zkvm::Prover; 20 | use shakmaty::fen::Fen; 21 | use shakmaty::{CastlingMode, Chess, FromSetup, Position, Setup}; 22 | 23 | fn pad_to_word(inp: &mut String) { 24 | inp.push_str(&" "[..4 - (inp.len() % 4)]); 25 | } 26 | 27 | fn main() { 28 | let matches = 29 | Command::new("chess") 30 | .arg(Arg::new("move").default_value("Qxf7")) 31 | .arg(Arg::new("board").default_value( 32 | "r1bqkb1r/pppp1ppp/2n2n2/4p2Q/2B1P3/8/PPPP1PPP/RNB1K1NR w KQkq - 4 4", 33 | )) 34 | .get_matches(); 35 | let mv = matches.get_one::("move").unwrap(); 36 | let mut initial_state = matches.get_one::("board").unwrap().to_string(); 37 | pad_to_word(&mut initial_state); 38 | 39 | let inputs = Inputs { 40 | board: initial_state, 41 | mv: mv.to_string(), 42 | }; 43 | 44 | // Make the prover. 45 | let mut prover = Prover::new(CHECKMATE_ELF, CHECKMATE_ID).unwrap(); 46 | 47 | prover.add_input_u32_slice(&to_vec(&inputs).expect("Should be serializable")); 48 | 49 | // Run prover & generate receipt 50 | let receipt = prover 51 | .run() 52 | .expect("Legal board state and checkmating move expected"); 53 | 54 | // Verify receipt and parse it for committed data 55 | receipt.verify(CHECKMATE_ID).unwrap(); 56 | let vec = receipt.journal; 57 | let committed_state: String = from_slice(&vec).unwrap(); 58 | assert_eq!(inputs.board, committed_state); 59 | let fen = Fen::from_ascii(committed_state.as_bytes()).unwrap(); 60 | let setup = Setup::from(fen); 61 | let pos = Chess::from_setup(setup, CastlingMode::Standard).unwrap(); 62 | 63 | println!( 64 | "There is a checkmate for {:?} in this position:\n{:?}", 65 | pos.turn(), 66 | pos.board() 67 | ); 68 | } 69 | -------------------------------------------------------------------------------- /sha/host/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use clap::{Arg, Command}; 16 | use methods::{HASH_ELF, HASH_ID}; 17 | use risc0_zkp::core::sha::Digest; 18 | use risc0_zkvm::serde::{from_slice, to_vec}; 19 | use risc0_zkvm::{Prover, Receipt}; 20 | 21 | fn provably_hash(input: &str) -> Receipt { 22 | // Make the prover. 23 | let mut prover = Prover::new(HASH_ELF, HASH_ID) 24 | .expect("Prover should be constructed from matching code and method ID"); 25 | 26 | prover.add_input_u32_slice(&to_vec(input).expect("input string should serialize")); 27 | 28 | // Run prover & generate receipt 29 | prover.run().expect("Code should be provable") 30 | } 31 | 32 | fn main() { 33 | // Parse command line 34 | let matches = Command::new("hash") 35 | .arg(Arg::new("message").default_value("")) 36 | .get_matches(); 37 | let message = matches.get_one::("message").unwrap(); 38 | 39 | // Prove hash and verify it 40 | let receipt = provably_hash(message); 41 | receipt.verify(HASH_ID).expect("Proven code should verify"); 42 | 43 | let journal = receipt.journal; 44 | let digest = 45 | from_slice::(journal.as_slice()).expect("Journal should contain SHA Digest"); 46 | 47 | println!("I provably know data whose SHA-256 hash is {}", digest); 48 | } 49 | 50 | #[cfg(test)] 51 | mod tests { 52 | use methods::HASH_ID; 53 | use risc0_zkp::core::sha::Digest; 54 | use risc0_zkvm::serde::from_slice; 55 | 56 | use crate::provably_hash; 57 | 58 | const TEST_STRING: &str = "abc"; 59 | 60 | #[test] 61 | fn main() { 62 | let receipt = provably_hash(TEST_STRING); 63 | receipt.verify(HASH_ID).expect("Proven code should verify"); 64 | 65 | let digest = from_slice::(receipt.journal.as_slice()) 66 | .expect("Journal should contain SHA Digest"); 67 | assert_eq!( 68 | hex::encode(digest.as_bytes()), 69 | "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", 70 | "We expect to match the reference SHA-256 hash of the standard test value 'abc'" 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /password-checker/methods/guest/src/bin/pw_checker.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![no_main] 16 | 17 | use password_checker_core::PasswordRequest; 18 | use risc0_zkvm::guest::env; 19 | use risc0_zkvm::sha::{Sha, sha}; 20 | 21 | risc0_zkvm::guest::entry!(main); 22 | 23 | pub fn main() { 24 | let request: PasswordRequest = env::read(); 25 | 26 | let policy = PasswordPolicy { 27 | min_length: 3, 28 | max_length: 64, 29 | min_numeric: 2, 30 | min_uppercase: 2, 31 | min_lowercase: 2, 32 | min_special_chars: 1, 33 | }; 34 | 35 | if !policy.is_valid(&request.password) { 36 | panic!("Password invalid. Please try again."); 37 | } 38 | 39 | let mut salted_password = request.password.as_bytes().to_vec(); 40 | salted_password.extend(request.salt); 41 | let password_hash = sha().hash_bytes(&salted_password[..]); 42 | 43 | env::commit(&*password_hash); 44 | env::commit(&request.salt); 45 | } 46 | 47 | struct PasswordPolicy { 48 | pub min_length: usize, 49 | pub max_length: usize, 50 | pub min_uppercase: usize, 51 | pub min_lowercase: usize, 52 | pub min_numeric: usize, 53 | pub min_special_chars: usize, 54 | } 55 | 56 | impl PasswordPolicy { 57 | pub fn is_valid(&self, pw: &str) -> bool { 58 | let metrics = PasswordMetrics::new(pw); 59 | self.correct_length(pw) 60 | && (metrics.numeric >= self.min_numeric) 61 | && (metrics.uppercase >= self.min_uppercase) 62 | && (metrics.lowercase >= self.min_lowercase) 63 | && (metrics.special >= self.min_special_chars) 64 | } 65 | 66 | fn correct_length(&self, password: &str) -> bool { 67 | password.len() > (self.min_length - 1) && password.len() < (self.max_length + 1) 68 | } 69 | } 70 | 71 | struct PasswordMetrics { 72 | pub numeric: usize, 73 | pub special: usize, 74 | pub uppercase: usize, 75 | pub lowercase: usize, 76 | } 77 | 78 | impl PasswordMetrics { 79 | pub fn new(password: &str) -> Self { 80 | let mut numeric = 0; 81 | let mut special = 0; 82 | let mut uppercase = 0; 83 | let mut lowercase = 0; 84 | for ch in password.chars() { 85 | if ch.is_ascii_digit() { 86 | numeric += 1; 87 | } 88 | if ch.is_ascii_punctuation() { 89 | special += 1; 90 | } 91 | if ch.is_ascii_uppercase() { 92 | uppercase += 1; 93 | } 94 | if ch.is_ascii_lowercase() { 95 | lowercase += 1; 96 | } 97 | } 98 | PasswordMetrics { 99 | numeric, 100 | special, 101 | uppercase, 102 | lowercase, 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /voting-machine/README.md: -------------------------------------------------------------------------------- 1 | # Voting machine on RISC Zero 2 | 3 | A simple voting machine built on the RISC Zero platform. 4 | 5 | **This example is for educational purposes only. Not for use in actual elections.** 6 | 7 | ## Overview 8 | 9 | A *voting machine* is a state machine with three operations: 10 | 11 | * *Initialize*, which officials use to configure the machine; 12 | * *Submit ballot*, which voters use to submit their ballot; 13 | * *Freeze*, which reveals the current vote count & puts the machine into a state where it no longer accepts ballots. 14 | 15 | Every time the voting machine updates its state it prints a "receipt" that 16 | commits it to that state. At the end of the election, officials can publish the 17 | full list of receipts and voters can check to ensure theirs is included. In this 18 | way, voters can confirm that their vote was counted. 19 | 20 | ## Running the tests 21 | 22 | ```bash 23 | cargo test --release 24 | ``` 25 | 26 | ```console 27 | [2022-03-29T18:13:44Z INFO test::tests] initial commit: Ok(InitializeVotingMachineCommit { polls_open: true, voter_bitfield: 0, state: c3e42245ffdff31c980d63b232de1414ca2461a08c6efccca2af96737ef4d068 }) 28 | [2022-03-29T18:13:44Z INFO test::tests] ballot 1: Ballot { voter: 0, vote_yes: false } 29 | [2022-03-29T18:13:44Z INFO test::tests] ballot 1 commit: Ok(SubmitBallotCommit { old_state: c3e42245ffdff31c980d63b232de1414ca2461a08c6efccca2af96737ef4d068, new_state: d05796eb3a889d209cc6e6e6a1429bbd9d218df2b58146a51be1fcafc3164042, polls_open: true, voter_bitfield: 1, voter: 0, vote_counted: true }) 30 | [2022-03-29T18:13:44Z INFO test::tests] ballot 2: Ballot { voter: 1, vote_yes: true } 31 | [2022-03-29T18:13:44Z INFO test::tests] ballot 2 commit: Ok(SubmitBallotCommit { old_state: d05796eb3a889d209cc6e6e6a1429bbd9d218df2b58146a51be1fcafc3164042, new_state: cf922f404db827ea91f8c423c0621c677b464641fe0b6c6a7aeeb755fa19758b, polls_open: true, voter_bitfield: 3, voter: 1, vote_counted: true }) 32 | [2022-03-29T18:13:44Z INFO test::tests] ballot 3: Ballot { voter: 2, vote_yes: true } 33 | [2022-03-29T18:13:44Z INFO test::tests] ballot 3 commit: Ok(SubmitBallotCommit { old_state: cf922f404db827ea91f8c423c0621c677b464641fe0b6c6a7aeeb755fa19758b, new_state: 3d5bc2f4e701d3184e5f2874d144b020bbfb3dd4a605509f703d82bd5daad5f2, polls_open: true, voter_bitfield: 7, voter: 2, vote_counted: true }) 34 | [2022-03-29T18:13:44Z INFO test::tests] ballot 4: Ballot { voter: 1, vote_yes: false } 35 | [2022-03-29T18:13:44Z INFO test::tests] ballot 4 commit: Ok(SubmitBallotCommit { old_state: 3d5bc2f4e701d3184e5f2874d144b020bbfb3dd4a605509f703d82bd5daad5f2, new_state: 3d5bc2f4e701d3184e5f2874d144b020bbfb3dd4a605509f703d82bd5daad5f2, polls_open: true, voter_bitfield: 7, voter: 1, vote_counted: false }) 36 | [2022-03-29T18:13:44Z INFO test::tests] ballot 5: Ballot { voter: 3, vote_yes: false } 37 | [2022-03-29T18:13:44Z INFO test::tests] ballot 5 commit: Ok(SubmitBallotCommit { old_state: 3d5bc2f4e701d3184e5f2874d144b020bbfb3dd4a605509f703d82bd5daad5f2, new_state: 560897b3110f28db5855b27a713d0bb98300526ced5c5786398d8710e55f5ab7, polls_open: true, voter_bitfield: 15, voter: 3, vote_counted: true }) 38 | [2022-03-29T18:13:44Z INFO test::tests] freeze commit: Ok(FreezeVotingMachineCommit { old_state: 560897b3110f28db5855b27a713d0bb98300526ced5c5786398d8710e55f5ab7, new_state: 9aad1eebf324176d836beec9af1f09812915408082c48895f6271e06943ec116, polls_open: false, voter_bitfield: 15, count: 2 }) 39 | [2022-03-29T18:13:44Z INFO test::tests] ballot 6: Ballot { voter: 4, vote_yes: true } 40 | [2022-03-29T18:13:44Z INFO test::tests] ballot 6 commit: Ok(SubmitBallotCommit { old_state: 9aad1eebf324176d836beec9af1f09812915408082c48895f6271e06943ec116, new_state: 9aad1eebf324176d836beec9af1f09812915408082c48895f6271e06943ec116, polls_open: false, voter_bitfield: 15, voter: 4, vote_counted: false }) 41 | [2022-03-29T18:13:44Z INFO test::tests] Final vote count: 2 42 | ... 43 | ``` 44 | -------------------------------------------------------------------------------- /digital-signature/cli/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | pub use digital_signature_core::{Message, Passphrase, SignMessageCommit, SigningRequest}; 16 | use digital_signature_methods::{SIGN_ELF, SIGN_ID}; 17 | use risc0_zkvm::serde::{from_slice, to_vec}; 18 | use risc0_zkvm::{Prover, Receipt, Result}; 19 | use sha2::{Digest, Sha256}; 20 | 21 | pub struct SignatureWithReceipt { 22 | receipt: Receipt, 23 | } 24 | 25 | impl SignatureWithReceipt { 26 | pub fn get_commit(&self) -> Result { 27 | let msg = &self.receipt.journal; 28 | Ok(from_slice(msg.as_slice()).unwrap()) 29 | } 30 | 31 | pub fn get_identity(&self) -> Result { 32 | let commit = self.get_commit()?; 33 | Ok(commit.identity) 34 | } 35 | 36 | pub fn get_message(&self) -> Result { 37 | let commit = self.get_commit()?; 38 | Ok(commit.msg) 39 | } 40 | 41 | pub fn verify(&self) -> Result { 42 | self.receipt.verify(SIGN_ID)?; 43 | self.get_commit() 44 | } 45 | } 46 | 47 | pub fn sign(pass_str: impl AsRef<[u8]>, msg_str: impl AsRef<[u8]>) -> Result { 48 | let mut pass_hasher = Sha256::new(); 49 | pass_hasher.update(pass_str); 50 | let mut pass_hash = [0u8; 32]; 51 | pass_hash.copy_from_slice(&pass_hasher.finalize()); 52 | 53 | let mut msg_hasher = Sha256::new(); 54 | msg_hasher.update(msg_str); 55 | let mut msg_hash = [0u8; 32]; 56 | msg_hash.copy_from_slice(&msg_hasher.finalize()); 57 | 58 | let pass = Passphrase { pass: pass_hash }; 59 | let msg = Message { msg: msg_hash }; 60 | 61 | let params = SigningRequest { 62 | passphrase: pass, 63 | msg: msg, 64 | }; 65 | 66 | let mut prover = Prover::new(SIGN_ELF, SIGN_ID)?; 67 | let vec = to_vec(¶ms).unwrap(); 68 | prover.add_input_u32_slice(vec.as_slice()); 69 | let receipt = prover.run()?; 70 | Ok(SignatureWithReceipt { receipt }) 71 | } 72 | 73 | #[cfg(test)] 74 | mod tests { 75 | use log::LevelFilter; 76 | 77 | use super::*; 78 | 79 | #[ctor::ctor] 80 | fn init() { 81 | env_logger::builder().filter_level(LevelFilter::Info).init(); 82 | } 83 | 84 | #[test] 85 | fn protocol() { 86 | let pass_str = "passphr4ase"; 87 | let msg_str = "This message was signed by me"; 88 | let signing_receipt = sign(pass_str, msg_str); 89 | let signing_receipt = match signing_receipt { 90 | Ok(signing_receipt) => signing_receipt, 91 | Err(err) => panic!("Problem generating receipt: {:?}", err), 92 | }; 93 | match signing_receipt.verify() { 94 | Ok(_) => {} 95 | Err(err) => panic!("Problem verifying receipt: {:?}", err), 96 | }; 97 | 98 | let mut msg_hasher = Sha256::new(); 99 | msg_hasher.update(msg_str); 100 | let mut msg_hash = [0u8; 32]; 101 | msg_hash.copy_from_slice(&msg_hasher.finalize()); 102 | 103 | let message = signing_receipt.get_message(); 104 | let message = match message { 105 | Ok(message) => message, 106 | Err(err) => panic!("Problem getting message: {:?}", err), 107 | }; 108 | assert_eq!(msg_hash, message.msg); 109 | 110 | log::info!("msg: {:?}", &msg_str); 111 | log::info!("commit: {:?}", &message); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /voting-machine/core/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #![cfg_attr(not(test), no_std)] 16 | 17 | use risc0_zkp::core::sha::Digest; 18 | use serde::{Deserialize, Serialize}; 19 | 20 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 21 | pub struct VotingMachineState { 22 | pub polls_open: bool, 23 | pub voter_bitfield: u32, 24 | pub count: u32, 25 | } 26 | 27 | impl VotingMachineState { 28 | pub fn vote(&mut self, voter: u32, vote_yes: bool) -> bool { 29 | let mut vote_counted = false; 30 | let voter_mask = 1 << voter; 31 | if self.polls_open && 0 == self.voter_bitfield & voter_mask { 32 | self.voter_bitfield |= voter_mask; 33 | if vote_yes { 34 | self.count += 1; 35 | } 36 | vote_counted = true 37 | } 38 | vote_counted 39 | } 40 | } 41 | 42 | #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)] 43 | pub struct InitializeVotingMachineCommit { 44 | pub polls_open: bool, 45 | pub voter_bitfield: u32, 46 | pub state: Digest, 47 | } 48 | 49 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 50 | pub struct Ballot { 51 | pub voter: u32, 52 | pub vote_yes: bool, 53 | } 54 | 55 | #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)] 56 | pub struct SubmitBallotCommit { 57 | pub old_state: Digest, 58 | pub new_state: Digest, 59 | pub polls_open: bool, 60 | pub voter_bitfield: u32, 61 | pub voter: u32, 62 | pub vote_yes: bool, 63 | pub vote_counted: bool, 64 | } 65 | 66 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 67 | pub struct SubmitBallotParams { 68 | pub state: VotingMachineState, 69 | pub ballot: Ballot, 70 | } 71 | 72 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 73 | pub struct SubmitBallotResult { 74 | pub state: VotingMachineState, 75 | pub vote_counted: bool, 76 | pub vote_yes: bool, 77 | } 78 | 79 | impl SubmitBallotParams { 80 | pub fn new(state: VotingMachineState, ballot: Ballot) -> Self { 81 | SubmitBallotParams { 82 | state: state, 83 | ballot: ballot, 84 | } 85 | } 86 | 87 | pub fn process(&self) -> SubmitBallotResult { 88 | let mut state = self.state.clone(); 89 | let vote_counted = state.vote(self.ballot.voter, self.ballot.vote_yes); 90 | SubmitBallotResult { 91 | state: state, 92 | vote_counted: vote_counted, 93 | vote_yes: self.ballot.vote_yes, 94 | } 95 | } 96 | } 97 | 98 | #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)] 99 | pub struct FreezeVotingMachineCommit { 100 | pub old_state: Digest, 101 | pub new_state: Digest, 102 | pub polls_open: bool, 103 | pub voter_bitfield: u32, 104 | pub count: u32, 105 | } 106 | 107 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 108 | pub struct FreezeVotingMachineParams { 109 | pub state: VotingMachineState, 110 | } 111 | 112 | #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] 113 | pub struct FreezeVotingMachineResult { 114 | pub state: VotingMachineState, 115 | } 116 | 117 | impl FreezeVotingMachineParams { 118 | pub fn new(state: VotingMachineState) -> Self { 119 | FreezeVotingMachineParams { state: state } 120 | } 121 | 122 | pub fn process(&self) -> FreezeVotingMachineResult { 123 | let mut state = self.state.clone(); 124 | state.polls_open = false; 125 | FreezeVotingMachineResult { state: state } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /waldo/README.md: -------------------------------------------------------------------------------- 1 | # Where's Waldo 2 | 3 | [Where's Waldo] is a [favorite analogy] for zero-knowledge proofs. In particular, there is this 4 | visual that if you take a Where's Waldo image and cover it up with a big piece of cardboard with a 5 | small cutout that just shows Waldo, you can prove you _know_ where he is while keeping that location 6 | secret. 7 | 8 | [Where's Waldo]: https://en.wikipedia.org/wiki/Where%27s_Wally%3F 9 | [favorite analogy]: https://medium.com/swlh/a-zero-knowledge-proof-for-wheres-wally-930c21e55399 10 | 11 | But these days, why not implement a real zero-knowledge proof to show you know where Waldo is? 12 | 13 | This example implements a RISC0 zero-knowledge program which allows a prover to convince a verifier 14 | they know Waldo's location in a public Where's Waldo puzzle, without revealing Waldo's coordinates. 15 | 16 | ## Approach 17 | 18 | The approach for this example is similar to the analogy. It takes the full image and "cuts out" just 19 | Waldo. This cutting out operation takes place in the zkvm guest such that a commitment to the source 20 | image and the cut out image of Waldo can be revealed, without giving the verifier the coordinates. 21 | Key to this proof is ensuring that the cutout came from the expected source image, and not some 22 | unrelated picture that includes Waldo. 23 | 24 | ### Merkleization 25 | 26 | In the simplest approach, the guest program would simply hash the whole Where's Waldo image in 27 | memory, then perform the crop and mask operations to cut out Waldo on that image. It would 28 | commit the image hash and the cut out image to the journal. Unfortunately, hashing the whole 29 | image, which we expect to be rather large, is cost prohibitive in the guest. 30 | 31 | Because we only need access to a relatively small portion of the image to produce the cutout, a 32 | viable approach is to split the image into a vector of small image chunks and use a Merkle tree to 33 | commit to this vector. The zkVM guest can then ask the host for image chunks, and along with the 34 | chunk the host can provide a Merkle path that proves the chunk is part of the committed image. 35 | 36 | In the `waldo_core::merkle` module is implemented a wrapper on the `merkle_light` crate with support 37 | for using the SHA256 guest circuit, and providing a `VectorOracle` abstraction. In the 38 | `waldo_core::image` module is implemented a specific MerkleTree type for images, and an 39 | `ImageOracle` type which can be used in the guest for image operations. 40 | 41 | Similar Merkle tree abstractions can be used to, for example, ensure a secret word is part of a 42 | dictionary, a payment destination is not in a list of banned addresses, or that a user is in the 43 | set of authorized users. 44 | 45 | ### zkVM Communication Channels 46 | 47 | In the RISC0 zkVM system, the guest and host can communicate over using channels at runtime. 48 | These channels are currently used to implement the `env::read` and `env::commit` functions in the guest, 49 | and the developer can create new channels for their own needs. In this example, a channel is used to 50 | allow the guest to request chunks of the Where's Waldo image on demand as a part of the `MerkleTree` 51 | and `VectorOracle` types. Using these channels allows us to write more flexible code that is more 52 | readable and follows familiar paradigms. 53 | 54 | ### Image Manipulation 55 | 56 | In order to manipulate the image and cut-out Waldo, and in particular to crop and apply a mask, this 57 | example utilizes the popular `image` crate. This is enabled by implementing 58 | `image::GenericImageView` on `ImageOracle`. With that trait, many of the image operations provided 59 | in the `image` crate, and by [others], can be used on `ImageOracle` inside the guest. A similar 60 | approach could be used to produce a provable blur, image down-scaling, and more. 61 | 62 | [others]: https://docs.rs/imageproc/latest/imageproc/ 63 | 64 | ## Run this example 65 | 66 | First, make sure [rustup](https://rustup.rs) is installed. 67 | This project uses a [nightly](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) version of [Rust](https://doc.rust-lang.org/book/ch01-01-installation.html). 68 | The [`rust-toolchain`](rust-toolchain) file will be used by `cargo` to automatically install the correct version. 69 | 70 | To build and run this example, try using the following commands. 71 | 72 | ```bash 73 | # Prove that you know where Waldo is in waldo.webp 74 | cargo run --release --bin prove -- -i waldo.webp -x 1150 -y 291 -w 58 -h 70 -m waldo_mask.png 75 | 76 | # Verify that the prover actually found Waldo. 77 | cargo run --release --bin verify -- -i waldo.webp -r receipt.bin 78 | ``` 79 | -------------------------------------------------------------------------------- /wordle/host/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::io; 16 | 17 | use methods::{WORDLE_ELF, WORDLE_ID}; 18 | use risc0_zkvm::serde::to_vec; 19 | use risc0_zkvm::{Prover, Receipt}; 20 | use wordle_core::WORD_LENGTH; 21 | 22 | use crate::wordlist::words::pick_word; 23 | 24 | mod wordlist; 25 | 26 | // The "server" is an agent in the Wordle game that checks the player's guesses. 27 | struct Server<'a> { 28 | // The server chooses the secret word, and remembers it until the end of the game. It is private 29 | // because the player shouldn't know the word until the game is over. 30 | secret_word: &'a str, 31 | } 32 | 33 | impl Server<'_> { 34 | pub fn new() -> Self { 35 | Self { 36 | secret_word: pick_word(), 37 | } 38 | } 39 | 40 | pub fn get_secret_word_hash(&self) -> Vec { 41 | let receipt = self.check_round("_____"); 42 | let journal = receipt.journal; 43 | journal[..16].to_owned() 44 | } 45 | 46 | pub fn check_round(&self, guess_word: &str) -> Receipt { 47 | let mut prover = Prover::new(WORDLE_ELF, WORDLE_ID).expect("failed to construct prover"); 48 | 49 | prover.add_input_u32_slice(to_vec(self.secret_word).unwrap().as_slice()); 50 | prover.add_input_u32_slice(to_vec(&guess_word).unwrap().as_slice()); 51 | 52 | return prover.run().unwrap(); 53 | } 54 | } 55 | 56 | // The "player" is an agent in the Wordle game that tries to guess the server's secret word. 57 | struct Player { 58 | // The player remembers the hash of the secret word that the server commits to at the beginning 59 | // of the game. By comparing the hash after each guess, the player knows if the server cheated 60 | // by changing the word. 61 | pub hash: Vec, 62 | } 63 | 64 | impl Player { 65 | pub fn check_receipt(&self, receipt: Receipt) -> Vec { 66 | receipt 67 | .verify(WORDLE_ID) 68 | .expect("receipt verification failed"); 69 | 70 | let journal = receipt.journal; 71 | let hash = &journal[..16]; 72 | 73 | if hash != self.hash { 74 | panic!("The hash mismatched, so the server cheated!"); 75 | } 76 | 77 | let score = &journal[16..]; 78 | return score.to_owned(); 79 | } 80 | } 81 | 82 | fn read_stdin_guess() -> String { 83 | let mut guess = String::new(); 84 | loop { 85 | io::stdin().read_line(&mut guess).unwrap(); 86 | guess.pop(); // remove trailing newline 87 | 88 | if guess.chars().count() == WORD_LENGTH { 89 | break; 90 | } else { 91 | println!("Your guess must have 5 letters!"); 92 | guess.clear(); 93 | } 94 | } 95 | guess 96 | } 97 | 98 | fn print_wordle_feedback(guess_word: &str, score: &Vec) { 99 | for i in 0..WORD_LENGTH { 100 | match score[i] { 101 | 0 => print!("\x1b[41m"), // correct: green 102 | 1 => print!("\x1b[43m"), // present: yellow 103 | _ => print!("\x1b[40m"), // miss: black 104 | } 105 | print!("{:}", guess_word.chars().nth(i).unwrap()); 106 | } 107 | println!("\x1b[0m"); 108 | } 109 | 110 | fn game_is_won(score: Vec) -> bool { 111 | return score.iter().all(|x| *x == 0u32); 112 | } 113 | 114 | fn main() { 115 | println!("Welcome to fair wordle!"); 116 | 117 | let server = Server::new(); 118 | let player = Player { 119 | hash: server.get_secret_word_hash(), 120 | }; 121 | 122 | let mut game_won = false; 123 | 124 | for _ in 0..6 { 125 | let guess_word = read_stdin_guess(); 126 | let receipt = server.check_round(guess_word.as_str()); 127 | let score = player.check_receipt(receipt); 128 | print_wordle_feedback(guess_word.as_str(), &score); 129 | if game_is_won(score) { 130 | game_won = true; 131 | break; 132 | } 133 | } 134 | 135 | if game_won { 136 | println!("You won!"); 137 | } else { 138 | println!("Game over"); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /waldo/host/src/bin/verify.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::error::Error; 16 | use std::fs; 17 | use std::path::PathBuf; 18 | 19 | use clap::Parser; 20 | use image::io::Reader as ImageReader; 21 | use image::{GenericImageView, RgbImage}; 22 | use risc0_zkvm::{serde, Receipt}; 23 | use waldo_core::image::{ImageMerkleTree, IMAGE_CHUNK_SIZE}; 24 | use waldo_core::Journal; 25 | use waldo_methods::IMAGE_CROP_ID; 26 | 27 | #[derive(Parser, Debug)] 28 | #[clap(author, version, about, long_about = None)] 29 | struct Args { 30 | /// Input file path to the full Where's Waldo image. 31 | /// Used to verify that the Waldo in the receipt actually came from this image. 32 | #[clap(short, long, value_parser, value_hint = clap::ValueHint::FilePath)] 33 | image: PathBuf, 34 | 35 | /// Input file path to fetch the receipt. Note that the receipt contains the cutout of waldo. 36 | #[clap(short = 'r', long, value_parser, default_value = "./receipt.bin", value_hint = clap::ValueHint::FilePath)] 37 | receipt: PathBuf, 38 | 39 | /// Output file path to save the cutout image of Waldo extracted from the receipt. 40 | /// SAFETY: Make sure to visually inspect the cutout and verify it really is Waldo and not some barber pole! 41 | #[clap(short = 'o', long, value_parser, default_value = "./waldo_cutout.png", value_hint = clap::ValueHint::FilePath)] 42 | waldo: PathBuf, 43 | 44 | /// Flag to disable displaying the Waldo cutout in the terminal. 45 | #[clap(long)] 46 | no_display: bool, 47 | } 48 | 49 | fn main() -> Result<(), Box> { 50 | env_logger::init(); 51 | 52 | let args = Args::parse(); 53 | 54 | // Read the full Where's Waldo image from disk. 55 | let img = ImageReader::open(&args.image)?.decode()?; 56 | println!( 57 | "Read image at {} with size: {} x {}", 58 | &args.image.display(), 59 | img.width(), 60 | img.height() 61 | ); 62 | 63 | // Construct a Merkle tree from the Where's Waldo image. 64 | let img_merkle_tree = ImageMerkleTree::<{ IMAGE_CHUNK_SIZE }>::new(&img); 65 | println!( 66 | "Created Merkle tree from image with root {:?}", 67 | img_merkle_tree.root(), 68 | ); 69 | 70 | // Load and verify the receipt file. 71 | let receipt: Receipt = bincode::deserialize(&fs::read(&args.receipt)?)?; 72 | receipt.verify(IMAGE_CROP_ID)?; 73 | 74 | // Check consistency of the journal against the input Where's Waldo image. 75 | let journal: Journal = serde::from_slice(&receipt.journal)?; 76 | if &journal.root != &img_merkle_tree.root() { 77 | return Err(format!( 78 | "Image root in journal does not match the expected image: {:?} != {:?}", 79 | &journal.root, 80 | &img_merkle_tree.root(), 81 | ) 82 | .into()); 83 | } 84 | 85 | if journal.image_dimensions != img.dimensions() { 86 | return Err(format!( 87 | "Image dimensions in the journal do not match the expected image: {:?} != {:?}", 88 | journal.image_dimensions, 89 | img.dimensions(), 90 | ) 91 | .into()); 92 | } 93 | 94 | println!( 95 | "Verified receipt with {}x{} subimage", 96 | journal.subimage_dimensions.0, journal.subimage_dimensions.1 97 | ); 98 | 99 | let subimage = RgbImage::from_raw( 100 | journal.subimage_dimensions.0, 101 | journal.subimage_dimensions.1, 102 | journal.subimage, 103 | ) 104 | .ok_or("Failed to load the returned subimage bytes into an image")?; 105 | 106 | // Save the image to disk for the verifier to inspect. 107 | subimage.save(&args.waldo)?; 108 | println!("Saved Waldo cutout to {}", &args.waldo.display()); 109 | 110 | if args.no_display { 111 | println!( 112 | "IMPORTANT: Verify that the cutout in {} contains Waldo.", 113 | &args.waldo.display() 114 | ); 115 | } else { 116 | // Display the image in the terminal for them to see whether it's Waldo. 117 | let viuer_config = viuer::Config { 118 | absolute_offset: false, 119 | ..Default::default() 120 | }; 121 | viuer::print_from_file(&args.waldo, &viuer_config)?; 122 | println!("Prover knows where this cutout is in the given image."); 123 | println!("Do you recognize this Waldo?"); 124 | } 125 | 126 | Ok(()) 127 | } 128 | -------------------------------------------------------------------------------- /waldo/host/src/bin/prove.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::error::Error; 16 | use std::fs; 17 | use std::path::PathBuf; 18 | 19 | use clap::Parser; 20 | use image::io::Reader as ImageReader; 21 | use image::GenericImageView; 22 | use risc0_zkvm::{serde, Prover, ProverOpts}; 23 | use waldo_core::image::{ImageMask, ImageMerkleTree, IMAGE_CHUNK_SIZE}; 24 | use waldo_core::merkle::VECTOR_ORACLE_CHANNEL; 25 | use waldo_core::PrivateInput; 26 | use waldo_methods::{IMAGE_CROP_ELF, IMAGE_CROP_ID}; 27 | 28 | #[derive(Parser, Debug)] 29 | #[clap(author, version, about, long_about = None)] 30 | struct Args { 31 | /// Input file path to the full Where's Waldo image. 32 | #[clap(short = 'i', long, value_parser, value_hint = clap::ValueHint::FilePath)] 33 | image: PathBuf, 34 | 35 | /// X coordinate, in pixels from the top-left corner, of Waldo. 36 | #[clap(short = 'x', long, value_parser)] 37 | waldo_x: u32, 38 | 39 | /// Y coordinate, in pixels from the top-left corner, of Waldo. 40 | #[clap(short = 'y', long, value_parser)] 41 | waldo_y: u32, 42 | 43 | /// Width, in pixels, of the cutout for Waldo. 44 | #[clap(short = 'w', long, value_parser)] 45 | waldo_width: u32, 46 | 47 | /// Height, in pixels, of the cutout for Waldo. 48 | #[clap(short = 'h', long, value_parser)] 49 | waldo_height: u32, 50 | 51 | /// Optional input file path to an image mask to apply to Waldo. 52 | /// Grayscale pixel values will be subtracted from the cropped image of Waldo such that a black 53 | /// pixel in the mask will result in the cooresponding image pixel being blacked out. 54 | /// Must be the same dimensions, in pixels, as the cut out x and y. 55 | #[clap(short = 'm', long, value_parser, value_hint = clap::ValueHint::FilePath)] 56 | mask: Option, 57 | 58 | /// Output file path to save the receipt. Note that the receipt contains the cutout of waldo. 59 | #[clap(short = 'r', long, value_parser, default_value = "./receipt.bin", value_hint = clap::ValueHint::FilePath)] 60 | receipt: PathBuf, 61 | } 62 | 63 | fn main() -> Result<(), Box> { 64 | env_logger::init(); 65 | 66 | let args = Args::parse(); 67 | 68 | // Read the image from disk. 69 | let img = ImageReader::open(&args.image)?.decode()?; 70 | println!( 71 | "Read image at {} with size: {} x {}", 72 | &args.image.display(), 73 | img.width(), 74 | img.height() 75 | ); 76 | 77 | let crop_location = (args.waldo_x, args.waldo_y); 78 | let crop_dimensions = (args.waldo_width, args.waldo_height); 79 | 80 | // Read the image mask from disk, if provided. 81 | let mask = args.mask.map_or(Ok::<_, Box>(None), |path| { 82 | // Read the image mask from disk. Reads any format and color image. 83 | let mask: ImageMask = ImageReader::open(&path)?.decode()?.into(); 84 | if mask.dimensions() != crop_dimensions { 85 | return Err(format!( 86 | "Mask dimensions do not match specified height and width for Waldo: {:?} != {:?}", 87 | mask.dimensions(), 88 | crop_dimensions 89 | ) 90 | .into()); 91 | } 92 | println!("Read image mask at {}", &path.display(),); 93 | 94 | Ok(Some(mask.into_raw())) 95 | })?; 96 | 97 | // Construct a Merkle tree from the full Where's Waldo image. 98 | let img_merkle_tree = ImageMerkleTree::<{ IMAGE_CHUNK_SIZE }>::new(&img); 99 | println!( 100 | "Created Merkle tree from image with root {:?}", 101 | img_merkle_tree.root(), 102 | ); 103 | 104 | // Make the prover, loading the image crop method binary and method ID, and registering a 105 | // send_recv callback to communicate vector oracle data from the Merkle tree. 106 | let prover_opts = ProverOpts::default().with_sendrecv_callback( 107 | VECTOR_ORACLE_CHANNEL, 108 | img_merkle_tree.vector_oracle_callback(), 109 | ); 110 | let mut prover = Prover::new_with_opts(IMAGE_CROP_ELF, IMAGE_CROP_ID, prover_opts)?; 111 | 112 | // Give the private input to the guest, including Waldo's location. 113 | let input = PrivateInput { 114 | root: img_merkle_tree.root(), 115 | image_dimensions: img.dimensions(), 116 | mask, 117 | crop_location, 118 | crop_dimensions, 119 | }; 120 | prover.add_input_u32_slice(&serde::to_vec(&input)?); 121 | 122 | // Run prover and generate receipt 123 | println!( 124 | "Running the prover to cut out Waldo at {:?} with dimensions {:?}", 125 | input.crop_location, input.crop_dimensions, 126 | ); 127 | let receipt = prover.run()?; 128 | 129 | // Save the receipt to disk so it can be sent to the verifier. 130 | fs::write(&args.receipt, bincode::serialize(&receipt)?)?; 131 | 132 | println!("Success! Saved the receipt to {}", &args.receipt.display()); 133 | 134 | Ok(()) 135 | } 136 | -------------------------------------------------------------------------------- /voting-machine/host/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use risc0_zkvm::serde::{from_slice, to_vec}; 16 | use risc0_zkvm::{Prover, Receipt, Result}; 17 | use voting_machine_core::{ 18 | Ballot, FreezeVotingMachineCommit, FreezeVotingMachineParams, FreezeVotingMachineResult, 19 | InitializeVotingMachineCommit, SubmitBallotCommit, SubmitBallotParams, SubmitBallotResult, 20 | VotingMachineState, 21 | }; 22 | use voting_machine_methods::{FREEZE_ELF, FREEZE_ID, INIT_ELF, INIT_ID, SUBMIT_ELF, SUBMIT_ID}; 23 | 24 | pub struct InitMessage { 25 | receipt: Receipt, 26 | } 27 | 28 | impl InitMessage { 29 | pub fn get_state(&self) -> Result { 30 | Ok(from_slice(&self.receipt.journal).unwrap()) 31 | } 32 | 33 | pub fn verify_and_get_commit(&self) -> Result { 34 | self.receipt.verify(INIT_ID)?; 35 | self.get_state() 36 | } 37 | } 38 | 39 | pub struct SubmitBallotMessage { 40 | receipt: Receipt, 41 | } 42 | 43 | impl SubmitBallotMessage { 44 | pub fn get_commit(&self) -> Result { 45 | Ok(from_slice(&self.receipt.journal).unwrap()) 46 | } 47 | 48 | pub fn verify_and_get_commit(&self) -> Result { 49 | self.receipt.verify(SUBMIT_ID)?; 50 | self.get_commit() 51 | } 52 | } 53 | 54 | pub struct FreezeStationMessage { 55 | receipt: Receipt, 56 | } 57 | 58 | impl FreezeStationMessage { 59 | pub fn get_commit(&self) -> Result { 60 | Ok(from_slice(&self.receipt.journal).unwrap()) 61 | } 62 | 63 | pub fn verify_and_get_commit(&self) -> Result { 64 | self.receipt.verify(FREEZE_ID)?; 65 | self.get_commit() 66 | } 67 | } 68 | 69 | #[derive(Debug)] 70 | pub struct PollingStation { 71 | state: VotingMachineState, 72 | } 73 | 74 | impl PollingStation { 75 | pub fn new(state: VotingMachineState) -> Self { 76 | PollingStation { state } 77 | } 78 | 79 | pub fn init(&self) -> Result { 80 | log::info!("init"); 81 | let mut prover = Prover::new(INIT_ELF, INIT_ID)?; 82 | let vec = to_vec(&self.state).unwrap(); 83 | prover.add_input_u32_slice(vec.as_slice()); 84 | let receipt = prover.run()?; 85 | Ok(InitMessage { receipt }) 86 | } 87 | 88 | pub fn submit(&mut self, ballot: &Ballot) -> Result { 89 | log::info!("submit: {:?}", ballot); 90 | let params = SubmitBallotParams::new(self.state.clone(), ballot.clone()); 91 | let mut prover = Prover::new(SUBMIT_ELF, SUBMIT_ID)?; 92 | let vec = to_vec(¶ms).unwrap(); 93 | prover.add_input_u32_slice(vec.as_slice()); 94 | let receipt = prover.run()?; 95 | let vec = prover.get_output_u32_vec()?; 96 | log::info!("{:?}", vec); 97 | let result = from_slice::(&vec); 98 | log::info!("{:?}", result); 99 | self.state = result.unwrap().state.clone(); 100 | Ok(SubmitBallotMessage { receipt }) 101 | } 102 | 103 | pub fn freeze(&mut self) -> Result { 104 | log::info!("freeze"); 105 | let params = FreezeVotingMachineParams::new(self.state.clone()); 106 | let mut prover = Prover::new(FREEZE_ELF, FREEZE_ID)?; 107 | let vec = to_vec(¶ms).unwrap(); 108 | prover.add_input_u32_slice(vec.as_slice()); 109 | let receipt = prover.run()?; 110 | let slice = prover.get_output_u32_vec()?; 111 | let result = from_slice::(&slice).unwrap(); 112 | self.state = result.state.clone(); 113 | Ok(FreezeStationMessage { receipt }) 114 | } 115 | } 116 | 117 | #[cfg(test)] 118 | mod tests { 119 | use log::LevelFilter; 120 | 121 | use super::*; 122 | 123 | #[ctor::ctor] 124 | fn init() { 125 | env_logger::builder().filter_level(LevelFilter::Info).init(); 126 | } 127 | 128 | #[test] 129 | fn protocol() { 130 | let polling_station_state = VotingMachineState { 131 | polls_open: true, 132 | voter_bitfield: 0, 133 | count: 0, 134 | }; 135 | 136 | let mut polling_station = PollingStation::new(polling_station_state); 137 | 138 | let ballot1 = Ballot { 139 | voter: 0, 140 | vote_yes: false, 141 | }; 142 | let ballot2 = Ballot { 143 | voter: 1, 144 | vote_yes: true, 145 | }; 146 | let ballot3 = Ballot { 147 | voter: 2, 148 | vote_yes: true, 149 | }; 150 | let ballot4 = Ballot { 151 | voter: 1, 152 | vote_yes: false, 153 | }; 154 | let ballot5 = Ballot { 155 | voter: 3, 156 | vote_yes: false, 157 | }; 158 | let ballot6 = Ballot { 159 | voter: 4, 160 | vote_yes: true, 161 | }; 162 | 163 | let init_msg = polling_station.init().unwrap(); 164 | let ballot_msg1 = polling_station.submit(&ballot1).unwrap(); 165 | let ballot_msg2 = polling_station.submit(&ballot2).unwrap(); 166 | let ballot_msg3 = polling_station.submit(&ballot3).unwrap(); 167 | let ballot_msg4 = polling_station.submit(&ballot4).unwrap(); 168 | let ballot_msg5 = polling_station.submit(&ballot5).unwrap(); 169 | let close_msg = polling_station.freeze().unwrap(); 170 | let ballot_msg6 = polling_station.submit(&ballot6).unwrap(); 171 | 172 | assert_eq!(polling_station.state.count, 2); 173 | 174 | let init_state = init_msg.verify_and_get_commit(); 175 | let ballot_commit1 = ballot_msg1.verify_and_get_commit(); 176 | let ballot_commit2 = ballot_msg2.verify_and_get_commit(); 177 | let ballot_commit3 = ballot_msg3.verify_and_get_commit(); 178 | let ballot_commit4 = ballot_msg4.verify_and_get_commit(); 179 | let ballot_commit5 = ballot_msg5.verify_and_get_commit(); 180 | let close_state = close_msg.verify_and_get_commit(); 181 | let ballot_commit6 = ballot_msg6.verify_and_get_commit(); 182 | 183 | log::info!("initial commit: {:?}", init_state); 184 | log::info!("ballot 1: {:?}", ballot1); 185 | log::info!("ballot 1 commit: {:?}", ballot_commit1); 186 | log::info!("ballot 2: {:?}", ballot2); 187 | log::info!("ballot 2 commit: {:?}", ballot_commit2); 188 | log::info!("ballot 3: {:?}", ballot3); 189 | log::info!("ballot 3 commit: {:?}", ballot_commit3); 190 | log::info!("ballot 4: {:?}", ballot4); 191 | log::info!("ballot 4 commit: {:?}", ballot_commit4); 192 | log::info!("ballot 5: {:?}", ballot5); 193 | log::info!("ballot 5 commit: {:?}", ballot_commit5); 194 | log::info!("freeze commit: {:?}", close_state); 195 | log::info!("ballot 6: {:?}", ballot6); 196 | log::info!("ballot 6 commit: {:?}", ballot_commit6); 197 | log::info!("Final vote count: {:?}", polling_station.state.count); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /waldo/core/src/image.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use image::{DynamicImage, GrayImage, Rgb, RgbImage}; 16 | use serde::{Deserialize, Serialize}; 17 | 18 | use crate::merkle::{MerkleTree, Node}; 19 | 20 | /// Recommended default chunk size to use in the ImageMerkleTree and ImageOracle. 21 | pub const IMAGE_CHUNK_SIZE: u32 = 8; 22 | 23 | // Chunk struct used internally to wrap the raw bytes and include a width value. Important for 24 | // chunks at the edge of the image which may have a width or height of less than N. 25 | #[derive(Debug, Clone, Serialize, Deserialize, Hashable)] 26 | struct ImageChunk { 27 | data: Vec, 28 | width: u32, 29 | height: u32, 30 | } 31 | 32 | impl From for ImageChunk { 33 | fn from(image: RgbImage) -> Self { 34 | Self { 35 | width: image.width(), 36 | height: image.height(), 37 | data: image.into_raw(), 38 | } 39 | } 40 | } 41 | 42 | impl Into for ImageChunk { 43 | fn into(self: Self) -> RgbImage { 44 | RgbImage::from_raw(self.width, self.height, self.data).unwrap() 45 | } 46 | } 47 | 48 | /// Mask image that can be applied to an image to include or exclude pixels. 49 | /// Pixel values are treated as booleans controlling whether or not the corresponding pixel from 50 | /// the base image is included. A pixel value of 0 results in the corresponding pixel being masked 51 | /// out. 52 | pub struct ImageMask(pub GrayImage); 53 | 54 | impl ImageMask { 55 | /// Apply the mask to the given image, masking out any pixels in image where the mask contains 56 | /// a 0 value. Any mask pixel value of greater than zero passes the base pixel through. 57 | pub fn apply(&self, mut image: RgbImage) -> RgbImage { 58 | assert_eq!(image.dimensions(), self.0.dimensions()); 59 | 60 | let zero_pixel: Rgb = [0, 0, 0].into(); 61 | for x in 0..image.width() { 62 | for y in 0..image.height() { 63 | let m = self.0.get_pixel(x, y); 64 | if m.0[0] == 0 { 65 | image.put_pixel(x, y, zero_pixel); 66 | } 67 | } 68 | } 69 | image 70 | } 71 | 72 | pub fn into_raw(self) -> Vec { 73 | self.0.into_raw() 74 | } 75 | 76 | pub fn dimensions(&self) -> (u32, u32) { 77 | self.0.dimensions() 78 | } 79 | 80 | pub fn from_raw(width: u32, height: u32, data: Vec) -> Option { 81 | GrayImage::from_raw(width, height, data).map(|img| img.into()) 82 | } 83 | } 84 | 85 | impl From for ImageMask { 86 | fn from(image: DynamicImage) -> Self { 87 | Self(image.into_luma8()) 88 | } 89 | } 90 | 91 | impl From for ImageMask { 92 | fn from(image: GrayImage) -> Self { 93 | Self(image) 94 | } 95 | } 96 | 97 | /// ImageMerkleTree is a merklization of an image, constructed with leaf elements of NxN 98 | /// square chunks, traversed in left-to-right and top-to-bottom order. 99 | /// 100 | /// Chunks on the right and bottom boundaries will be incomplete if the width or height cannot be 101 | /// divided by N. At the right edge, the width of the chunks will be truncated and on the bottom 102 | /// edge the height will be truncated. 103 | pub struct ImageMerkleTree(MerkleTree); 104 | 105 | impl ImageMerkleTree { 106 | pub fn new(image: &DynamicImage) -> Self { 107 | let chunks: Vec = { 108 | (0..image.height()) 109 | .step_by(usize::try_from(N).unwrap()) 110 | .map(|y| { 111 | (0..image.width()) 112 | .step_by(usize::try_from(N).unwrap()) 113 | .map(move |x| image.crop_imm(x, y, N, N).into_rgb8().into()) 114 | }) 115 | .flatten() 116 | .collect() 117 | }; 118 | 119 | Self(MerkleTree::new(chunks)) 120 | } 121 | 122 | pub fn root(&self) -> Node { 123 | self.0.root() 124 | } 125 | 126 | #[cfg(not(target_os = "zkvm"))] 127 | pub fn vector_oracle_callback<'a>(&'a self) -> impl Fn(u32, &[u8]) -> Vec + 'a { 128 | self.0.vector_oracle_callback() 129 | } 130 | } 131 | 132 | #[cfg(target_os = "zkvm")] 133 | mod zkvm { 134 | use divrem::{DivCeil, DivRem}; 135 | use elsa::FrozenBTreeMap; 136 | use image::{GenericImageView, Rgb, RgbImage}; 137 | 138 | use super::ImageChunk; 139 | use crate::merkle::{Node, VectorOracle}; 140 | 141 | /// ImageOracle provides verified access to an image held by the host and implements 142 | /// image::GenericImageView so that functions from the image crate, and those built against 143 | /// it's API, can be applied to the ImageOracle. 144 | pub struct ImageOracle { 145 | chunks: VectorOracle, 146 | 147 | // Width and height of the image in pixels. 148 | width: u32, 149 | height: u32, 150 | 151 | // Fields used internally for precomputation and caching. 152 | width_chunks: u32, 153 | cache: FrozenBTreeMap<(u32, u32), Box>, 154 | } 155 | 156 | impl ImageOracle { 157 | pub fn new(root: Node, width: u32, height: u32) -> Self { 158 | Self { 159 | chunks: VectorOracle::new(root), 160 | width, 161 | height, 162 | width_chunks: DivCeil::div_ceil(width, N), 163 | cache: Default::default(), 164 | } 165 | } 166 | 167 | /// Memoized method for getting chunks of the image. Inputs x and y are chunk coordinates. 168 | fn get_chunk(&self, x: u32, y: u32) -> &RgbImage { 169 | // Check that the given x if within the bounds of the width. No need to check y since 170 | // if y is out of bounds the VectorOrcacle query will be out of bounds. 171 | match self.cache.get(&(x, y)) { 172 | Some(chunk) => chunk, 173 | None => { 174 | assert!(x < self.width_chunks); 175 | 176 | let chunk = self 177 | .chunks 178 | .get(usize::try_from(y * self.width_chunks + x).unwrap()); 179 | self.cache 180 | .insert((x, y), RgbImage::from(chunk.into()).into()); 181 | self.cache.get(&(x, y)).unwrap() 182 | } 183 | } 184 | } 185 | 186 | pub fn root(&self) -> &Node { 187 | self.chunks.root() 188 | } 189 | } 190 | 191 | impl GenericImageView for ImageOracle { 192 | type Pixel = Rgb; 193 | 194 | fn dimensions(&self) -> (u32, u32) { 195 | (self.width, self.height) 196 | } 197 | 198 | fn bounds(&self) -> (u32, u32, u32, u32) { 199 | (0, 0, self.width, self.height) 200 | } 201 | 202 | #[inline(always)] 203 | fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel { 204 | assert!(self.in_bounds(x, y)); 205 | 206 | // Calculate split x and y into the chunk selector portion and offset. 207 | let (x_chunk, x_offset) = DivRem::div_rem(x, N); 208 | let (y_chunk, y_offset) = DivRem::div_rem(y, N); 209 | 210 | let chunk = &self.get_chunk(x_chunk, y_chunk); 211 | *chunk.get_pixel(x_offset, y_offset) 212 | } 213 | } 214 | } 215 | 216 | #[cfg(target_os = "zkvm")] 217 | pub use crate::image::zkvm::*; 218 | -------------------------------------------------------------------------------- /wordle/host/src/wordlist.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | pub mod words { 16 | 17 | use rand::seq::SliceRandom; 18 | 19 | pub static WORDS: [&str; 775] = [ 20 | "abate", "abbey", "abhor", "abide", "abort", "abuse", "abyss", "acorn", "actor", "acute", 21 | "adage", "adapt", "adept", "admit", "adopt", "adore", "adorn", "affix", "again", "agile", 22 | "aging", "agony", "agree", "aisle", "alarm", "alert", "alias", "alibi", "alien", "align", 23 | "alike", "alive", "allay", "alley", "allot", "allow", "alloy", "aloft", "aloud", "altar", 24 | "alter", "amass", "amaze", "amber", "amend", "ample", "amuse", "anger", "angry", "ankle", 25 | "annex", "annoy", "anvil", "apart", "apply", "april", "argue", "arise", "armed", "armor", 26 | "array", "arson", "aside", "aspen", "asset", "atlas", "attic", "aural", "avail", "avert", 27 | "avoid", "await", "awake", "award", "aware", "awash", "awful", "basic", "basis", "bathe", 28 | "beach", "beard", "begin", "below", "berth", "beset", "binge", "birth", "black", "blame", 29 | "blank", "blaze", "bleak", "blend", "bless", "blind", "blink", "bliss", "blood", "bloom", 30 | "blunt", "blush", "board", "boast", "boost", "booze", "bored", "bosom", "bosom", "bough", 31 | "bound", "bowel", "brace", "brain", "brake", "brand", "brash", "brass", "brave", "brawn", 32 | "bread", "break", "breed", "bride", "brick", "bride", "brief", "bring", "brisk", "broad", 33 | "brook", "brunt", "brush", "brute", "build", "bully", "bunch", "burst", "cabin", "camel", 34 | "canal", "carry", "catch", "cause", "cease", "chair", "chant", "chaos", "charm", "chart", 35 | "chase", "chasm", "cheap", "cheat", "cheek", "cheer", "chest", "chief", "child", "chill", 36 | "choke", "chore", "civic", "civil", "claim", "clash", "class", "clean", "clear", "clerk", 37 | "click", "cliff", "climb", "cling", "cloak", "close", "cloth", "cloud", "coach", "coast", 38 | "color", "comet", "cough", "count", "court", "crack", "craft", "crash", "crawl", "craze", 39 | "crazy", "creed", "creek", "creep", "crest", "crime", "crisp", "crock", "crone", "crony", 40 | "cross", "crowd", "crown", "crude", "cruel", "crumb", "crush", "crust", "cubic", "curio", 41 | "curly", "curse", "cycle", "daily", "cairy", "daunt", "death", "debit", "decay", "defer", 42 | "deity", "delay", "delve", "dense", "depot", "depth", "detox", "devil", "digit", "dirty", 43 | "ditch", "dizzy", "doing", "doubt", "dozen", "draft", "drain", "dread", "dream", "drift", 44 | "drill", "drink", "drive", "droop", "drown", "drunk", "dummy", "dwell", "eager", "early", 45 | "earth", "edict", "elder", "elect", "elite", "elude", "empty", "enact", "endow", "enemy", 46 | "enjoy", "enter", "epoch", "equal", "equip", "erase", "erect", "erode", "error", "erupt", 47 | "ethic", "ethos", "event", "every", "evoke", "exact", "exalt", "excel", "exert", "exile", 48 | "exist", "expel", "extra", "faint", "faith", "false", "famed", "fatal", "fatty", "fault", 49 | "favor", "feast", "fetch", "fever", "fiber", "fiend", "fight", "filth", "final", "first", 50 | "fixed", "flame", "flame", "flesh", "flick", "fling", "flirt", "float", "flock", "flood", 51 | "flora", "flour", "fluid", "fluke", "flunk", "flush", "focus", "folly", "foray", "force", 52 | "found", "frail", "frame", "frank", "fresh", "front", "frown", "funny", "fussy", "fuzzy", 53 | "gamut", "gauge", "glare", "gleam", "globe", "glory", "goods", "goody", "goose", "gourd", 54 | "grace", "grade", "graft", "grain", "grant", "grasp", "grass", "grave", "great", "greed", 55 | "greet", "grief", "grind", "gripe", "groan", "grope", "gross", "grove", "growl", "grown", 56 | "guess", "guilt", "gusto", "habit", "happy", "harsh", "haste", "hasty", "hatch", "haunt", 57 | "heave", "heavy", "hence", "hinge", "hoard", "hoist", "honor", "horse", "hotly", "house", 58 | "hover", "human", "humid", "hunch", "hurry", "ideal", "idiot", "imply", "incur", "index", 59 | "inert", "infer", "inlet", "inner", "irony", "issue", "ivory", "jewel", "joint", "jolly", 60 | "judge", "kneel", "labor", "lance", "lapse", "large", "larva", "later", "laugh", "layer", 61 | "learn", "least", "leave", "leech", "lefty", "legal", "level", "lever", "light", "linen", 62 | "liver", "local", "lofty", "logic", "loose", "lower", "loyal", "lunar", "lunch", "lyric", 63 | "major", "maple", "marry", "match", "maxim", "maybe", "mayor", "means", "mercy", "merge", 64 | "merry", "mimic", "minor", "moist", "money", "month", "mount", "mouth", "muddy", "mummy", 65 | "music", "naked", "nasty", "nerve", "never", "niece", "night", "noble", "noise", "novel", 66 | "nudge", "occur", "ocean", "offer", "often", "opium", "orbit", "order", "organ", "other", 67 | "outer", "overt", "oxide", "patch", "peace", "peril", "petal", "petty", "phase", "piece", 68 | "piety", "pilot", "pinch", "pious", "pique", "place", "plain", "plane", "plant", "plate", 69 | "plead", "pluck", "plumb", "plump", "point", "pound", "power", "prawn", "press", "prick", 70 | "prime", "prior", "prize", "probe", "prone", "proof", "prose", "proud", "prove", "pulse", 71 | "pupil", "puppy", "quail", "quake", "queer", "quell", "quest", "quick", "quiet", "quite", 72 | "quota", "quote", "rainy", "raise", "range", "rapid", "ratio", "reach", "react", "ready", 73 | "realm", "rebel", "recur", "refer", "reign", "relax", "relay", "relic", "remit", "renew", 74 | "repel", "reply", "rhyme", "right", "rigid", "rigor", "risky", "rival", "river", "rough", 75 | "round", "rouse", "royal", "ruler", "rumor", "rural", "rusty", "sadly", "saint", "scale", 76 | "scare", "scary", "scene", "scent", "scope", "score", "scorn", "screw", "scrub", "seize", 77 | "sense", "serve", "sever", "sewer", "shade", "shaft", "shake", "shame", "shape", "share", 78 | "shark", "sharp", "shear", "sheer", "shelf", "shell", "shift", "shine", "shiny", "shore", 79 | "short", "shout", "shove", "sight", "silly", "skill", "slack", "slant", "slave", "sleep", 80 | "slide", "smack", "small", "smart", "smear", "smell", "smile", "snare", "sneak", "sneer", 81 | "sober", "solar", "solid", "solve", "sorry", "sound", "space", "spare", "speak", "speck", 82 | "spell", "spend", "spice", "spill", "spine", "spite", "split", "spoil", "spook", "sport", 83 | "spurt", "stain", "stair", "stake", "stale", "stand", "stare", "start", "state", "steal", 84 | "steam", "steel", "steep", "steer", "stern", "stick", "stiff", "still", "sting", "stink", 85 | "stock", "stoop", "store", "storm", "stout", "straw", "strip", "stuff", "stump", "suave", 86 | "suite", "sunny", "swarm", "swear", "sweat", "sweep", "swell", "swift", "swing", "swirl", 87 | "swish", "table", "tacit", "tacky", "taste", "tasty", "taunt", "tease", "tempt", "tense", 88 | "terms", "thank", "thick", "thief", "thing", "think", "third", "throb", "throw", "thumb", 89 | "tight", "timid", "tired", "token", "tooth", "total", "tough", "toxic", "trace", "track", 90 | "trade", "train", "trait", "tramp", "trash", "tread", "treat", "trend", "trial", "tribe", 91 | "troop", "truly", "trunk", "trust", "truth", "twice", "twist", "ulcer", "uncle", "unify", 92 | "union", "unite", "unity", "upper", "upset", "urban", "usage", "usher", "usual", "utter", 93 | "vague", "valid", "value", "vapor", "verge", "vigor", "virus", "visit", "vista", "vital", 94 | "vivid", "vogue", "voice", "vouch", "wages", "waste", "watch", "water", "weary", "weave", 95 | "wedge", "weigh", "weird", "wheel", "whole", "whore", "widen", "width", "witch", "witty", 96 | "world", "worry", "worse", "worst", "worth", "wound", "wrath", "wreck", "wring", "write", 97 | "wrong", "yearn", "yield", "young", "youth", 98 | ]; 99 | 100 | pub fn pick_word() -> &'static str { 101 | return WORDS.choose(&mut rand::thread_rng()).unwrap(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /waldo/core/src/merkle.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2023 RISC Zero, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | use std::cmp::Ordering; 16 | use std::hash::Hasher; 17 | use std::marker::PhantomData; 18 | use std::ops::Deref; 19 | 20 | use bytemuck::{Pod, Zeroable}; 21 | use merkle_light::hash::{Algorithm, Hashable}; 22 | use merkle_light::{merkle, proof}; 23 | use risc0_zkp::core::sha::{Digest, Sha}; 24 | #[cfg(target_os = "zkvm")] 25 | use risc0_zkvm::guest; 26 | use risc0_zkvm::sha::sha; 27 | use serde::{Deserialize, Serialize}; 28 | 29 | /// RISC0 channel identifier for providing oracle access to a vector to the guest from the host. 30 | pub const VECTOR_ORACLE_CHANNEL: u32 = 0x09ac1e00; 31 | 32 | /// Merkle tree for use as a vector commitment over elements of the specified type. 33 | /// 34 | /// MerkleTree is a wrapper around the `merkle_light::merkle::MerkleTree`, created to integrate 35 | /// with the RISC0 SHA256 coprocessor, functionality to act as a vector oracle for the for the 36 | /// guest, and some convinience functions. 37 | pub struct MerkleTree 38 | where 39 | Element: Hashable, 40 | { 41 | tree: merkle::MerkleTree, 42 | elements: Vec, 43 | } 44 | 45 | impl MerkleTree 46 | where 47 | Element: Hashable, 48 | { 49 | pub fn new(elements: Vec) -> Self { 50 | Self { 51 | tree: merkle::MerkleTree::<_, ShaHasher>::from_data(elements.iter()), 52 | elements, 53 | } 54 | } 55 | 56 | pub fn elements(&self) -> &[Element] { 57 | &self.elements 58 | } 59 | 60 | pub fn prove(&self, i: usize) -> Proof { 61 | self.tree.gen_proof(i).into() 62 | } 63 | } 64 | 65 | #[cfg(not(target_os = "zkvm"))] 66 | impl MerkleTree 67 | where 68 | Element: Hashable + Serialize, 69 | { 70 | pub fn vector_oracle_callback<'a>(&'a self) -> impl Fn(u32, &[u8]) -> Vec + 'a { 71 | |channel_id, data| { 72 | // Callback function must only be registered as a callback for the VECTOR_ORACLE_CHANNEL. 73 | assert_eq!(channel_id, VECTOR_ORACLE_CHANNEL); 74 | // TODO: Using bincode here, but it would likely be better on the guest side to use the 75 | // risc0 zeroio or serde crates. I should try to use one of those (again). 76 | let index: usize = bincode::deserialize::(data) 77 | .unwrap() 78 | .try_into() 79 | .unwrap(); 80 | 81 | let value = &self.elements()[index]; 82 | let proof = self.prove(index); 83 | 84 | assert!(proof.verify(&self.root(), &value)); 85 | bincode::serialize(&(value, proof)).unwrap() 86 | } 87 | } 88 | } 89 | 90 | // Implement Deref so that all the methods on the wrapped type are accessible. 91 | impl Deref for MerkleTree 92 | where 93 | Element: Hashable, 94 | { 95 | type Target = merkle::MerkleTree; 96 | 97 | fn deref(&self) -> &Self::Target { 98 | &self.tree 99 | } 100 | } 101 | 102 | /// Wrapper for the `merkle_light` inclusion proof. Includes an improved API for verifying that a 103 | /// proof supports serialization and references an expected element and position. 104 | #[derive(Debug, Serialize, Deserialize)] 105 | #[serde(from = "(Vec, Vec)", into = "(Vec, Vec)")] 106 | pub struct Proof 107 | where 108 | Element: Hashable, 109 | { 110 | inner: proof::Proof, 111 | phantom_elem: PhantomData, 112 | } 113 | 114 | impl Proof 115 | where 116 | Element: Hashable, 117 | { 118 | /// Verify that the proof commits to the inclusion of the given element in a Merkle tree with 119 | /// the given root. 120 | pub fn verify(&self, root: &Node, element: &Element) -> bool { 121 | // Check that the root of the proof matches the provided root. 122 | match &self.verified_root(element) { 123 | Some(ref verified_root) => verified_root == root, 124 | None => false, 125 | } 126 | } 127 | 128 | /// Verify that the proof commits to the element in _some_ Merkle tree and return the 129 | /// calculated Merkle root. 130 | pub fn verified_root(&self, element: &Element) -> Option { 131 | // Check that the path from the leaf to the root is consistent. 132 | if !self.inner.validate::() { 133 | return None; 134 | } 135 | 136 | // Check the element hashes to the leaf in the proof. 137 | let algorithm = &mut ShaHasher::default(); 138 | element.hash(algorithm); 139 | let elem_hash = algorithm.hash(); 140 | 141 | // Hash the element to get the leaf, and check that it matches. 142 | algorithm.reset(); 143 | if algorithm.leaf(elem_hash) != self.inner.item() { 144 | return None; 145 | } 146 | 147 | Some(self.root()) 148 | } 149 | 150 | /// Compute the vector index of the proven element. 151 | pub fn index(&self) -> usize { 152 | self.inner 153 | .path() 154 | .iter() 155 | .rfold(0, |index, bit| (index << 1) + (!*bit as usize)) 156 | } 157 | } 158 | 159 | impl Clone for Proof 160 | where 161 | Element: Hashable, 162 | { 163 | fn clone(&self) -> Self { 164 | Self { 165 | inner: self.inner.clone(), 166 | phantom_elem: PhantomData, 167 | } 168 | } 169 | } 170 | 171 | impl Deref for Proof 172 | where 173 | Element: Hashable, 174 | { 175 | type Target = proof::Proof; 176 | 177 | fn deref(&self) -> &Self::Target { 178 | &self.inner 179 | } 180 | } 181 | 182 | impl From> for Proof 183 | where 184 | Element: Hashable, 185 | { 186 | fn from(inner: proof::Proof) -> Self { 187 | Self { 188 | inner, 189 | phantom_elem: PhantomData, 190 | } 191 | } 192 | } 193 | 194 | // From tuple representation provided to enable serde deserialization. 195 | impl From<(Vec, Vec)> for Proof 196 | where 197 | Element: Hashable, 198 | { 199 | fn from(tuple: (Vec, Vec)) -> Self { 200 | proof::Proof::new(tuple.0, tuple.1).into() 201 | } 202 | } 203 | 204 | // Into tuple representation provided to enable serde deserialization. 205 | impl Into<(Vec, Vec)> for Proof 206 | where 207 | Element: Hashable, 208 | { 209 | fn into(self) -> (Vec, Vec) { 210 | (self.inner.lemma().to_vec(), self.inner.path().to_vec()) 211 | } 212 | } 213 | 214 | /// Wrapper on the RISC0 Digest type to allow it to act as a merkle_light Element. 215 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Pod, Zeroable, Deserialize, Serialize)] 216 | #[repr(transparent)] 217 | pub struct Node(Digest); 218 | 219 | impl AsRef<[u8]> for Node { 220 | fn as_ref(&self) -> &[u8] { 221 | self.0.as_bytes() 222 | } 223 | } 224 | 225 | impl Ord for Node { 226 | fn cmp(&self, other: &Self) -> Ordering { 227 | self.0.get().cmp(other.0.get()) 228 | } 229 | } 230 | 231 | impl PartialOrd for Node { 232 | fn partial_cmp(&self, other: &Self) -> Option { 233 | Some(self.cmp(other)) 234 | } 235 | } 236 | 237 | impl From for Node { 238 | fn from(digest: Digest) -> Self { 239 | Self(digest) 240 | } 241 | } 242 | 243 | impl Into for Node { 244 | fn into(self) -> Digest { 245 | self.0 246 | } 247 | } 248 | 249 | /// ShaHasher is a wrapper around the RISC0 SHA2-256 implementations that implements the Algorithm 250 | /// trait for use with the merkle_light package. 251 | #[derive(Default)] 252 | pub struct ShaHasher { 253 | data: Vec, 254 | } 255 | 256 | // NOTE: The Hasher trait is really designed for use with hashmaps and is quite ill-suited as an 257 | // interface for use by merkle_light. This is one of the design weaknesses of this package. 258 | impl Hasher for ShaHasher { 259 | // NOTE: RISC0 Sha trait currently only provides clean ways to hash data in one shot. To 260 | // accommodate this, we append the data to an array here and only compress at the end. 261 | fn write(&mut self, bytes: &[u8]) { 262 | self.data.extend_from_slice(bytes); 263 | } 264 | 265 | fn finish(&self) -> u64 { 266 | unimplemented!("finish is not implemented for merkletree hashers"); 267 | } 268 | } 269 | 270 | impl Algorithm for ShaHasher { 271 | fn hash(&mut self) -> Node { 272 | Node::from(*sha().hash_bytes(&self.data)) 273 | } 274 | } 275 | 276 | /// VectorOracle is used inside the zkVM guest to access elements of a vector which are held by the 277 | /// host in a committed Merkle tree. On each access, the guest will verify a Merkle proof against 278 | /// the root given when the VectorOracle is created to ensure all accessed values are consistent 279 | /// with a vector with that root. 280 | #[cfg(target_os = "zkvm")] 281 | pub struct VectorOracle 282 | where 283 | Element: Hashable + Deserialize<'static>, 284 | { 285 | root: Node, 286 | phantom_elem: PhantomData, 287 | } 288 | 289 | #[cfg(target_os = "zkvm")] 290 | impl VectorOracle 291 | where 292 | Element: Hashable + Deserialize<'static>, 293 | { 294 | pub fn new(root: Node) -> Self { 295 | Self { 296 | root, 297 | phantom_elem: PhantomData, 298 | } 299 | } 300 | 301 | // NOTE: VectorOracle does not attempt to verify the length of the committed vector, or that 302 | // there is a valid, known element at every index. Any out of bounds access or access to an 303 | // index for which there is no element will not return since no valid proof can be generated. 304 | // NOTE: This implementation deserializes proof and element values, which copies them from the 305 | // address returned by send_recv onto the heap. This is fairly inefficient and could be 306 | // improved on with an implementation of Merkle proofs that can be verified without 307 | // deserialization, and by returning references to the underlying element, which points to the 308 | // memory initialized by send_recv. Additionally note that this implementation uses bincode 309 | // instead of any serializer that is more native to (and efficient in) the guest. 310 | pub fn get(&self, index: usize) -> Element { 311 | let (value, proof): (Element, Proof) = 312 | bincode::deserialize(guest::env::send_recv( 313 | VECTOR_ORACLE_CHANNEL, 314 | // Cast the index to u32 since usize is an architecture dependent type. 315 | &bincode::serialize(&(u32::try_from(index).unwrap())).unwrap(), 316 | )) 317 | .unwrap(); 318 | 319 | // Verify the proof for the value of the element at the given index in the committed vector. 320 | assert_eq!(index, proof.index()); 321 | assert!(proof.verify(&self.root, &value)); 322 | value 323 | } 324 | 325 | pub fn root(&self) -> &Node { 326 | &self.root 327 | } 328 | } 329 | 330 | #[cfg(test)] 331 | mod test { 332 | use rand::Rng; 333 | use sha2::Digest as Sha2Digest; 334 | 335 | use super::*; 336 | 337 | /// Build and return a random Merkle tree with 1028 u32 elements. 338 | fn random_merkle_tree() -> MerkleTree { 339 | let item_count: usize = rand::thread_rng().gen_range((1 << 10)..(1 << 12)); 340 | let items: Vec = (0..item_count).map(|_| rand::thread_rng().gen()).collect(); 341 | MerkleTree::::new(items) 342 | } 343 | 344 | #[test] 345 | fn merkle_tree_proving_works() { 346 | let tree = random_merkle_tree(); 347 | for (index, item) in tree.elements().iter().enumerate() { 348 | let proof = tree.prove(index); 349 | assert!(proof.verify(&tree.root(), &item)); 350 | } 351 | } 352 | 353 | #[test] 354 | fn merkle_proof_serialization_works() { 355 | let tree = random_merkle_tree(); 356 | for (index, item) in tree.elements().iter().enumerate() { 357 | let proof = tree.prove(index); 358 | 359 | let proof_bytes = bincode::serialize(&proof).unwrap(); 360 | let proof_deserialized: Proof = bincode::deserialize(&proof_bytes).unwrap(); 361 | 362 | assert!(proof_deserialized.verify(&tree.root(), &item)); 363 | } 364 | } 365 | 366 | #[test] 367 | fn merkle_proof_index_works() { 368 | let tree = random_merkle_tree(); 369 | for (index, _item) in tree.elements().iter().enumerate() { 370 | let proof = tree.prove(index); 371 | assert_eq!(proof.index(), index); 372 | } 373 | } 374 | 375 | #[test] 376 | fn algorithm_is_consistent_with_sha2() { 377 | let test_string: &'static [u8] = "RISCO SHA hasher test string".as_bytes(); 378 | let mut hasher = ShaHasher::default(); 379 | hasher.write(test_string); 380 | let node = hasher.hash(); 381 | 382 | let reference_hash = sha2::Sha256::digest(test_string); 383 | assert_eq!(hex::encode(node), hex::encode(reference_hash)); 384 | } 385 | } 386 | --------------------------------------------------------------------------------