├── scripts ├── clippy.sh ├── fmt-check.sh ├── bench.sh ├── init.sh ├── build-wasm.sh ├── test.sh └── build.sh ├── .gitignore ├── arkworks ├── setups │ ├── src │ │ ├── plonk │ │ │ └── mod.rs │ │ ├── r1cs │ │ │ └── mod.rs │ │ ├── utxo.rs │ │ ├── keypair.rs │ │ ├── lib.rs │ │ ├── common.rs │ │ └── aead.rs │ ├── .gitignore │ └── Cargo.toml ├── plonk-circuits │ ├── .gitignore │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── plonk-gadgets │ ├── .gitignore │ ├── src │ │ ├── lib.rs │ │ ├── poseidon │ │ │ └── sbox.rs │ │ └── set.rs │ └── Cargo.toml ├── plonk-hashing │ ├── .gitignore │ ├── src │ │ ├── poseidon │ │ │ ├── mod.rs │ │ │ ├── constants.rs │ │ │ ├── preprocessing.rs │ │ │ ├── round_constant.rs │ │ │ ├── round_numbers.rs │ │ │ └── mds.rs │ │ └── lib.rs │ └── Cargo.toml ├── utils │ ├── .gitignore │ ├── src │ │ ├── poseidon_params │ │ │ ├── bn254_x5_3_result.rs │ │ │ ├── bn254_x5_5_result.rs │ │ │ ├── mod.rs │ │ │ ├── bn254_x5_2.rs │ │ │ ├── ed_on_bn254_x17_3.rs │ │ │ └── bn254_x17_3.rs │ │ ├── mimc_params │ │ │ └── mod.rs │ │ └── lib.rs │ └── Cargo.toml ├── benchmarks │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── native-gadgets │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ ├── poseidon │ │ └── sbox.rs │ │ └── mimc.rs ├── r1cs-circuits │ ├── .gitignore │ ├── src │ │ ├── mod.rs │ │ ├── lib.rs │ │ ├── basic.rs │ │ ├── mixer.rs │ │ ├── poseidon.rs │ │ ├── anchor.rs │ │ └── vanchor.rs │ └── Cargo.toml └── r1cs-gadgets │ ├── .gitignore │ ├── src │ ├── lib.rs │ ├── poseidon │ │ ├── sbox.rs │ │ └── mod.rs │ └── set.rs │ └── Cargo.toml ├── .github ├── assets │ ├── webb_banner_dark.png │ └── webb_banner_light.png └── workflows │ ├── checks.yml │ └── coverage.yml ├── rust-toolchain.toml ├── rustfmt.toml ├── Cargo.toml ├── LICENSE-MIT ├── .codecov.yml └── assets └── webb-icon.svg /scripts/clippy.sh: -------------------------------------------------------------------------------- 1 | cargo clippy -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | 3 | .idea 4 | -------------------------------------------------------------------------------- /arkworks/setups/src/plonk/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /arkworks/plonk-circuits/.gitignore: -------------------------------------------------------------------------------- 1 | /target -------------------------------------------------------------------------------- /arkworks/plonk-gadgets/.gitignore: -------------------------------------------------------------------------------- 1 | /target -------------------------------------------------------------------------------- /arkworks/plonk-hashing/.gitignore: -------------------------------------------------------------------------------- 1 | /target -------------------------------------------------------------------------------- /scripts/fmt-check.sh: -------------------------------------------------------------------------------- 1 | cargo fmt --all -- --check -------------------------------------------------------------------------------- /arkworks/setups/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /arkworks/utils/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /arkworks/benchmarks/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /arkworks/native-gadgets/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /arkworks/r1cs-circuits/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /arkworks/r1cs-gadgets/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /scripts/bench.sh: -------------------------------------------------------------------------------- 1 | cargo bench --features "r1cs, test" -- --nocapture -------------------------------------------------------------------------------- /arkworks/setups/src/r1cs/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod anchor; 2 | pub mod mixer; 3 | pub mod vanchor; 4 | -------------------------------------------------------------------------------- /.github/assets/webb_banner_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangle-network/zero-knowledge-gadgets/HEAD/.github/assets/webb_banner_dark.png -------------------------------------------------------------------------------- /.github/assets/webb_banner_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangle-network/zero-knowledge-gadgets/HEAD/.github/assets/webb_banner_light.png -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2022-01-06" 3 | components = ["rustfmt", "clippy"] 4 | targets = ["wasm32-unknown-unknown"] 5 | -------------------------------------------------------------------------------- /scripts/init.sh: -------------------------------------------------------------------------------- 1 | if [[ $(cargo --version) ]]; then 2 | echo "Found cargo" 3 | else 4 | curl https://sh.rustup.rs -sSf | sh -s -- -y 5 | source $HOME/.cargo/env 6 | export PATH=$HOME/.cargo/bin:$PATH 7 | fi -------------------------------------------------------------------------------- /arkworks/plonk-circuits/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | pub extern crate ark_std; 4 | 5 | pub mod anchor; 6 | pub mod mixer; 7 | pub mod vanchor; 8 | 9 | #[cfg(test)] 10 | pub mod utils; -------------------------------------------------------------------------------- /scripts/build-wasm.sh: -------------------------------------------------------------------------------- 1 | cargo build \ 2 | --target wasm32-unknown-unknown \ 3 | --release \ 4 | --no-default-features \ 5 | --workspace \ 6 | --exclude arkworks-circom-verifier \ 7 | --exclude akworks-plonk-circuits \ 8 | --exclude arkworks-benchmarks 9 | -------------------------------------------------------------------------------- /arkworks/r1cs-gadgets/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | #[macro_use] 4 | pub extern crate ark_std; 5 | 6 | pub(crate) use ark_std::vec::Vec; 7 | 8 | pub mod merkle_tree; 9 | pub mod poseidon; 10 | pub mod set; 11 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | condense_wildcard_suffixes = true 2 | format_code_in_doc_comments = true 3 | max_width = 100 4 | hard_tabs = true 5 | imports_granularity="Crate" 6 | overflow_delimited_expr = true 7 | reorder_impl_items = true 8 | use_field_init_shorthand = true 9 | wrap_comments = true -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | BASEDIR=$(dirname "$0") 2 | 3 | cargo test --release --features plonk --features r1cs && \ 4 | cargo test --manifest-path $BASEDIR/../arkworks/plonk-circuits/Cargo.toml --release && \ 5 | cargo test --manifest-path $BASEDIR/../arkworks/plonk-gadgets/Cargo.toml --release 6 | -------------------------------------------------------------------------------- /arkworks/utils/src/poseidon_params/bn254_x5_3_result.rs: -------------------------------------------------------------------------------- 1 | pub const RESULT: &[&str] = &[ 2 | "0x115cc0f5e7d690413df64c6b9662e9cf2a3617f2743245519e19607a4417189a", 3 | "0x0fca49b798923ab0239de1c9e7a4a9a2210312b6a2f616d18b5a87f9b628ae29", 4 | "0x0e7ae82e40091e63cbd4f16a6d16310b3729d4b6e138fcf54110e2867045a30c", 5 | ]; 6 | -------------------------------------------------------------------------------- /arkworks/plonk-hashing/src/poseidon/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod constants; 2 | pub mod matrix; 3 | pub mod mds; 4 | pub mod poseidon; 5 | pub mod poseidon_ref; 6 | pub mod preprocessing; 7 | pub mod round_constant; 8 | pub mod round_numbers; 9 | // pub mod constraints; 10 | 11 | use thiserror::Error; 12 | 13 | #[derive(Error, Debug)] 14 | pub enum PoseidonError { 15 | #[error("Buffer is full")] 16 | FullBuffer, 17 | } 18 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "arkworks/native-gadgets", 5 | # R1CS gadgets + circuits 6 | "arkworks/r1cs-circuits", 7 | "arkworks/r1cs-gadgets", 8 | # Utils and setups 9 | "arkworks/setups", 10 | "arkworks/utils", 11 | "arkworks/benchmarks", 12 | ] 13 | 14 | exclude = [ 15 | "arkworks/plonk-hashing", 16 | "arkworks/plonk-gadgets", 17 | "arkworks/plonk-circuits", 18 | "arkworks/utils" 19 | ] -------------------------------------------------------------------------------- /arkworks/utils/src/poseidon_params/bn254_x5_5_result.rs: -------------------------------------------------------------------------------- 1 | pub const RESULT: &[&str] = &[ 2 | "0x299c867db6c1fdd79dcefa40e4510b9837e60ebb1ce0663dbaa525df65250465", 3 | "0x1148aaef609aa338b27dafd89bb98862d8bb2b429aceac47d86206154ffe053d", 4 | "0x24febb87fed7462e23f6665ff9a0111f4044c38ee1672c1ac6b0637d34f24907", 5 | "0x0eb08f6d809668a981c186beaf6110060707059576406b248e5d9cf6e78b3d3e", 6 | "0x07748bc6877c9b82c8b98666ee9d0626ec7f5be4205f79ee8528ef1c4a376fc7", 7 | ]; 8 | -------------------------------------------------------------------------------- /arkworks/plonk-hashing/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | // 5 | // Copyright (c) ZK-GARAGE. All rights reserved. 6 | 7 | //! PLONK Hashing Library 8 | 9 | // #![cfg_attr(not(any(feature = "std", test)), no_std)] 10 | #![cfg_attr(doc_cfg, feature(doc_cfg))] 11 | #![forbid(rustdoc::broken_intra_doc_links)] 12 | // #![forbid(missing_docs)] 13 | 14 | pub extern crate alloc; 15 | 16 | pub mod poseidon; 17 | -------------------------------------------------------------------------------- /arkworks/r1cs-circuits/src/mod.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Webb. 2 | 3 | // Copyright (C) 2021 Webb Technologies Inc. 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | pub mod anchor; 19 | pub mod basic; 20 | pub mod mixer; 21 | pub mod poseidon; 22 | pub mod vanchor; 23 | -------------------------------------------------------------------------------- /arkworks/utils/src/mimc_params/mod.rs: -------------------------------------------------------------------------------- 1 | use super::{parse_vec, Bytes, Curve, FromHexError}; 2 | 3 | pub use ark_std::vec::Vec; 4 | 5 | pub struct MimcData { 6 | pub constants: Vec, 7 | pub rounds: u16, 8 | pub width: u8, 9 | } 10 | 11 | impl MimcData { 12 | pub fn new(constants: Vec, rounds: u16, width: u8) -> Self { 13 | Self { 14 | constants, 15 | rounds, 16 | width, 17 | } 18 | } 19 | } 20 | 21 | pub fn setup_mimc_params(curve: Curve, rounds: u16, width: u8) -> Result { 22 | match (curve, rounds, width) { 23 | #[cfg(feature = "mimc_ed_on_bn254_220")] 24 | (Curve::Bn254, 220, 3) => { 25 | #[path = "./ed_on_bn254_220.rs"] 26 | pub mod ed_on_bn254_220; 27 | use ed_on_bn254_220::{CONSTANTS, MIMC_ROUNDS, WIDTH}; 28 | get_mimc_data(CONSTANTS, MIMC_ROUNDS, WIDTH) 29 | } 30 | _ => unimplemented!(), 31 | } 32 | } 33 | 34 | pub fn get_mimc_data(constants: &[&str], rounds: u16, width: u8) -> Result { 35 | let constants = parse_vec(constants.to_vec())?; 36 | Ok(MimcData::new(constants, rounds, width)) 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | # For more configuration details: 4 | # https://docs.codecov.io/docs/codecov-yaml 5 | 6 | # Check if this file is valid by running in bash: 7 | # curl -X POST --data-binary @.codecov.yml https://codecov.io/validate 8 | 9 | # Coverage configuration 10 | # ---------------------- 11 | coverage: 12 | status: 13 | patch: false 14 | 15 | range: 70..90 # First number represents red, and second represents green 16 | # (default is 70..100) 17 | round: up # up, down, or nearest 18 | precision: 2 # Number of decimal places, between 0 and 5 19 | 20 | # Ignoring Paths 21 | # -------------- 22 | # which folders/files to ignore 23 | # Ignoring for now until we can include them in workspace 24 | ignore: 25 | - arkworks/benchmarks/*/** 26 | - arkworks/plonk-circuits/*/** 27 | - arkworks/plonk-gadgets/*/** 28 | 29 | # Pull request comments: 30 | # ---------------------- 31 | # Diff is the Coverage Diff of the pull request. 32 | # Files are the files impacted by the pull request 33 | # comment: 34 | # layout: diff, files # - accepted in any order: reach, diff, flags, and/or files -------------------------------------------------------------------------------- /arkworks/r1cs-circuits/src/lib.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Webb. 2 | 3 | // Copyright (C) 2021 Webb Technologies Inc. 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #![cfg_attr(not(feature = "std"), no_std)] 19 | 20 | #[macro_use] 21 | pub extern crate ark_std; 22 | 23 | use ark_std::boxed::Box; 24 | 25 | pub mod anchor; 26 | pub mod basic; 27 | pub mod mixer; 28 | pub mod poseidon; 29 | pub mod vanchor; 30 | 31 | pub type Error = Box; 32 | 33 | pub mod prelude { 34 | pub use ark_ff; 35 | pub use ark_std; 36 | } 37 | -------------------------------------------------------------------------------- /.github/workflows/checks.yml: -------------------------------------------------------------------------------- 1 | name: checks 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | env: 13 | CARGO_TERM_COLOR: always 14 | 15 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 16 | jobs: 17 | build: 18 | # The type of runner that the job will run on 19 | runs-on: ubuntu-18.04 20 | 21 | # Steps represent a sequence of tasks that will be executed as part of the job 22 | steps: 23 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 24 | - uses: actions/checkout@v2 25 | 26 | - name: Set-Up 27 | run: ./scripts/init.sh 28 | 29 | - name: Fmt Check 30 | run: ./scripts/fmt-check.sh 31 | 32 | - name: Clippy Check 33 | run: ./scripts/clippy.sh 34 | 35 | - name: Build 36 | run: ./scripts/build.sh 37 | 38 | - name: Wasm Build 39 | run: ./scripts/build-wasm.sh 40 | 41 | - name: Test 42 | run: ./scripts/test.sh 43 | -------------------------------------------------------------------------------- /arkworks/plonk-gadgets/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | pub extern crate ark_std; 4 | 5 | pub mod merkle_tree; 6 | pub mod poseidon; 7 | pub mod set; 8 | 9 | use ark_ec::models::TEModelParameters; 10 | use ark_ff::PrimeField; 11 | use ark_std::vec::Vec; 12 | use plonk_core::{constraint_system::StandardComposer, prelude::Variable}; 13 | 14 | /// Add a variable to a circuit and constrain it to a public input value that 15 | /// is expected to be different in each instance of the circuit. 16 | pub fn add_public_input_variable(composer: &mut StandardComposer, value: F) -> Variable 17 | where 18 | F: PrimeField, 19 | P: TEModelParameters, 20 | { 21 | let variable = composer.add_input(value); 22 | composer.poly_gate( 23 | variable, 24 | variable, 25 | variable, 26 | F::zero(), 27 | -F::one(), 28 | F::zero(), 29 | F::zero(), 30 | F::zero(), 31 | Some(value), 32 | ); 33 | variable 34 | } 35 | 36 | pub fn add_public_input_variables( 37 | composer: &mut StandardComposer, 38 | items: Vec, 39 | ) -> Vec 40 | where 41 | F: PrimeField, 42 | P: TEModelParameters, 43 | { 44 | let mut vars = Vec::new(); 45 | for item in items { 46 | vars.push(add_public_input_variable(composer, item)); 47 | } 48 | vars 49 | } 50 | -------------------------------------------------------------------------------- /arkworks/utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arkworks-utils" 3 | version = "1.0.1" 4 | authors = ["Webb Developers"] 5 | edition = "2018" 6 | description = "Webb protocol's utils for zero-knowledge gadgets and circuits" 7 | license = "Apache-2.0" 8 | repository = "https://github.com/webb-tools/zero-knowledge-gadgets" 9 | homepage = "https://webb.tools" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | hex = { version = "0.4", default-features = false, features = ["alloc"] } 15 | ark-std = { version = "^0.3.0", default-features = false } 16 | ark-ff = { version = "^0.3.0", default-features = false } 17 | 18 | [features] 19 | std = ["ark-std/std", "hex/std"] 20 | 21 | poseidon_bls381_x3_3 = [] 22 | poseidon_bls381_x3_5 = [] 23 | 24 | poseidon_bls381_x5_3 = [] 25 | poseidon_bls381_x5_5 = [] 26 | 27 | poseidon_bls381_x17_3 = [] 28 | poseidon_bls381_x17_5 = [] 29 | 30 | poseidon_bn254_x3_3 = [] 31 | poseidon_bn254_x3_5 = [] 32 | 33 | poseidon_bn254_x5_2 = [] 34 | poseidon_bn254_x5_3 = [] 35 | poseidon_bn254_x5_4 = [] 36 | poseidon_bn254_x5_5 = [] 37 | 38 | poseidon_bn254_x17_3 = [] 39 | poseidon_bn254_x17_5 = [] 40 | 41 | mimc_ed_on_bn254_220 = [] 42 | 43 | parallel = [ 44 | "ark-std/parallel", 45 | "ark-ff/parallel", 46 | ] 47 | -------------------------------------------------------------------------------- /arkworks/utils/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | #[macro_use] 4 | extern crate ark_std; 5 | 6 | use ark_ff::PrimeField; 7 | pub use ark_std::vec::Vec; 8 | pub use hex::FromHexError; 9 | 10 | pub mod mimc_params; 11 | pub mod poseidon_params; 12 | 13 | type Bytes = Vec; 14 | 15 | #[derive(Copy, Clone)] 16 | pub enum Curve { 17 | Bls381, 18 | Bn254, 19 | } 20 | 21 | pub fn decode_hex(s: &str) -> Result { 22 | let s = &s[2..]; 23 | hex::decode(s) 24 | } 25 | 26 | pub fn parse_vec(arr: Vec<&str>) -> Result, FromHexError> { 27 | let mut res = Vec::new(); 28 | for r in arr.iter() { 29 | res.push(decode_hex(r)?); 30 | } 31 | Ok(res) 32 | } 33 | 34 | pub fn parse_matrix(mds_entries: Vec>) -> Result>, FromHexError> { 35 | let width = mds_entries.len(); 36 | let mut mds = vec![vec![Vec::new(); width]; width]; 37 | for i in 0..width { 38 | for j in 0..width { 39 | mds[i][j] = decode_hex(mds_entries[i][j])?; 40 | } 41 | } 42 | Ok(mds) 43 | } 44 | 45 | pub fn bytes_vec_to_f(bytes_vec: &Vec>) -> Vec { 46 | bytes_vec 47 | .iter() 48 | .map(|x| F::from_be_bytes_mod_order(x)) 49 | .collect() 50 | } 51 | 52 | pub fn bytes_matrix_to_f(bytes_matrix: &Vec>>) -> Vec> { 53 | bytes_matrix.iter().map(|x| bytes_vec_to_f(x)).collect() 54 | } 55 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: check 2 | 3 | # Controls when the action will run. 4 | on: 5 | # Triggers the workflow on push or pull request events but only for the master branch 6 | push: 7 | branches: [ master ] 8 | pull_request: 9 | branches: [ master ] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 15 | jobs: 16 | coverage: 17 | name: coverage 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - name: Cancel Previous Runs 22 | uses: styfle/cancel-workflow-action@0.9.1 23 | with: 24 | access_token: ${{ github.token }} 25 | 26 | - name: Checkout repository 27 | uses: actions/checkout@v2 28 | 29 | - name: Install Toolchain 30 | uses: actions-rs/toolchain@v1 31 | with: 32 | toolchain: stable 33 | override: true 34 | 35 | - name: Rust Cache 36 | uses: Swatinem/rust-cache@v1.3.0 37 | 38 | - name: Run Tarpaulin 39 | uses: actions-rs/tarpaulin@v0.1 40 | with: 41 | args: '--workspace --release --locked --out Xml --jobs 16 --timeout 5600 -- --test-threads 16' 42 | 43 | - name: Upload to codecov.io 44 | uses: codecov/codecov-action@v2 45 | with: 46 | fail_ci_if_error: true -------------------------------------------------------------------------------- /arkworks/native-gadgets/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arkworks-native-gadgets" 3 | version = "1.2.1" 4 | authors = ["Webb Developers"] 5 | edition = "2018" 6 | description = "Webb protocol's native gadgets" 7 | license = "Apache-2.0" 8 | repository = "https://github.com/webb-tools/zero-knowledge-gadgets" 9 | homepage = "https://webb.tools" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | ark-ff = { version = "^0.3.0", default-features = false } 15 | ark-std = { version = "^0.3.0", default-features = false } 16 | ark-crypto-primitives = { version = "^0.3.0", features = ["r1cs"], default-features = false } 17 | 18 | [dev-dependencies] 19 | # curves 20 | ark-ed-on-bls12-381 = { version = "^0.3.0", default-features = false, features = [ "r1cs" ] } 21 | ark-ed-on-bn254 = { version = "^0.3.0", default-features = false, features = [ "r1cs" ] } 22 | ark-bn254 = { version = "^0.3.0", default-features = false } 23 | 24 | [dev-dependencies.arkworks-utils] 25 | path = "../utils" 26 | default-features = false 27 | features = ["poseidon_bn254_x5_2", "poseidon_bn254_x5_3", "poseidon_bn254_x5_4", "poseidon_bn254_x5_5", "poseidon_bls381_x5_3", "mimc_ed_on_bn254_220"] 28 | 29 | [features] 30 | default = ["std"] 31 | std = [ 32 | "ark-std/std", 33 | "ark-ff/std", 34 | "ark-crypto-primitives/std", 35 | ] 36 | parallel = [ 37 | "ark-crypto-primitives/parallel", 38 | "ark-ff/parallel", 39 | "ark-std/parallel", 40 | ] 41 | -------------------------------------------------------------------------------- /arkworks/plonk-hashing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "plonk-hashing" 3 | version = "0.8.2" 4 | authors = ["ZK-GARAGE Authors, Webb Developers "] 5 | readme = "README.md" 6 | repository = "https://github.com/zk-garage/plonk" 7 | keywords = ["cryptography", "plonk", "zk-snarks", "zero-knowledge", "crypto"] 8 | categories = ["algorithms", "cryptography", "science"] 9 | description = "A pure-Rust implementation of the PLONK ZK-Proof algorithm." 10 | license = "MIT OR Apache-2.0" 11 | edition = "2021" 12 | 13 | [package.metadata.docs.rs] 14 | # To build locally: 15 | # RUSTDOCFLAGS="--cfg doc_cfg" cargo +nightly doc --all-features --open 16 | all-features = true 17 | rustdoc-args = ["--cfg", "doc_cfg"] 18 | 19 | [dependencies] 20 | plonk-core = { version = "^0.1", git = "https://github.com/ZK-Garage/plonk", default-features = false } 21 | ark-ec = { version = "0.3", features = ["std"] } 22 | ark-ff = { version = "0.3", features = ["std"] } 23 | ark-serialize = { version = "0.3", features = ["derive"] } 24 | ark-poly = "0.3" 25 | ark-poly-commit = "0.3" 26 | ark-crypto-primitives = { version = "^0.3.0", features = ["r1cs"], default-features = false } 27 | ark-std = { version = "^0.3.0", default-features = false } 28 | itertools = { version = "0.10.1", default-features = false } 29 | num-traits = "0.2.14" 30 | derivative = { version = "2.2.0", default-features = false, features = ["use_core"] } 31 | hashbrown = { version = "0.11.2", default-features = false, features = ["ahash"] } 32 | ark-relations = "0.3.0" 33 | ark-r1cs-std = "0.3.1" 34 | thiserror = "1.0.30" 35 | 36 | [features] 37 | # Enable Standard Library 38 | std = [] -------------------------------------------------------------------------------- /arkworks/native-gadgets/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | use ark_ff::{BigInteger, PrimeField}; 4 | use ark_std::{boxed::Box, vec::Vec}; 5 | 6 | #[macro_use] 7 | pub extern crate ark_std; 8 | 9 | pub mod merkle_tree; 10 | pub mod mimc; 11 | pub mod poseidon; 12 | 13 | pub type Error = Box; 14 | 15 | pub mod prelude { 16 | pub use ark_crypto_primitives; 17 | pub use ark_ff; 18 | pub use ark_std; 19 | } 20 | 21 | // bytes field is assumed to contain concatenated, Big-endian encoded chunks. 22 | pub fn to_field_elements(bytes: &[u8]) -> Result, Error> { 23 | let max_size_bytes = F::BigInt::NUM_LIMBS * 8; 24 | 25 | // Pad the input with zeros to prevent crashes in arkworks 26 | let padding_len = (max_size_bytes - (bytes.len() % max_size_bytes)) % max_size_bytes; 27 | let padded_input: Vec = bytes 28 | .iter() 29 | .cloned() 30 | .chain(core::iter::repeat(0u8).take(padding_len)) 31 | .collect(); 32 | 33 | // Reverse all chunks so the values are formatted in little-endian. 34 | // This is necessary because arkworks assumes little-endian. 35 | let mut reversed_chunks: Vec = Vec::with_capacity(bytes.len() + padding_len); 36 | 37 | for chunk in padded_input.chunks(max_size_bytes) { 38 | reversed_chunks.extend(chunk.iter().rev()); 39 | } 40 | 41 | // Read the chunks into arkworks to convert into field elements. 42 | let res = reversed_chunks 43 | .chunks(max_size_bytes) 44 | .map(F::read) 45 | .collect::, _>>()?; 46 | Ok(res) 47 | } 48 | 49 | pub fn from_field_elements(elts: &[F]) -> Result, Error> { 50 | let res = elts.iter().fold(vec![], |mut acc, prev| { 51 | acc.extend_from_slice(&prev.into_repr().to_bytes_be()); 52 | acc 53 | }); 54 | 55 | Ok(res) 56 | } 57 | -------------------------------------------------------------------------------- /arkworks/native-gadgets/src/poseidon/sbox.rs: -------------------------------------------------------------------------------- 1 | //! The S-box used in the Poseidon hash function. 2 | //! 3 | //! The `PoseidonSbox` struct contains only one signed 8-bit integer. 4 | //! In the notation of 5 | //! [the original Poseidon paper](https://eprint.iacr.org/2019/458.pdf), 6 | //! this is alpha. 7 | //! 8 | //! The value of alpha can be either 3, 5, 17, or -1: the default is 5. 9 | //! Trying to use any other value will result in a `PoseidonError`. 10 | //! 11 | //! The `apply_sbox` method takes an element of a prime field `F` 12 | //! and raises it to the power alpha (in `F`). 13 | 14 | /// Importing dependencies 15 | use super::PoseidonError; 16 | use ark_ff::PrimeField; 17 | 18 | /// The PoseidonSbox struct contains just a public signed 8-bit integer. 19 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 20 | pub struct PoseidonSbox(pub i8); 21 | 22 | /// The default value for PoseidonSbox is 5. 23 | impl Default for PoseidonSbox { 24 | fn default() -> Self { 25 | PoseidonSbox(5) 26 | } 27 | } 28 | 29 | impl PoseidonSbox { 30 | /// Takes in an element of a prime field and raises it to the power alpha 31 | /// (`sbox.0`) within that field. The method assumes that alpha is either 3, 32 | /// 5, 17, or -1. If not, it throws `PoseidonError`. 33 | pub fn apply_sbox(&self, elem: F) -> Result { 34 | let res = match self.0 { 35 | 3 => elem * elem * elem, 36 | 5 => { 37 | let sqr = elem.square(); 38 | sqr.square().mul(elem) 39 | } 40 | 17 => { 41 | let sqr = elem * elem; 42 | let quad = sqr * sqr; 43 | let eighth = quad * quad; 44 | let sixteenth = eighth * eighth; 45 | sixteenth * elem 46 | } 47 | -1 => elem.inverse().ok_or(PoseidonError::ApplySboxFailed)?, 48 | n => return Err(PoseidonError::InvalidSboxSize(n)), 49 | }; 50 | Ok(res) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /arkworks/plonk-gadgets/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arkworks-plonk-gadgets" 3 | version = "1.2.1" 4 | authors = ["Webb Developers"] 5 | edition = "2021" 6 | description = "Webb protocol's plonk zero-knowledge gadgets written using Arkworks (ark-plonk)" 7 | license = "Apache-2.0" 8 | repository = "https://github.com/webb-tools/zero-knowledge-gadgets" 9 | homepage = "https://webb.tools" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | arkworks-native-gadgets = { path = "../native-gadgets", version = "1.2.1", default-features = false } 15 | 16 | ark-ff = { version = "^0.3.0", default-features = false } 17 | ark-std = { version = "^0.3.0", default-features = false } 18 | plonk-core = { version = "^0.1", git = "https://github.com/ZK-Garage/plonk", default-features = false } 19 | ark-ec = { version = "^0.3.0", default-features = false } 20 | 21 | [dev-dependencies] 22 | plonk-core = { version = "^0.1", git = "https://github.com/ZK-Garage/plonk", features = ["trace"], default-features = false } 23 | plonk-hashing = { path = "../plonk-hashing" } 24 | ark-poly-commit = { version = "^0.3.0", default-features = false } 25 | ark-poly = { version = "^0.3.0", default-features = false } 26 | ark-serialize = { version = "^0.3.0", default-features = false } 27 | 28 | # curves 29 | ark-ed-on-bn254 = { version = "^0.3.0", default-features = false, features = [ "r1cs" ] } 30 | ark-bn254 = { version = "^0.3.0", default-features = false, features = [ "curve" ] } 31 | 32 | [dev-dependencies.arkworks-utils] 33 | path = "../utils" 34 | default-features = false 35 | features = ["poseidon_bn254_x5_3"] 36 | 37 | 38 | 39 | [features] 40 | default = ["std"] 41 | std = [ 42 | "ark-std/std", 43 | "arkworks-native-gadgets/std", 44 | "ark-ff/std", 45 | "ark-ec/std", 46 | ] 47 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | # Build each crate with isolated features 2 | BASEDIR=$(dirname "$0") 3 | 4 | # Native Gadgets 5 | cargo build -p arkworks-native-gadgets --release --no-default-features && \ 6 | cargo build -p arkworks-native-gadgets --release --no-default-features --features parallel && \ 7 | cargo build -p arkworks-native-gadgets --release --all-features && \ 8 | 9 | # R1CS Gadgets 10 | cargo build -p arkworks-r1cs-gadgets --release --no-default-features && \ 11 | cargo build -p arkworks-r1cs-gadgets --release --no-default-features --features parallel && \ 12 | cargo build -p arkworks-r1cs-gadgets --release --all-features && \ 13 | 14 | # R1CS Circuits 15 | cargo build -p arkworks-r1cs-circuits --release --no-default-features && \ 16 | cargo build -p arkworks-r1cs-circuits --release --no-default-features --features parallel && \ 17 | cargo build -p arkworks-r1cs-circuits --release --all-features && \ 18 | 19 | # Arkworks Utils 20 | cargo build -p arkworks-utils --release --no-default-features && \ 21 | cargo build -p arkworks-utils --release --no-default-features --features parallel && \ 22 | cargo build -p arkworks-utils --release --all-features && \ 23 | 24 | # Arkworks Setups 25 | cargo build -p arkworks-setups --release --no-default-features && \ 26 | cargo build -p arkworks-setups --release --no-default-features --features parallel && \ 27 | cargo build -p arkworks-setups --release --no-default-features --features aead && \ 28 | cargo build -p arkworks-setups --release --all-features 29 | 30 | # PLONK gadgets 31 | cargo build --manifest-path $BASEDIR/../arkworks/plonk-gadgets/Cargo.toml --release --no-default-features && \ 32 | cargo build --manifest-path $BASEDIR/../arkworks/plonk-gadgets/Cargo.toml --release && \ 33 | 34 | # PLONK circuits 35 | cargo build --manifest-path $BASEDIR/../arkworks/plonk-gadgets/Cargo.toml --release --no-default-features && \ 36 | cargo build --manifest-path $BASEDIR/../arkworks/plonk-gadgets/Cargo.toml --release -------------------------------------------------------------------------------- /arkworks/plonk-circuits/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arkworks-plonk-circuits" 3 | version = "1.2.1" 4 | authors = ["Webb Developers"] 5 | edition = "2021" 6 | description = "Webb protocol's plonk zero-knowledge circuits written using Arkworks (ark-plonk)" 7 | license = "Apache-2.0" 8 | repository = "https://github.com/webb-tools/zero-knowledge-gadgets" 9 | homepage = "https://webb.tools" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | arkworks-native-gadgets = { path = "../native-gadgets", version = "1.2.1", default-features = false } 15 | arkworks-plonk-gadgets = { path = "../plonk-gadgets", version = "1.2.1", default-features = false } 16 | 17 | plonk-core = { version = "^0.1.0", git = "https://github.com/ZK-Garage/plonk", features = ["trace"], default-features = false } 18 | ark-ff = { version = "^0.3.0", default-features = false } 19 | ark-std = { version = "^0.3.0", default-features = false } 20 | ark-poly-commit = { version = "^0.3.0", default-features = false } 21 | ark-poly = { version = "^0.3.0", default-features = false } 22 | ark-ec = { version = "^0.3.0", default-features = false } 23 | 24 | [dev-dependencies] 25 | # curves 26 | ark-ed-on-bn254 = { version = "^0.3.0", default-features = false, features = [ "r1cs" ] } 27 | ark-bn254 = { version = "^0.3.0", default-features = false, features = [ "curve" ] } 28 | plonk-hashing = { path = "../plonk-hashing" } 29 | ark-serialize = { version = "^0.3.0", default-features = false } 30 | 31 | [dev-dependencies.arkworks-utils] 32 | path = "../utils" 33 | default-features = false 34 | features = ["poseidon_bn254_x5_2", "poseidon_bn254_x5_3", "poseidon_bn254_x5_4", "poseidon_bn254_x5_5"] 35 | 36 | [features] 37 | default = ["std"] 38 | std = [ 39 | "ark-std/std", 40 | "arkworks-native-gadgets/std", 41 | "arkworks-plonk-gadgets/std", 42 | "ark-ff/std", 43 | "ark-ec/std", 44 | "ark-poly-commit/std", 45 | "ark-poly/std", 46 | ] 47 | -------------------------------------------------------------------------------- /arkworks/r1cs-gadgets/src/poseidon/sbox.rs: -------------------------------------------------------------------------------- 1 | use super::PoseidonSbox; 2 | use ark_ff::PrimeField; 3 | use ark_r1cs_std::fields::{fp::FpVar, FieldVar}; 4 | use ark_relations::r1cs::SynthesisError; 5 | 6 | pub trait SboxConstraints { 7 | fn synthesize_sbox(&self, input: &FpVar) -> Result, SynthesisError>; 8 | } 9 | 10 | impl SboxConstraints for PoseidonSbox { 11 | fn synthesize_sbox( 12 | &self, 13 | input_var: &FpVar, 14 | ) -> Result, SynthesisError> { 15 | match self.0 { 16 | 3 => synthesize_exp3_sbox::(input_var), 17 | 5 => synthesize_exp5_sbox::(input_var), 18 | 17 => synthesize_exp17_sbox::(input_var), 19 | -1 => synthesize_inverse_sbox::(input_var), 20 | _ => synthesize_exp3_sbox::(input_var), 21 | } 22 | } 23 | } 24 | 25 | // Allocate variables in circuit and enforce constraints when Sbox as cube 26 | fn synthesize_exp3_sbox(input_var: &FpVar) -> Result, SynthesisError> { 27 | let sqr = input_var * input_var; 28 | let cube = input_var * sqr; 29 | Ok(cube) 30 | } 31 | 32 | // Allocate variables in circuit and enforce constraints when Sbox as cube 33 | fn synthesize_exp5_sbox(input_var: &FpVar) -> Result, SynthesisError> { 34 | let sqr = input_var * input_var; 35 | let fourth = &sqr * &sqr; 36 | let fifth = input_var * fourth; 37 | Ok(fifth) 38 | } 39 | 40 | // Allocate variables in circuit and enforce constraints when Sbox as cube 41 | fn synthesize_exp17_sbox(input_var: &FpVar) -> Result, SynthesisError> { 42 | let sqr = input_var * input_var; 43 | let fourth = &sqr * &sqr; 44 | let eigth = &fourth * &fourth; 45 | let sixteenth = &eigth * &eigth; 46 | let seventeenth = &sixteenth * input_var; 47 | Ok(seventeenth) 48 | } 49 | 50 | // Allocate variables in circuit and enforce constraints when Sbox as 51 | // inverse 52 | fn synthesize_inverse_sbox( 53 | input_var: &FpVar, 54 | ) -> Result, SynthesisError> { 55 | input_var.inverse() 56 | } 57 | -------------------------------------------------------------------------------- /arkworks/r1cs-circuits/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arkworks-r1cs-circuits" 3 | version = "1.2.1" 4 | authors = ["Webb Developers"] 5 | edition = "2018" 6 | description = "Webb protocol's r1cs zero-knowledge circuits written using Arkworks" 7 | license = "Apache-2.0" 8 | repository = "https://github.com/webb-tools/zero-knowledge-gadgets" 9 | homepage = "https://webb.tools" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | arkworks-r1cs-gadgets = { path = "../r1cs-gadgets", version = "1.2.1", default-features = false } 15 | arkworks-native-gadgets = { path = "../native-gadgets", version = "1.2.1", default-features = false } 16 | 17 | ark-ff = { version = "^0.3.0", default-features = false } 18 | ark-std = { version = "^0.3.0", default-features = false } 19 | ark-r1cs-std = { version = "^0.3.0", default-features = false } 20 | ark-relations = { version = "^0.3.0", default-features = false } 21 | 22 | [dev-dependencies] 23 | ark-crypto-primitives = { version = "^0.3.0", features = ["r1cs"], default-features = false } 24 | ark-marlin = { version = "^0.3.0", default-features = false } 25 | ark-groth16 = { version = "^0.3.0", default-features = false } 26 | ark-poly-commit = { version = "^0.3.0", default-features = false } 27 | ark-poly = { version = "^0.3.0", default-features = false } 28 | ark-snark = { version = "^0.3.0", default-features = false } 29 | 30 | blake2 = { version = "0.9", default-features = false } 31 | digest = { version = "0.9" } 32 | 33 | # curves 34 | ark-ed-on-bn254 = { version = "^0.3.0", default-features = false, features = [ "r1cs" ] } 35 | ark-bls12-381 = { version = "^0.3.0", default-features = false, features = [ "curve" ] } 36 | 37 | [dev-dependencies.arkworks-utils] 38 | path = "../utils" 39 | default-features = false 40 | features = ["poseidon_bn254_x5_2", "poseidon_bn254_x5_3", "poseidon_bn254_x5_4", "poseidon_bn254_x5_5", "poseidon_bls381_x5_3"] 41 | 42 | [features] 43 | default = ["std"] 44 | std = [ 45 | "ark-std/std", 46 | "arkworks-r1cs-gadgets/std", 47 | "arkworks-native-gadgets/std", 48 | "ark-ff/std", 49 | "ark-r1cs-std/std", 50 | "ark-relations/std", 51 | ] 52 | parallel = [ 53 | "ark-ff/parallel", 54 | "ark-std/parallel", 55 | "ark-r1cs-std/parallel", 56 | ] 57 | 58 | -------------------------------------------------------------------------------- /arkworks/benchmarks/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arkworks-benchmarks" 3 | version = "1.2.1" 4 | authors = ["Webb Developers"] 5 | edition = "2018" 6 | description = "Webb protocol's zero-knowledge gadgets written using Arkworks" 7 | license = "Apache-2.0" 8 | repository = "https://github.com/webb-tools/zero-knowledge-gadgets" 9 | homepage = "https://webb.tools" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | arkworks-utils = { path = "../utils", version = "1.0.1", features = [ 15 | "poseidon_bn254_x5_3", 16 | "poseidon_bn254_x5_4", 17 | "poseidon_bn254_x5_5" 18 | ], default-features = false } 19 | arkworks-r1cs-circuits = { path = "../r1cs-circuits", version = "1.2.1" } 20 | arkworks-r1cs-gadgets = { path = "../r1cs-gadgets", version = "1.2.1" } 21 | arkworks-native-gadgets = { path = "../native-gadgets", version = "1.2.1" } 22 | arkworks-setups = { path = "../setups", version = "1.2.1", features = ["r1cs"] } 23 | 24 | ark-crypto-primitives = { version = "^0.3.0", features = ["r1cs"], default-features = false } 25 | ark-ff = { version = "^0.3.0", default-features = false } 26 | ark-std = { version = "^0.3.0", default-features = false } 27 | ark-r1cs-std = { version = "^0.3.0", default-features = false } 28 | ark-relations = { version = "^0.3.0", default-features = false } 29 | 30 | ark-marlin = {version = "^0.3.0", default-features = false } 31 | ark-groth16 = {version = "^0.3.0", default-features = false } 32 | blake2 = { version = "0.9", default-features = false } 33 | ark-poly-commit = { version = "^0.3.0", default-features = false } 34 | ark-poly = { version = "^0.3.0", default-features = false } 35 | ark-snark = { version = "^0.3.0", default-features = false } 36 | ark-ec = { version = "^0.3.0", default-features = false } 37 | ark-serialize = {version = "^0.3.0", default-features = false } 38 | digest = { version = "0.9" } 39 | 40 | # curves 41 | ark-ed-on-bls12-381 = { version = "^0.3.0", default-features = false, features = [ "r1cs" ] } 42 | ark-ed-on-bn254 = { version = "^0.3.0", default-features = false, features = [ "r1cs" ] } 43 | ark-bls12-381 = { version = "^0.3.0", default-features = false, features = [ "curve" ] } 44 | ark-bn254 = { version = "^0.3.0", default-features = false, features = [ "curve" ] } 45 | 46 | -------------------------------------------------------------------------------- /arkworks/r1cs-gadgets/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arkworks-r1cs-gadgets" 3 | version = "1.2.1" 4 | authors = ["Webb Developers"] 5 | edition = "2018" 6 | description = "Webb protocol's r1cs zero-knowledge gadgets written using Arkworks" 7 | license = "Apache-2.0" 8 | repository = "https://github.com/webb-tools/zero-knowledge-gadgets" 9 | homepage = "https://webb.tools" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | arkworks-native-gadgets = { path = "../native-gadgets", version = "1.2.1", default-features = false } 15 | 16 | ark-crypto-primitives = { version = "^0.3.0", features = ["r1cs"], default-features = false } 17 | ark-ff = { version = "^0.3.0", default-features = false } 18 | ark-std = { version = "^0.3.0", default-features = false } 19 | ark-r1cs-std = { version = "^0.3.0", default-features = false } 20 | ark-relations = { version = "^0.3.0", default-features = false } 21 | 22 | [dev-dependencies] 23 | ark-marlin = { version = "^0.3.0", default-features = false } 24 | ark-groth16 = { version = "^0.3.0", default-features = false } 25 | blake2 = { version = "0.9", default-features = false } 26 | ark-poly-commit = { version = "^0.3.0", default-features = false } 27 | ark-poly = { version = "^0.3.0", default-features = false } 28 | ark-snark = { version = "^0.3.0", default-features = false } 29 | ark-ec = { version = "^0.3.0", default-features = false } 30 | ark-serialize = {version = "^0.3.0", default-features = false } 31 | digest = { version = "0.9" } 32 | crypto_box = { version = "0.7.1" } 33 | 34 | # curves 35 | ark-ed-on-bn254 = { version = "^0.3.0", default-features = false, features = [ "r1cs" ] } 36 | ark-bls12-381 = { version = "^0.3.0", default-features = false, features = [ "curve" ] } 37 | 38 | [dev-dependencies.arkworks-utils] 39 | path = "../utils" 40 | default-features = false 41 | features = ["poseidon_bn254_x5_3", "mimc_ed_on_bn254_220"] 42 | 43 | [features] 44 | default = ["std"] 45 | std = [ 46 | "ark-std/std", 47 | "arkworks-native-gadgets/std", 48 | "ark-ff/std", 49 | "ark-std/std", 50 | "ark-r1cs-std/std", 51 | "ark-relations/std" 52 | ] 53 | parallel = [ 54 | "ark-crypto-primitives/parallel", 55 | "arkworks-native-gadgets/parallel", 56 | "ark-ff/parallel", 57 | "ark-std/parallel", 58 | "ark-r1cs-std/parallel", 59 | ] 60 | -------------------------------------------------------------------------------- /arkworks/plonk-hashing/src/poseidon/constants.rs: -------------------------------------------------------------------------------- 1 | use crate::poseidon::{ 2 | matrix::Matrix, 3 | mds::{factor_to_sparse_matrixes, MdsMatrices, SparseMatrix}, 4 | preprocessing::compress_round_constants, 5 | round_constant::generate_constants, 6 | round_numbers::calc_round_numbers, 7 | }; 8 | use ark_ff::PrimeField; 9 | 10 | #[derive(Clone, Debug, PartialEq)] 11 | pub struct PoseidonConstants { 12 | pub mds_matrices: MdsMatrices, 13 | pub round_constants: Vec, 14 | pub compressed_round_constants: Vec, 15 | pub pre_sparse_matrix: Matrix, 16 | pub sparse_matrixes: Vec>, 17 | pub domain_tag: F, 18 | pub full_rounds: usize, 19 | pub half_full_rounds: usize, 20 | pub partial_rounds: usize, 21 | } 22 | 23 | impl PoseidonConstants { 24 | /// Generate all constants needed for poseidon hash of specified 25 | /// width. Note that WIDTH = ARITY + 1 26 | pub fn generate() -> Self { 27 | let arity = WIDTH - 1; 28 | let mds_matrices = MdsMatrices::new(WIDTH); 29 | let (num_full_rounds, num_partial_rounds) = 30 | calc_round_numbers(WIDTH, true); 31 | 32 | debug_assert_eq!(num_full_rounds % 2, 0); 33 | let num_half_full_rounds = num_full_rounds / 2; 34 | let round_constants = generate_constants( 35 | 1, // prime field 36 | 1, // sbox 37 | F::size_in_bits() as u16, 38 | WIDTH.try_into().expect("WIDTH is too large"), 39 | num_full_rounds 40 | .try_into() 41 | .expect("num_full_rounds is too large"), 42 | num_partial_rounds 43 | .try_into() 44 | .expect("num_partial_rounds is too large"), 45 | ); 46 | let domain_tag = F::from(((1 << arity) - 1) as u64); 47 | 48 | let compressed_round_constants = compress_round_constants( 49 | WIDTH, 50 | num_full_rounds, 51 | num_partial_rounds, 52 | &round_constants, 53 | &mds_matrices, 54 | ); 55 | 56 | let (pre_sparse_matrix, sparse_matrixes) = factor_to_sparse_matrixes( 57 | mds_matrices.m.clone(), 58 | num_partial_rounds, 59 | ); 60 | 61 | assert!( 62 | WIDTH * (num_full_rounds + num_partial_rounds) 63 | <= round_constants.len(), 64 | "Not enough round constants" 65 | ); 66 | 67 | PoseidonConstants { 68 | mds_matrices, 69 | round_constants, 70 | domain_tag, 71 | full_rounds: num_full_rounds, 72 | half_full_rounds: num_half_full_rounds, 73 | partial_rounds: num_partial_rounds, 74 | compressed_round_constants, 75 | pre_sparse_matrix, 76 | sparse_matrixes, 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /arkworks/plonk-gadgets/src/poseidon/sbox.rs: -------------------------------------------------------------------------------- 1 | use ark_ec::TEModelParameters; 2 | use ark_ff::PrimeField; 3 | use arkworks_native_gadgets::poseidon::sbox::PoseidonSbox; 4 | use plonk_core::{constraint_system::StandardComposer, error::Error, prelude::Variable}; 5 | 6 | pub trait SboxConstraints { 7 | fn synthesize_sbox>( 8 | &self, 9 | input: &Variable, 10 | composer: &mut StandardComposer, 11 | ) -> Result; 12 | } 13 | 14 | impl SboxConstraints for PoseidonSbox { 15 | fn synthesize_sbox>( 16 | &self, 17 | input_var: &Variable, 18 | composer: &mut StandardComposer, 19 | ) -> Result { 20 | match self { 21 | PoseidonSbox(val) => match val { 22 | 3 => synthesize_exp3_sbox::(input_var, composer), 23 | 5 => synthesize_exp5_sbox::(input_var, composer), 24 | 17 => synthesize_exp17_sbox::(input_var, composer), 25 | _ => synthesize_exp3_sbox::(input_var, composer), 26 | }, 27 | _ => synthesize_exp3_sbox::(input_var, composer), 28 | } 29 | } 30 | } 31 | 32 | // Allocate variables in circuit and enforce constraints when Sbox as cube 33 | fn synthesize_exp3_sbox>( 34 | input_var: &Variable, 35 | composer: &mut StandardComposer, 36 | ) -> Result { 37 | let sqr = 38 | composer.arithmetic_gate(|gate| gate.witness(*input_var, *input_var, None).mul(F::one())); 39 | let cube = composer.arithmetic_gate(|gate| gate.witness(sqr, *input_var, None).mul(F::one())); 40 | Ok(cube) 41 | } 42 | 43 | // Allocate variables in circuit and enforce constraints when Sbox as cube 44 | fn synthesize_exp5_sbox>( 45 | input_var: &Variable, 46 | composer: &mut StandardComposer, 47 | ) -> Result { 48 | let sqr = 49 | composer.arithmetic_gate(|gate| gate.witness(*input_var, *input_var, None).mul(F::one())); 50 | let fourth = composer.arithmetic_gate(|gate| gate.witness(sqr, sqr, None).mul(F::one())); 51 | let fifth = 52 | composer.arithmetic_gate(|gate| gate.witness(fourth, *input_var, None).mul(F::one())); 53 | Ok(fifth) 54 | } 55 | 56 | // Allocate variables in circuit and enforce constraints when Sbox as cube 57 | fn synthesize_exp17_sbox>( 58 | input_var: &Variable, 59 | composer: &mut StandardComposer, 60 | ) -> Result { 61 | let sqr = 62 | composer.arithmetic_gate(|gate| gate.witness(*input_var, *input_var, None).mul(F::one())); 63 | let fourth = composer.arithmetic_gate(|gate| gate.witness(sqr, sqr, None).mul(F::one())); 64 | let eigth = composer.arithmetic_gate(|gate| gate.witness(fourth, fourth, None).mul(F::one())); 65 | let sixteenth = composer.arithmetic_gate(|gate| gate.witness(eigth, eigth, None).mul(F::one())); 66 | let seventeenth = 67 | composer.arithmetic_gate(|gate| gate.witness(sixteenth, *input_var, None).mul(F::one())); 68 | Ok(seventeenth) 69 | } 70 | -------------------------------------------------------------------------------- /arkworks/setups/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arkworks-setups" 3 | version = "1.2.2" 4 | edition = "2021" 5 | license = "Apache-2.0" 6 | description = "Webb protocol's API for zero-knowledge circuits" 7 | repository = "https://github.com/webb-tools/zero-knowledge-gadgets" 8 | homepage = "https://webb.tools" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | 12 | [dependencies] 13 | arkworks-r1cs-circuits = { path = "../r1cs-circuits", version = "1.2.1", default-features = false } 14 | arkworks-r1cs-gadgets = { path = "../r1cs-gadgets", version = "1.2.1", default-features = false } 15 | arkworks-native-gadgets = { path = "../native-gadgets", version = "1.2.1", default-features = false } 16 | 17 | ark-crypto-primitives = { version = "^0.3.0", features = ["r1cs"], default-features = false } 18 | ark-ff = { version = "^0.3.0", default-features = false } 19 | ark-std = { version = "^0.3.0", default-features = false } 20 | ark-r1cs-std = { version = "^0.3.0", default-features = false } 21 | ark-relations = { version = "^0.3.0", default-features = false } 22 | ark-ec = { version = "^0.3.0", default-features = false } 23 | ark-serialize = { version = "^0.3.0", default-features = false } 24 | ark-groth16 = { version = "^0.3.0", default-features = false } 25 | 26 | tiny-keccak = { version = "2.0.2", features = ["keccak"] } 27 | codec = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } 28 | crypto_box = { version = "0.7.1", optional = true } 29 | 30 | tracing = { version = "0.1", default-features = false, features = [ "attributes" ], optional = true } 31 | tracing-subscriber = { version = "0.2", optional = true } 32 | 33 | [dependencies.arkworks-utils] 34 | path = "../utils" 35 | version = "1.0.0" 36 | default-features = false 37 | features = ["poseidon_bn254_x5_2", "poseidon_bn254_x5_3", "poseidon_bn254_x5_4", "poseidon_bn254_x5_5"] 38 | 39 | [dev-dependencies] 40 | ark-snark = { version = "^0.3.0", default-features = false } 41 | digest = { version = "0.9" } 42 | 43 | # curves 44 | ark-bn254 = { version = "^0.3.0", default-features = false, features = [ "curve" ] } 45 | hex-literal = { version = "0.3.4" } 46 | 47 | [features] 48 | default = ["std", "r1cs"] 49 | aead = ["crypto_box"] 50 | r1cs = [] 51 | plonk = [] 52 | std = [ 53 | "arkworks-r1cs-circuits/std", 54 | "arkworks-r1cs-gadgets/std", 55 | "arkworks-native-gadgets/std", 56 | "ark-crypto-primitives/std", 57 | "ark-ff/std", 58 | "ark-std/std", 59 | "ark-r1cs-std/std", 60 | "ark-relations/std", 61 | "ark-ec/std", 62 | "ark-groth16/std", 63 | "ark-serialize/std", 64 | "arkworks-utils/std", 65 | "codec/std", 66 | ] 67 | parallel = [ 68 | "ark-crypto-primitives/parallel", 69 | "ark-std/parallel", 70 | "ark-r1cs-std/parallel", 71 | "ark-ec/parallel", 72 | "ark-groth16/parallel", 73 | "ark-ff/parallel", 74 | "arkworks-r1cs-circuits/parallel", 75 | "arkworks-r1cs-gadgets/parallel", 76 | "arkworks-native-gadgets/parallel", 77 | ] 78 | trace = [ 79 | "tracing", 80 | "tracing-subscriber", 81 | ] 82 | -------------------------------------------------------------------------------- /arkworks/plonk-hashing/src/poseidon/preprocessing.rs: -------------------------------------------------------------------------------- 1 | //! acknowledgement: adapted from FileCoin Project: https://github.com/filecoin-project/neptune/blob/master/src/preprocessing.rs 2 | 3 | use super::{matrix::vec_add, mds::MdsMatrices}; 4 | use ark_ff::vec::Vec; 5 | use ark_ff::PrimeField; 6 | 7 | // - Compress constants by pushing them back through linear layers and through 8 | // the identity components of partial layers. 9 | // - As a result, constants need only be added after each S-box. 10 | pub(crate) fn compress_round_constants( 11 | width: usize, 12 | full_rounds: usize, 13 | partial_rounds: usize, 14 | round_constants: &Vec, 15 | mds_matrices: &MdsMatrices, 16 | ) -> Vec { 17 | let inverse_matrix = &mds_matrices.m_inv; 18 | 19 | let mut res: Vec = Vec::new(); 20 | 21 | let round_keys = |r: usize| &round_constants[r * width..(r + 1) * width]; 22 | 23 | // This is half full-rounds. 24 | let half_full_rounds = full_rounds / 2; 25 | 26 | // First round constants are unchanged. 27 | res.extend(round_keys(0)); 28 | 29 | // Post S-box adds for the first set of full rounds should be 'inverted' 30 | // from next round. The final round is skipped when fully preprocessing 31 | // because that value must be obtained from the result of preprocessing 32 | // the partial rounds. 33 | let end = half_full_rounds - 1; 34 | for i in 0..end { 35 | let next_round = round_keys(i + 1); 36 | let inverted = inverse_matrix.right_apply(next_round); 37 | res.extend(inverted); 38 | } 39 | 40 | // The plan: 41 | // - Work backwards from last row in this group 42 | // - Invert the row. 43 | // - Save first constant (corresponding to the one S-box performed). 44 | // - Add inverted result to previous row. 45 | // - Repeat until all partial round key rows have been consumed. 46 | // - Extend the preprocessed result by the final resultant row. 47 | // - Move the accumulated list of single round keys to the preprocesed 48 | // result. 49 | // - (Last produced should be first applied, so either pop until empty, or 50 | // reverse and extend, etc.) 51 | 52 | // 'partial_keys' will accumulated the single post-S-box constant for each 53 | // partial-round, in reverse order. 54 | let mut partial_keys: Vec = Vec::new(); 55 | 56 | let final_round = half_full_rounds + partial_rounds; 57 | let final_round_key = round_keys(final_round).to_vec(); 58 | 59 | // 'round_acc' holds the accumulated result of inverting and adding 60 | // subsequent round constants (in reverse). 61 | let round_acc = (0..partial_rounds) 62 | .map(|i| round_keys(final_round - i - 1)) 63 | .fold(final_round_key, |acc, previous_round_keys| { 64 | let mut inverted = inverse_matrix.right_apply(&acc); 65 | 66 | partial_keys.push(inverted[0]); 67 | inverted[0] = F::zero(); 68 | 69 | vec_add(&previous_round_keys, &inverted) 70 | }); 71 | 72 | res.extend(inverse_matrix.right_apply(&round_acc)); 73 | 74 | while let Some(x) = partial_keys.pop() { 75 | res.push(x) 76 | } 77 | 78 | // Post S-box adds for the first set of full rounds should be 'inverted' 79 | // from next round. 80 | for i in 1..(half_full_rounds) { 81 | let start = half_full_rounds + partial_rounds; 82 | let next_round = round_keys(i + start); 83 | let inverted = inverse_matrix.right_apply(next_round); 84 | res.extend(inverted); 85 | } 86 | 87 | res 88 | } 89 | -------------------------------------------------------------------------------- /arkworks/setups/src/utxo.rs: -------------------------------------------------------------------------------- 1 | use crate::keypair::Keypair; 2 | use ark_crypto_primitives::Error; 3 | use ark_ff::PrimeField; 4 | use ark_std::{error::Error as ArkError, rand::RngCore, string::ToString}; 5 | use arkworks_native_gadgets::poseidon::{FieldHasher, Poseidon}; 6 | 7 | #[derive(Debug)] 8 | pub enum UtxoError { 9 | NullifierNotCalculated, 10 | EncryptedDataDecodeError, 11 | IndexNotSet, 12 | } 13 | 14 | impl core::fmt::Display for UtxoError { 15 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 16 | let msg = match self { 17 | UtxoError::NullifierNotCalculated => "Nullifier not calculated".to_string(), 18 | UtxoError::EncryptedDataDecodeError => "Failed to decode encrypted data".to_string(), 19 | &UtxoError::IndexNotSet => "Utxo index not set".to_string(), 20 | }; 21 | write!(f, "{}", msg) 22 | } 23 | } 24 | 25 | impl ArkError for UtxoError {} 26 | 27 | #[derive(Clone)] 28 | pub struct Utxo { 29 | pub chain_id_raw: u64, 30 | pub chain_id: F, 31 | pub amount: F, 32 | pub blinding: F, 33 | pub keypair: Keypair>, 34 | pub index: Option, 35 | pub commitment: F, 36 | } 37 | 38 | impl Utxo { 39 | pub fn new( 40 | chain_id_raw: u64, 41 | amount: F, 42 | index: Option, 43 | private_key: Option, 44 | blinding: Option, 45 | hasher2: &Poseidon, 46 | hasher5: &Poseidon, 47 | rng: &mut R, 48 | ) -> Result { 49 | let chain_id = F::from(chain_id_raw); 50 | let blinding = blinding.unwrap_or(F::rand(rng)); 51 | 52 | let private_key = private_key.unwrap_or(F::rand(rng)); 53 | let keypair = Keypair::new(private_key, hasher2); 54 | 55 | let pub_key = keypair.public_key; 56 | let leaf = hasher5.hash(&[chain_id, amount, pub_key, blinding])?; 57 | 58 | Ok(Self { 59 | chain_id_raw, 60 | chain_id, 61 | amount, 62 | keypair, 63 | blinding, 64 | index, 65 | commitment: leaf, 66 | }) 67 | } 68 | 69 | pub fn new_with_privates( 70 | chain_id_raw: u64, 71 | amount: F, 72 | index: Option, 73 | private_key: F, 74 | blinding: F, 75 | hasher2: &Poseidon, 76 | hasher5: &Poseidon, 77 | ) -> Result { 78 | let chain_id = F::from(chain_id_raw); 79 | let keypair = Keypair::new(private_key, hasher2); 80 | 81 | let pub_key = keypair.public_key; 82 | let leaf = hasher5.hash(&[chain_id, amount, pub_key, blinding])?; 83 | 84 | Ok(Self { 85 | chain_id_raw, 86 | chain_id, 87 | amount, 88 | keypair, 89 | blinding, 90 | index, 91 | commitment: leaf, 92 | }) 93 | } 94 | 95 | pub fn new_with_public( 96 | chain_id_raw: u64, 97 | amount: F, 98 | index: Option, 99 | public_key: F, 100 | blinding: F, 101 | hasher5: &Poseidon, 102 | ) -> Result { 103 | let chain_id = F::from(chain_id_raw); 104 | let keypair = Keypair::new_from_public_key(public_key); 105 | 106 | let commitment = hasher5.hash(&[chain_id, amount, public_key, blinding])?; 107 | 108 | Ok(Self { 109 | chain_id_raw, 110 | chain_id, 111 | amount, 112 | keypair, 113 | blinding, 114 | index, 115 | commitment, 116 | }) 117 | } 118 | 119 | pub fn set_index(&mut self, index: u64) { 120 | self.index = Some(index); 121 | } 122 | 123 | pub fn calculate_nullifier(&self, hasher4: &Poseidon) -> Result { 124 | let index = self.index; 125 | match index { 126 | Some(val) => { 127 | let i = F::from(val); 128 | let signature = self.keypair.signature(&self.commitment, &i, hasher4)?; 129 | let nullifier = hasher4.hash(&[self.commitment, i, signature]); 130 | let nullifier = 131 | nullifier.map_err::(|_| UtxoError::NullifierNotCalculated)?; 132 | Ok(nullifier) 133 | } 134 | None => Err(UtxoError::IndexNotSet.into()), 135 | } 136 | } 137 | 138 | pub fn get_index(&self) -> Result { 139 | self.index.ok_or(UtxoError::IndexNotSet.into()) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /arkworks/setups/src/keypair.rs: -------------------------------------------------------------------------------- 1 | use ark_crypto_primitives::Error; 2 | use ark_ff::PrimeField; 3 | use ark_std::{error::Error as ArkError, marker::PhantomData, string::ToString}; 4 | use arkworks_native_gadgets::poseidon::FieldHasher; 5 | 6 | #[derive(Debug)] 7 | pub enum KeypairError { 8 | EncryptionFailed, 9 | DecryptionFailed, 10 | SecretKeyParseFailed, 11 | DecodeFailed, 12 | EncodeFailed, 13 | } 14 | 15 | impl core::fmt::Display for KeypairError { 16 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 17 | let msg = match self { 18 | KeypairError::EncryptionFailed => "Data encryption failed".to_string(), 19 | KeypairError::DecryptionFailed => "Data decryption failed".to_string(), 20 | KeypairError::SecretKeyParseFailed => "Failed to parse secret key".to_string(), 21 | KeypairError::DecodeFailed => "Failed to decode encrypted data".to_string(), 22 | KeypairError::EncodeFailed => "Failed to encode encrypted data".to_string(), 23 | }; 24 | write!(f, "{}", msg) 25 | } 26 | } 27 | 28 | impl ArkError for KeypairError {} 29 | 30 | #[derive(Default, Debug, Copy)] 31 | pub struct Keypair> { 32 | pub secret_key: Option, 33 | pub public_key: F, 34 | _h: PhantomData, 35 | } 36 | 37 | impl> Keypair { 38 | pub fn new(secret_key: F, hasher: &H) -> Self { 39 | let pubkey = hasher.hash(&[secret_key]).unwrap(); 40 | 41 | Self { 42 | public_key: pubkey, 43 | secret_key: Some(secret_key), 44 | _h: PhantomData, 45 | } 46 | } 47 | 48 | pub fn new_from_keys(public_key: F, secret_key: Option) -> Self { 49 | Self { 50 | public_key, 51 | secret_key, 52 | _h: PhantomData, 53 | } 54 | } 55 | 56 | pub fn new_from_public_key(public_key: F) -> Self { 57 | Self { 58 | public_key, 59 | secret_key: None, 60 | _h: PhantomData, 61 | } 62 | } 63 | 64 | // Computes the signature = hash(secret_key, commitment, pathIndices) 65 | // If the secret_key is not configured on this Keypair, return an error 66 | pub fn signature(&self, commitment: &F, index: &F, hasher4: &H) -> Result { 67 | let res = hasher4.hash(&[self.secret_key.unwrap(), *commitment, *index])?; 68 | Ok(res) 69 | } 70 | } 71 | 72 | impl> Clone for Keypair { 73 | fn clone(&self) -> Self { 74 | match self.secret_key { 75 | Some(secret) => Self::new_from_keys(self.public_key, Some(secret)), 76 | None => Self::new_from_public_key(self.public_key), 77 | } 78 | } 79 | } 80 | 81 | #[cfg(test)] 82 | mod test { 83 | use crate::common::setup_params; 84 | use ark_bn254::Fq; 85 | use ark_std::{test_rng, UniformRand, Zero}; 86 | use arkworks_native_gadgets::poseidon::{FieldHasher, Poseidon}; 87 | use arkworks_utils::Curve; 88 | 89 | use super::Keypair; 90 | 91 | #[test] 92 | fn should_create_new_public_key() { 93 | let rng = &mut test_rng(); 94 | let curve = Curve::Bn254; 95 | 96 | let params = setup_params(curve, 5, 2); 97 | let hasher = Poseidon::::new(params); 98 | let private_key = Fq::rand(rng); 99 | 100 | let pubkey = hasher.hash(&[private_key]).unwrap(); 101 | 102 | let keypair = Keypair::>::new(private_key, &hasher); 103 | let new_pubkey = keypair.public_key; 104 | 105 | assert_eq!(new_pubkey, pubkey) 106 | } 107 | #[test] 108 | fn should_create_new_signature() { 109 | let rng = &mut test_rng(); 110 | let index = Fq::zero(); 111 | let private_key = Fq::rand(rng); 112 | let curve = Curve::Bn254; 113 | // create the hasher which is used for deriving the public key from the private 114 | // key 115 | let params2 = setup_params(curve, 5, 2); 116 | let hasher2 = Poseidon::::new(params2); 117 | 118 | // create the hasher which is used for generating a signature. 119 | let params4 = setup_params(curve, 5, 4); 120 | let hasher4 = Poseidon::::new(params4); 121 | let commitment = Fq::rand(rng); 122 | 123 | let keypair = Keypair::>::new(private_key, &hasher2); 124 | 125 | // Since signature = hash(privKey, commitment, pathIndices) 126 | let ev_res = hasher4.hash(&[private_key, commitment, index]).unwrap(); 127 | let signature = keypair.signature(&commitment, &index, &hasher4).unwrap(); 128 | assert_eq!(ev_res, signature); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /arkworks/setups/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | use ark_std::collections::BTreeMap; 3 | 4 | use ark_crypto_primitives::Error; 5 | use ark_ec::PairingEngine; 6 | use ark_ff::{PrimeField, SquareRootField}; 7 | use ark_std::{ 8 | rand::{CryptoRng, RngCore}, 9 | vec::Vec, 10 | }; 11 | 12 | pub use arkworks_utils::Curve; 13 | use common::{AnchorProof, Leaf, MixerProof, VAnchorProof}; 14 | use utxo::Utxo; 15 | 16 | #[cfg(feature = "aead")] 17 | pub mod aead; 18 | 19 | pub mod common; 20 | pub mod keypair; 21 | pub mod utxo; 22 | 23 | #[cfg(feature = "r1cs")] 24 | pub mod r1cs; 25 | 26 | #[cfg(feature = "plonk")] 27 | pub mod plonk; 28 | 29 | pub trait MixerProver { 30 | // For creating leaves where we supply the secret and the nullifier, for 31 | // generating new values, pass None 32 | fn create_leaf_with_privates( 33 | curve: Curve, 34 | secret: Vec, 35 | nullifier: Vec, 36 | ) -> Result; 37 | /// Create random leaf 38 | fn create_random_leaf(curve: Curve, rng: &mut R) 39 | -> Result; 40 | // For making proofs 41 | fn create_proof( 42 | curve: Curve, 43 | secret: Vec, 44 | nullifier: Vec, 45 | leaves: Vec>, 46 | index: u64, 47 | recipient: Vec, 48 | relayer: Vec, 49 | fee: u128, 50 | refund: u128, 51 | pk: Vec, 52 | default_leaf: [u8; 32], 53 | rng: &mut R, 54 | ) -> Result; 55 | } 56 | 57 | pub trait AnchorProver { 58 | // For creating leaves where we supply the chain_id, secret and the nullifier, 59 | // for generating new values, pass None 60 | fn create_leaf_with_privates( 61 | curve: Curve, 62 | chain_id: u64, 63 | secret: Vec, 64 | nullifier: Vec, 65 | ) -> Result; 66 | /// Create random leaf 67 | fn create_random_leaf( 68 | curve: Curve, 69 | chain_id: u64, 70 | rng: &mut R, 71 | ) -> Result; 72 | // For making proofs 73 | fn create_proof( 74 | curve: Curve, 75 | chain_id: u64, 76 | secret: Vec, 77 | nullifier: Vec, 78 | leaves: Vec>, 79 | index: u64, 80 | root_set: [Vec; ANCHOR_CT], 81 | recipient: Vec, 82 | relayer: Vec, 83 | fee: u128, 84 | refund: u128, 85 | commitment: Vec, 86 | pk: Vec, 87 | default_leaf: [u8; 32], 88 | rng: &mut R, 89 | ) -> Result; 90 | } 91 | 92 | pub trait VAnchorProver< 93 | E: PairingEngine, 94 | const HEIGHT: usize, 95 | const ANCHOR_CT: usize, 96 | const INS: usize, 97 | const OUTS: usize, 98 | > where 99 | ::Fr: PrimeField + SquareRootField + From, 100 | { 101 | fn create_leaf_with_privates( 102 | curve: Curve, 103 | chain_id: u64, 104 | amount: u128, 105 | index: Option, 106 | private_key: Vec, 107 | blinding: Vec, 108 | ) -> Result, Error> { 109 | Self::create_utxo(curve, chain_id, amount, index, private_key, blinding) 110 | } 111 | /// Create random leaf 112 | fn create_random_leaf( 113 | curve: Curve, 114 | chain_id: u64, 115 | amount: u128, 116 | index: Option, 117 | rng: &mut R, 118 | ) -> Result, Error> { 119 | Self::create_random_utxo(curve, chain_id, amount, index, rng) 120 | } 121 | /// For creating UTXO from with secrets already generated 122 | fn create_utxo( 123 | curve: Curve, 124 | chain_id: u64, 125 | amount: u128, 126 | index: Option, 127 | private_key: Vec, 128 | blinding: Vec, 129 | ) -> Result, Error>; 130 | /// For creating UTXO and generating secrets 131 | fn create_random_utxo( 132 | curve: Curve, 133 | chain_id: u64, 134 | amount: u128, 135 | index: Option, 136 | rng: &mut R, 137 | ) -> Result, Error>; 138 | /// For creating UTXO without private key 139 | fn create_public_utxo( 140 | curve: Curve, 141 | chain_id: u64, 142 | amount: u128, 143 | blinding: Vec, 144 | public_key: Vec, 145 | index: Option, 146 | ) -> Result, Error>; 147 | /// For making proofs 148 | fn create_proof( 149 | curve: Curve, 150 | chain_id: u64, 151 | // External data 152 | public_amount: i128, 153 | ext_data_hash: Vec, 154 | in_root_set: [Vec; ANCHOR_CT], 155 | in_indices: [u64; INS], 156 | in_leaves: BTreeMap>>, 157 | // Input transactions 158 | in_utxos: [Utxo; INS], 159 | // Output transactions 160 | out_utxos: [Utxo; OUTS], 161 | pk: Vec, 162 | default_leaf: [u8; 32], 163 | rng: &mut R, 164 | ) -> Result; 165 | } 166 | -------------------------------------------------------------------------------- /arkworks/r1cs-circuits/src/basic.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Webb. 2 | 3 | // Copyright (C) 2021 Webb Technologies Inc. 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | //! Dummy example to show how interfaces should be used 19 | use ark_ff::PrimeField; 20 | use ark_relations::{ 21 | lc, 22 | r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}, 23 | }; 24 | 25 | /// Defines `DummyCircuit` 26 | #[derive(Copy)] 27 | struct DummyCircuit { 28 | pub a: Option, 29 | pub b: Option, 30 | pub num_variables: usize, 31 | pub num_constraints: usize, 32 | } 33 | 34 | /// constructor for DummyCircuit 35 | impl Clone for DummyCircuit { 36 | fn clone(&self) -> Self { 37 | DummyCircuit { 38 | a: self.a, 39 | b: self.b, 40 | num_variables: self.num_variables, 41 | num_constraints: self.num_constraints, 42 | } 43 | } 44 | } 45 | 46 | /// Implementation of the `ConstraintSynthesizer` trait for the `DummyCircuit` 47 | /// https://github.com/arkworks-rs/snark/blob/master/relations/src/r1cs/constraint_system.rs 48 | /// 49 | /// This is the main function that is called by the `R1CS` library to generate 50 | /// the constraints for the `DummyCircuit`. 51 | impl ConstraintSynthesizer for DummyCircuit { 52 | fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { 53 | let a = cs.new_witness_variable(|| self.a.ok_or(SynthesisError::AssignmentMissing))?; 54 | let b = cs.new_witness_variable(|| self.b.ok_or(SynthesisError::AssignmentMissing))?; 55 | let c = cs.new_input_variable(|| { 56 | let a = self.a.ok_or(SynthesisError::AssignmentMissing)?; 57 | let b = self.b.ok_or(SynthesisError::AssignmentMissing)?; 58 | 59 | Ok(a * b) 60 | })?; 61 | 62 | for _ in 0..self.num_constraints { 63 | cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; 64 | } 65 | 66 | Ok(()) 67 | } 68 | } 69 | 70 | #[cfg(test)] 71 | mod test { 72 | use super::*; 73 | use ark_bls12_381::{Bls12_381, Fr as BlsFr}; 74 | use ark_ed_on_bn254::{EdwardsAffine, Fr as BabyJubJub}; 75 | use ark_groth16::Groth16; 76 | use ark_marlin::Marlin; 77 | use ark_poly::univariate::DensePolynomial; 78 | use ark_poly_commit::{ipa_pc::InnerProductArgPC, marlin_pc::MarlinKZG10}; 79 | use ark_snark::SNARK; 80 | use ark_std::{ops::*, UniformRand}; 81 | use blake2::Blake2s; 82 | 83 | #[test] 84 | fn should_verify_basic_circuit() { 85 | let rng = &mut ark_std::test_rng(); 86 | 87 | let nc = 3; 88 | let nv = 3; 89 | let c = DummyCircuit:: { 90 | a: Some(BlsFr::rand(rng)), 91 | b: Some(BlsFr::rand(rng)), 92 | num_variables: nv, 93 | num_constraints: nc, 94 | }; 95 | 96 | type KZG10 = MarlinKZG10>; 97 | type MarlinSetup = Marlin; 98 | 99 | let srs = MarlinSetup::universal_setup(nc, nv, nv, rng).unwrap(); 100 | let (pk, vk) = MarlinSetup::index(&srs, c).unwrap(); 101 | let proof = MarlinSetup::prove(&pk, c.clone(), rng).unwrap(); 102 | 103 | let v = c.a.unwrap().mul(c.b.unwrap()); 104 | 105 | let res = MarlinSetup::verify(&vk, &vec![v], &proof, rng).unwrap(); 106 | assert!(res); 107 | } 108 | 109 | #[test] 110 | fn should_verify_basic_ipa_circuit() { 111 | let rng = &mut ark_std::test_rng(); 112 | 113 | let nc = 3; 114 | let nv = 3; 115 | let c = DummyCircuit:: { 116 | a: Some(BabyJubJub::rand(rng)), 117 | b: Some(BabyJubJub::rand(rng)), 118 | num_variables: nv, 119 | num_constraints: nc, 120 | }; 121 | 122 | type UniPoly = DensePolynomial; 123 | type IPA = InnerProductArgPC; 124 | type MarlinSetup = Marlin; 125 | 126 | let srs = MarlinSetup::universal_setup(nc, nc, nc, rng).unwrap(); 127 | let (pk, vk) = MarlinSetup::index(&srs, c).unwrap(); 128 | let proof = MarlinSetup::prove(&pk, c, rng).unwrap(); 129 | 130 | let v = c.a.unwrap().mul(c.b.unwrap()); 131 | 132 | let res = MarlinSetup::verify(&vk, &vec![v], &proof, rng).unwrap(); 133 | assert!(res); 134 | } 135 | 136 | #[test] 137 | fn should_verify_basic_circuit_groth16() { 138 | let rng = &mut ark_std::test_rng(); 139 | let c = DummyCircuit:: { 140 | a: Some(BlsFr::rand(rng)), 141 | b: Some(BlsFr::rand(rng)), 142 | num_variables: 0, 143 | num_constraints: 3, 144 | }; 145 | 146 | let (pk, vk) = Groth16::::circuit_specific_setup(c, rng).unwrap(); 147 | let proof = Groth16::::prove(&pk, c.clone(), rng).unwrap(); 148 | 149 | let v = c.a.unwrap().mul(c.b.unwrap()); 150 | 151 | let res = Groth16::::verify(&vk, &vec![v], &proof).unwrap(); 152 | assert!(res); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /arkworks/r1cs-circuits/src/mixer.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Webb. 2 | 3 | // Copyright (C) 2021 Webb Technologies Inc. 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | //! The Mixer is a fixed sized deposit/withdraw shielded pool. 19 | //! This is the simplest circuit in arkworks-circuits. 20 | //! It implements a on-chain mixer contract that allows for users to deposit 21 | //! tokens using one wallet and withdraw using another one. This system uses 22 | //! zero-knowledge proofs so no private information about the user gets leaked. 23 | //! 24 | //! Will take inputs and do a merkle tree reconstruction for each node in the 25 | //! path to check if the reconstructed root matches current merkle root. 26 | //! 27 | //! This is the Groth16 setup implementation of the Mixer 28 | use ark_ff::fields::PrimeField; 29 | use ark_r1cs_std::{eq::EqGadget, fields::fp::FpVar, prelude::*}; 30 | use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; 31 | use arkworks_native_gadgets::merkle_tree::Path; 32 | use arkworks_r1cs_gadgets::{merkle_tree::PathVar, poseidon::FieldHasherGadget}; 33 | 34 | /// Defines a `MixerCircuit` struct that hold all the information thats needed 35 | /// to verify the following statement: 36 | 37 | /// * Alice knows a witness tuple `(secret, nullifier, merklePath)` and a 38 | /// commitment `Hash(secret, nullifier)` that is stored in the merkle tree. 39 | /// 40 | /// Needs to implement `ConstraintSynthesizer` and a 41 | /// constructor to generate proper constraints 42 | #[derive(Clone)] 43 | pub struct MixerCircuit, const N: usize> { 44 | // Represents the hash of recepient + relayer + fee + refunds + commitment 45 | arbitrary_input: F, 46 | // Secret 47 | secret: F, 48 | // Nullifier to prevent double spending 49 | nullifier: F, 50 | // Merkle path to transaction 51 | path: Path, 52 | // Merkle root with transaction in it 53 | root: F, 54 | // Nullifier hash to prevent double spending 55 | nullifier_hash: F, 56 | // Hasher to be used inside the circuit 57 | hasher: HG::Native, 58 | } 59 | 60 | /// Constructor for MixerCircuit 61 | impl MixerCircuit 62 | where 63 | F: PrimeField, 64 | HG: FieldHasherGadget, 65 | { 66 | pub fn new( 67 | arbitrary_input: F, 68 | secret: F, 69 | nullifier: F, 70 | path: Path, 71 | root: F, 72 | nullifier_hash: F, 73 | hasher: HG::Native, 74 | ) -> Self { 75 | Self { 76 | arbitrary_input, 77 | secret, 78 | nullifier, 79 | path, 80 | root, 81 | nullifier_hash, 82 | hasher, 83 | } 84 | } 85 | } 86 | /// Implementation of the `ConstraintSynthesizer` trait for the `MixerCircuit` 87 | /// https://github.com/arkworks-rs/snark/blob/master/relations/src/r1cs/constraint_system.rs 88 | /// 89 | /// This is the main function that is called by the `R1CS` library to generate 90 | /// the constraints for the `AnchorCircuit`. 91 | impl ConstraintSynthesizer for MixerCircuit 92 | where 93 | F: PrimeField, 94 | HG: FieldHasherGadget, 95 | { 96 | fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { 97 | let arbitrary_input = self.arbitrary_input; 98 | let secret = self.secret; 99 | let nullifier = self.nullifier; 100 | let path = self.path; 101 | let root = self.root; 102 | let nullifier_hash = self.nullifier_hash; 103 | 104 | // Generating vars 105 | // Public inputs 106 | let nullifier_hash_var = FpVar::::new_input(cs.clone(), || Ok(nullifier_hash))?; 107 | let root_var = FpVar::::new_input(cs.clone(), || Ok(root))?; 108 | let arbitrary_input_var = FpVar::::new_input(cs.clone(), || Ok(arbitrary_input))?; 109 | 110 | // Hashers 111 | let hasher: HG = FieldHasherGadget::::from_native(&mut cs.clone(), self.hasher)?; 112 | 113 | // Private inputs 114 | let secret_var = FpVar::::new_witness(cs.clone(), || Ok(secret))?; 115 | let nullifier_var = FpVar::::new_witness(cs.clone(), || Ok(nullifier))?; 116 | let path_var = PathVar::::new_witness(cs.clone(), || Ok(path))?; 117 | 118 | // Creating the leaf and checking the membership inside the tree 119 | let mixer_leaf_hash: FpVar = hasher.hash_two(&secret_var, &nullifier_var)?; 120 | let mixer_nullifier_hash = hasher.hash_two(&nullifier_var, &nullifier_var)?; 121 | 122 | let is_member = path_var.check_membership(&root_var, &mixer_leaf_hash, &hasher)?; 123 | // Constraining arbitrary inputs 124 | let _ = &arbitrary_input_var * &arbitrary_input_var; 125 | 126 | // Enforcing constraints 127 | is_member.enforce_equal(&Boolean::TRUE)?; 128 | mixer_nullifier_hash.enforce_equal(&nullifier_hash_var)?; 129 | 130 | Ok(()) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /arkworks/r1cs-circuits/src/poseidon.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Webb. 2 | 3 | // Copyright (C) 2021 Webb Technologies Inc. 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | //! Poseidon hasher circuit to prove Hash(a, b) == c 19 | //! 20 | //! This is the Groth16 setup implementation of Poseidon 21 | use ark_ff::PrimeField; 22 | use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, fields::fp::FpVar}; 23 | use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; 24 | use arkworks_r1cs_gadgets::poseidon::FieldHasherGadget; 25 | 26 | #[derive(Copy)] 27 | struct PoseidonCircuit> { 28 | pub a: F, 29 | pub b: F, 30 | pub c: F, 31 | hasher: HG::Native, 32 | } 33 | 34 | /// Constructor for PoseidonCircuit 35 | #[allow(dead_code)] 36 | impl> PoseidonCircuit { 37 | pub fn new(a: F, b: F, c: F, hasher: HG::Native) -> Self { 38 | Self { a, b, c, hasher } 39 | } 40 | } 41 | 42 | impl> Clone for PoseidonCircuit { 43 | fn clone(&self) -> Self { 44 | PoseidonCircuit { 45 | a: self.a, 46 | b: self.b, 47 | c: self.c, 48 | hasher: self.hasher.clone(), 49 | } 50 | } 51 | } 52 | 53 | /// Implementation of the `ConstraintSynthesizer` trait for the 54 | /// `PoseidonCircuit` https://github.com/arkworks-rs/snark/blob/master/relations/src/r1cs/constraint_system.rs 55 | /// 56 | /// This is the main function that is called by the `R1CS` library to generate 57 | /// the constraints for the `PoseidonCircuit`. 58 | impl> ConstraintSynthesizer for PoseidonCircuit { 59 | fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { 60 | let a = FpVar::new_witness(cs.clone(), || Ok(self.a))?; 61 | let b = FpVar::new_witness(cs.clone(), || Ok(self.b))?; 62 | let res_target = FpVar::::new_input(cs.clone(), || Ok(&self.c))?; 63 | let hasher_gadget: HG = FieldHasherGadget::::from_native(&mut cs.clone(), self.hasher)?; 64 | 65 | let res_var = hasher_gadget.hash(&[a, b])?; 66 | 67 | res_var.enforce_equal(&res_target)?; 68 | 69 | Ok(()) 70 | } 71 | } 72 | 73 | #[cfg(test)] 74 | mod test { 75 | use super::*; 76 | use ark_bls12_381::{Bls12_381, Fr as BlsFr}; 77 | use ark_crypto_primitives::SNARK; 78 | use ark_groth16::Groth16; 79 | use ark_marlin::Marlin; 80 | use ark_poly::univariate::DensePolynomial; 81 | use ark_poly_commit::marlin_pc::MarlinKZG10; 82 | use ark_std::UniformRand; 83 | use arkworks_native_gadgets::poseidon::{ 84 | sbox::PoseidonSbox, FieldHasher, Poseidon, PoseidonParameters, 85 | }; 86 | use arkworks_r1cs_gadgets::poseidon::PoseidonGadget; 87 | use arkworks_utils::{ 88 | bytes_matrix_to_f, bytes_vec_to_f, poseidon_params::setup_poseidon_params, Curve, 89 | }; 90 | use blake2::Blake2s; 91 | type PoseidonC = PoseidonCircuit>; 92 | 93 | pub fn setup_params(curve: Curve, exp: i8, width: u8) -> PoseidonParameters { 94 | let pos_data = setup_poseidon_params(curve, exp, width).unwrap(); 95 | 96 | let mds_f = bytes_matrix_to_f(&pos_data.mds); 97 | let rounds_f = bytes_vec_to_f(&pos_data.rounds); 98 | 99 | let pos = PoseidonParameters { 100 | mds_matrix: mds_f, 101 | round_keys: rounds_f, 102 | full_rounds: pos_data.full_rounds, 103 | partial_rounds: pos_data.partial_rounds, 104 | sbox: PoseidonSbox(pos_data.exp), 105 | width: pos_data.width, 106 | }; 107 | 108 | pos 109 | } 110 | 111 | #[test] 112 | fn should_verify_poseidon_circuit() { 113 | let rng = &mut ark_std::test_rng(); 114 | let curve = Curve::Bls381; 115 | 116 | let a = BlsFr::rand(rng); 117 | let b = BlsFr::rand(rng); 118 | let parameters = setup_params(curve, 5, 3); 119 | let hasher = Poseidon::::new(parameters); 120 | 121 | let c = hasher.hash(&[a, b]).unwrap(); 122 | let nc = 3000; 123 | let nv = 2; 124 | let circuit = PoseidonC::new(a, b, c, hasher); 125 | 126 | type KZG10 = MarlinKZG10>; 127 | type MarlinSetup = Marlin; 128 | 129 | let srs = MarlinSetup::universal_setup(nc, nv, nv, rng).unwrap(); 130 | let (pk, vk) = MarlinSetup::index(&srs, circuit.clone()).unwrap(); 131 | let proof = MarlinSetup::prove(&pk, circuit, rng).unwrap(); 132 | 133 | let res = MarlinSetup::verify(&vk, &vec![c], &proof, rng).unwrap(); 134 | assert!(res); 135 | } 136 | 137 | #[test] 138 | fn should_verify_poseidon_circuit_groth16() { 139 | let rng = &mut ark_std::test_rng(); 140 | let curve = Curve::Bls381; 141 | 142 | let a = BlsFr::rand(rng); 143 | let b = BlsFr::rand(rng); 144 | let parameters = setup_params(curve, 5, 3); 145 | let hasher = Poseidon::::new(parameters); 146 | let c = hasher.hash(&[a, b]).unwrap(); 147 | let circuit = PoseidonC::new(a, b, c, hasher); 148 | 149 | type GrothSetup = Groth16; 150 | 151 | let (pk, vk) = GrothSetup::circuit_specific_setup(circuit.clone(), rng).unwrap(); 152 | let proof = GrothSetup::prove(&pk, circuit, rng).unwrap(); 153 | 154 | let res = GrothSetup::verify(&vk, &vec![c], &proof).unwrap(); 155 | assert!(res); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /arkworks/r1cs-gadgets/src/poseidon/mod.rs: -------------------------------------------------------------------------------- 1 | //! A R1CS contraint generation implementation of the Poseidon hash function. 2 | //! 3 | //! For a more through description for poseidon hash refer to 4 | //! [arkworks_native_gadgets::poseidon] 5 | 6 | ///Importing dependencies 7 | use ark_ff::PrimeField; 8 | use ark_r1cs_std::{ 9 | alloc::AllocVar, 10 | fields::{fp::FpVar, FieldVar}, 11 | prelude::*, 12 | }; 13 | use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError}; 14 | use ark_std::{fmt::Debug, vec::Vec}; 15 | use arkworks_native_gadgets::poseidon::{ 16 | sbox::PoseidonSbox, FieldHasher, Poseidon, PoseidonParameters, 17 | }; 18 | 19 | use core::{ 20 | borrow::Borrow, 21 | ops::{Add, AddAssign, Mul}, 22 | }; 23 | 24 | pub mod sbox; 25 | use sbox::SboxConstraints; 26 | 27 | /// FieldHasher gadget for `PrimeFields` 28 | pub trait FieldHasherGadget 29 | where 30 | Self: Sized, 31 | { 32 | type Native: Debug + Clone + FieldHasher; 33 | 34 | // For easy conversion from native version 35 | fn from_native( 36 | cs: &mut ConstraintSystemRef, 37 | native: Self::Native, 38 | ) -> Result; 39 | fn hash(&self, inputs: &[FpVar]) -> Result, SynthesisError>; 40 | fn hash_two(&self, left: &FpVar, right: &FpVar) -> Result, SynthesisError>; 41 | } 42 | 43 | /// Parameters for poseidon hash 44 | #[derive(Default, Clone)] 45 | pub struct PoseidonParametersVar { 46 | /// The round key constants 47 | pub round_keys: Vec>, 48 | /// The MDS matrix to apply in the mix layer. 49 | pub mds_matrix: Vec>>, 50 | /// Number of full SBox rounds 51 | pub full_rounds: u8, 52 | /// Number of partial rounds 53 | pub partial_rounds: u8, 54 | /// The size of the permutation, in field elements. 55 | pub width: u8, 56 | /// The S-box to apply in the sub words layer. 57 | pub sbox: PoseidonSbox, 58 | } 59 | 60 | impl AllocVar, F> for PoseidonParametersVar { 61 | fn new_variable>>( 62 | cs: impl Into>, 63 | f: impl FnOnce() -> Result, 64 | mode: AllocationMode, 65 | ) -> Result { 66 | let params = f()?.borrow().clone(); 67 | let mut round_keys_var = Vec::new(); 68 | let ns = cs.into(); 69 | let cs = ns.cs(); 70 | for rk in params.round_keys { 71 | round_keys_var.push(FpVar::::new_variable(cs.clone(), || Ok(rk), mode)?); 72 | } 73 | let mut mds_var = Vec::new(); 74 | for row in params.mds_matrix { 75 | let mut row_var = Vec::new(); 76 | for mk in row { 77 | row_var.push(FpVar::::new_variable(cs.clone(), || Ok(mk), mode)?); 78 | } 79 | mds_var.push(row_var); 80 | } 81 | let full_rounds = params.full_rounds; 82 | let partial_rounds = params.partial_rounds; 83 | let width = params.width; 84 | let sbox = params.sbox; 85 | 86 | Ok(Self { 87 | round_keys: round_keys_var, 88 | mds_matrix: mds_var, 89 | full_rounds, 90 | partial_rounds, 91 | width, 92 | sbox, 93 | }) 94 | } 95 | } 96 | 97 | #[derive(Default, Clone)] 98 | pub struct PoseidonGadget { 99 | pub params: PoseidonParametersVar, 100 | } 101 | 102 | impl PoseidonGadget { 103 | /// Calculates poseidon permutations of state wrt `PoseidonParametersVar` 104 | pub fn permute(&self, mut state: Vec>) -> Result>, SynthesisError> { 105 | let params = &self.params; 106 | let nr = (params.full_rounds + params.partial_rounds) as usize; 107 | for r in 0..nr { 108 | state.iter_mut().enumerate().for_each(|(i, a)| { 109 | let c = ¶ms.round_keys[(r * (params.width as usize) + i)]; 110 | a.add_assign(c); 111 | }); 112 | 113 | let half_rounds = (params.full_rounds as usize) / 2; 114 | if r < half_rounds || r >= half_rounds + (params.partial_rounds as usize) { 115 | state 116 | .iter_mut() 117 | .try_for_each(|a| params.sbox.synthesize_sbox(a).map(|f| *a = f))?; 118 | } else { 119 | state[0] = params.sbox.synthesize_sbox(&state[0])?; 120 | } 121 | 122 | state = state 123 | .iter() 124 | .enumerate() 125 | .map(|(i, _)| { 126 | state 127 | .iter() 128 | .enumerate() 129 | .fold(FpVar::::zero(), |acc, (j, a)| { 130 | let m = ¶ms.mds_matrix[i][j]; 131 | acc.add(m.mul(a)) 132 | }) 133 | }) 134 | .collect(); 135 | } 136 | Ok(state) 137 | } 138 | } 139 | 140 | impl FieldHasherGadget for PoseidonGadget { 141 | type Native = Poseidon; 142 | 143 | fn from_native( 144 | cs: &mut ConstraintSystemRef, 145 | native: Self::Native, 146 | ) -> Result { 147 | let params = PoseidonParametersVar::new_variable( 148 | cs.clone(), 149 | || Ok(native.params), 150 | AllocationMode::Constant, 151 | )?; 152 | Ok(Self { params }) 153 | } 154 | 155 | /// Calculates poseidon hash of inputs wrt `PoseidonParametersVar` 156 | fn hash(&self, inputs: &[FpVar]) -> Result, SynthesisError> { 157 | let parameters = &self.params; 158 | if inputs.len() >= parameters.width.into() { 159 | panic!( 160 | "incorrect input length {:?} for width {:?} -- input bits {:?}", 161 | inputs.len(), 162 | parameters.width, 163 | inputs.len() 164 | ); 165 | } 166 | 167 | let mut buffer = vec![FpVar::zero(); parameters.width as usize]; 168 | buffer 169 | .iter_mut() 170 | .skip(1) 171 | .zip(inputs) 172 | .for_each(|(a, b)| *a = b.clone()); 173 | let result = self.permute(buffer); 174 | result.map(|x| x.get(0).cloned().ok_or(SynthesisError::AssignmentMissing))? 175 | } 176 | 177 | /// utility function to hash to adjacent leaves together 178 | fn hash_two(&self, left: &FpVar, right: &FpVar) -> Result, SynthesisError> { 179 | self.hash(&[left.clone(), right.clone()]) 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /arkworks/r1cs-circuits/src/anchor.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Webb. 2 | 3 | // Copyright (C) 2021 Webb Technologies Inc. 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | //! The Anchor is a cross-chain fixed sized deposit/withdraw shielded pool. 19 | //! It allows for users to deposit tokens on one chain and withdraw in another 20 | //! one without linking the deposit to the withdrawal. 21 | 22 | //! We will take inputs and do a merkle tree reconstruction for each node in the 23 | //! path and check if the reconstructed root is inside the current root set. 24 | //! 25 | //! This is the Groth16 setup implementation of Anchor 26 | use ark_ff::fields::PrimeField; 27 | use ark_r1cs_std::{eq::EqGadget, fields::fp::FpVar, prelude::*}; 28 | use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; 29 | use ark_std::vec::Vec; 30 | use arkworks_native_gadgets::merkle_tree::Path; 31 | use arkworks_r1cs_gadgets::{merkle_tree::PathVar, poseidon::FieldHasherGadget, set::SetGadget}; 32 | 33 | /// Defines an `AnchorCircuit` struct that hold all the information thats needed 34 | /// to verify the following statements: 35 | /// * Alice knows a witness tuple `(secret, nullifier, merklePath)` 36 | /// and a commitment `Hash(chain_id, nullifier, secret)` stored in one of the 37 | /// Anchor merkle trees, 38 | /// * The Anchor smart contract / end-user application hasn't seen this 39 | /// `nullifier_hash` before. 40 | /// 41 | /// Needs to implement `ConstraintSynthesizer` and a 42 | /// constructor to generate proper constraints 43 | #[derive(Clone)] 44 | pub struct AnchorCircuit, const N: usize, const M: usize> { 45 | // Represents the hash of 46 | // recepient + relayer + fee + refunds + commitment 47 | arbitrary_input: F, 48 | // secret 49 | secret: F, 50 | // nullifier to prevent double spending 51 | nullifier: F, 52 | // source chain_id 53 | chain_id: F, 54 | // Merkle root set to use on one-of-many proof 55 | root_set: [F; M], 56 | // Merkle path to transaction 57 | path: Path, 58 | nullifier_hash: F, 59 | // 3 input hasher 60 | hasher3: HG::Native, 61 | // 4 input hasher 62 | hasher4: HG::Native, 63 | } 64 | 65 | /// A constructor for the `AnchorCircuit` 66 | impl AnchorCircuit 67 | where 68 | F: PrimeField, 69 | HG: FieldHasherGadget, 70 | { 71 | #[allow(clippy::too_many_arguments)] 72 | pub fn new( 73 | arbitrary_input: F, 74 | secret: F, 75 | nullifier: F, 76 | chain_id: F, 77 | root_set: [F; M], 78 | path: Path, 79 | nullifier_hash: F, 80 | hasher3: HG::Native, 81 | hasher4: HG::Native, 82 | ) -> Self { 83 | Self { 84 | arbitrary_input, 85 | secret, 86 | nullifier, 87 | chain_id, 88 | root_set, 89 | path, 90 | nullifier_hash, 91 | hasher3, 92 | hasher4, 93 | } 94 | } 95 | } 96 | 97 | /// Implementation of the `ConstraintSynthesizer` trait for the `AnchorCircuit` 98 | /// https://github.com/arkworks-rs/snark/blob/master/relations/src/r1cs/constraint_system.rs 99 | /// 100 | /// This is the main function that is called by the `R1CS` library to generate 101 | /// the constraints for the `AnchorCircuit`. 102 | impl ConstraintSynthesizer for AnchorCircuit 103 | where 104 | F: PrimeField, 105 | HG: FieldHasherGadget, 106 | { 107 | fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { 108 | let arbitrary_input = self.arbitrary_input; 109 | let secret = self.secret; 110 | let nullifier = self.nullifier; 111 | let chain_id = self.chain_id; 112 | let root_set = self.root_set; 113 | let path = self.path; 114 | let nullifier_hash = self.nullifier_hash; 115 | 116 | // Generating vars 117 | // Public inputs 118 | let nullifier_hash_var = FpVar::::new_input(cs.clone(), || Ok(nullifier_hash))?; 119 | let arbitrary_input_var = FpVar::::new_input(cs.clone(), || Ok(arbitrary_input))?; 120 | let chain_id_var = FpVar::::new_input(cs.clone(), || Ok(chain_id))?; 121 | let roots_var = Vec::>::new_input(cs.clone(), || Ok(root_set))?; 122 | 123 | // Hashers 124 | let hasher3_gadget: HG = 125 | FieldHasherGadget::::from_native(&mut cs.clone(), self.hasher3)?; 126 | let hasher4_gadget: HG = 127 | FieldHasherGadget::::from_native(&mut cs.clone(), self.hasher4)?; 128 | 129 | // Private inputs 130 | let secret_var = FpVar::::new_witness(cs.clone(), || Ok(secret))?; 131 | let nullifier_var = FpVar::::new_witness(cs.clone(), || Ok(nullifier))?; 132 | let path_var = PathVar::::new_witness(cs.clone(), || Ok(path))?; 133 | 134 | // Creating the leaf and checking the membership inside the tree 135 | let anchor_leaf = 136 | hasher4_gadget.hash(&[chain_id_var, nullifier_var.clone(), secret_var])?; 137 | let anchor_nullifier = hasher3_gadget.hash_two(&nullifier_var, &nullifier_var)?; 138 | let root_var = path_var.root_hash(&anchor_leaf, &hasher3_gadget)?; 139 | // Check if target root is in set 140 | let set_gadget = SetGadget::new(roots_var); 141 | let is_set_member = set_gadget.check_membership(&root_var)?; 142 | // Constraining arbitrary inputs 143 | let _ = &arbitrary_input_var * &arbitrary_input_var; 144 | 145 | // Enforcing constraints 146 | is_set_member.enforce_equal(&Boolean::TRUE)?; 147 | anchor_nullifier.enforce_equal(&nullifier_hash_var)?; 148 | 149 | Ok(()) 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /arkworks/r1cs-gadgets/src/set.rs: -------------------------------------------------------------------------------- 1 | use crate::Vec; 2 | use ark_ff::fields::PrimeField; 3 | use ark_r1cs_std::{ 4 | eq::EqGadget, 5 | fields::{fp::FpVar, FieldVar}, 6 | prelude::*, 7 | }; 8 | use ark_relations::r1cs::SynthesisError; 9 | 10 | pub struct SetGadget { 11 | set: Vec>, 12 | } 13 | 14 | impl SetGadget { 15 | pub fn new(set: Vec>) -> Self { 16 | Self { set } 17 | } 18 | 19 | /// Calculates product between (set_element - target) for every set_element. 20 | /// Outputs 0 iff `set_element == target` for at least one element of the 21 | /// set. This is an utility function to prove membership of a merkle_root in 22 | /// a set of merkle_roots 23 | pub fn calculate_product>( 24 | &self, 25 | target: &T, 26 | ) -> Result, SynthesisError> { 27 | let target = Boolean::le_bits_to_fp_var(&target.to_bytes()?.to_bits_le()?)?; 28 | // Calculating the diffs inside the circuit 29 | let mut diffs = Vec::new(); 30 | for item in &self.set { 31 | diffs.push(item - &target); 32 | } 33 | 34 | // Checking the membership 35 | let mut product = 36 | FpVar::::new_variable(target.cs(), || Ok(F::one()), AllocationMode::Constant)?; 37 | for diff in diffs.iter() { 38 | product *= diff; 39 | } 40 | 41 | Ok(product) 42 | } 43 | 44 | /// Checks if target is present in the set 45 | pub fn check_membership>( 46 | &self, 47 | target: &T, 48 | ) -> Result, SynthesisError> { 49 | let product = self.calculate_product(target)?; 50 | 51 | product.is_eq(&FpVar::::zero()) 52 | } 53 | 54 | pub fn check_membership_enabled>( 55 | &self, 56 | target: &T, 57 | is_enabled: &FpVar, 58 | ) -> Result, SynthesisError> { 59 | let mut product = self.calculate_product(target)?; 60 | 61 | product *= is_enabled; 62 | product.is_eq(&FpVar::::zero()) 63 | } 64 | } 65 | 66 | #[cfg(test)] 67 | mod test { 68 | use super::*; 69 | use ark_bls12_381::Fr; 70 | use ark_relations::r1cs::ConstraintSystem; 71 | 72 | #[test] 73 | fn should_verify_set_membership() { 74 | let cs = ConstraintSystem::::new_ref(); 75 | 76 | let set = vec![Fr::from(1u32), Fr::from(2u32), Fr::from(3u32)]; 77 | let target = Fr::from(1u32); 78 | let target_var = FpVar::::new_input(cs.clone(), || Ok(target)).unwrap(); 79 | let set_var = Vec::>::new_input(cs.clone(), || Ok(set)).unwrap(); 80 | 81 | let set_gadget = SetGadget::new(set_var); 82 | let is_member = set_gadget.check_membership(&target_var).unwrap(); 83 | 84 | is_member.enforce_equal(&Boolean::TRUE).unwrap(); 85 | 86 | assert!(cs.is_satisfied().unwrap()); 87 | } 88 | 89 | #[test] 90 | fn should_not_verify_set_non_membership() { 91 | let cs = ConstraintSystem::::new_ref(); 92 | 93 | let set = vec![Fr::from(1u32), Fr::from(2u32), Fr::from(3u32)]; 94 | let target = Fr::from(4u32); 95 | let target_var = FpVar::::new_input(cs.clone(), || Ok(target)).unwrap(); 96 | let set_var = Vec::>::new_input(cs.clone(), || Ok(set)).unwrap(); 97 | 98 | let set_gadget = SetGadget::new(set_var); 99 | let is_member = set_gadget.check_membership(&target_var).unwrap(); 100 | 101 | is_member.enforce_equal(&Boolean::TRUE).unwrap(); 102 | 103 | assert!(!cs.is_satisfied().unwrap()); 104 | } 105 | 106 | #[test] 107 | fn should_verify_set_membership_if_enabled() { 108 | let cs = ConstraintSystem::::new_ref(); 109 | 110 | // enable == 1 == true 111 | let enabled = Fr::from(1u32); 112 | let set = vec![Fr::from(1u32), Fr::from(2u32), Fr::from(3u32)]; 113 | let target = Fr::from(1u32); 114 | 115 | let enabled_var = FpVar::::new_input(cs.clone(), || Ok(enabled)).unwrap(); 116 | let target_var = FpVar::::new_input(cs.clone(), || Ok(target)).unwrap(); 117 | let set_var = Vec::>::new_input(cs.clone(), || Ok(set)).unwrap(); 118 | 119 | let set_gadget = SetGadget::new(set_var); 120 | let is_member = set_gadget 121 | .check_membership_enabled(&target_var, &enabled_var) 122 | .unwrap(); 123 | 124 | is_member.enforce_equal(&Boolean::TRUE).unwrap(); 125 | 126 | assert!(cs.is_satisfied().unwrap()); 127 | } 128 | 129 | #[test] 130 | fn should_not_verify_non_set_membership_if_enabled() { 131 | let cs = ConstraintSystem::::new_ref(); 132 | 133 | // enable == 1 == true 134 | // Set gadget now functions normally, meaning it values that are not in the set 135 | // will yeald to false 136 | let enabled = Fr::from(1u32); 137 | let set = vec![Fr::from(1u32), Fr::from(2u32), Fr::from(3u32)]; 138 | let target = Fr::from(4u32); 139 | 140 | let enabled_var = FpVar::::new_input(cs.clone(), || Ok(enabled)).unwrap(); 141 | let target_var = FpVar::::new_input(cs.clone(), || Ok(target)).unwrap(); 142 | let set_var = Vec::>::new_input(cs.clone(), || Ok(set)).unwrap(); 143 | 144 | let set_gadget = SetGadget::new(set_var); 145 | let is_member = set_gadget 146 | .check_membership_enabled(&target_var, &enabled_var) 147 | .unwrap(); 148 | 149 | is_member.enforce_equal(&Boolean::TRUE).unwrap(); 150 | 151 | assert!(!cs.is_satisfied().unwrap()); 152 | } 153 | 154 | #[test] 155 | fn should_verify_set_membership_if_not_enabled() { 156 | let cs = ConstraintSystem::::new_ref(); 157 | 158 | // enable == 0 == false 159 | // Which means everything will evaluate to true, meaning it is in the set 160 | let enabled = Fr::from(0u32); 161 | let set = vec![Fr::from(1u32), Fr::from(2u32), Fr::from(3u32)]; 162 | let target = Fr::from(4u32); 163 | 164 | let enabled_var = FpVar::::new_input(cs.clone(), || Ok(enabled)).unwrap(); 165 | let target_var = FpVar::::new_input(cs.clone(), || Ok(target)).unwrap(); 166 | let set_var = Vec::>::new_input(cs.clone(), || Ok(set)).unwrap(); 167 | 168 | let set_gadget = SetGadget::new(set_var); 169 | let is_member = set_gadget 170 | .check_membership_enabled(&target_var, &enabled_var) 171 | .unwrap(); 172 | 173 | is_member.enforce_equal(&Boolean::TRUE).unwrap(); 174 | 175 | assert!(cs.is_satisfied().unwrap()); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /arkworks/plonk-hashing/src/poseidon/round_constant.rs: -------------------------------------------------------------------------------- 1 | use alloc::collections::vec_deque::VecDeque; 2 | use ark_ff::{BigInteger, PrimeField}; 3 | /// From the paper 4 | /// THe parameter describes the initial state of constant generation (80-bits) 5 | /// * `field`: description of field. b0, b1 6 | /// * `sbox`: description of s-box. b2..=b5 7 | /// * `field_size`: binary representation of field size. b6..=b17 8 | /// * `t`: binary representation of t. b18..=b29 9 | /// * `rf`: binary representation of rf. b30..=b39 10 | /// * `rp`: binary representation of rp. b40..=b49 11 | /// * `ones`: set to 1. b50..=b79 12 | pub fn generate_constants( 13 | field: u8, 14 | sbox: u8, 15 | field_size: u16, 16 | t: u16, 17 | r_f: u16, 18 | r_p: u16, 19 | ) -> Vec { 20 | let n_bytes = (F::size_in_bits() + 8 - 1) / 8; 21 | if n_bytes != 32 { 22 | unimplemented!("neptune currently supports 32-byte fields exclusively"); 23 | }; 24 | assert_eq!((field_size as f32 / 8.0).ceil() as usize, n_bytes); 25 | 26 | // r_f here is 2* number of *half* full rounds. 27 | let num_constants = (r_f + r_p) * t; 28 | let mut init_sequence: VecDeque = VecDeque::new(); 29 | append_bits(&mut init_sequence, 2, field); // Bits 0-1 30 | append_bits(&mut init_sequence, 4, sbox); // Bits 2-5 31 | append_bits(&mut init_sequence, 12, field_size); // Bits 6-17 32 | append_bits(&mut init_sequence, 12, t); // Bits 18-29 33 | append_bits(&mut init_sequence, 10, r_f); // Bits 30-39 34 | append_bits(&mut init_sequence, 10, r_p); // Bits 40-49 35 | append_bits(&mut init_sequence, 30, 0b111111111111111111111111111111u128); // Bits 50-79 36 | 37 | let mut grain = GrainLFSR::new(init_sequence, field_size); 38 | let mut round_constants: Vec = Vec::new(); 39 | 40 | match field { 41 | 1 => { 42 | for _ in 0..num_constants { 43 | while { 44 | // TODO: Please review this part. May be different from 45 | // neptune. 46 | 47 | // Generate 32 bytes and interpret them as a big-endian 48 | // integer. Bytes are big-endian to 49 | // agree with the integers generated by grain_random_bits in 50 | // the reference implementation: 51 | // 52 | // def grain_random_bits(num_bits): 53 | // random_bits = [grain_gen.next() for i in range(0, 54 | // num_bits)] random_int = 55 | // int("".join(str(i) for i in random_bits), 2) 56 | // return random_int 57 | let mut repr = F::default().into_repr().to_bytes_be(); 58 | grain.get_next_bytes(repr.as_mut()); 59 | repr.reverse(); 60 | if let Some(f) = F::from_random_bytes(&repr) { 61 | round_constants.push(f); 62 | false 63 | } else { 64 | true 65 | } 66 | } {} 67 | } 68 | } 69 | _ => { 70 | panic!("Only prime fields are supported."); 71 | } 72 | } 73 | round_constants 74 | } 75 | 76 | fn append_bits>(vec: &mut VecDeque, n: usize, from: T) { 77 | let val = from.into() as u128; 78 | for i in (0..n).rev() { 79 | vec.push_back((val >> i) & 1 != 0); 80 | } 81 | } 82 | 83 | // adapted from: https://github.com/filecoin-project/neptune/blob/master/src/round_constants.rs 84 | struct GrainLFSR { 85 | state: VecDeque, 86 | field_size: u16, 87 | } 88 | 89 | impl GrainLFSR { 90 | pub fn new(initial_sequence: VecDeque, field_size: u16) -> Self { 91 | assert_eq!( 92 | initial_sequence.len(), 93 | 80, 94 | "Initial Sequence must be 80 bits" 95 | ); 96 | let mut g = GrainLFSR { 97 | state: initial_sequence, 98 | field_size, 99 | }; 100 | (0..160).for_each(|_| { 101 | g.generate_new_bit(); 102 | }); 103 | assert_eq!(80, g.state.len()); 104 | g 105 | } 106 | 107 | fn generate_new_bit(&mut self) -> bool { 108 | let new_bit = self.bit(62) 109 | ^ self.bit(51) 110 | ^ self.bit(38) 111 | ^ self.bit(23) 112 | ^ self.bit(13) 113 | ^ self.bit(0); 114 | self.state.pop_front(); 115 | self.state.push_back(new_bit); 116 | new_bit 117 | } 118 | 119 | fn bit(&self, index: usize) -> bool { 120 | self.state[index] 121 | } 122 | 123 | fn next_byte(&mut self, bit_count: usize) -> u8 { 124 | // Accumulate bits from most to least significant, so the most 125 | // significant bit is the one generated first by the bit stream 126 | let mut acc: u8 = 0; 127 | self.take(bit_count).for_each(|bit| { 128 | acc <<= 1; 129 | if bit { 130 | acc += 1; 131 | } 132 | }); 133 | 134 | acc 135 | } 136 | 137 | fn get_next_bytes(&mut self, result: &mut [u8]) { 138 | let remainder_bits = self.field_size as usize % 8; 139 | // Prime fields will always have remainder bits, 140 | // but other field types could be supported in the future. 141 | if remainder_bits > 0 { 142 | // If there is an unfull byte, it should be the first. 143 | // Subsequent bytes are packed into result in the order generated. 144 | result[0] = self.next_byte(remainder_bits); 145 | } else { 146 | result[0] = self.next_byte(8); 147 | } 148 | 149 | // First byte is already set 150 | for item in result.iter_mut().skip(1) { 151 | *item = self.next_byte(8) 152 | } 153 | } 154 | } 155 | 156 | impl Iterator for GrainLFSR { 157 | type Item = bool; 158 | 159 | // TO BE checked 160 | fn next(&mut self) -> Option { 161 | let mut new_bit = self.generate_new_bit(); 162 | while !new_bit { 163 | let _new_bit = self.generate_new_bit(); 164 | new_bit = self.generate_new_bit(); 165 | } 166 | new_bit = self.generate_new_bit(); 167 | Some(new_bit) 168 | } 169 | } 170 | 171 | // TODO: TO BE TESTED! 172 | -------------------------------------------------------------------------------- /arkworks/setups/src/common.rs: -------------------------------------------------------------------------------- 1 | use ark_crypto_primitives::{Error, SNARK}; 2 | use ark_ec::PairingEngine; 3 | use ark_ff::fields::PrimeField; 4 | use ark_groth16::{Groth16, Proof, ProvingKey, VerifyingKey}; 5 | use ark_relations::r1cs::ConstraintSynthesizer; 6 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; 7 | use ark_std::{ 8 | collections::BTreeMap, 9 | rand::{CryptoRng, RngCore}, 10 | vec::Vec, 11 | }; 12 | use arkworks_native_gadgets::{ 13 | merkle_tree::{Path, SparseMerkleTree}, 14 | poseidon::{sbox::PoseidonSbox, FieldHasher, PoseidonParameters}, 15 | }; 16 | use arkworks_utils::{ 17 | bytes_matrix_to_f, bytes_vec_to_f, poseidon_params::setup_poseidon_params, Curve, 18 | }; 19 | use tiny_keccak::{Hasher, Keccak}; 20 | 21 | pub struct VAnchorLeaf { 22 | pub chain_id_bytes: Vec, 23 | pub amount: u128, 24 | pub public_key_bytes: Vec, 25 | pub blinding_bytes: Vec, 26 | pub index: u32, 27 | pub private_key_bytes: Vec, 28 | pub nullifier_bytes: Vec, 29 | pub leaf_bytes: Vec, 30 | pub nullifier_hash_bytes: Vec, 31 | } 32 | 33 | pub struct Leaf { 34 | pub chain_id_bytes: Option>, 35 | pub secret_bytes: Vec, 36 | pub nullifier_bytes: Vec, 37 | pub leaf_bytes: Vec, 38 | pub nullifier_hash_bytes: Vec, 39 | } 40 | 41 | pub struct VAnchorProof { 42 | pub proof: Vec, 43 | pub public_inputs_raw: Vec>, 44 | } 45 | 46 | pub struct AnchorProof { 47 | pub proof: Vec, 48 | pub leaf_raw: Vec, 49 | pub nullifier_hash_raw: Vec, 50 | pub roots_raw: Vec>, 51 | pub public_inputs_raw: Vec>, 52 | } 53 | 54 | pub struct MixerProof { 55 | pub proof: Vec, 56 | pub leaf_raw: Vec, 57 | pub nullifier_hash_raw: Vec, 58 | pub root_raw: Vec, 59 | pub public_inputs_raw: Vec>, 60 | } 61 | 62 | pub struct Keys { 63 | pub pk: Vec, 64 | pub vk: Vec, 65 | } 66 | 67 | pub fn setup_keys>( 68 | circuit: C, 69 | rng: &mut R, 70 | ) -> Result<(Vec, Vec), Error> { 71 | let (pk, vk) = Groth16::::circuit_specific_setup(circuit, rng)?; 72 | 73 | let mut pk_bytes = Vec::new(); 74 | let mut vk_bytes = Vec::new(); 75 | pk.serialize(&mut pk_bytes)?; 76 | vk.serialize(&mut vk_bytes)?; 77 | Ok((pk_bytes, vk_bytes)) 78 | } 79 | 80 | pub fn setup_keys_unchecked< 81 | E: PairingEngine, 82 | R: RngCore + CryptoRng, 83 | C: ConstraintSynthesizer, 84 | >( 85 | circuit: C, 86 | rng: &mut R, 87 | ) -> Result<(Vec, Vec), Error> { 88 | let (pk, vk) = Groth16::::circuit_specific_setup(circuit, rng)?; 89 | 90 | let mut pk_bytes = Vec::new(); 91 | let mut vk_bytes = Vec::new(); 92 | pk.serialize_unchecked(&mut pk_bytes)?; 93 | vk.serialize_unchecked(&mut vk_bytes)?; 94 | Ok((pk_bytes, vk_bytes)) 95 | } 96 | 97 | pub fn prove>( 98 | circuit: C, 99 | pk_bytes: &[u8], 100 | rng: &mut R, 101 | ) -> Result, Error> { 102 | let pk = ProvingKey::::deserialize(pk_bytes)?; 103 | 104 | let proof = Groth16::prove(&pk, circuit, rng)?; 105 | let mut proof_bytes = Vec::new(); 106 | proof.serialize(&mut proof_bytes)?; 107 | Ok(proof_bytes) 108 | } 109 | 110 | pub fn prove_unchecked< 111 | E: PairingEngine, 112 | R: RngCore + CryptoRng, 113 | C: ConstraintSynthesizer, 114 | >( 115 | circuit: C, 116 | pk_unchecked_bytes: &[u8], 117 | rng: &mut R, 118 | ) -> Result, Error> { 119 | let pk = ProvingKey::::deserialize_unchecked(pk_unchecked_bytes)?; 120 | 121 | let proof = Groth16::prove(&pk, circuit, rng)?; 122 | let mut proof_bytes = Vec::new(); 123 | proof.serialize(&mut proof_bytes)?; 124 | Ok(proof_bytes) 125 | } 126 | 127 | pub fn verify( 128 | public_inputs: &[E::Fr], 129 | vk_bytes: &[u8], 130 | proof: &[u8], 131 | ) -> Result { 132 | let vk = VerifyingKey::::deserialize(vk_bytes)?; 133 | let proof = Proof::::deserialize(proof)?; 134 | verify_groth16(&vk, public_inputs, &proof) 135 | } 136 | 137 | pub fn verify_unchecked( 138 | public_inputs: &[E::Fr], 139 | vk_unchecked_bytes: &[u8], 140 | proof: &[u8], 141 | ) -> Result { 142 | let vk = VerifyingKey::::deserialize_unchecked(vk_unchecked_bytes)?; 143 | let proof = Proof::::deserialize(proof)?; 144 | verify_groth16(&vk, public_inputs, &proof) 145 | } 146 | 147 | pub fn verify_unchecked_raw( 148 | public_inputs: &[Vec], 149 | vk_unchecked_bytes: &[u8], 150 | proof: &[u8], 151 | ) -> Result { 152 | let pub_ins: Vec = public_inputs 153 | .iter() 154 | .map(|x| E::Fr::from_be_bytes_mod_order(x)) 155 | .collect(); 156 | let vk = VerifyingKey::::deserialize_unchecked(vk_unchecked_bytes)?; 157 | let proof = Proof::::deserialize(proof)?; 158 | verify_groth16(&vk, &pub_ins, &proof) 159 | } 160 | 161 | pub fn verify_groth16( 162 | vk: &VerifyingKey, 163 | public_inputs: &[E::Fr], 164 | proof: &Proof, 165 | ) -> Result { 166 | let res = Groth16::::verify(vk, public_inputs, proof)?; 167 | Ok(res) 168 | } 169 | 170 | pub fn keccak_256(input: &[u8]) -> Vec { 171 | let mut keccak = Keccak::v256(); 172 | keccak.update(input); 173 | 174 | let mut output = [0u8; 32]; 175 | keccak.finalize(&mut output); 176 | output.to_vec() 177 | } 178 | 179 | pub type SMT = SparseMerkleTree; 180 | 181 | pub fn create_merkle_tree, const N: usize>( 182 | hasher: &H, 183 | leaves: &[F], 184 | default_leaf: &[u8], 185 | ) -> SparseMerkleTree { 186 | let pairs: BTreeMap = leaves 187 | .iter() 188 | .enumerate() 189 | .map(|(i, l)| (i as u32, *l)) 190 | .collect(); 191 | let smt = SparseMerkleTree::::new(&pairs, hasher, default_leaf).unwrap(); 192 | 193 | smt 194 | } 195 | 196 | pub fn setup_tree_and_create_path, const HEIGHT: usize>( 197 | hasher: &H, 198 | leaves: &[F], 199 | index: u64, 200 | default_leaf: &[u8], 201 | ) -> Result<(SMT, Path), Error> { 202 | // Making the merkle tree 203 | let smt = create_merkle_tree::(hasher, leaves, default_leaf); 204 | // Getting the proof path 205 | let path = smt.generate_membership_proof(index); 206 | Ok((smt, path)) 207 | } 208 | 209 | pub fn setup_params(curve: Curve, exp: i8, width: u8) -> PoseidonParameters { 210 | let pos_data = setup_poseidon_params(curve, exp, width).unwrap(); 211 | 212 | let mds_f = bytes_matrix_to_f(&pos_data.mds); 213 | let rounds_f = bytes_vec_to_f(&pos_data.rounds); 214 | 215 | PoseidonParameters { 216 | mds_matrix: mds_f, 217 | round_keys: rounds_f, 218 | full_rounds: pos_data.full_rounds, 219 | partial_rounds: pos_data.partial_rounds, 220 | sbox: PoseidonSbox(pos_data.exp), 221 | width: pos_data.width, 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /arkworks/native-gadgets/src/mimc.rs: -------------------------------------------------------------------------------- 1 | use crate::ark_std::string::ToString; 2 | use ark_crypto_primitives::{crh::TwoToOneCRH, Error, CRH as CRHTrait}; 3 | use ark_ff::{fields::PrimeField, BigInteger}; 4 | use ark_std::{error::Error as ArkError, marker::PhantomData, rand::Rng, vec::Vec}; 5 | 6 | use super::to_field_elements; 7 | 8 | #[derive(Debug)] 9 | pub enum MiMCError { 10 | InvalidInputs, 11 | } 12 | 13 | impl core::fmt::Display for MiMCError { 14 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 15 | use MiMCError::*; 16 | let msg = match self { 17 | InvalidInputs => "invalid inputs".to_string(), 18 | }; 19 | write!(f, "{}", msg) 20 | } 21 | } 22 | 23 | impl ArkError for MiMCError {} 24 | 25 | #[derive(Default, Clone)] 26 | pub struct MiMCParameters { 27 | pub k: F, 28 | pub rounds: usize, 29 | pub num_inputs: usize, 30 | pub num_outputs: usize, 31 | pub round_keys: Vec, 32 | } 33 | 34 | impl MiMCParameters { 35 | pub fn new( 36 | k: F, 37 | rounds: usize, 38 | num_inputs: usize, 39 | num_outputs: usize, 40 | round_keys: Vec, 41 | ) -> Self { 42 | Self { 43 | k, 44 | rounds, 45 | num_inputs, 46 | num_outputs, 47 | round_keys, 48 | } 49 | } 50 | 51 | pub fn generate(rng: &mut R) -> Self { 52 | Self { 53 | round_keys: Self::create_round_keys(rng), 54 | rounds: 220, 55 | k: F::zero(), 56 | num_inputs: 2, 57 | num_outputs: 1, 58 | } 59 | } 60 | 61 | pub fn create_round_keys(_rng: &mut R) -> Vec { 62 | todo!(); 63 | } 64 | } 65 | 66 | pub trait Rounds: Default + Clone { 67 | /// The size of the input vector 68 | const WIDTH: u8; 69 | /// Number of mimc rounds 70 | const ROUNDS: u16; 71 | } 72 | 73 | pub struct CRH { 74 | field: PhantomData, 75 | rounds: PhantomData

, 76 | } 77 | 78 | impl CRH { 79 | fn mimc(params: &MiMCParameters, state: Vec) -> Result, MiMCError> { 80 | assert!(state.len() == params.num_inputs); 81 | let mut l_out: F = F::zero(); 82 | let mut r_out: F = F::zero(); 83 | for (i, s) in state.iter().enumerate() { 84 | let l: F; 85 | let r: F; 86 | if i == 0 { 87 | l = *s; 88 | r = F::zero(); 89 | } else { 90 | l = l_out + s; 91 | r = r_out; 92 | } 93 | 94 | let res = Self::feistel(params, l, r)?; 95 | l_out = res[0]; 96 | r_out = res[1]; 97 | } 98 | 99 | let mut outs = vec![l_out]; 100 | for _ in 0..params.num_outputs { 101 | let res = Self::feistel(params, l_out, r_out)?; 102 | l_out = res[0]; 103 | r_out = res[1]; 104 | outs.push(l_out); 105 | } 106 | 107 | Ok(outs) 108 | } 109 | 110 | fn feistel(params: &MiMCParameters, left: F, right: F) -> Result<[F; 2], MiMCError> { 111 | let mut x_l = left; 112 | let mut x_r = right; 113 | let mut c: F; 114 | let mut t: F; 115 | let mut t2: F; 116 | let mut t4: F; 117 | for i in 0..params.rounds { 118 | c = if i == 0 || i == params.rounds - 1 { 119 | F::zero() 120 | } else { 121 | params.round_keys[i - 1] 122 | }; 123 | t = if i == 0 { 124 | params.k + x_l 125 | } else { 126 | params.k + x_l + c 127 | }; 128 | 129 | t2 = t * t; 130 | t4 = t2 * t2; 131 | 132 | let temp_x_l = x_l; 133 | let temp_x_r = x_r; 134 | 135 | if i < params.rounds - 1 { 136 | x_l = if i == 0 { 137 | temp_x_r 138 | } else { 139 | temp_x_r + (t4 * t) 140 | }; 141 | 142 | x_r = temp_x_l; 143 | } else { 144 | x_r = temp_x_r + (t4 * t); 145 | x_l = temp_x_l; 146 | } 147 | } 148 | 149 | Ok([x_l, x_r]) 150 | } 151 | } 152 | 153 | impl CRHTrait for CRH { 154 | type Output = F; 155 | type Parameters = MiMCParameters; 156 | 157 | const INPUT_SIZE_BITS: usize = F::BigInt::NUM_LIMBS * 8 * P::WIDTH as usize * 8; 158 | 159 | // Not sure what's the purpose of this function of we are going to pass 160 | // parameters 161 | fn setup(rng: &mut R) -> Result { 162 | Ok(Self::Parameters::generate(rng)) 163 | } 164 | 165 | fn evaluate(parameters: &Self::Parameters, input: &[u8]) -> Result { 166 | let eval_time = start_timer!(|| "PoseidonCRH::Eval"); 167 | 168 | let f_inputs: Vec = to_field_elements(input)?; 169 | 170 | if f_inputs.len() > P::WIDTH as usize { 171 | panic!( 172 | "incorrect input length {:?} for width {:?} -- input bits {:?}", 173 | f_inputs.len(), 174 | P::WIDTH, 175 | input.len() 176 | ); 177 | } 178 | 179 | let mut buffer = vec![F::zero(); P::WIDTH as usize]; 180 | buffer.iter_mut().zip(f_inputs).for_each(|(p, v)| *p = v); 181 | let result = Self::mimc(parameters, buffer)?; 182 | end_timer!(eval_time); 183 | Ok(result.get(0).cloned().ok_or(MiMCError::InvalidInputs)?) 184 | } 185 | } 186 | 187 | impl TwoToOneCRH for CRH { 188 | type Output = F; 189 | type Parameters = MiMCParameters; 190 | 191 | const LEFT_INPUT_SIZE_BITS: usize = Self::INPUT_SIZE_BITS / 2; 192 | const RIGHT_INPUT_SIZE_BITS: usize = Self::INPUT_SIZE_BITS / 2; 193 | 194 | fn setup(rng: &mut R) -> Result { 195 | ::setup(rng) 196 | } 197 | 198 | /// A simple implementation of TwoToOneCRH by asserting left and right input 199 | /// has same length and chain them together. 200 | fn evaluate( 201 | parameters: &Self::Parameters, 202 | left_input: &[u8], 203 | right_input: &[u8], 204 | ) -> Result { 205 | assert_eq!(left_input.len(), right_input.len()); 206 | assert!(left_input.len() * 8 <= Self::LEFT_INPUT_SIZE_BITS); 207 | let chained: Vec<_> = left_input 208 | .iter() 209 | .chain(right_input.iter()) 210 | .copied() 211 | .collect(); 212 | 213 | ::evaluate(parameters, &chained) 214 | } 215 | } 216 | 217 | #[cfg(test)] 218 | mod test { 219 | use super::*; 220 | use ark_ed_on_bn254::Fq; 221 | use ark_ff::{to_bytes, Zero}; 222 | use arkworks_utils::{bytes_vec_to_f, mimc_params::setup_mimc_params, Curve}; 223 | 224 | #[derive(Default, Clone)] 225 | struct MiMCRounds220; 226 | 227 | impl Rounds for MiMCRounds220 { 228 | const ROUNDS: u16 = 220; 229 | const WIDTH: u8 = 3; 230 | } 231 | 232 | type MiMC220 = CRH; 233 | 234 | pub fn setup_mimc(curve: Curve, rounds: u16, width: u8) -> MiMCParameters { 235 | let mimc_data = setup_mimc_params(curve, rounds, width).unwrap(); 236 | let constants_f = bytes_vec_to_f(&mimc_data.constants); 237 | 238 | MiMCParameters { 239 | k: F::zero(), 240 | num_inputs: mimc_data.width as usize, 241 | num_outputs: mimc_data.width as usize, 242 | rounds: mimc_data.rounds as usize, 243 | round_keys: constants_f, 244 | } 245 | } 246 | 247 | #[test] 248 | fn test_hash() { 249 | let curve = Curve::Bn254; 250 | let params = setup_mimc(curve, MiMCRounds220::ROUNDS, MiMCRounds220::WIDTH); 251 | 252 | let inp = to_bytes![Fq::zero(), Fq::from(1u128), Fq::from(2u128)].unwrap(); 253 | 254 | let mimc_res = ::evaluate(¶ms, &inp).unwrap(); 255 | println!("{:?}", mimc_res); 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /arkworks/plonk-hashing/src/poseidon/round_numbers.rs: -------------------------------------------------------------------------------- 1 | // Adapted from https://github.com/filecoin-project/neptune/blob/master/src/round_numbers.rs 2 | 3 | // The number of bits of the Poseidon prime field modulus. Denoted `n` in the 4 | // Poseidon paper (where `n = ceil(log2(p))`). Note that BLS12-381's scalar 5 | // field modulus is 255 bits, however we use 256 bits for simplicity when 6 | // operating on bytes as the single bit difference does not affect 7 | // the round number security properties. 8 | const PRIME_BITLEN: usize = 256; 9 | 10 | // Security level (in bits), denoted `M` in the Poseidon paper. 11 | const M: usize = 128; 12 | 13 | /// The number of S-boxes (also called the "cost") given by equation (14) in the 14 | /// Poseidon paper: `cost = t * R_F + R_P`. 15 | fn n_sboxes(t: usize, rf: usize, rp: usize) -> usize { 16 | t * rf + rp 17 | } 18 | 19 | /// Returns the round numbers for a given arity `(R_F, R_P)`. 20 | pub(crate) fn round_numbers_base(arity: usize) -> (usize, usize) { 21 | let t = arity + 1; 22 | calc_round_numbers(t, true) 23 | } 24 | 25 | /// In case of newly-discovered attacks, we may need stronger security. 26 | /// This option exists so we can preemptively create circuits in order to switch 27 | /// to them quickly if needed. 28 | /// 29 | /// "A realistic alternative is to increase the number of partial rounds by 25%. 30 | /// Then it is unlikely that a new attack breaks through this number, 31 | /// but even if this happens then the complexity is almost surely above 2^64, 32 | /// and you will be safe." 33 | /// - D Khovratovich 34 | pub(crate) fn round_numbers_strengthened(arity: usize) -> (usize, usize) { 35 | let (full_round, partial_rounds) = round_numbers_base(arity); 36 | 37 | // Increase by 25%, rounding up. 38 | let strengthened_partial_rounds = 39 | f64::ceil(partial_rounds as f64 * 1.25) as usize; 40 | 41 | (full_round, strengthened_partial_rounds) 42 | } 43 | 44 | /// Returns the round numbers for a given width `t`. Here, the `security_margin` 45 | /// parameter does not indicate that we are calculating `R_F` and `R_P` for the 46 | /// "strengthened" round numbers, done in the function 47 | /// `round_numbers_strengthened()`. 48 | pub(crate) fn calc_round_numbers( 49 | t: usize, 50 | security_margin: bool, 51 | ) -> (usize, usize) { 52 | let mut rf = 0; 53 | let mut rp = 0; 54 | let mut n_sboxes_min = usize::MAX; 55 | 56 | for mut rf_test in (2..=1000).step_by(2) { 57 | for mut rp_test in 4..200 { 58 | if round_numbers_are_secure(t, rf_test, rp_test) { 59 | if security_margin { 60 | rf_test += 2; 61 | rp_test = (1.075 * rp_test as f32).ceil() as usize; 62 | } 63 | let n_sboxes = n_sboxes(t, rf_test, rp_test); 64 | if n_sboxes < n_sboxes_min 65 | || (n_sboxes == n_sboxes_min && rf_test < rf) 66 | { 67 | rf = rf_test; 68 | rp = rp_test; 69 | n_sboxes_min = n_sboxes; 70 | } 71 | } 72 | } 73 | } 74 | 75 | (rf, rp) 76 | } 77 | 78 | /// Returns `true` if the provided round numbers satisfy the security 79 | /// inequalities specified in the Poseidon paper. 80 | fn round_numbers_are_secure(t: usize, rf: usize, rp: usize) -> bool { 81 | let (rp, t, n, m) = (rp as f32, t as f32, PRIME_BITLEN as f32, M as f32); 82 | let rf_stat = if m <= (n - 3.0) * (t + 1.0) { 83 | 6.0 84 | } else { 85 | 10.0 86 | }; 87 | let rf_interp = 0.43 * m + t.log2() - rp; 88 | let rf_grob_1 = 0.21 * n - rp; 89 | let rf_grob_2 = (0.14 * n - 1.0 - rp) / (t - 1.0); 90 | let rf_max = [rf_stat, rf_interp, rf_grob_1, rf_grob_2] 91 | .iter() 92 | .map(|rf| rf.ceil() as usize) 93 | .max() 94 | .unwrap(); 95 | rf >= rf_max 96 | } 97 | 98 | #[cfg(test)] 99 | mod tests { 100 | use super::*; 101 | 102 | use std::fs; 103 | 104 | #[test] 105 | fn test_round_numbers_against_known_values() { 106 | // Each case contains a `t` (where `t = arity + 1`) and the `R_P` 107 | // expected for that `t`. 108 | let cases = [ 109 | (2usize, 55usize), 110 | (3, 55), 111 | (4, 56), 112 | (5, 56), 113 | (6, 56), 114 | (7, 56), 115 | (8, 57), 116 | (9, 57), 117 | (10, 57), 118 | (11, 57), 119 | (12, 57), 120 | (13, 57), 121 | (14, 57), 122 | (15, 57), 123 | (16, 59), 124 | (17, 59), 125 | (25, 59), 126 | (37, 60), 127 | (65, 61), 128 | ]; 129 | for (t, rp_expected) in cases.iter() { 130 | let (rf, rp) = calc_round_numbers(*t, true); 131 | assert_eq!(rf, 8); 132 | assert_eq!(rp, *rp_expected); 133 | } 134 | } 135 | 136 | #[ignore] 137 | #[test] 138 | fn test_round_numbers_against_python_script() { 139 | // A parsed line from `parameters/round_numbers.txt`. 140 | struct Line { 141 | t: usize, 142 | rf: usize, 143 | rp: usize, 144 | sbox_cost: usize, 145 | size_cost: usize, 146 | } 147 | 148 | let lines: Vec = fs::read_to_string( 149 | "parameters/round_numbers.txt", 150 | ) 151 | .expect( 152 | "failed to read round numbers file: `parameters/round_numbers.txt`", 153 | ) 154 | .lines() 155 | .skip_while(|line| line.starts_with('#')) 156 | .map(|line| { 157 | let nums: Vec = line 158 | .split(' ') 159 | .map(|s| { 160 | s.parse().unwrap_or_else(|_| { 161 | panic!("failed to parse line as `usize`s: {}", line) 162 | }) 163 | }) 164 | .collect(); 165 | assert_eq!( 166 | nums.len(), 167 | 5, 168 | "line in does not contain 5 values: {}", 169 | line 170 | ); 171 | Line { 172 | t: nums[0], 173 | rf: nums[1], 174 | rp: nums[2], 175 | sbox_cost: nums[3], 176 | size_cost: nums[4], 177 | } 178 | }) 179 | .collect(); 180 | 181 | assert!( 182 | !lines.is_empty(), 183 | "no lines were parsed from `round_numbers.txt`", 184 | ); 185 | 186 | for line in lines { 187 | let (rf, rp) = calc_round_numbers(line.t, true); 188 | let sbox_cost = n_sboxes(line.t, rf, rp); 189 | let size_cost = sbox_cost * PRIME_BITLEN; 190 | 191 | assert_eq!(rf, line.rf, "full rounds differ from script"); 192 | assert_eq!(rp, line.rp, "partial rounds differ from script"); 193 | assert_eq!(sbox_cost, line.sbox_cost, "cost differs from script"); 194 | assert_eq!( 195 | size_cost, line.size_cost, 196 | "size-cost differs from script" 197 | ); 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /arkworks/plonk-gadgets/src/set.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Webb and was adapted from Arkworks. 2 | // 3 | // Copyright (C) 2021 Webb Technologies Inc. 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | //! A Plonk gadget to check membership within a set. 19 | //! 20 | //! To check whether an element `x` is in a set `A`, the gadget takes the 21 | //! difference between `x` and every element of `A`, takes the product of 22 | //! all those differences, and checks if it is equal to zero. The product 23 | //! is zero if and only if `x` is in `A`; however, the individual 24 | //! elements of `A` are not revealed, making it zero-knowledge. 25 | //! 26 | //! For example, one could check if a certain Merkle root hash is a member 27 | //! of a set of Merkle root hashes. 28 | 29 | use ark_ec::models::TEModelParameters; 30 | use ark_ff::PrimeField; 31 | use ark_std::{marker::PhantomData, vec::Vec}; 32 | use plonk_core::{constraint_system::StandardComposer, prelude::Variable}; 33 | 34 | use crate::add_public_input_variables; 35 | 36 | pub struct SetGadget> { 37 | items: Vec, 38 | te: PhantomData

, 39 | } 40 | 41 | impl> SetGadget { 42 | pub fn from_native(composer: &mut StandardComposer, items: Vec) -> Self { 43 | let vars = add_public_input_variables(composer, items); 44 | 45 | Self { 46 | items: vars, 47 | te: PhantomData, 48 | } 49 | } 50 | 51 | /// A function whose output is 1 if `member` belongs to `set` 52 | /// and 0 otherwise. Contraints are added to a StandardComposer 53 | /// and the output is added as a variable to the StandardComposer. 54 | /// The set is assumed to consist of public inputs, such as roots 55 | /// of various Merkle trees. 56 | pub fn check_set_membership( 57 | &self, 58 | composer: &mut StandardComposer, 59 | member: Variable, 60 | ) -> Variable { 61 | // Compute all differences between `member` and set elements 62 | let mut diffs = Vec::new(); 63 | for x in self.items.iter() { 64 | let diff = composer 65 | .arithmetic_gate(|gate| gate.witness(member, *x, None).add(F::one(), -F::one())); 66 | diffs.push(diff); 67 | } 68 | 69 | // Accumulate the product of all differences 70 | let mut accumulator = composer.add_witness_to_circuit_description(F::one()); 71 | for diff in diffs { 72 | accumulator = composer 73 | .arithmetic_gate(|gate| gate.witness(accumulator, diff, None).mul(F::one())); 74 | } 75 | 76 | composer.is_zero_with_output(accumulator) 77 | } 78 | 79 | /// Similar to the check_set_membership function, 80 | /// except that it accepts an `is_enabled` argument 81 | /// that turns the set membership check on/off. 82 | /// Intended usage is when verifying input UTXOs: the 83 | /// validity of an input only needs to be verified if 84 | /// its amount is non-zero, so adding the input amount 85 | /// as the `is_enabled` argument is a way of turning the 86 | /// set membership check on only when it is needed. 87 | pub fn check_set_membership_is_enabled( 88 | &self, 89 | composer: &mut StandardComposer, 90 | member: Variable, 91 | is_enabled: Variable, 92 | ) -> Variable { 93 | // Compute all differences between `member` and set elements 94 | let mut diffs = Vec::new(); 95 | for x in self.items.iter() { 96 | let diff = composer 97 | .arithmetic_gate(|gate| gate.witness(member, *x, None).add(F::one(), -F::one())); 98 | diffs.push(diff); 99 | } 100 | 101 | // Accumulate the product of all differences 102 | let mut accumulator = composer.add_witness_to_circuit_description(F::one()); 103 | for diff in diffs { 104 | accumulator = composer 105 | .arithmetic_gate(|gate| gate.witness(accumulator, diff, None).mul(F::one())); 106 | } 107 | // Multiply accumulated product by `is_enabled` 108 | accumulator = composer 109 | .arithmetic_gate(|gate| gate.witness(accumulator, is_enabled, None).mul(F::one())); 110 | 111 | composer.is_zero_with_output(accumulator) 112 | } 113 | } 114 | 115 | #[cfg(test)] 116 | pub(crate) mod tests { 117 | //copied from ark-plonk 118 | use super::*; 119 | use ark_ed_on_bn254::{EdwardsParameters as JubjubParameters, Fq}; 120 | 121 | #[test] 122 | fn test_verify_set_membership_functions() { 123 | let set = vec![Fq::from(1u32), Fq::from(2u32), Fq::from(3u32)]; 124 | let mut composer = StandardComposer::::new(); 125 | 126 | let set_gadget = SetGadget::from_native(&mut composer, set); 127 | 128 | let one = composer.add_input(Fq::from(1u32)); 129 | let member = composer.add_input(Fq::from(2u32)); 130 | 131 | let result_private = set_gadget.check_set_membership(&mut composer, member); 132 | composer.assert_equal(result_private, one); 133 | composer.check_circuit_satisfied(); 134 | } 135 | 136 | #[test] 137 | fn test_fail_to_verify_set_membership_functions() { 138 | let set = vec![Fq::from(1u32), Fq::from(2u32), Fq::from(3u32)]; 139 | let mut composer = StandardComposer::::new(); 140 | 141 | let set_gadget = SetGadget::from_native(&mut composer, set); 142 | 143 | let zero = composer.zero_var(); 144 | let member = composer.add_input(Fq::from(4u32)); 145 | 146 | let result_private = set_gadget.check_set_membership(&mut composer, member); 147 | composer.assert_equal(result_private, zero); 148 | composer.check_circuit_satisfied(); 149 | } 150 | 151 | #[test] 152 | fn test_verify_set_membership_enabled_functions() { 153 | let set = vec![Fq::from(1u32), Fq::from(2u32), Fq::from(3u32)]; 154 | let mut composer = StandardComposer::::new(); 155 | 156 | let set_gadget = SetGadget::from_native(&mut composer, set); 157 | 158 | let one = composer.add_input(Fq::from(1u32)); 159 | // This is not a member of the set 160 | let member = composer.add_input(Fq::from(4u32)); 161 | // We set `is_enabled` to 0, so check should pass 162 | let is_enabled = composer.add_input(Fq::from(0u32)); 163 | 164 | let result_private = 165 | set_gadget.check_set_membership_is_enabled(&mut composer, member, is_enabled); 166 | composer.assert_equal(result_private, one); 167 | composer.check_circuit_satisfied(); 168 | } 169 | 170 | #[test] 171 | fn test_fail_to_verify_set_membership_enabled_functions() { 172 | let set = vec![Fq::from(1u32), Fq::from(2u32), Fq::from(3u32)]; 173 | let mut composer = StandardComposer::::new(); 174 | 175 | let set_gadget = SetGadget::from_native(&mut composer, set); 176 | 177 | let zero = composer.zero_var(); 178 | // This is not a member of the set 179 | let member = composer.add_input(Fq::from(4u32)); 180 | // We set `is_enabled` to 1, so check should fail 181 | let is_enabled = composer.add_input(Fq::from(1u32)); 182 | 183 | let result_private = 184 | set_gadget.check_set_membership_is_enabled(&mut composer, member, is_enabled); 185 | composer.assert_equal(result_private, zero); 186 | composer.check_circuit_satisfied(); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /arkworks/utils/src/poseidon_params/mod.rs: -------------------------------------------------------------------------------- 1 | use super::{parse_matrix, parse_vec, Bytes, Curve, FromHexError}; 2 | 3 | pub use ark_std::vec::Vec; 4 | 5 | pub struct PoseidonData { 6 | pub mds: Vec>, 7 | pub rounds: Vec, 8 | pub full_rounds: u8, 9 | pub partial_rounds: u8, 10 | pub width: u8, 11 | pub exp: i8, 12 | } 13 | 14 | impl PoseidonData { 15 | pub fn new( 16 | mds: Vec>, 17 | rounds: Vec, 18 | full_rounds: u8, 19 | partial_rounds: u8, 20 | width: u8, 21 | exp: i8, 22 | ) -> Self { 23 | Self { 24 | mds, 25 | rounds, 26 | full_rounds, 27 | partial_rounds, 28 | exp, 29 | width, 30 | } 31 | } 32 | } 33 | 34 | pub fn setup_poseidon_params( 35 | curve: Curve, 36 | exp: i8, 37 | width: u8, 38 | ) -> Result { 39 | // Making params for poseidon in merkle tree 40 | match (curve, exp, width) { 41 | #[cfg(feature = "poseidon_bls381_x3_3")] 42 | (Curve::Bls381, 3, 3) => { 43 | #[path = "./bls381_x3_3.rs"] 44 | mod bls381_x3_3; 45 | use bls381_x3_3::{ 46 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 47 | }; 48 | get_poseidon_data( 49 | ROUND_CONSTS, 50 | MDS_ENTRIES, 51 | FULL_ROUNDS, 52 | PARTIAL_ROUNDS, 53 | WIDTH, 54 | EXPONENTIATION, 55 | ) 56 | } 57 | #[cfg(feature = "poseidon_bn254_x3_3")] 58 | (Curve::Bn254, 3, 3) => { 59 | #[path = "./bn254_x3_3.rs"] 60 | pub mod bn254_x3_3; 61 | use bn254_x3_3::{ 62 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 63 | }; 64 | get_poseidon_data( 65 | ROUND_CONSTS, 66 | MDS_ENTRIES, 67 | FULL_ROUNDS, 68 | PARTIAL_ROUNDS, 69 | WIDTH, 70 | EXPONENTIATION, 71 | ) 72 | } 73 | #[cfg(feature = "poseidon_bls381_x3_5")] 74 | (Curve::Bls381, 3, 5) => { 75 | #[path = "./bls381_x3_5.rs"] 76 | pub mod bls381_x3_5; 77 | use bls381_x3_5::{ 78 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 79 | }; 80 | get_poseidon_data( 81 | ROUND_CONSTS, 82 | MDS_ENTRIES, 83 | FULL_ROUNDS, 84 | PARTIAL_ROUNDS, 85 | WIDTH, 86 | EXPONENTIATION, 87 | ) 88 | } 89 | #[cfg(feature = "poseidon_bn254_x3_5")] 90 | (Curve::Bn254, 3, 5) => { 91 | #[path = "./bn254_x3_5.rs"] 92 | pub mod bn254_x3_5; 93 | use bn254_x3_5::{ 94 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 95 | }; 96 | get_poseidon_data( 97 | ROUND_CONSTS, 98 | MDS_ENTRIES, 99 | FULL_ROUNDS, 100 | PARTIAL_ROUNDS, 101 | WIDTH, 102 | EXPONENTIATION, 103 | ) 104 | } 105 | #[cfg(feature = "poseidon_bls381_x5_3")] 106 | (Curve::Bls381, 5, 3) => { 107 | #[path = "./bls381_x5_3.rs"] 108 | pub mod bls381_x5_3; 109 | use bls381_x5_3::{ 110 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 111 | }; 112 | get_poseidon_data( 113 | ROUND_CONSTS, 114 | MDS_ENTRIES, 115 | FULL_ROUNDS, 116 | PARTIAL_ROUNDS, 117 | WIDTH, 118 | EXPONENTIATION, 119 | ) 120 | } 121 | #[cfg(feature = "poseidon_bn254_x5_3")] 122 | (Curve::Bn254, 5, 3) => { 123 | #[path = "./bn254_x5_3.rs"] 124 | pub mod bn254_x5_3; 125 | use bn254_x5_3::{ 126 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 127 | }; 128 | get_poseidon_data( 129 | ROUND_CONSTS, 130 | MDS_ENTRIES, 131 | FULL_ROUNDS, 132 | PARTIAL_ROUNDS, 133 | WIDTH, 134 | EXPONENTIATION, 135 | ) 136 | } 137 | #[cfg(feature = "poseidon_bn254_x5_2")] 138 | (Curve::Bn254, 5, 2) => { 139 | #[path = "./bn254_x5_2.rs"] 140 | pub mod bn254_x5_2; 141 | use bn254_x5_2::{ 142 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 143 | }; 144 | get_poseidon_data( 145 | ROUND_CONSTS, 146 | MDS_ENTRIES, 147 | FULL_ROUNDS, 148 | PARTIAL_ROUNDS, 149 | WIDTH, 150 | EXPONENTIATION, 151 | ) 152 | } 153 | #[cfg(feature = "poseidon_bn254_x5_4")] 154 | (Curve::Bn254, 5, 4) => { 155 | #[path = "./bn254_x5_4.rs"] 156 | pub mod bn254_x5_4; 157 | use bn254_x5_4::{ 158 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 159 | }; 160 | get_poseidon_data( 161 | ROUND_CONSTS, 162 | MDS_ENTRIES, 163 | FULL_ROUNDS, 164 | PARTIAL_ROUNDS, 165 | WIDTH, 166 | EXPONENTIATION, 167 | ) 168 | } 169 | #[cfg(feature = "poseidon_bls381_x5_5")] 170 | (Curve::Bls381, 5, 5) => { 171 | #[path = "./bls381_x5_5.rs"] 172 | pub mod bls381_x5_5; 173 | use bls381_x5_5::{ 174 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 175 | }; 176 | get_poseidon_data( 177 | ROUND_CONSTS, 178 | MDS_ENTRIES, 179 | FULL_ROUNDS, 180 | PARTIAL_ROUNDS, 181 | WIDTH, 182 | EXPONENTIATION, 183 | ) 184 | } 185 | #[cfg(feature = "poseidon_bn254_x5_5")] 186 | (Curve::Bn254, 5, 5) => { 187 | #[path = "./bn254_x5_5.rs"] 188 | pub mod bn254_x5_5; 189 | use bn254_x5_5::{ 190 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 191 | }; 192 | get_poseidon_data( 193 | ROUND_CONSTS, 194 | MDS_ENTRIES, 195 | FULL_ROUNDS, 196 | PARTIAL_ROUNDS, 197 | WIDTH, 198 | EXPONENTIATION, 199 | ) 200 | } 201 | #[cfg(feature = "poseidon_bls381_x17_3")] 202 | (Curve::Bls381, 17, 3) => { 203 | #[path = "./bls381_x17_3.rs"] 204 | pub mod bls381_x17_3; 205 | use bls381_x17_3::{ 206 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 207 | }; 208 | get_poseidon_data( 209 | ROUND_CONSTS, 210 | MDS_ENTRIES, 211 | FULL_ROUNDS, 212 | PARTIAL_ROUNDS, 213 | WIDTH, 214 | EXPONENTIATION, 215 | ) 216 | } 217 | #[cfg(feature = "poseidon_bn254_x17_3")] 218 | (Curve::Bn254, 17, 3) => { 219 | #[path = "./bn254_x17_3.rs"] 220 | pub mod bn254_x17_3; 221 | use bn254_x17_3::{ 222 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 223 | }; 224 | get_poseidon_data( 225 | ROUND_CONSTS, 226 | MDS_ENTRIES, 227 | FULL_ROUNDS, 228 | PARTIAL_ROUNDS, 229 | WIDTH, 230 | EXPONENTIATION, 231 | ) 232 | } 233 | #[cfg(feature = "poseidon_bls381_x17_5")] 234 | (Curve::Bls381, 17, 5) => { 235 | #[path = "./bls381_x17_5.rs"] 236 | pub mod bls381_x17_5; 237 | use bls381_x17_5::{ 238 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 239 | }; 240 | get_poseidon_data( 241 | ROUND_CONSTS, 242 | MDS_ENTRIES, 243 | FULL_ROUNDS, 244 | PARTIAL_ROUNDS, 245 | WIDTH, 246 | EXPONENTIATION, 247 | ) 248 | } 249 | #[cfg(feature = "poseidon_bn254_x17_5")] 250 | (Curve::Bn254, 17, 5) => { 251 | #[path = "./bn254_x17_5.rs"] 252 | pub mod bn254_x17_5; 253 | use bn254_x17_5::{ 254 | EXPONENTIATION, FULL_ROUNDS, MDS_ENTRIES, PARTIAL_ROUNDS, ROUND_CONSTS, WIDTH, 255 | }; 256 | get_poseidon_data( 257 | ROUND_CONSTS, 258 | MDS_ENTRIES, 259 | FULL_ROUNDS, 260 | PARTIAL_ROUNDS, 261 | WIDTH, 262 | EXPONENTIATION, 263 | ) 264 | } 265 | _ => unimplemented!(), 266 | } 267 | } 268 | 269 | pub fn get_poseidon_result(curve: Curve, exp: i8, width: u8) -> Result, FromHexError> { 270 | match (curve, exp, width) { 271 | #[cfg(feature = "poseidon_bn254_x5_5")] 272 | (Curve::Bn254, 5, 5) => { 273 | #[path = "./bn254_x5_5_result.rs"] 274 | pub mod bn254_x5_5_result; 275 | parse_vec(bn254_x5_5_result::RESULT.to_vec()) 276 | } 277 | #[cfg(feature = "poseidon_bn254_x5_3")] 278 | (Curve::Bn254, 5, 3) => { 279 | #[path = "./bn254_x5_3_result.rs"] 280 | pub mod bn254_x5_3_result; 281 | parse_vec(bn254_x5_3_result::RESULT.to_vec()) 282 | } 283 | _ => unimplemented!(), 284 | } 285 | } 286 | 287 | pub fn get_poseidon_data( 288 | rounds: &[&str], 289 | mds: &[&[&str]], 290 | full_rounds: u8, 291 | partial_rounds: u8, 292 | width: u8, 293 | exp: i8, 294 | ) -> Result { 295 | let rounds = parse_vec(rounds.to_vec())?; 296 | let mds = parse_matrix(mds.iter().map(|x| x.to_vec()).collect::>())?; 297 | Ok(PoseidonData::new( 298 | mds, 299 | rounds, 300 | full_rounds, 301 | partial_rounds, 302 | width, 303 | exp, 304 | )) 305 | } 306 | -------------------------------------------------------------------------------- /arkworks/setups/src/aead.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | keypair::{Keypair, KeypairError}, 3 | utxo::{Utxo, UtxoError}, 4 | }; 5 | use ark_crypto_primitives::Error; 6 | use ark_ff::{to_bytes, PrimeField}; 7 | use ark_std::{ 8 | convert::TryInto, 9 | rand::{CryptoRng, RngCore}, 10 | vec::Vec, 11 | }; 12 | use arkworks_native_gadgets::poseidon::FieldHasher; 13 | use codec::{Decode, Encode}; 14 | use crypto_box::{ 15 | aead::{generic_array::GenericArray, Aead, AeadCore, Payload}, 16 | generate_nonce, PublicKey, SalsaBox, SecretKey, 17 | }; 18 | 19 | type NonceSize = ::NonceSize; 20 | type Nonce = GenericArray; 21 | pub struct EncryptedData { 22 | pub nonce: Nonce, 23 | pub ephemeral_pk: PublicKey, 24 | pub cypher_text: Vec, 25 | } 26 | 27 | impl Decode for EncryptedData { 28 | fn decode(input: &mut I) -> Result { 29 | // Getting the size of Nonce 30 | const NONCE_LEN: usize = core::mem::size_of::(); 31 | // Getting the size of pub key 32 | const PUB_KEY_LEN: usize = core::mem::size_of::(); 33 | let mut nonce_data = [0u8; NONCE_LEN]; 34 | let mut ephemeral_pk_data = [0u8; PUB_KEY_LEN]; 35 | 36 | // Reading the data for nonce and public key 37 | input.read(&mut nonce_data)?; 38 | input.read(&mut ephemeral_pk_data)?; 39 | 40 | // Getting the length of the remaining data 41 | let remaining_len: usize = input.remaining_len()?.unwrap_or(0usize); 42 | let mut cypher_text_data = ark_std::vec![0u8; remaining_len]; 43 | 44 | // Use the remaining data as cypher text 45 | input.read(&mut cypher_text_data)?; 46 | 47 | let nonce: Nonce = *GenericArray::::from_slice(&nonce_data); 48 | let ephemeral_pk: PublicKey = PublicKey::from(ephemeral_pk_data); 49 | let cypher_text = cypher_text_data.to_vec(); 50 | 51 | Ok(Self { 52 | nonce, 53 | ephemeral_pk, 54 | cypher_text, 55 | }) 56 | } 57 | } 58 | impl Encode for EncryptedData { 59 | fn encode(&self) -> Vec { 60 | const NONCE_LEN: usize = core::mem::size_of::(); 61 | const PUB_KEY_LEN: usize = core::mem::size_of::(); 62 | 63 | // Initialize return array 64 | let mut ret = ark_std::vec![0u8; self.encoded_size()]; 65 | 66 | // Populate it with data 67 | ret[0..NONCE_LEN].copy_from_slice(&self.nonce.as_slice()); 68 | ret[NONCE_LEN..(NONCE_LEN + PUB_KEY_LEN)].copy_from_slice(self.ephemeral_pk.as_bytes()); 69 | ret[(NONCE_LEN + PUB_KEY_LEN)..].copy_from_slice(&self.cypher_text); 70 | 71 | ret 72 | } 73 | 74 | fn encoded_size(&self) -> usize { 75 | const NONCE_LEN: usize = core::mem::size_of::(); 76 | const PUB_KEY_LEN: usize = core::mem::size_of::(); 77 | let cypher_text_len = self.cypher_text.len(); 78 | NONCE_LEN + PUB_KEY_LEN + cypher_text_len 79 | } 80 | } 81 | 82 | impl> Keypair { 83 | pub fn encrypt( 84 | &self, 85 | msg: &[u8], 86 | rng: &mut R, 87 | ) -> Result { 88 | // Generate new nonce 89 | let nonce = generate_nonce(rng); 90 | 91 | // Convert private key into bytes array 92 | let secret_key_bytes = to_bytes!(self.secret_key)?; 93 | let sc_bytes: [u8; 32] = secret_key_bytes 94 | .try_into() 95 | .map_err(|_| KeypairError::SecretKeyParseFailed)?; 96 | 97 | // Generate public key from secret key 98 | // QUESTION: Should we derive the public key with poseidon.hash(secret_key)? 99 | let secret_key = SecretKey::from(sc_bytes); 100 | let public_key = PublicKey::from(&secret_key); 101 | 102 | // Generate ephemeral sk/pk 103 | let ephemeral_sk = SecretKey::generate(rng); 104 | let ephemeral_pk = PublicKey::from(&ephemeral_sk); 105 | 106 | let my_box = SalsaBox::new(&public_key, &ephemeral_sk); 107 | 108 | // Encrypting the message 109 | let ct = my_box 110 | .encrypt(&nonce, Payload { 111 | msg: &msg, 112 | aad: &[], 113 | }) 114 | .map_err::(|_| KeypairError::EncryptionFailed.into())?; 115 | 116 | Ok(EncryptedData { 117 | nonce, 118 | cypher_text: ct, 119 | ephemeral_pk, 120 | }) 121 | } 122 | 123 | pub fn decrypt(&self, encrypted_data: &EncryptedData) -> Result, Error> { 124 | // Creating a secret key 125 | let secret_key_bytes = to_bytes![self.secret_key]?; 126 | 127 | let sc_bytes: [u8; 32] = secret_key_bytes 128 | .try_into() 129 | .map_err(|_| KeypairError::SecretKeyParseFailed)?; 130 | let secret_key = SecretKey::from(sc_bytes); 131 | 132 | // Making ephemeral public key from the encryption data 133 | let my_box = SalsaBox::new(&encrypted_data.ephemeral_pk, &secret_key); 134 | 135 | // Converting nonce into proper type 136 | let nonce = GenericArray::from_slice(&encrypted_data.nonce); 137 | 138 | // Decrypt the cypher text, get the plaintext 139 | let plaintext = my_box 140 | .decrypt(&nonce, Payload { 141 | msg: &encrypted_data.cypher_text, 142 | aad: &[], 143 | }) 144 | .map_err::(|_| KeypairError::DecryptionFailed.into())?; 145 | Ok(plaintext) 146 | } 147 | } 148 | 149 | impl Utxo { 150 | pub fn encrypt(&self, rng: &mut R) -> Result, Error> { 151 | // We are encrypting the amount and the blinding 152 | let msg = to_bytes![self.chain_id, self.amount, self.blinding]?; 153 | // Encrypting the message 154 | let enc_data = self.keypair.encrypt(&msg, rng)?; 155 | 156 | Ok(enc_data.encode()) 157 | } 158 | 159 | pub fn decrypt(&self, data: &[u8]) -> Result<(Vec, Vec, Vec), Error> { 160 | let decoded_ed = EncryptedData::decode(&mut &data[..]) 161 | .map_err(|_| UtxoError::EncryptedDataDecodeError)?; 162 | // Decrypting the message 163 | let plaintext = self.keypair.decrypt(&decoded_ed)?; 164 | 165 | // First 32 bytes is chain id 166 | let chain_id = plaintext[..32].to_vec(); 167 | // Second 32 bytes is amount 168 | let amount = plaintext[32..64].to_vec(); 169 | // Third 32 bytes is blinding 170 | let blinding = plaintext[64..96].to_vec(); 171 | 172 | Ok((chain_id, amount, blinding)) 173 | } 174 | } 175 | 176 | #[cfg(test)] 177 | mod test { 178 | use crate::common::setup_params; 179 | use ark_bn254::Fr; 180 | use ark_ff::{BigInteger, PrimeField}; 181 | use ark_std::{test_rng, UniformRand}; 182 | use arkworks_native_gadgets::poseidon::Poseidon; 183 | use arkworks_utils::Curve; 184 | use codec::{Decode, Encode}; 185 | 186 | use super::EncryptedData; 187 | use crate::{keypair::Keypair, utxo::Utxo}; 188 | 189 | #[test] 190 | fn should_encrypt_decrypt() { 191 | let rng = &mut test_rng(); 192 | let curve = Curve::Bn254; 193 | // create the hasher which is used for deriving the public key from the private 194 | // key 195 | let params2 = setup_params(curve, 5, 2); 196 | let hasher2 = Poseidon::::new(params2.clone()); 197 | let private_key = Fr::rand(rng); 198 | let keypair = Keypair::>::new(private_key.clone(), &hasher2); 199 | 200 | let msg = vec![1, 2, 3]; 201 | let encrypted_data = keypair.encrypt(&msg, rng).unwrap(); 202 | let plaintext = keypair.decrypt(&encrypted_data).unwrap(); 203 | 204 | assert_eq!(plaintext, msg); 205 | } 206 | 207 | #[test] 208 | fn should_encode_decode_encrypted_data() { 209 | let rng = &mut test_rng(); 210 | let curve = Curve::Bn254; 211 | // create the hasher which is used for deriving the public key from the private 212 | // key 213 | let params2 = setup_params(curve, 5, 2); 214 | let hasher2 = Poseidon::::new(params2.clone()); 215 | let private_key = Fr::rand(rng); 216 | let keypair = Keypair::>::new(private_key.clone(), &hasher2); 217 | 218 | let msg = vec![1, 2, 3]; 219 | let encrypted_data = keypair.encrypt(&msg, rng).unwrap(); 220 | let encoded_ed = encrypted_data.encode(); 221 | let decoded_ed = EncryptedData::decode(&mut &encoded_ed[..]).unwrap(); 222 | let plaintext = keypair.decrypt(&decoded_ed).unwrap(); 223 | 224 | assert_eq!(plaintext, msg); 225 | } 226 | 227 | #[test] 228 | fn test_utxo_encrypt() { 229 | let curve = Curve::Bn254; 230 | let params2 = setup_params::(curve, 5, 2); 231 | let params4 = setup_params::(curve, 5, 4); 232 | let params5 = setup_params::(curve, 5, 5); 233 | let poseidon2 = Poseidon::new(params2); 234 | let poseidon4 = Poseidon::new(params4); 235 | let poseidon5 = Poseidon::new(params5); 236 | 237 | let rng = &mut test_rng(); 238 | 239 | let chain_id_raw = 0u64; 240 | let chain_id = Fr::from(chain_id_raw); 241 | let amount = Fr::rand(rng); 242 | let blinding = Fr::rand(rng); 243 | // let utxo 244 | let utxo = Utxo::new( 245 | chain_id_raw, 246 | amount, 247 | None, 248 | None, 249 | Some(blinding), 250 | &poseidon2, 251 | &poseidon4, 252 | &poseidon5, 253 | rng, 254 | ) 255 | .unwrap(); 256 | 257 | let encrypted_data = utxo.encrypt(rng).unwrap(); 258 | let (chain_id_bytes, amount_bytes, blinding_bytes) = utxo.decrypt(&encrypted_data).unwrap(); 259 | 260 | assert_eq!(chain_id_bytes, chain_id.into_repr().to_bytes_be()); 261 | assert_eq!(amount_bytes, amount.into_repr().to_bytes_be()); 262 | assert_eq!(blinding_bytes, blinding.into_repr().to_bytes_be()); 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /arkworks/plonk-hashing/src/poseidon/mds.rs: -------------------------------------------------------------------------------- 1 | // adapted from https://github.com/filecoin-project/neptune/blob/master/src/mds.rs 2 | use crate::poseidon::matrix::Matrix; 3 | use ark_ff::vec::*; 4 | use ark_ff::PrimeField; 5 | 6 | #[derive(Clone, Debug, PartialEq)] 7 | pub struct MdsMatrices { 8 | pub m: Matrix, 9 | pub m_inv: Matrix, 10 | pub m_hat: Matrix, 11 | pub m_hat_inv: Matrix, 12 | pub m_prime: Matrix, 13 | pub m_double_prime: Matrix, 14 | } 15 | 16 | impl MdsMatrices { 17 | /// Derive MDS matrix of size `dim*dim` and relevant things 18 | pub fn new(dim: usize) -> Self { 19 | let m = Self::generate_mds(dim); 20 | Self::derive_mds_matrices(m) 21 | } 22 | 23 | /// Given an MDS matrix `m`, compute all its associated matrices. 24 | pub(crate) fn derive_mds_matrices(m: Matrix) -> Self { 25 | let m_inv = m.invert().expect("Derived MDS matrix is not invertible"); 26 | let m_hat = m.minor(0, 0); 27 | let m_hat_inv = 28 | m_hat.invert().expect("Derived MDS matrix is not correct"); 29 | let m_prime = Self::make_prime(&m); 30 | let m_double_prime = Self::make_double_prime(&m, &m_hat_inv); 31 | MdsMatrices { 32 | m, 33 | m_inv, 34 | m_hat, 35 | m_hat_inv, 36 | m_prime, 37 | m_double_prime, 38 | } 39 | } 40 | 41 | fn generate_mds(t: usize) -> Matrix { 42 | let xs: Vec = (0..t as u64).map(F::from).collect(); 43 | let ys: Vec = (t as u64..2 * t as u64).map(F::from).collect(); 44 | 45 | let matrix = xs 46 | .iter() 47 | .map(|xs_item| { 48 | ys.iter() 49 | .map(|ys_item| { 50 | // Generate the entry at (i,j) 51 | let mut tmp = *xs_item; 52 | tmp.add_assign(ys_item); 53 | tmp.inverse().unwrap() 54 | }) 55 | .collect() 56 | }) 57 | .collect::>(); 58 | 59 | debug_assert!(matrix.is_invertible()); 60 | debug_assert_eq!(matrix, matrix.transpose()); 61 | matrix 62 | } 63 | 64 | /// Returns a matrix associated to `m` in the optimization of 65 | /// MDS matrices. 66 | fn make_prime(m: &Matrix) -> Matrix { 67 | m.iter_rows() 68 | .enumerate() 69 | .map(|(i, row)| match i { 70 | 0 => { 71 | let mut new_row = vec![F::zero(); row.len()]; 72 | new_row[0] = F::one(); 73 | new_row 74 | } 75 | _ => { 76 | let mut new_row = vec![F::zero(); row.len()]; 77 | new_row[1..].copy_from_slice(&row[1..]); 78 | new_row 79 | } 80 | }) 81 | .collect() 82 | } 83 | 84 | /// Returns a matrix associated to `m` in the optimization of 85 | /// MDS matrices. 86 | fn make_double_prime(m: &Matrix, m_hat_inv: &Matrix) -> Matrix { 87 | let (v, w) = Self::make_v_w(m); 88 | let w_hat = m_hat_inv.right_apply(&w); 89 | 90 | m.iter_rows() 91 | .enumerate() 92 | .map(|(i, row)| match i { 93 | 0 => { 94 | let mut new_row = Vec::with_capacity(row.len()); 95 | new_row.push(row[0]); 96 | new_row.extend(&v); 97 | new_row 98 | } 99 | _ => { 100 | let mut new_row = vec![F::zero(); row.len()]; 101 | new_row[0] = w_hat[i - 1]; 102 | new_row[i] = F::one(); 103 | new_row 104 | } 105 | }) 106 | .collect() 107 | } 108 | 109 | /// Returns two vectors associated to `m` in the optimization of 110 | /// MDS matrices. 111 | fn make_v_w(m: &Matrix) -> (Vec, Vec) { 112 | let v = m[0][1..].to_vec(); 113 | let w = m.iter_rows().skip(1).map(|column| column[0]).collect(); 114 | (v, w) 115 | } 116 | } 117 | 118 | /// A `SparseMatrix` is specifically one of the form of M''. 119 | /// This means its first row and column are each dense, and the interior matrix 120 | /// (minor to the element in both the row and column) is the identity. 121 | /// We will pluralize this compact structure `sparse_matrixes` to distinguish 122 | /// from `sparse_matrices` from which they are created. 123 | #[derive(Debug, Clone, PartialEq)] 124 | pub struct SparseMatrix { 125 | /// `w_hat` is the first column of the M'' matrix. It will be directly 126 | /// multiplied (scalar product) with a row of state elements. 127 | pub w_hat: Vec, 128 | /// `v_rest` contains all but the first (already included in `w_hat`). 129 | pub v_rest: Vec, 130 | } 131 | 132 | impl SparseMatrix { 133 | pub fn new(m_double_prime: &Matrix) -> Self { 134 | assert!(m_double_prime.is_sparse()); 135 | 136 | let w_hat = m_double_prime.iter_rows().map(|r| r[0]).collect(); 137 | let v_rest = m_double_prime[0][1..].to_vec(); 138 | Self { w_hat, v_rest } 139 | } 140 | 141 | pub fn size(&self) -> usize { 142 | self.w_hat.len() 143 | } 144 | 145 | pub fn to_matrix(&self) -> Matrix { 146 | let mut m = Matrix::identity(self.size()); 147 | for (j, elt) in self.w_hat.iter().enumerate() { 148 | m[j][0] = *elt; 149 | } 150 | for (i, elt) in self.v_rest.iter().enumerate() { 151 | m[0][i + 1] = *elt; 152 | } 153 | m 154 | } 155 | } 156 | 157 | // TODO: naming is from https://github.com/filecoin-project/neptune/blob/master/src/mds.rs 158 | // TODO: which is little difficult to follow... We need to change it 159 | 160 | pub fn factor_to_sparse_matrixes( 161 | base_matrix: Matrix, 162 | n: usize, 163 | ) -> (Matrix, Vec>) { 164 | let (pre_sparse, mut sparse_matrices) = 165 | (0..n).fold((base_matrix.clone(), Vec::new()), |(curr, mut acc), _| { 166 | let derived = MdsMatrices::derive_mds_matrices(curr); 167 | acc.push(derived.m_double_prime); 168 | let new = base_matrix.matmul(&derived.m_prime).unwrap(); 169 | (new, acc) 170 | }); 171 | sparse_matrices.reverse(); 172 | let sparse_matrixes = sparse_matrices 173 | .iter() 174 | .map(|m| SparseMatrix::::new(m)) 175 | .collect::>(); 176 | 177 | (pre_sparse, sparse_matrixes) 178 | } 179 | 180 | #[cfg(test)] 181 | mod tests { 182 | use crate::poseidon::mds::MdsMatrices; 183 | use ark_bls12_381::Fr; 184 | use ark_std::{test_rng, UniformRand}; 185 | 186 | #[test] 187 | fn test_mds_matrices_creation() { 188 | for i in 2..5 { 189 | test_mds_matrices_creation_aux(i); 190 | } 191 | } 192 | 193 | fn test_mds_matrices_creation_aux(width: usize) { 194 | let MdsMatrices { 195 | m, 196 | m_inv, 197 | m_hat, 198 | m_hat_inv: _, 199 | m_prime, 200 | m_double_prime, 201 | } = MdsMatrices::::new(width); 202 | 203 | for i in 0..m_hat.num_rows() { 204 | for j in 0..m_hat.num_columns() { 205 | assert_eq!( 206 | m[i + 1][j + 1], 207 | m_hat[i][j], 208 | "MDS minor has wrong value." 209 | ); 210 | } 211 | } 212 | 213 | // M^-1 x M = I 214 | assert!(m_inv.matmul(&m).unwrap().is_identity()); 215 | 216 | // M' x M'' = M 217 | assert_eq!(m, m_prime.matmul(&m_double_prime).unwrap()); 218 | } 219 | 220 | #[test] 221 | fn test_swapping() { 222 | test_swapping_aux(3) 223 | } 224 | 225 | fn test_swapping_aux(width: usize) { 226 | let mut rng = test_rng(); 227 | let mds = MdsMatrices::::new(width); 228 | 229 | let base = (0..width).map(|_| Fr::rand(&mut rng)).collect::>(); 230 | let x = { 231 | let mut x = base.clone(); 232 | x[0] = Fr::rand(&mut rng); 233 | x 234 | }; 235 | let y = { 236 | let mut y = base.clone(); 237 | y[0] = Fr::rand(&mut rng); 238 | y 239 | }; 240 | 241 | let qx = mds.m_prime.right_apply(&x); 242 | let qy = mds.m_prime.right_apply(&y); 243 | assert_eq!(qx[0], x[0]); 244 | assert_eq!(qy[0], y[0]); 245 | assert_eq!(qx[1..], qy[1..]); 246 | 247 | let mx = mds.m.left_apply(&x); 248 | let m1_m2_x = 249 | mds.m_prime.left_apply(&mds.m_double_prime.left_apply(&x)); 250 | assert_eq!(mx, m1_m2_x); 251 | 252 | let xm = mds.m.right_apply(&x); 253 | let x_m1_m2 = 254 | mds.m_double_prime.right_apply(&mds.m_prime.right_apply(&x)); 255 | assert_eq!(xm, x_m1_m2); 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /assets/webb-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /arkworks/benchmarks/src/main.rs: -------------------------------------------------------------------------------- 1 | use ark_bls12_381::{Bls12_381, Fr as BlsFr}; 2 | use ark_bn254::Bn254; 3 | use ark_crypto_primitives::{Error, SNARK}; 4 | use ark_ed_on_bls12_381::{EdwardsAffine, Fr as EdBlsFr}; 5 | use ark_ff::{BigInteger, One, PrimeField, UniformRand}; 6 | use ark_groth16::Groth16; 7 | use ark_marlin::Marlin; 8 | use ark_poly::univariate::DensePolynomial; 9 | use ark_poly_commit::{ipa_pc::InnerProductArgPC, marlin_pc::MarlinKZG10, sonic_pc::SonicKZG10}; 10 | use ark_std::{self, test_rng, time::Instant, vec::Vec}; 11 | use arkworks_native_gadgets::{ 12 | merkle_tree::SparseMerkleTree, 13 | poseidon::{sbox::PoseidonSbox, FieldHasher, Poseidon, PoseidonParameters}, 14 | }; 15 | use arkworks_r1cs_circuits::vanchor::VAnchorCircuit; 16 | use arkworks_r1cs_gadgets::poseidon::PoseidonGadget; 17 | use arkworks_setups::{ 18 | common::{setup_keys_unchecked, setup_tree_and_create_path, SMT}, 19 | r1cs::vanchor::VAnchorR1CSProver, 20 | VAnchorProver, 21 | }; 22 | use arkworks_utils::{ 23 | bytes_matrix_to_f, bytes_vec_to_f, poseidon_params::setup_poseidon_params, Curve, 24 | }; 25 | use blake2::Blake2s; 26 | use std::collections::btree_map::BTreeMap; 27 | 28 | pub fn setup_params(curve: Curve, exp: i8, width: u8) -> PoseidonParameters { 29 | let pos_data = setup_poseidon_params(curve, exp, width).unwrap(); 30 | 31 | let mds_f = bytes_matrix_to_f(&pos_data.mds); 32 | let rounds_f = bytes_vec_to_f(&pos_data.rounds); 33 | 34 | PoseidonParameters { 35 | mds_matrix: mds_f, 36 | round_keys: rounds_f, 37 | full_rounds: pos_data.full_rounds, 38 | partial_rounds: pos_data.partial_rounds, 39 | sbox: PoseidonSbox(pos_data.exp), 40 | width: pos_data.width, 41 | } 42 | } 43 | 44 | macro_rules! setup_circuit { 45 | ($test_engine:ty, $test_field:ty, $test_curve:expr) => {{ 46 | const N_INS: usize = 2; 47 | const N_OUTS: usize = 2; 48 | const ANCHOR_CT: usize = 2; 49 | const HEIGHT: usize = 30; 50 | const DEFAULT_LEAF: [u8; 32] = [0u8; 32]; 51 | 52 | // Initialize hashers 53 | let params2 = setup_params::<$test_field>($test_curve, 5, 2); 54 | let params3 = setup_params::<$test_field>($test_curve, 5, 3); 55 | let params4 = setup_params::<$test_field>($test_curve, 5, 4); 56 | let params5 = setup_params::<$test_field>($test_curve, 5, 5); 57 | 58 | let keypair_hasher = Poseidon::<$test_field> { params: params2 }; 59 | let tree_hasher = Poseidon::<$test_field> { params: params3 }; 60 | let nullifier_hasher = Poseidon::<$test_field> { params: params4 }; 61 | let leaf_hasher = Poseidon::<$test_field> { params: params5 }; 62 | 63 | #[allow(non_camel_case_types)] 64 | type Prover = VAnchorR1CSProver<$test_engine, HEIGHT, ANCHOR_CT, N_INS, N_OUTS>; 65 | 66 | let rng = &mut test_rng(); 67 | let random_circuit = Prover::setup_random_circuit($test_curve, DEFAULT_LEAF, rng); 68 | 69 | // Make a proof now 70 | let public_amount: u32 = 10; 71 | let ext_data_hash = <$test_field>::rand(rng); 72 | 73 | // Input Utxos 74 | let in_chain_id = 0u64; 75 | let in_amount = 5; 76 | let index = 0u64; 77 | let in_utxo1 = 78 | Prover::create_random_utxo($test_curve, in_chain_id, in_amount, Some(index), rng) 79 | .unwrap(); 80 | let in_utxo2 = 81 | Prover::create_random_utxo($test_curve, in_chain_id, in_amount, Some(1), rng).unwrap(); 82 | let in_utxos = [in_utxo1.clone(), in_utxo2.clone()]; 83 | 84 | // Output Utxos 85 | let out_chain_id = 0u64; 86 | let out_amount = 10; 87 | let out_utxo1 = 88 | Prover::create_random_utxo($test_curve, out_chain_id, out_amount, None, rng).unwrap(); 89 | let out_utxo2 = 90 | Prover::create_random_utxo($test_curve, out_chain_id, out_amount, None, rng).unwrap(); 91 | let out_utxos = [out_utxo1, out_utxo2]; 92 | 93 | let leaf0 = in_utxo1.commitment; 94 | let leaf1 = in_utxo2.commitment; 95 | 96 | let (smt, _) = setup_tree_and_create_path::<$test_field, Poseidon<$test_field>, HEIGHT>( 97 | &tree_hasher, 98 | &[leaf0, leaf1], 99 | 0, 100 | &DEFAULT_LEAF, 101 | ) 102 | .unwrap(); 103 | 104 | let in_paths = [ 105 | smt.generate_membership_proof(0), 106 | smt.generate_membership_proof(1), 107 | ]; 108 | 109 | let mut in_leaves = BTreeMap::new(); 110 | in_leaves.insert(in_chain_id, vec![ 111 | leaf0.into_repr().to_bytes_be(), 112 | leaf1.into_repr().to_bytes_be(), 113 | ]); 114 | let in_indices: [u32; 2] = [0, 1]; 115 | let in_root_set = [ 116 | smt.root().into_repr().to_bytes_be(), 117 | smt.root().into_repr().to_bytes_be(), 118 | ]; 119 | 120 | let in_nullifiers: Vec<$test_field> = in_utxos 121 | .iter() 122 | .map(|x| x.calculate_nullifier(&nullifier_hasher.clone()).unwrap()) 123 | .collect(); 124 | 125 | // Cast as field elements 126 | let chain_id_elt = <$test_field>::from(in_chain_id); 127 | let public_amount_elt = <$test_field>::from(public_amount); 128 | let ext_data_hash_elt = 129 | <$test_field>::from_be_bytes_mod_order(&ext_data_hash.into_repr().to_bytes_be()); 130 | // Generate the paths for each UTXO 131 | let mut trees = BTreeMap::, HEIGHT>>::new(); 132 | 133 | let public_inputs = Prover::construct_public_inputs( 134 | chain_id_elt, 135 | public_amount_elt, 136 | in_root_set 137 | .clone() 138 | .map(|elt| <$test_field>::from_be_bytes_mod_order(&elt)) 139 | .to_vec(), 140 | in_nullifiers.to_vec(), 141 | out_utxos.clone().map(|utxo| utxo.commitment).to_vec(), 142 | ext_data_hash_elt, 143 | ); 144 | 145 | // Get the circuit 146 | let circuit = Prover::setup_circuit( 147 | chain_id_elt, 148 | public_amount_elt, 149 | ext_data_hash_elt, 150 | in_utxos, 151 | in_indices.map(<$test_field>::from), 152 | in_paths.to_vec(), 153 | in_root_set.map(|elt| <$test_field>::from_be_bytes_mod_order(&elt)), 154 | out_utxos.clone(), 155 | keypair_hasher, 156 | tree_hasher, 157 | nullifier_hasher, 158 | leaf_hasher, 159 | ) 160 | .unwrap(); 161 | 162 | (public_inputs, circuit) 163 | }}; 164 | } 165 | 166 | macro_rules! measure { 167 | ($task:block, $backend:expr, $task_name:expr, $num_iter:expr) => {{ 168 | let start = Instant::now(); 169 | for _ in 0..($num_iter - 1) { 170 | $task; 171 | } 172 | let res = $task; 173 | let end = start.elapsed(); 174 | println!( 175 | "{}: Average {} time: {:?}", 176 | $backend, 177 | $task_name, 178 | end / $num_iter 179 | ); 180 | res 181 | }}; 182 | } 183 | 184 | macro_rules! benchmark_marlin { 185 | ($marlin:ty, $engine:ty, $field:ty, $curve:expr, $name:expr, $nc:expr, $nv:expr, $num_iter:expr) => { 186 | let rng = &mut test_rng(); 187 | let (public_inputs, circuit) = setup_circuit!($engine, $field, $curve); 188 | 189 | // Setup 190 | let srs = measure!( 191 | { <$marlin>::universal_setup($nc, $nv, 3 * $nv, rng).unwrap() }, 192 | $name, 193 | "setup", 194 | $num_iter 195 | ); 196 | 197 | // Index 198 | let keys = measure!( 199 | { <$marlin>::index(&srs, circuit.clone()).unwrap() }, 200 | $name, 201 | "index", 202 | $num_iter 203 | ); 204 | 205 | // Prove 206 | let proof = measure!( 207 | { <$marlin>::prove(&keys.0, circuit.clone(), rng).unwrap() }, 208 | $name, 209 | "prove", 210 | $num_iter 211 | ); 212 | 213 | // verify 214 | let _ = measure!( 215 | { <$marlin>::verify(&keys.1, &public_inputs, &proof, rng).unwrap() }, 216 | $name, 217 | "verify", 218 | $num_iter 219 | ); 220 | }; 221 | } 222 | 223 | macro_rules! benchmark_groth { 224 | ($groth:ty, $engine:ty, $field:ty, $curve:expr, $num_iter:expr) => { 225 | let rng = &mut test_rng(); 226 | let (public_inputs, circuit) = setup_circuit!($engine, $field, $curve); 227 | 228 | // Setup 229 | let keys = measure!( 230 | { <$groth>::circuit_specific_setup(circuit.clone(), rng).unwrap() }, 231 | "Groth16", 232 | "setup", 233 | $num_iter 234 | ); 235 | 236 | // Prove 237 | let proof = measure!( 238 | { <$groth>::prove(&keys.0, circuit.clone(), rng).unwrap() }, 239 | "Groth16", 240 | "prove", 241 | $num_iter 242 | ); 243 | 244 | // verify 245 | let _ = measure!( 246 | { <$groth>::verify(&keys.1, &public_inputs, &proof).unwrap() }, 247 | "Groth16", 248 | "verify", 249 | $num_iter 250 | ); 251 | }; 252 | } 253 | 254 | fn benchmark_groth16(num_iter: u32) { 255 | type GrothSetup = Groth16; 256 | benchmark_groth!(GrothSetup, Bn254, ark_bn254::Fr, Curve::Bn254, num_iter); 257 | } 258 | 259 | // fn benchmark_marlin_poly(nc: usize, nv: usize, num_iter: u32) { 260 | // type KZG10 = MarlinKZG10>; 261 | // type MarlinSetup = Marlin; 262 | // benchmark_marlin!(MarlinSetup, BlsFr, "Marlin_PolyKZG10", nc, nv, num_iter); 263 | // } 264 | 265 | // fn benchmark_marlin_sonic(nc: usize, nv: usize, num_iter: u32) { 266 | // type Sonic = SonicKZG10>; 267 | // type MarlinSetup = Marlin; 268 | 269 | // benchmark_marlin!(MarlinSetup, BlsFr, "Marlin_Sonic", nc, nv, num_iter); 270 | // } 271 | 272 | // fn benchmark_marlin_ipa_pc(nc: usize, nv: usize, num_iter: u32) { 273 | // type IPA = InnerProductArgPC>; type MarlinSetup = Marlin; 275 | 276 | // benchmark_marlin!(MarlinSetup, EdBlsFr, "Marlin_IPA_PC", nc, nv, num_iter); 277 | // } 278 | 279 | fn main() { 280 | let nc = 65536; 281 | let nv = 65536; 282 | let num_iter = 5; 283 | 284 | // Groth16 285 | benchmark_groth16(num_iter); 286 | // // MarlinKZG10 287 | // benchmark_marlin_poly(nc, nv, num_iter); 288 | // // Sonic 289 | // benchmark_marlin_sonic(nc, nv, num_iter); 290 | // // IPA 291 | // benchmark_marlin_ipa_pc(nc, nv, num_iter); 292 | } 293 | -------------------------------------------------------------------------------- /arkworks/utils/src/poseidon_params/bn254_x5_2.rs: -------------------------------------------------------------------------------- 1 | pub const FULL_ROUNDS: u8 = 8; 2 | pub const PARTIAL_ROUNDS: u8 = 56; 3 | pub const WIDTH: u8 = 2; 4 | pub const EXPONENTIATION: i8 = 5; 5 | 6 | pub const ROUND_CONSTS: &[&str] = &[ 7 | "0x09c46e9ec68e9bd4fe1faaba294cba38a71aa177534cdd1b6c7dc0dbd0abd7a7", 8 | "0x0c0356530896eec42a97ed937f3135cfc5142b3ae405b8343c1d83ffa604cb81", 9 | "0x1e28a1d935698ad1142e51182bb54cf4a00ea5aabd6268bd317ea977cc154a30", 10 | "0x27af2d831a9d2748080965db30e298e40e5757c3e008db964cf9e2b12b91251f", 11 | "0x1e6f11ce60fc8f513a6a3cfe16ae175a41291462f214cd0879aaf43545b74e03", 12 | "0x2a67384d3bbd5e438541819cb681f0be04462ed14c3613d8f719206268d142d3", 13 | "0x0b66fdf356093a611609f8e12fbfecf0b985e381f025188936408f5d5c9f45d0", 14 | "0x012ee3ec1e78d470830c61093c2ade370b26c83cc5cebeeddaa6852dbdb09e21", 15 | "0x0252ba5f6760bfbdfd88f67f8175e3fd6cd1c431b099b6bb2d108e7b445bb1b9", 16 | "0x179474cceca5ff676c6bec3cef54296354391a8935ff71d6ef5aeaad7ca932f1", 17 | "0x2c24261379a51bfa9228ff4a503fd4ed9c1f974a264969b37e1a2589bbed2b91", 18 | "0x1cc1d7b62692e63eac2f288bd0695b43c2f63f5001fc0fc553e66c0551801b05", 19 | "0x255059301aada98bb2ed55f852979e9600784dbf17fbacd05d9eff5fd9c91b56", 20 | "0x28437be3ac1cb2e479e1f5c0eccd32b3aea24234970a8193b11c29ce7e59efd9", 21 | "0x28216a442f2e1f711ca4fa6b53766eb118548da8fb4f78d4338762c37f5f2043", 22 | "0x2c1f47cd17fa5adf1f39f4e7056dd03feee1efce03094581131f2377323482c9", 23 | "0x07abad02b7a5ebc48632bcc9356ceb7dd9dafca276638a63646b8566a621afc9", 24 | "0x0230264601ffdf29275b33ffaab51dfe9429f90880a69cd137da0c4d15f96c3c", 25 | "0x1bc973054e51d905a0f168656497ca40a864414557ee289e717e5d66899aa0a9", 26 | "0x2e1c22f964435008206c3157e86341edd249aff5c2d8421f2a6b22288f0a67fc", 27 | "0x1224f38df67c5378121c1d5f461bbc509e8ea1598e46c9f7a70452bc2bba86b8", 28 | "0x02e4e69d8ba59e519280b4bd9ed0068fd7bfe8cd9dfeda1969d2989186cde20e", 29 | "0x1f1eccc34aaba0137f5df81fc04ff3ee4f19ee364e653f076d47e9735d98018e", 30 | "0x1672ad3d709a353974266c3039a9a7311424448032cd1819eacb8a4d4284f582", 31 | "0x283e3fdc2c6e420c56f44af5192b4ae9cda6961f284d24991d2ed602df8c8fc7", 32 | "0x1c2a3d120c550ecfd0db0957170fa013683751f8fdff59d6614fbd69ff394bcc", 33 | "0x216f84877aac6172f7897a7323456efe143a9a43773ea6f296cb6b8177653fbd", 34 | "0x2c0d272becf2a75764ba7e8e3e28d12bceaa47ea61ca59a411a1f51552f94788", 35 | "0x16e34299865c0e28484ee7a74c454e9f170a5480abe0508fcb4a6c3d89546f43", 36 | "0x175ceba599e96f5b375a232a6fb9cc71772047765802290f48cd939755488fc5", 37 | "0x0c7594440dc48c16fead9e1758b028066aa410bfbc354f54d8c5ffbb44a1ee32", 38 | "0x1a3c29bc39f21bb5c466db7d7eb6fd8f760e20013ccf912c92479882d919fd8d", 39 | "0x0ccfdd906f3426e5c0986ea049b253400855d349074f5a6695c8eeabcd22e68f", 40 | "0x14f6bc81d9f186f62bdb475ce6c9411866a7a8a3fd065b3ce0e699b67dd9e796", 41 | "0x0962b82789fb3d129702ca70b2f6c5aacc099810c9c495c888edeb7386b97052", 42 | "0x1a880af7074d18b3bf20c79de25127bc13284ab01ef02575afef0c8f6a31a86d", 43 | "0x10cba18419a6a332cd5e77f0211c154b20af2924fc20ff3f4c3012bb7ae9311b", 44 | "0x057e62a9a8f89b3ebdc76ba63a9eaca8fa27b7319cae3406756a2849f302f10d", 45 | "0x287c971de91dc0abd44adf5384b4988cb961303bbf65cff5afa0413b44280cee", 46 | "0x21df3388af1687bbb3bca9da0cca908f1e562bc46d4aba4e6f7f7960e306891d", 47 | "0x1be5c887d25bce703e25cc974d0934cd789df8f70b498fd83eff8b560e1682b3", 48 | "0x268da36f76e568fb68117175cea2cd0dd2cb5d42fda5acea48d59c2706a0d5c1", 49 | "0x0e17ab091f6eae50c609beaf5510ececc5d8bb74135ebd05bd06460cc26a5ed6", 50 | "0x04d727e728ffa0a67aee535ab074a43091ef62d8cf83d270040f5caa1f62af40", 51 | "0x0ddbd7bf9c29341581b549762bc022ed33702ac10f1bfd862b15417d7e39ca6e", 52 | "0x2790eb3351621752768162e82989c6c234f5b0d1d3af9b588a29c49c8789654b", 53 | "0x1e457c601a63b73e4471950193d8a570395f3d9ab8b2fd0984b764206142f9e9", 54 | "0x21ae64301dca9625638d6ab2bbe7135ffa90ecd0c43ff91fc4c686fc46e091b0", 55 | "0x0379f63c8ce3468d4da293166f494928854be9e3432e09555858534eed8d350b", 56 | "0x002d56420359d0266a744a080809e054ca0e4921a46686ac8c9f58a324c35049", 57 | "0x123158e5965b5d9b1d68b3cd32e10bbeda8d62459e21f4090fc2c5af963515a6", 58 | "0x0be29fc40847a941661d14bbf6cbe0420fbb2b6f52836d4e60c80eb49cad9ec1", 59 | "0x1ac96991dec2bb0557716142015a453c36db9d859cad5f9a233802f24fdf4c1a", 60 | "0x1596443f763dbcc25f4964fc61d23b3e5e12c9fa97f18a9251ca3355bcb0627e", 61 | "0x12e0bcd3654bdfa76b2861d4ec3aeae0f1857d9f17e715aed6d049eae3ba3212", 62 | "0x0fc92b4f1bbea82b9ea73d4af9af2a50ceabac7f37154b1904e6c76c7cf964ba", 63 | "0x1f9c0b1610446442d6f2e592a8013f40b14f7c7722236f4f9c7e965233872762", 64 | "0x0ebd74244ae72675f8cde06157a782f4050d914da38b4c058d159f643dbbf4d3", 65 | "0x2cb7f0ed39e16e9f69a9fafd4ab951c03b0671e97346ee397a839839dccfc6d1", 66 | "0x1a9d6e2ecff022cc5605443ee41bab20ce761d0514ce526690c72bca7352d9bf", 67 | "0x2a115439607f335a5ea83c3bc44a9331d0c13326a9a7ba3087da182d648ec72f", 68 | "0x23f9b6529b5d040d15b8fa7aee3e3410e738b56305cd44f29535c115c5a4c060", 69 | "0x05872c16db0f72a2249ac6ba484bb9c3a3ce97c16d58b68b260eb939f0e6e8a7", 70 | "0x1300bdee08bb7824ca20fb80118075f40219b6151d55b5c52b624a7cdeddf6a7", 71 | "0x19b9b63d2f108e17e63817863a8f6c288d7ad29916d98cb1072e4e7b7d52b376", 72 | "0x015bee1357e3c015b5bda237668522f613d1c88726b5ec4224a20128481b4f7f", 73 | "0x2953736e94bb6b9f1b9707a4f1615e4efe1e1ce4bab218cbea92c785b128ffd1", 74 | "0x0b069353ba091618862f806180c0385f851b98d372b45f544ce7266ed6608dfc", 75 | "0x304f74d461ccc13115e4e0bcfb93817e55aeb7eb9306b64e4f588ac97d81f429", 76 | "0x15bbf146ce9bca09e8a33f5e77dfe4f5aad2a164a4617a4cb8ee5415cde913fc", 77 | "0x0ab4dfe0c2742cde44901031487964ed9b8f4b850405c10ca9ff23859572c8c6", 78 | "0x0e32db320a044e3197f45f7649a19675ef5eedfea546dea9251de39f9639779a", 79 | "0x0a1756aa1f378ca4b27635a78b6888e66797733a82774896a3078efa516da016", 80 | "0x044c4a33b10f693447fd17177f952ef895e61d328f85efa94254d6a2a25d93ef", 81 | "0x2ed3611b725b8a70be655b537f66f700fe0879d79a496891d37b07b5466c4b8b", 82 | "0x1f9ba4e8bab7ce42c8ecc3d722aa2e0eadfdeb9cfdd347b5d8339ea7120858aa", 83 | "0x1b233043052e8c288f7ee907a84e518aa38e82ac4502066db74056f865c5d3da", 84 | "0x2431e1cc164bb8d074031ab72bd55b4c902053bfc0f14db0ca2f97b020875954", 85 | "0x082f934c91f5aac330cd6953a0a7db45a13e322097583319a791f273965801fd", 86 | "0x2b9a0a223e7538b0a34be074315542a3c77245e2ae7cbe999ad6bb930c48997c", 87 | "0x0e1cd91edd2cfa2cceb85483b887a9be8164163e75a8a00eb0b589cc70214e7d", 88 | "0x2e1eac0f2bfdfd63c951f61477e3698999774f19854d00f588d324601cebe2f9", 89 | "0x0cbfa95f37fb74060c76158e769d6d157345784d8efdb33c23d748115b500b83", 90 | "0x08f05b3be923ed44d65ad49d8a61e9a676d991e3a77513d9980c232dfa4a4f84", 91 | "0x22719e2a070bcd0852bf8e21984d0443e7284925dc0758a325a2dd510c047ef6", 92 | "0x041f596a9ee1cb2bc060f7fcc3a1ab4c7bdbf036119982c0f41f62b2f26830c0", 93 | "0x233fd35de1be520a87628eb06f6b1d4c021be1c2d0dc464a19fcdd0986b10f89", 94 | "0x0524b46d1aa87a5e4325e0a423ebc810d31e078aa1b4707eefcb453c61c9c267", 95 | "0x2c34f424c81e5716ce47fcac894b85824227bb954b0f3199cc4486237c515211", 96 | "0x0b5f2a4b63387819207effc2b5541fb72dd2025b5457cc97f33010327de4915e", 97 | "0x22207856082ccc54c5b72fe439d2cfd6c17435d2f57af6ceaefac41fe05c659f", 98 | "0x24d57a8bf5da63fe4e24159b7f8950b5cdfb210194caf79f27854048ce2c8171", 99 | "0x0afab181fdd5e0583b371d75bd693f98374ad7097bb01a8573919bb23b79396e", 100 | "0x2dba9b108f208772998a52efac7cbd5676c0057194c16c0bf16290d62b1128ee", 101 | "0x26349b66edb8b16f56f881c788f53f83cbb83de0bd592b255aff13e6bce420b3", 102 | "0x25af7ce0e5e10357685e95f92339753ad81a56d28ecc193b235288a3e6f137db", 103 | "0x25b4ce7bd2294390c094d6a55edd68b970eed7aae88b2bff1f7c0187fe35011f", 104 | "0x22c543f10f6c89ec387e53f1908a88e5de9cef28ebdf30b18cb9d54c1e02b631", 105 | "0x0236f93e7789c4724fc7908a9f191e1e425e906a919d7a34df668e74882f87a9", 106 | "0x29350b401166ca010e7d27e37d05da99652bdae114eb01659cb497af980c4b52", 107 | "0x0eed787d65820d3f6bd31bbab547f75a65edb75d844ebb89ee1260916652363f", 108 | "0x07cc1170f13b46f2036a753f520b3291fdcd0e99bd94297d1906f656f4de6fad", 109 | "0x22b939233b1d7205f49bcf613a3d30b1908786d7f9f5d10c2059435689e8acea", 110 | "0x01451762a0aab81c8aad1dc8bc33e870740f083a5aa85438add650ace60ae5a6", 111 | "0x23506bb5d8727d4461fabf1025d46d1fe32eaa61dec7da57e704fec0892fce89", 112 | "0x2e484c44e838aea0bac06ae3f71bdd092a3709531e1efea97f8bd68907355522", 113 | "0x0f4bc7d07ebafd64379e78c50bd2e42baf4a594545cedc2545418da26835b54c", 114 | "0x1f4d3c8f6583e9e5fa76637862faaee851582388725df460e620996d50d8e74e", 115 | "0x093514e0c70711f82660d07be0e4a988fae02abc7b681d9153eb9bcb48fe7389", 116 | "0x1adab0c8e2b3bad346699a2b5f3bc03643ee83ece47228f24a58e0a347e153d8", 117 | "0x1672b1726057d99dd14709ebb474641a378c1b94b8072bac1a22dbef9e80dad2", 118 | "0x1dfd53d4576af2e38f44f53fdcab468cc5d8e2fae0acc4ee30d47b239b479c14", 119 | "0x0c6888a10b75b0f3a70a36263a37e17fe6d77d640f6fc3debc7f207753205c60", 120 | "0x1addb933a65be77092b34a7e77d12fe8611a61e00ee6848b85091ecca9d1e508", 121 | "0x00d7540dcd268a845c10ae18d1de933cf638ff5425f0afff7935628e299d1791", 122 | "0x140c0e42687e9ead01b2827a5664ca9c26fedde4acd99db1d316939d20b82c0e", 123 | "0x2f0c3a115d4317d191ba89b8d13d1806c20a0f9b24f8c5edc091e2ae56565984", 124 | "0x0c4ee778ff7c14553006ed220cf9c81008a0cff670b22b82d8c538a1dc958c61", 125 | "0x1704f2766d46f82c3693f00440ccc3609424ed26c0acc66227c3d7485de74c69", 126 | "0x2f2d19cc3ea5d78ea7a02c1b51d244abf0769c9f8544e40239b66fe9009c3cfa", 127 | "0x1ae03853b75fcaba5053f112e2a8e8dcdd7ee6cb9cfed9c7d6c766a806fc6629", 128 | "0x0971aabf795241df51d131d0fa61aa5f3556921b2d6f014e4e41a86ddaf056d5", 129 | "0x1408c316e6014e1a91d4cf6b6e0de73eda624f8380df1c875f5c29f7bfe2f646", 130 | "0x1667f3fe2edbe850248abe42b543093b6c89f1f773ef285341691f39822ef5bd", 131 | "0x13bf7c5d0d2c4376a48b0a03557cdf915b81718409e5c133424c69576500fe37", 132 | "0x07620a6dfb0b6cec3016adf3d3533c24024b95347856b79719bc0ba743a62c2c", 133 | "0x1574c7ef0c43545f36a8ca08bdbdd8b075d2959e2f322b731675de3e1982b4d0", 134 | "0x269e4b5b7a2eb21afd567970a717ceec5bd4184571c254fdc06e03a7ff8378f0", 135 | ]; 136 | 137 | pub const MDS_ENTRIES: &[&[&str]] = &[ 138 | &[ 139 | "0x066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad5", 140 | "0x2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e8", 141 | ], 142 | &[ 143 | "0x0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff9", 144 | "0x1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c8", 145 | ], 146 | ]; -------------------------------------------------------------------------------- /arkworks/utils/src/poseidon_params/ed_on_bn254_x17_3.rs: -------------------------------------------------------------------------------- 1 | // sage generate_parameters_grain.sage 1 0 254 3 8 33 2 | // 0x60c89ce5c263405370a08b6d0302b0bab3eedb83920ee0a677297dc392126f1 3 | pub const ROUND_CONSTS: [&str; 123] = [ 4 | "0x014e086a0e26de2206c607c19c294d9a4f1271642ec3e6fa25d75b34d3edd896", 5 | "0x015506a250a1fb6f5fc65a3386f33a93dc53b26aa4f495fe907bb37d802c7b5f", 6 | "0x045a0001f5ca1008c1297c8c845f438819a3e1de12a4db6601d364fefce08466", 7 | "0x001cd295eabaac4a64c57e07364caf03279e25b58805d1590e493e79b2dd1ae4", 8 | "0x01efcc089f07fe8a25fde5c328678633c9ec23cdaf554d21b17a7f11ffd13cb7", 9 | "0x04f981ebe367ab4076112d77fbafb9e1467738b9300bbb7526de0a526c81288c", 10 | "0x0041d72e6ecaf8313949f8ad7b5f370ffa403abff55cfd285be93083a810d90a", 11 | "0x0453618b764c28db39028e848007d73ec0262a5a2b38033238b1e27d6468cdb0", 12 | "0x04728521ee32f7da39fdd4fae3160234e81d682160a89a34a76273bff47136f6", 13 | "0x0336c68f9dab0d529e632f6bc7a20702e81d7c2285b73541ad6536e5fa1ee91f", 14 | "0x01106e7cd76c36f68de5fbbf89e5aae2fdb80551cf7b41bd96524b8ed8341491", 15 | "0x04d00b6ec45cc0f116abca222ff9d71bc20be198e629a00af5bd12589e10d81e", 16 | "0x015dbb9f5d98bc2b626163e32f3dc567974e0f3d40509898ff86dc20725f5a3d", 17 | "0x001bff94b71b594b57c5890e6e2fb135c7917f175689e8f35991681561396f1f", 18 | "0x02501be69afc8a130f75690ed96104492eac825f77556b7bbdd5ee34c5c21aca", 19 | "0x0354196e45373845b6fdcfa1f6086907f28225ffdeaa6d05e35db9c83875fb01", 20 | "0x00e12a5f7536ce4aac8f96711b7a71ea52856bd00a3ccaa423dccd3404441892", 21 | "0x0386f033c3b0e0cadb465c670424bb8555bd6d082b07169009137ad387e3af48", 22 | "0x03a608df451797f8192cb934ed0e877a447cff5332bdec78dc100e61e9701254", 23 | "0x008e2c012a0ec28acfad7d62de08df74b3264d4389f50ab19400f9bd2edb3dd0", 24 | "0x03b319850f0e791bf092aebdd64d81380b13131bebfc7d42c88dde4cf3f1b5fe", 25 | "0x01473f6a0a0b85558ede1ae9e573dd65da42acfdfd45fa441f77001857efcadc", 26 | "0x0253f9cfc6c65954b5784cbf9ca270f279e949fa509f6aec5c05f73e79cfe1f4", 27 | "0x018f9a3692bb8dbd026aae9aa0f90e708bd1678d8b97af8a1a38e4a540313e11", 28 | "0x01d4c8b6642f5ad2f6902d4816f60346a7ab923b07c12d69f2bd4d6a1ddd9644", 29 | "0x04552a3f7ee5866a11309ed097e76282434c40009b10b57340267c8bcd7547a1", 30 | "0x055b4c4c76f5c628dcb6fdbd4c71a2775f9c11cc39f8f32f01dde231232f5d5a", 31 | "0x04fcaaaf0bbb9063623516beb78d42acf7e18c22afd0c0c0e33511f07b9f7c36", 32 | "0x0256b73ef289430c22fd282efa785ca9fd5ec07fb5df36d52aecea1e4806b7c0", 33 | "0x03d599a46b1dd605c843e56a18231df3eefe9b98c28dee0c0c6c2c48902264fc", 34 | "0x00443406a46d75e68bccb364619c501aad4e03b63bb3f4ca714b8f262fa5c766", 35 | "0x04bedfdef7b6e86a8f6a5de3bd5a9f52627320ecee9a98dbf26d5c23237e3e69", 36 | "0x03988c43103eef81ca9a668c43927255d507c4fbad0738323be0c5002e687475", 37 | "0x00746cd943a037cfefaa4cb058929f8ef3d47c8adc74304f0152bb31c9eafee2", 38 | "0x04d5757a6eb1cf8fbf08f7efd766533c0d4bf959ab7fefdfc1d215e50fb662f9", 39 | "0x00f4e41ed81a018045a6b8e12cf5faa236cd16ca18bd403af8476b4b7d4f316e", 40 | "0x05e94dcac1a26ce8fcc913227a3e9b0f30dc7a175d125717aad3257e527014b2", 41 | "0x05a434468f634eda0b487c370edbd1994c5c289b7f173c666a2d1eda7265e85b", 42 | "0x01b75a949a98b579935b123082f4e7a00b9cef08a4d870ec163d7076ba6f41e1", 43 | "0x02350469e5435eba49cf66c6af138d1744eea40d9b1e3cf766125b6491974807", 44 | "0x03dabb2755f07a41e5a53206c95b9e7ebf95eba33eb8bb2d827e50daa043005e", 45 | "0x0502f7b95c682e95f92a0d4b645c6a8633282929f6dd72092d25da9c377b95d2", 46 | "0x042754067c526243e4d677ef6a25dbfe3638e6bb4366edd4545c80cbae673375", 47 | "0x037124f26a36ea7be546efdbc238bfe38e71713bbbffcabb4bdc503b79e4d75e", 48 | "0x040049aeedadce23d9eeb949862cef30f971ce87820d4a05f5f6b7f2299ca0bf", 49 | "0x02d0d6f30ee69051d503cd1264573d467d668667ed214bd85a9f269b1f1c66fd", 50 | "0x0256d33893982386fce8ee10870945eab6711b23dc9bbdac1aaa670a4c6febad", 51 | "0x0119e98547ecd21942f6e720d45cfa94f11399ee469a6ea7d55a26abe89d5d3d", 52 | "0x05bc94a5e51f18f6728bc18180e14067949779cf981dc6333efc01c1e92da5d3", 53 | "0x05e6656c1fa2607befd8a913b3187072915dfd790bee8ea2b825b388f8b157f3", 54 | "0x0043ca60e08d74d85b3eda4a663199c8c3957cc5d452b53602be2ac18b6edf82", 55 | "0x04943a2e7ab2602fcaf3af431fdf61f1647f6205ce7656e866589d394961b01f", 56 | "0x050d2cafd1a8233b0f8a972fdd0a9d255a2d41c61b8a4a402579989b58421077", 57 | "0x00a27dc534e03b40b3b2c571261f5f27ca18139c4b414237710a3cdc4970a09d", 58 | "0x0290fad8b9cb750fe8824626b6d1be2ddddec6a5d7d9fd3304ed0e1d03fc37d5", 59 | "0x00a0932894c80b1032267f0e0848b6f88c4ab7b32bc7adbdf3b26b82e76d82f4", 60 | "0x04178c208f0c3d091b968312e6c53029e2f359fda52ddc1644d4c01b0eff1736", 61 | "0x04ac8af76611ad0115cf7c763de317dc2d0cad6fba4a2a507d8ca95ab9dc2285", 62 | "0x00aeb00e6717e2858d00f8c9e0ab3cc884765b688534501a491750cfa8312454", 63 | "0x03c22157504bde1577780ac27ced1bc29935875fb7b74e1ae67067e2cc419b63", 64 | "0x0431cdc05b25e9db3cf7495906dec3fa7506d10dfb0251b510b2951bedc1cc83", 65 | "0x0474a3d3dfd3ffdae081b44bf570edecb9f32fb6ea61b2748805ecef50f68f6f", 66 | "0x00bb3b9e5ca86b503681162217e6d1286c3b24e5001415de44d35e6f514b1429", 67 | "0x013c5205144c2ce1f88b763778199fffcec31df53608131e55cc5cc32ebac8f6", 68 | "0x025887031d994eccc2ad1952563442a2e94a2b32843a6d4f8f4c79f1b9df1477", 69 | "0x048f39496c8449e764980288caabc12c9892127edcae0028d10b8be63768487b", 70 | "0x02c4637bd00818f73df619223e53555396076af548e94b40cc33ede39a39f1b1", 71 | "0x0479d7c6ff2049ac4554902ff748a7f19826042af0f2736ea2515d3896d6a4d1", 72 | "0x0520809bb7a281adf77adab925c333c369f2a8e7e246230e5a78079e2788d2ca", 73 | "0x039a63613c03c1f07c07874f9853865e56ec6c2282bc65422f95ba5079fde419", 74 | "0x0591e8cf5d1a718b69c330311313bdf848b007d3aa0392fe0bfa5a6cd94535a0", 75 | "0x03cf4f8642a832962dcd1b5029743f923a10a184ee36ae66d7f9ee21858423aa", 76 | "0x054a717e9e4041d43638bc03fc42b72cd81fa1e3e52a356ef7b15883a6624188", 77 | "0x04b8b70eb2a6272d06401d4d240a497f7c739024e717fa6e2ccc41017beaa48c", 78 | "0x05c0d44645ef1a3d82f1d7fc72b8513f0278601a3156ec9d5ad2b2902d17d17d", 79 | "0x03ae1d9a0172c2bc17c26643b67c2a7d4e23beff7e79e6c69c681abf3982dd13", 80 | "0x014685aba452330b8c91fcb001c93ebc7100a0d0da75b8e84499c18c77fe6d6d", 81 | "0x02ed9846e2aec0480c03ea9e29a14d8a9a979134d549be2eed11946b563a79a4", 82 | "0x021cb9d7e26c05be16abee3f6ea7c41a7c641c1d9c3878a524d5fc079736ac5e", 83 | "0x00478b2228cbbd724a25e31136e864761b1b50054f7e35d35551ca94a94cc230", 84 | "0x02dbd89a95cdc39b4a9215b985373c27f8160662f186ae548c1c3817edeba429", 85 | "0x042c3ad26a91606c0b9fe14740588db92bc3147ee7ad583844468871ead1e4d6", 86 | "0x0269e2949c858845b6529f9a9002337a2131379feca0b3599a0002e67a058d15", 87 | "0x00d0304ed09176a0c2937b229a3554ce5ff26ee23fed7301d20970f1e747070b", 88 | "0x03ca8fdbbe8bff72bd047569518b2c3b198cf2b6b2c03054214f6b51a6090bb1", 89 | "0x02f573e6c130ff091e8ff0db4cf9ce84e5646c18bf6ebca798a1ed86427dd7e0", 90 | "0x013a84aef38438d77288ca49ee11cd30e17311b6640c405b89bb5c4a65f857ca", 91 | "0x01200c4bd29cd6996cde149248dedd832d60e51304090649a3b6c8c235cff855", 92 | "0x05f987a5ad487f1ded2be7ba927e45e62b4984df78d307a28a3ebde3e05f3790", 93 | "0x0587de656aa8a542e198790cc3c6d487fd37c89604e0590fd32c2598b9d543bb", 94 | "0x0166f9bb6409e00ac64aa4a149d47cbdd017ae2c1fa02246b54f58f88e1a2c78", 95 | "0x00c1dc093135fce3a892674e0016b9ea5a01c343567423755b4967047ff72a92", 96 | "0x031666888460eb246902d65fc8fecda442b9e18028f17778e1734d076db5c03e", 97 | "0x052cc60267651ff534fd13043664eea114ffb9c6cd45fa4d32fcb255f5c0e6f5", 98 | "0x023e4db2df37a29e6f5b3ffbff6b27b6d4d0787aae7cab9a17e7bac99f7992e3", 99 | "0x053a12ee8386b6643f8be2b8cb98dfd6a551e76434e2a0102be19693936137ba", 100 | "0x0553805099487c554d264fb2f358a5f682f5b63ddd14304be1d450d6f6a4b53b", 101 | "0x03f2910ba52718ee7d717658637088948c1e700125cedaab0105aac4b93cddfc", 102 | "0x038e6fa9507b7efa1318d9f4131a5b19d80f81d1a4e8d1b6cd71c75fef9b4841", 103 | "0x041175884c1d813a21d299a75ba435c626343911b90febc8f166042626cca198", 104 | "0x049b57ea3884e0c51732db52c72f6f4beee010b0a08903e4cda54cb8aaf3aaa7", 105 | "0x02f9bfdd2df04d7b5623b268e1aad21ca941a4a81b8e58fd2d293af1de8dd2b1", 106 | "0x04e157aeaef5b3ef414d0028d9a81d3f47716c94d821127cd8fb1cf0c9347e76", 107 | "0x0484a4a089d9401611c5bb59255f1f30eb9f67305f9baf75f42ac8b8a4360830", 108 | "0x024c36e2d80873a30314f4dfb687e7ee1a895e1b44fab6be0463f4dc71a0340b", 109 | "0x01afb935a6da3b71fe48ca74c71a3b4759d88119d24014b32bdd1405bc851714", 110 | "0x03efc676a43b034758da40d6966eb7f9fad063314c2817f28fcb5edf41aa33e2", 111 | "0x04fabd92b3541eb91247802989b3ee25a206e4101fa276c783cd04582ef8ddfd", 112 | "0x02d513fcf15b78afbf44721b88b71e7574e22c2a7089a9e1ef07012bd7b9b383", 113 | "0x001b924a795cb953ec94313d0cae5906525980a423e7190833eee38bb76f496a", 114 | "0x00be8c338931b90d26e448a1a652e9aaa8b40d5786bcca7f66cbb5c3802989f8", 115 | "0x01534841031f3a14edd199189f861a3c458bb58e8588f511724400463ea3670b", 116 | "0x00df0b0ba902b2eea5313c22a92d9af7e7fc71b08edcf2f6b9e3d04d7577e7f2", 117 | "0x02ae3290b84338003ce5933f31f954725b30e473a735dd8c598463686f04b059", 118 | "0x0168a8f7db83f0208f2fe2d699ddd32caa1c4ce2eae4837029b249eb335bb3ed", 119 | "0x0333bb1c73838c0560e62287209d695a2763f701f522d9102da15416b0e523a1", 120 | "0x0248cdf5a7863b4f81838275c3b0cd1316d06c78620250c9cc156c2434112e43", 121 | "0x05134439ef26c3e3d3c6f4de41522f1bebdc9cf504c471d6095def1fa0891860", 122 | "0x0229ce576f2123839b7f7a7019c0d9a323f50e4a8efcff8584371345b0a1f88e", 123 | "0x024b7cb66c8e411b8c317aeaa6bd0e6065262513a12941bd0db73a4797ef5fc0", 124 | "0x007aea65a6b71c112191096baf6bec9ed98afa015c970d1178a84484f1fe547e", 125 | "0x01b935821f13d6dd5caa915e1450cab0929d669a1e577a8a851097c3448e6fb0", 126 | "0x04072758d2b8ce6a58f53f513592a47415bbb09acc761ee99ab41b29d2448dce", 127 | ]; 128 | pub const MDS_ENTRIES: [[&str; 3]; 3] = [ 129 | [ 130 | "0x055d8126365f4fd884ca1f52f10f0455f88b070476c5fffde9bf2bb5ef07a394", 131 | "0x056f2e948db739e02a12d68e8eb629120afc2c63c86f6fdbb57018e68495dd24", 132 | "0x056fdea02d4751eec55aa670cecba5567a57200f8b5dfb48dfd1eae8af46eeb1", 133 | ], 134 | [ 135 | "0x03cb4a21fd13393ba31cceaa984c94833417bccd63a3e41eef0b06926dc35086", 136 | "0x02b7a624d5d58fef0b124dc7e9fde43866891e425747304778dbd36d4c2fb9c3", 137 | "0x04c08de963026bb129915750146820b2592cdae362574f3ca0a7a26502fea6fe", 138 | ], 139 | [ 140 | "0x01d346915ade64140d6ddaca825f62e99582a17373b0f7942c2b1c648f435c19", 141 | "0x05d9d163b66c50d0fb82250781120b54369471733f98ed142e5a706d91769fb8", 142 | "0x033de9bed682bf475337b9a8bd5f0538d6ca417bb55d4a5c0b93d814bd732340", 143 | ], 144 | ]; 145 | -------------------------------------------------------------------------------- /arkworks/utils/src/poseidon_params/bn254_x17_3.rs: -------------------------------------------------------------------------------- 1 | pub const FULL_ROUNDS: u8 = 8; 2 | pub const PARTIAL_ROUNDS: u8 = 57; 3 | pub const WIDTH: u8 = 3; 4 | pub const EXPONENTIATION: i8 = 17; 5 | 6 | pub const ROUND_CONSTS: &[&str] = &[ 7 | "0x1b3076f41cbcf5e9fa4b78634027ea500524cba9bbbad22fa1c4b7cc19aa66c3", 8 | "0x2bf1bc122783fa0c18aded20b5f1bd9aaefd0d87b6a8ea8fad2bddf367cc083d", 9 | "0x2f6f368166d3e953002ccc2e0c0e61663fdbb0034bb97b51ea95a935f0a9d49b", 10 | "0x25686dd23dc2d13b1f5495c9766ff0b529958dfa7568e1dbf9ba1a72d5e8207f", 11 | "0x10bda68ef40806e06c7a5a337200f7bb0780e78726fb3e656b40cb3eeadd2234", 12 | "0x28d2c5710e7bf5f003c277f1c6dd77e9be9368e01312c6d8c0c5b44194729db6", 13 | "0x2d595d8bfea5799caacdccf6a679d758999ce723fb5031e5632535adedf9fcb0", 14 | "0x298b70c75b803c70d32fbf16b6270fe96fca63b71f2458fe3752631e4b3283a7", 15 | "0x215f35ff3c6092ccd587a1c7e0f76cc058d4c1215c0709145c0df5fddbf610d1", 16 | "0x1f95bb518cee738e8ba1c5bef5ee4245c335e80d8066529f483d842bb8724108", 17 | "0x014e086a0e26de2206c607c19c294d9a4f1271642ec3e6fa25d75b34d3edd896", 18 | "0x1bc43ff9bc4dada561a29a272522b5ce78a607b27823b36702fa49b2caf0737d", 19 | "0x0feb0ad8ec3390116eb8ec87c2f8db1b8de77de5f0ceaa048af31846737c704b", 20 | "0x297861c63fc1006e29cb4453c0f52816daba75b697f7506a505b741e3c1012d9", 21 | "0x1a77213275c2433f16588a5802e35e34c66e36f5a55599fe7f306e05bf6031c8", 22 | "0x1db5a0c8a1fad3fca0edf3ced0caf927725633d2a7e004d3c2e0d911631bb597", 23 | "0x2ed8c931f260729c27badbfac10ffac282a932de62374bd3ac9678496764e5a4", 24 | "0x0ec01e6492f3d1016e906dd15a671c24d00a962e32c915065ca42533a36a8eb1", 25 | "0x1d5d981cc72a322e7684d9799600c4b938ae611b85ccc0359db9d50a14443edf", 26 | "0x1b4bf8681db9becdcb407038189624cbe13e3a1c9e730d5973bd01bc2e0b0b30", 27 | "0x2d4e57bda01ba34988e59232a99997e61d9079d0f7e93579a19432e90b527366", 28 | "0x242f43b7b5c2a7efe2457d534a82266de37f7d07b8bb558eab4596edb712e804", 29 | "0x15f4cf135455a6b6d08be9090458b92b6906fb109309679e10da9b895f76b0a1", 30 | "0x1c87f41b43d145318d4691e949b5251e608775a94f5955a8bc9bbf28087b72fd", 31 | "0x2ff9a5cde190b4e0e9c118daf823d0296b5b733974a42479d4f1208a52fe0814", 32 | "0x2462bf4ca426f9321111c199599054179995a6b73ce156035c59a16bd70bf2f7", 33 | "0x2398a82cba8e0cea9bbf22967159ad1144505be8799bb7a9b598fd8b1d2eb63e", 34 | "0x0ae80bd7e2cc3a57f9cedfc234e544c8098e2a22eab3b41befaf9ae1f45fabca", 35 | "0x015506a250a1fb6f5fc65a3386f33a93dc53b26aa4f495fe907bb37d802c7b5f", 36 | "0x16e741399442b2d58927d2594bb7e0d5a983a1eeea8dadb2fd8b93aeeec26655", 37 | "0x1bd3b94b87302d11a3d4d04f767a73790d68b73248c2e571c4d6347e39ca6917", 38 | "0x1a010f2e472e644cf4e0eeb7c18ecce574ec7820fbef669c326d52e1b097e272", 39 | "0x0797cb1c81f29d9d3f0884f643aa4233165186535cba0c2197afc75fe25ceef2", 40 | "0x17a8be97d599f43ffefc64559d3f4e14fab35ddd80b5b60c88cddccc9bb80e4d", 41 | "0x0dc0c75325ff35a54ca0979107cfbd05008b1811e5dbd13dda372576377c37cb", 42 | "0x07933bbb92bc777e0857ed9f4571a9af14cbb751d98b434c8eb41f837af0471c", 43 | "0x0abfdd844e379184e9941e370de6992f0dffd70b9fb6ba868972791c47390a38", 44 | "0x0e188bc2aac54a48e42e94ac535af5c68df6fa8ce64bf43dfd6b20b3f5a1f989", 45 | "0x242052180b3a9a1107743b627a15edc956c211680c004ef8812df8bc65d37da6", 46 | "0x0e9bd8d7e31cfc09d362c27017555ee4cb6536b8f664663afc5be308aaa55aa2", 47 | "0x0907a05e96848e94ba98195f0834606aea8df71ae86be5261959dc41779bb0cc", 48 | "0x27137bccb6552c33fafdfe103a856564a412b50af49d6f512ccc3cbd79da7716", 49 | "0x0864f9061ebb55440d5c877aaf4d36d3952d897e8f4581e01e1a4b75a5fb7b57", 50 | "0x1951ec61a3c2085511849a92fe479185356cb5921b2807dc5c822fa58e0e179a", 51 | "0x0e5207ab6856d389c917134b647a8d4a85731614c5e319155ae2b3ab91fdf5af", 52 | "0x15349491fa137b868541bcf10c3fe6f6ba2d3e238ca27bfcd044047811dfe388", 53 | "0x096b26a94ce9af3e87871606f27e3b767f8f46bd98ff4d7e454c1ba5fb49c9f3", 54 | "0x10047b0649fba4f0cab2c289fb2eb17fd4dc63f2ffbaf9a3cd441fe753157815", 55 | "0x0a516d7e68946f915be287d8d7000923e27a09d49198108a5636fc6ecd82d416", 56 | "0x2ead013caba384351de47091b8aaad12764debc85c368ff98de89f75cf558482", 57 | "0x1a258e974fc498e766987463fbd111eea24cb8ea8a232de8079ee49ab534264e", 58 | "0x1f392db78f8adfd70fea8d88c3e7388d062999b0d8f19c0f2b4c85d2196a7ea9", 59 | "0x0ff2cdd0237410ff183ceccaff4f48446d41a712b7c4babdd4a09c79bce40322", 60 | "0x1954994cd2ab37da04bb80325c4e16652ed79e9c84879ba1204eba55f66bc4b1", 61 | "0x091dace3590396c4bbc0bc75c15dbb9e379f8cb450f340673efc0353b12cc42d", 62 | "0x2a1d4c5e20d6567cfdb428365faa28177d900b268d71eeffa0e852a32e500de5", 63 | "0x08f7df5ae38ec0a864203d5ce74aca86cd6273e5d045cb98e2908004ed2183e5", 64 | "0x15ee3fc251e3afdb1d87fbdf5297088064b89959e47c96b451644082129a0a63", 65 | "0x17e8b55b6b221947a0e89a2df49533190cf71c906fed16f1d85aaa65fbcb5345", 66 | "0x045a0001f5ca1008c1297c8c845f438819a3e1de12a4db6601d364fefce08466", 67 | "0x21ffc6a3475e5a77759c45f9e15f5a140cb6d23d103951b951467acefdcbe48a", 68 | "0x1cb90d3f9df7e3838e40c7b8776f692b10ddc169e7d29d5485f1c478ff3e9b74", 69 | "0x1274b0e74b22eedbd0b3edf57270525c14c4dc13b3098b0bbf089953b8f2b4b8", 70 | "0x0f919a05a6d6762f3ca0b3042148f0b4501751ec146cda108bc6a4937dcd7a20", 71 | "0x278d8a78a647db6b698ba4740533fffe59412591f8f9eb295ea50e08ce38bf08", 72 | "0x211320e94a851bf7c2660648a3bba16f822aef5118561805427651995f8db3f4", 73 | "0x1950aa5510490993c0a5470f4d300223c26e0abf8ec3bab547a6fb1668319afe", 74 | "0x12612b4f58eb767dab7223de0b53106e5f78f60ae5854c862b14f834c7e34e2d", 75 | "0x0ccf8cdab25538f28cf9e2ab2aa54043b40365a5dfce0dc56940118a175a4936", 76 | "0x225d91a14448a93785457903a1444e2c0bca0ae3bb3490b4a1f448bbde88321a", 77 | "0x17f866a83abbfb3f5b20a0fb40861b669fdeaac1673ccf7233bff2726ef07c12", 78 | "0x274ff4db91a135b7ba61d39ddd2734fac38587d980992415c29dda232958e785", 79 | "0x2c7003822597c33cdb0b1c6fab8661f76ca8ed03be676a582572d773a3433dfc", 80 | "0x001cd295eabaac4a64c57e07364caf03279e25b58805d1590e493e79b2dd1ae4", 81 | "0x09d6d81f21776bbef325f9bae6f9f417059bdaeef40c3d3de755203370493efc", 82 | "0x09136a76223adbe2bac5105bdbe30e0a4aad7f84b30226712572adac387199d9", 83 | "0x1cfcd0dee899234b8829088c6a46c2892050a436fe261a9fe4180d0e8719f94b", 84 | "0x1f45484b7e5d4bd51a2ddef8d7bbfb1d3f4aa19728233025eb422837af8d9072", 85 | "0x1c4abe3b58f679db34b38c58a4df389ed7e981bce43df9e53099bec757963a57", 86 | "0x06982e0f4b537c75a436b321de06f9ab347519500a38a5b22ea7554a8f56e0f8", 87 | "0x07046365d522cc5022a72f52bf0dcacca143e90f54cd1b0caee3a5b19d2246f4", 88 | "0x01efcc089f07fe8a25fde5c328678633c9ec23cdaf554d21b17a7f11ffd13cb7", 89 | "0x14bc004b83a71020e8b683b6e845db1073bcf25b0d7203f43d8a7fff2b5fae77", 90 | "0x2ddd92756d1ca22599283cb365f50d429f4737d258a4241f80d9babae4730b4c", 91 | "0x17ece7004ca56d33c9c5968ef9e150da329b8882987c323d81093d6ac0824b2e", 92 | "0x281bbf1c45bff63378c0457dc44fb069d8c237e27995dc61846d46cebbb18238", 93 | "0x1a00b62874d4619e211be98505ef9ef764b21f9e0c63d95ae5baa5bd9956e1af", 94 | "0x20ad921df9e684a135efa3f1391f81c3dbbde67b7ba74892540eabed4b8a18e5", 95 | "0x06bbbd8057fe0e147cf1cbbd40251f0bf5987e7cd67f69a512b66e3070173ffc", 96 | "0x1e1c12cb34e808e17fb41da0a333d721a674864cc579b7ea0b38cadcadcaa680", 97 | "0x2b883aff71e7de12f8cbd77e365315fce4cef16f39e0ba936dd486fc93143d82", 98 | "0x2b0c1f712a5d20afc47b55229943b6e18624294f5ecd61c9a63fa5460a7ca60b", 99 | "0x20318affc0894f26029dc515a9481d42cae1bdceae78ba8fd3148868dedcf5fb", 100 | "0x0c6e1b2ac252339f0df200a40e58be6a84ad16eed290688a93ccbd89f4218170", 101 | "0x2006de7a6d053e39653625c6b32429a189794bf217b16ff2157ea40ee9795f4e", 102 | "0x13eb3541962c2a5408302a4a7ef4ae5b42e1aeb65b663f5c2b62bd13c7cc214e", 103 | "0x180631350852e5a0c04efd2898d963bc5b3ad352ec98116840e7898f259a9713", 104 | "0x1e93c8feacc032df27f42338fc2764e60cf84ff4e24ed1adf6509b2989eb411e", 105 | "0x07911273cff73e90c9c63fe23d05a7fde3fd086ccff068c4fb42bb2a8ce4304d", 106 | "0x24133be73ee303f6ded5cec002ff07c22534ec770055b03dff7ce601691f49b1", 107 | "0x120a1a812ebcd499ff86344575d580c545f2a87d6abe23f0576e66ea3daee174", 108 | "0x0b91597db31d928492d432dfc29817b5bbb8255cc43f3ddb27dd8bcd4bfb50b8", 109 | "0x140715365175ebd2328718b979ac6d994e304dc26a0a57484abf61a72f4b856f", 110 | "0x2a1fc89fe556f8675356da275941577f76c3743f45ea6381c437bfd2c072d1c1", 111 | "0x04f981ebe367ab4076112d77fbafb9e1467738b9300bbb7526de0a526c81288c", 112 | "0x090294318e3ce0b78e5afa9a0dce6b35e83169e07c4416239a3b45f89e672711", 113 | "0x2c242a8b017fe4ca2b5eba61e1da12b5739e01681409e697331c0692c0906031", 114 | "0x2dbe33685c5ac43222a9d6ba08183a3866938c8935a8f2e848441a6665f8c9a0", 115 | "0x076a8f44648ee1b4cf58ca4aa24a9a81c86f729a1fbae07effc0b7301fbcbe84", 116 | "0x0923e6801cdbb68c1762040ab0745b7e0cc0a0775d6c9df01b90e299174fa03c", 117 | "0x28187baae9864f27813aeb073775f9ed0752167e598612a2e21652da9e1e9cd7", 118 | "0x0041d72e6ecaf8313949f8ad7b5f370ffa403abff55cfd285be93083a810d90a", 119 | "0x0453618b764c28db39028e848007d73ec0262a5a2b38033238b1e27d6468cdb0", 120 | "0x142da4aab19cf148479876d07ef12d2105e504f2980b8fa21a0869344e6b167a", 121 | "0x157ac3ce8fff96af9216dd67cc31d93c10fc38437398a57c22997aad11851d46", 122 | "0x076d9c8634610797282a670a965cf9c72cc3200c7da2f1fcdbd375fa07e2fab4", 123 | "0x2002548afde4ddb43cdfc34b7ac0e0c6e35863bc649b161f52244eba8b792973", 124 | "0x04728521ee32f7da39fdd4fae3160234e81d682160a89a34a76273bff47136f6", 125 | "0x09d2d5ad962d3faaf1735bcef4878aca2cb3e9d667ea366a3c97f1e4e38fd07b", 126 | "0x069e6ab1f581cfa30207b88ae57c3b14e36119ffcd81db94ea295fab5e81b174", 127 | "0x2a0343cb81ef3a8b39a96185d2289c9cf36cda665bb76a241282b35564e51add", 128 | "0x0336c68f9dab0d529e632f6bc7a20702e81d7c2285b73541ad6536e5fa1ee91f", 129 | "0x196f84b4b83f43f417a720c73b1afc4351085da4426fe6ca79b44e0beb6a065b", 130 | ]; 131 | 132 | pub const MDS_ENTRIES: &[&[&str]] = &[ 133 | &[ 134 | "0x11092c76ff96d6a5a24f9bb3b960f3d860d35e0b95a0f94fd6ffa3784ece5ce4", 135 | "0x19e8e51059fbe675b15135eb37fb1bd7cfe8ecb5720cfcf215d72274a16b9eae", 136 | "0x2850794e401ab8618711e58af8befe1a486515e401a6df5d89c306f820c91f20", 137 | ], 138 | &[ 139 | "0x2b188f45b21764e43e4ace9ebf0cddb859e0e2a00c2b51b1c4471e73c6648d35", 140 | "0x01f574af43d21ea5ed52561538aa36cdeb8436589314368262f42a988d83ad5f", 141 | "0x1190ec00645944c68d1a3134f5f0fdedb38130950f55b996a2b2b70d84809b60", 142 | ], 143 | &[ 144 | "0x27be16a50d71f7009fd08e84936e1156ac558a467fb595281bb27530edbd4416", 145 | "0x0a2dbdac4f4e49c36bfc08c9b3f6b3f2fc3d1aa3601a2ae1dbd64c46ae5491d2", 146 | "0x160f3229d7a28e97795fb81af3858237d7992950dac77754b465d5bc40ad17cc", 147 | ], 148 | ]; 149 | -------------------------------------------------------------------------------- /arkworks/r1cs-circuits/src/vanchor.rs: -------------------------------------------------------------------------------- 1 | // This file is part of Webb. 2 | 3 | // Copyright (C) 2021 Webb Technologies Inc. 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | use ark_ff::fields::PrimeField; 19 | use ark_r1cs_std::{eq::EqGadget, fields::fp::FpVar, prelude::*}; 20 | use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; 21 | use ark_std::vec::Vec; 22 | use arkworks_native_gadgets::merkle_tree::Path; 23 | use arkworks_r1cs_gadgets::{merkle_tree::PathVar, poseidon::FieldHasherGadget, set::SetGadget}; 24 | use core::cmp::Ordering::Less; 25 | 26 | /// Defines a VAnchorCircuit struct that hold all the information thats needed 27 | /// to verify the following statements: 28 | /// * Alice knows a witness tuple `(in_amounts, in_blindings, in_private_keys, 29 | /// in_path_elements, in_path_indices)` and a commitment_hash `Hash(chain_id, 30 | /// amount, pub_key, blinding)` stored in one of the valid VAnchor merkle 31 | /// trees 32 | /// * The VAnchor contract hasn't seen this nullifier_hash before. 33 | /// 34 | /// Needs to implement ConstraintSynthesizer and a 35 | /// constructor to generate proper constraints 36 | #[derive(Clone)] 37 | pub struct VAnchorCircuit< 38 | F: PrimeField, 39 | HG: FieldHasherGadget, 40 | const HEIGHT: usize, 41 | const N_INS: usize, 42 | const N_OUTS: usize, 43 | const ANCHOR_CT: usize, 44 | > { 45 | public_amount: F, 46 | ext_data_hash: F, 47 | 48 | in_amounts: Vec, 49 | in_blindings: Vec, 50 | in_private_keys: Vec, 51 | in_chain_id: F, 52 | root_set: [F; ANCHOR_CT], 53 | 54 | paths: Vec>, 55 | indices: Vec, 56 | nullifier_hash: Vec, 57 | 58 | out_commitment: Vec, 59 | out_amounts: Vec, 60 | out_blindings: Vec, 61 | out_chain_ids: Vec, 62 | out_pubkey: Vec, 63 | 64 | tree_hasher: HG::Native, 65 | keypair_hasher: HG::Native, 66 | leaf_hasher: HG::Native, 67 | nullifier_hasher: HG::Native, 68 | } 69 | 70 | /// Constructor for VAnchorCircuit 71 | impl< 72 | F, 73 | HG, 74 | const HEIGHT: usize, 75 | const N_INS: usize, 76 | const N_OUTS: usize, 77 | const ANCHOR_CT: usize, 78 | > VAnchorCircuit 79 | where 80 | F: PrimeField, 81 | HG: FieldHasherGadget, 82 | { 83 | #[allow(clippy::too_many_arguments)] 84 | pub fn new( 85 | public_amount: F, 86 | ext_data_hash: F, 87 | in_amounts: Vec, 88 | in_blindings: Vec, 89 | in_private_keys: Vec, 90 | in_chain_id: F, 91 | root_set: [F; ANCHOR_CT], 92 | paths: Vec>, 93 | indices: Vec, 94 | nullifier_hash: Vec, 95 | out_commitment: Vec, 96 | out_amounts: Vec, 97 | out_blindings: Vec, 98 | out_chain_ids: Vec, 99 | out_pubkey: Vec, 100 | tree_hasher: HG::Native, 101 | keypair_hasher: HG::Native, 102 | leaf_hasher: HG::Native, 103 | nullifier_hasher: HG::Native, 104 | ) -> Self { 105 | Self { 106 | public_amount, 107 | ext_data_hash, 108 | in_amounts, 109 | in_blindings, 110 | in_private_keys, 111 | in_chain_id, 112 | root_set, 113 | paths, 114 | indices, 115 | nullifier_hash, 116 | out_commitment, 117 | out_amounts, 118 | out_blindings, 119 | out_chain_ids, 120 | out_pubkey, 121 | tree_hasher, 122 | keypair_hasher, 123 | leaf_hasher, 124 | nullifier_hasher, 125 | } 126 | } 127 | 128 | // Check that there are no same nullifiers among all inputs 129 | pub fn verify_no_same_nul(in_nullifier_var: &[FpVar]) -> Result<(), SynthesisError> { 130 | for i in 0..N_INS - 1 { 131 | for j in (i + 1)..N_INS { 132 | in_nullifier_var[i].enforce_not_equal(&in_nullifier_var[j])?; 133 | } 134 | } 135 | 136 | Ok(()) 137 | } 138 | 139 | // Verify amount invariant 140 | pub fn verify_input_invariant( 141 | public_amount_var: &FpVar, 142 | sum_ins_var: &FpVar, 143 | sum_outs_var: &FpVar, 144 | ) -> Result<(), SynthesisError> { 145 | let res = sum_ins_var + public_amount_var; 146 | res.enforce_equal(sum_outs_var)?; 147 | Ok(()) 148 | } 149 | } 150 | 151 | impl< 152 | F, 153 | HG, 154 | const HEIGHT: usize, 155 | const N_INS: usize, 156 | const N_OUTS: usize, 157 | const ANCHOR_CT: usize, 158 | > ConstraintSynthesizer for VAnchorCircuit 159 | where 160 | F: PrimeField, 161 | HG: FieldHasherGadget, 162 | { 163 | fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { 164 | let public_amount = self.public_amount; 165 | let ext_data_hash = self.ext_data_hash; 166 | let in_amounts = self.in_amounts; 167 | let in_blindings = self.in_blindings; 168 | let in_chain_id = self.in_chain_id; 169 | let in_private_keys = self.in_private_keys; 170 | let out_chain_ids = self.out_chain_ids; 171 | let root_set = self.root_set; 172 | let paths = self.paths; 173 | let indices = self.indices; 174 | let nullifier_hash = self.nullifier_hash; 175 | 176 | let out_commitment = self.out_commitment; 177 | let out_amounts = self.out_amounts; 178 | let out_blindings = self.out_blindings; 179 | let out_pubkey = self.out_pubkey; 180 | 181 | // 2^248 182 | let limit: F = F::from_str( 183 | "452312848583266388373324160190187140051835877600158453279131187530910662656", 184 | ) 185 | .unwrap_or_default(); 186 | // check the previous conversion is done correctly 187 | assert_ne!(limit, F::default()); 188 | // Generating vars 189 | // Public inputs 190 | let public_amount_var = FpVar::::new_input(cs.clone(), || Ok(public_amount))?; 191 | let arbitrary_input_var = FpVar::::new_input(cs.clone(), || Ok(ext_data_hash))?; 192 | let in_nullifier_var = Vec::>::new_input(cs.clone(), || Ok(nullifier_hash))?; 193 | let out_commitment_var = Vec::>::new_input(cs.clone(), || Ok(out_commitment))?; 194 | let in_chain_id_var = FpVar::::new_input(cs.clone(), || Ok(in_chain_id))?; 195 | let root_set_var = Vec::>::new_input(cs.clone(), || Ok(root_set))?; 196 | 197 | // Constants 198 | let limit_var: FpVar = FpVar::::new_constant(cs.clone(), limit)?; 199 | 200 | // Hashers 201 | let tree_hasher = HG::from_native(&mut cs.clone(), self.tree_hasher)?; 202 | let keypair_hasher = HG::from_native(&mut cs.clone(), self.keypair_hasher)?; 203 | let leaf_hasher = HG::from_native(&mut cs.clone(), self.leaf_hasher)?; 204 | let nullifier_hasher = HG::from_native(&mut cs.clone(), self.nullifier_hasher)?; 205 | 206 | // Private inputs 207 | let in_amounts_var = Vec::>::new_witness(cs.clone(), || Ok(in_amounts))?; 208 | let in_blindings_var = Vec::>::new_witness(cs.clone(), || Ok(in_blindings))?; 209 | let in_private_keys_var = Vec::>::new_witness(cs.clone(), || Ok(in_private_keys))?; 210 | let in_path_elements_var = 211 | Vec::>::new_witness(cs.clone(), || Ok(paths))?; 212 | let in_path_indices_var = Vec::>::new_witness(cs.clone(), || Ok(indices))?; 213 | 214 | // Outputs 215 | let out_amounts_var = Vec::>::new_witness(cs.clone(), || Ok(out_amounts))?; 216 | let out_blindings_var = Vec::>::new_witness(cs.clone(), || Ok(out_blindings))?; 217 | let out_chain_ids_var = Vec::>::new_witness(cs.clone(), || Ok(out_chain_ids))?; 218 | let out_pubkey_var = Vec::>::new_witness(cs, || Ok(out_pubkey))?; 219 | 220 | let set_gadget = SetGadget::new(root_set_var); 221 | 222 | // verify correctness of transaction inputs 223 | let mut sum_ins_var = FpVar::::zero(); 224 | for tx in 0..N_INS { 225 | // Computing the public key 226 | let pub_key = keypair_hasher.hash(&[in_private_keys_var[tx].clone()])?; 227 | // Computing the hash 228 | let in_leaf = leaf_hasher.hash(&[ 229 | in_chain_id_var.clone(), 230 | in_amounts_var[tx].clone(), 231 | pub_key, 232 | in_blindings_var[tx].clone(), 233 | ])?; 234 | // End of computing the hash 235 | 236 | let signature = nullifier_hasher.hash(&[ 237 | in_private_keys_var[tx].clone(), 238 | in_leaf.clone(), 239 | in_path_indices_var[tx].clone(), 240 | ])?; 241 | // Nullifier 242 | let nullifier_hash = nullifier_hasher.hash(&[ 243 | in_leaf.clone(), 244 | in_path_indices_var[tx].clone(), 245 | signature, 246 | ])?; 247 | 248 | nullifier_hash.enforce_equal(&in_nullifier_var[tx])?; 249 | 250 | // Add the roots and diffs signals to the vanchor circuit 251 | let roothash = &in_path_elements_var[tx].root_hash(&in_leaf, &tree_hasher)?; 252 | let in_amount_tx = &in_amounts_var[tx]; 253 | 254 | // Check membership if in_amount is non zero 255 | let check = set_gadget.check_membership_enabled(&roothash, in_amount_tx)?; 256 | check.enforce_equal(&Boolean::TRUE)?; 257 | 258 | sum_ins_var += in_amount_tx; 259 | } 260 | // verify correctness of transaction outputs 261 | let mut sum_outs_var = FpVar::::zero(); 262 | for tx in 0..N_OUTS { 263 | // Computing the hash 264 | let leaf = leaf_hasher.hash(&[ 265 | out_chain_ids_var[tx].clone(), 266 | out_amounts_var[tx].clone(), 267 | out_pubkey_var[tx].clone(), 268 | out_blindings_var[tx].clone(), 269 | ])?; 270 | // End of computing the hash 271 | let out_amount_var = &out_amounts_var[tx]; 272 | leaf.enforce_equal(&out_commitment_var[tx])?; 273 | 274 | // Check that amount is less than 2^248 in the field (to prevent overflow) 275 | out_amount_var.enforce_cmp_unchecked(&limit_var, Less, false)?; 276 | 277 | sum_outs_var += out_amount_var; 278 | } 279 | 280 | // check that there are no same nullifiers among all inputs 281 | Self::verify_no_same_nul(&in_nullifier_var)?; 282 | 283 | // verify amount invariant 284 | Self::verify_input_invariant(&public_amount_var, &sum_ins_var, &sum_outs_var)?; 285 | 286 | // optional safety constraint to make sure extDataHash cannot be changed 287 | let _ = &arbitrary_input_var * &arbitrary_input_var; 288 | 289 | Ok(()) 290 | } 291 | } 292 | --------------------------------------------------------------------------------