├── bellman ├── .gitignore ├── COPYRIGHT ├── README.md ├── Cargo.toml ├── LICENSE-MIT ├── src │ ├── groth16 │ │ └── verifier.rs │ ├── multicore.rs │ └── multiexp.rs └── tests │ └── mimc.rs ├── ff ├── .gitignore ├── ff_derive │ └── Cargo.toml ├── Cargo.toml ├── LICENSE-MIT └── README.md ├── pairing ├── .gitignore ├── src │ ├── bls12_381 │ │ ├── tests │ │ │ ├── g1_uncompressed_invalid_test_vectors.dat │ │ │ ├── g1_compressed_valid_test_vectors.dat │ │ │ ├── g2_compressed_valid_test_vectors.dat │ │ │ ├── g1_uncompressed_valid_test_vectors.dat │ │ │ └── g2_uncompressed_valid_test_vectors.dat │ │ ├── fq12.rs │ │ └── README.md │ ├── tests │ │ ├── mod.rs │ │ ├── repr.rs │ │ ├── engine.rs │ │ └── field.rs │ ├── bn256 │ │ ├── README.md │ │ ├── fr.rs │ │ └── fq12.rs │ └── wnaf.rs ├── benches │ ├── pairing_benches.rs │ ├── bn256 │ │ ├── fq12.rs │ │ ├── mod.rs │ │ ├── fq2.rs │ │ ├── ec.rs │ │ ├── fq.rs │ │ └── fr.rs │ └── bls12_381 │ │ ├── fq12.rs │ │ ├── mod.rs │ │ ├── fq2.rs │ │ ├── ec.rs │ │ ├── fq.rs │ │ └── fr.rs ├── COPYRIGHT ├── Cargo.toml ├── LICENSE-MIT └── README.md ├── sapling-crypto ├── .gitignore ├── src │ ├── circuit │ │ ├── sprout │ │ │ ├── test_vectors.dat │ │ │ ├── commitment.rs │ │ │ ├── output.rs │ │ │ ├── prfs.rs │ │ │ └── input.rs │ │ ├── mod.rs │ │ ├── multipack.rs │ │ ├── multieq.rs │ │ └── baby_pedersen_hash.rs │ ├── baby_util.rs │ ├── util.rs │ ├── lib.rs │ ├── baby_group_hash.rs │ ├── constants.rs │ ├── group_hash.rs │ ├── baby_pedersen_hash.rs │ ├── pedersen_hash.rs │ └── primitives │ │ └── mod.rs ├── COPYRIGHT ├── benches │ ├── pedersen_hash.rs │ └── baby_pedersen_hash.rs ├── README.md ├── Cargo.toml ├── LICENSE-MIT └── examples │ └── bench.rs ├── .gitignore ├── Cargo.toml ├── README.md └── src ├── zk_util.rs ├── blake_merkle_tree.rs └── merkle_tree.rs /bellman/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /ff/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /pairing/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | .vscode -------------------------------------------------------------------------------- /pairing/src/bls12_381/tests/g1_uncompressed_invalid_test_vectors.dat: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sapling-crypto/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /test 2 | /target 3 | **/*/target 4 | **/*.rs.bk 5 | .DS_STORE 6 | -------------------------------------------------------------------------------- /pairing/src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod curve; 2 | pub mod engine; 3 | pub mod field; 4 | pub mod repr; 5 | -------------------------------------------------------------------------------- /sapling-crypto/src/circuit/sprout/test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drewstone/rust-miximus/HEAD/sapling-crypto/src/circuit/sprout/test_vectors.dat -------------------------------------------------------------------------------- /pairing/src/bls12_381/tests/g1_compressed_valid_test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drewstone/rust-miximus/HEAD/pairing/src/bls12_381/tests/g1_compressed_valid_test_vectors.dat -------------------------------------------------------------------------------- /pairing/src/bls12_381/tests/g2_compressed_valid_test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drewstone/rust-miximus/HEAD/pairing/src/bls12_381/tests/g2_compressed_valid_test_vectors.dat -------------------------------------------------------------------------------- /pairing/src/bls12_381/tests/g1_uncompressed_valid_test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drewstone/rust-miximus/HEAD/pairing/src/bls12_381/tests/g1_uncompressed_valid_test_vectors.dat -------------------------------------------------------------------------------- /pairing/src/bls12_381/tests/g2_uncompressed_valid_test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drewstone/rust-miximus/HEAD/pairing/src/bls12_381/tests/g2_uncompressed_valid_test_vectors.dat -------------------------------------------------------------------------------- /pairing/benches/pairing_benches.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate ff; 4 | extern crate pairing; 5 | extern crate rand; 6 | extern crate test; 7 | 8 | mod bls12_381; 9 | mod bn256; 10 | -------------------------------------------------------------------------------- /sapling-crypto/src/baby_util.rs: -------------------------------------------------------------------------------- 1 | use blake2_rfc::blake2b::Blake2b; 2 | 3 | use babyjubjub::{JubjubEngine, ToUniform}; 4 | 5 | pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> E::Fs { 6 | let mut hasher = Blake2b::with_params(64, &[], &[], persona); 7 | hasher.update(a); 8 | hasher.update(b); 9 | let ret = hasher.finalize(); 10 | E::Fs::to_uniform(ret.as_ref()) 11 | } 12 | -------------------------------------------------------------------------------- /pairing/src/bn256/README.md: -------------------------------------------------------------------------------- 1 | # BN256 2 | 3 | This is an implementation of the BN256 pairing-friendly elliptic curve construction. 4 | 5 | ## BN256 Parameterization 6 | 7 | Follows go-ethereum parametrization. 8 | 9 | ## Notes 10 | 11 | - I couldn't find an easy wat of getting random G2 for BN256 curve (also have no idea why just scaling by cofactor works for BLS12), so don't use it. Make random sccalar and multiply by generator. 12 | - For this reason tests had to be copied and modified for some cases. 13 | 14 | 15 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust-miximus" 3 | version = "0.1.0" 4 | authors = ["drewstone "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | sapling-crypto = { path = "./sapling-crypto" } 11 | pairing = { path = "./pairing" } 12 | ff = { path = "./ff" } 13 | blake2-rfc = "0.2.18" 14 | bellman = { path = "./bellman" } 15 | rand = "0.4" 16 | hex = "0.3.2" 17 | serde = "1.0.80" 18 | serde_derive = "1.0.80" 19 | serde_json = "1.0.33" 20 | num-bigint = "0.2.2" 21 | num-traits = "0.2" 22 | time = "0.1" 23 | 24 | [dependencies.wasm-bindgen] 25 | version = "0.2.33" 26 | features = ["serde-serialize"] 27 | -------------------------------------------------------------------------------- /bellman/COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyrights in the "bellman" library are retained by their contributors. No 2 | copyright assignment is required to contribute to the "bellman" library. 3 | 4 | The "bellman" library is licensed under either of 5 | 6 | * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) 7 | * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT) 8 | 9 | at your option. 10 | 11 | Unless you explicitly state otherwise, any contribution intentionally 12 | submitted for inclusion in the work by you, as defined in the Apache-2.0 13 | license, shall be dual licensed as above, without any additional terms or 14 | conditions. 15 | -------------------------------------------------------------------------------- /pairing/COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyrights in the "pairing" library are retained by their contributors. No 2 | copyright assignment is required to contribute to the "pairing" library. 3 | 4 | The "pairing" library is licensed under either of 5 | 6 | * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) 7 | * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT) 8 | 9 | at your option. 10 | 11 | Unless you explicitly state otherwise, any contribution intentionally 12 | submitted for inclusion in the work by you, as defined in the Apache-2.0 13 | license, shall be dual licensed as above, without any additional terms or 14 | conditions. 15 | -------------------------------------------------------------------------------- /sapling-crypto/COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyrights in the "sapling-crypto" library are retained by their contributors. No 2 | copyright assignment is required to contribute to the "sapling-crypto" library. 3 | 4 | The "sapling-crypto" library is licensed under either of 5 | 6 | * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) 7 | * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT) 8 | 9 | at your option. 10 | 11 | Unless you explicitly state otherwise, any contribution intentionally 12 | submitted for inclusion in the work by you, as defined in the Apache-2.0 13 | license, shall be dual licensed as above, without any additional terms or 14 | conditions. 15 | -------------------------------------------------------------------------------- /ff/ff_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ff_derive" 3 | version = "0.4.0" 4 | authors = ["Sean Bowe ", 5 | "Alex Gluchowski ", 6 | "Alex Vlasov "] 7 | description = "Procedural macro library used to build custom prime field implementations" 8 | documentation = "https://docs.rs/ff/" 9 | homepage = "https://github.com/matterinc/ff" 10 | license = "MIT/Apache-2.0" 11 | repository = "https://github.com/matterinc/ff" 12 | 13 | [lib] 14 | proc-macro = true 15 | 16 | [dependencies] 17 | num-bigint = "0.2" 18 | num-traits = "0.2" 19 | num-integer = "0.1" 20 | proc-macro2 = "0.4" 21 | quote = "0.6" 22 | syn = "0.14" 23 | serde_derive = "1.0.80" 24 | -------------------------------------------------------------------------------- /sapling-crypto/src/util.rs: -------------------------------------------------------------------------------- 1 | use blake2_rfc::blake2b::Blake2b; 2 | use blake2_rfc::blake2s::Blake2s; 3 | 4 | use jubjub::{JubjubEngine, ToUniform}; 5 | 6 | pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> E::Fs { 7 | let mut hasher = Blake2b::with_params(64, &[], &[], persona); 8 | hasher.update(a); 9 | hasher.update(b); 10 | let ret = hasher.finalize(); 11 | E::Fs::to_uniform(ret.as_ref()) 12 | } 13 | 14 | pub fn hash_to_scalar_s(persona: &[u8], a: &[u8], b: &[u8]) -> E::Fs { 15 | let mut hasher = Blake2s::with_params(32, &[], &[], persona); 16 | hasher.update(a); 17 | hasher.update(b); 18 | let ret = hasher.finalize(); 19 | E::Fs::to_uniform_32(ret.as_ref()) 20 | } -------------------------------------------------------------------------------- /ff/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ff" 3 | version = "0.5.0" 4 | authors = ["Sean Bowe ", 5 | "Alex Gluchowski ", 6 | "Alex Vlasov "] 7 | description = "Library for building and interfacing with finite fields" 8 | documentation = "https://docs.rs/ff/" 9 | homepage = "https://github.com/matterinc/ff" 10 | license = "MIT/Apache-2.0" 11 | repository = "https://github.com/matterinc/ff" 12 | 13 | [dependencies] 14 | byteorder = "1" 15 | rand = "0.4" 16 | ff_derive = { version = "0.4.0", path = "ff_derive", optional = true } 17 | #ff_asm = { version = "0.0.1", path = "ff_asm", optional = true } 18 | 19 | [features] 20 | default = [] 21 | derive = ["ff_derive"] 22 | #asm = ["ff_asm"] 23 | -------------------------------------------------------------------------------- /bellman/README.md: -------------------------------------------------------------------------------- 1 | # bellman [![Crates.io](https://img.shields.io/crates/v/bellman.svg)](https://crates.io/crates/bellman) # 2 | 3 | This is a research project being built for [Zcash](https://z.cash/). 4 | 5 | ## License 6 | 7 | Licensed under either of 8 | 9 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 10 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 11 | 12 | at your option. 13 | 14 | ### Contribution 15 | 16 | Unless you explicitly state otherwise, any contribution intentionally 17 | submitted for inclusion in the work by you, as defined in the Apache-2.0 18 | license, shall be dual licensed as above, without any additional terms or 19 | conditions. 20 | -------------------------------------------------------------------------------- /sapling-crypto/benches/pedersen_hash.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate rand; 4 | extern crate test; 5 | extern crate pairing; 6 | extern crate sapling_crypto; 7 | 8 | use rand::{Rand, thread_rng}; 9 | use pairing::bls12_381::Bls12; 10 | use sapling_crypto::jubjub::JubjubBls12; 11 | use sapling_crypto::pedersen_hash::{pedersen_hash, Personalization}; 12 | 13 | #[bench] 14 | fn bench_pedersen_hash(b: &mut test::Bencher) { 15 | let params = JubjubBls12::new(); 16 | let rng = &mut thread_rng(); 17 | let bits = (0..510).map(|_| bool::rand(rng)).collect::>(); 18 | let personalization = Personalization::MerkleTree(31); 19 | 20 | b.iter(|| { 21 | pedersen_hash::(personalization, bits.clone(), ¶ms) 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /sapling-crypto/benches/baby_pedersen_hash.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate rand; 4 | extern crate test; 5 | extern crate pairing; 6 | extern crate sapling_crypto; 7 | 8 | use rand::{Rand, thread_rng}; 9 | use pairing::bn256::Bn256; 10 | use sapling_crypto::alt_babyjubjub::AltJubjubBn256; 11 | use sapling_crypto::pedersen_hash::{pedersen_hash, Personalization}; 12 | 13 | #[bench] 14 | fn bench_baby_pedersen_hash(b: &mut test::Bencher) { 15 | let params = AltJubjubBn256::new(); 16 | let rng = &mut thread_rng(); 17 | let bits = (0..510).map(|_| bool::rand(rng)).collect::>(); 18 | let personalization = Personalization::MerkleTree(31); 19 | 20 | b.iter(|| { 21 | pedersen_hash::(personalization, bits.clone(), ¶ms) 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /bellman/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Sean Bowe "] 3 | description = "zk-SNARK library" 4 | documentation = "https://github.com/ebfull/bellman" 5 | homepage = "https://github.com/ebfull/bellman" 6 | license = "MIT/Apache-2.0" 7 | name = "bellman" 8 | repository = "https://github.com/ebfull/bellman" 9 | version = "0.1.0" 10 | 11 | [dependencies] 12 | rand = "0.4" 13 | bit-vec = "0.4.4" 14 | futures = "0.1" 15 | pairing = { path = "../pairing" } 16 | byteorder = "1" 17 | ff = { path = '../ff', features = ["derive"] } 18 | futures-cpupool = { version = "0.1", optional = true } 19 | num_cpus = { version = "1", optional = true } 20 | crossbeam = { version = "0.3", optional = true } 21 | 22 | #[features] 23 | #default = ["multithread"] 24 | #multithread = ["futures-cpupool", "num_cpus", "crossbeam"] 25 | -------------------------------------------------------------------------------- /sapling-crypto/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | #![allow(dead_code)] 3 | #![allow(unused_variables)] 4 | 5 | extern crate pairing; 6 | extern crate bellman; 7 | extern crate blake2_rfc; 8 | extern crate digest; 9 | extern crate rand; 10 | extern crate byteorder; 11 | extern crate ff; 12 | 13 | #[cfg(test)] 14 | #[macro_use] 15 | extern crate hex_literal; 16 | 17 | #[cfg(test)] 18 | extern crate crypto; 19 | 20 | pub mod babyjubjub; 21 | pub mod jubjub; 22 | pub mod alt_babyjubjub; 23 | pub mod baby_group_hash; 24 | pub mod group_hash; 25 | pub mod circuit; 26 | pub mod baby_pedersen_hash; 27 | pub mod pedersen_hash; 28 | pub mod primitives; 29 | pub mod constants; 30 | pub mod redbabyjubjub; 31 | pub mod redjubjub; 32 | pub mod baby_util; 33 | pub mod util; 34 | pub mod eddsa; 35 | 36 | extern crate serde; 37 | #[macro_use] 38 | extern crate serde_derive; -------------------------------------------------------------------------------- /sapling-crypto/README.md: -------------------------------------------------------------------------------- 1 | # sapling-crypto "Community edition" 2 | 3 | This repository contains an original implementation of Zcash's "Sapling" cryptography with extensions from us for Ethereum curves and some sugar functions. 4 | 5 | ## Security Warnings 6 | 7 | This library is under development and has not been reviewed. 8 | 9 | ## License 10 | 11 | Licensed under either of 12 | 13 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 14 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 15 | 16 | at your option. 17 | 18 | ### Contribution 19 | 20 | Unless you explicitly state otherwise, any contribution intentionally 21 | submitted for inclusion in the work by you, as defined in the Apache-2.0 22 | license, shall be dual licensed as above, without any additional terms or 23 | conditions. 24 | -------------------------------------------------------------------------------- /pairing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pairing" 3 | 4 | # Remember to change version string in README.md. 5 | version = "0.15.1" 6 | authors = [ 7 | "Sean Bowe ", 8 | "Jack Grigg ", 9 | "Alex Vlasov ", 10 | "Alex Gluchowski " 11 | ] 12 | license = "MIT/Apache-2.0" 13 | 14 | description = "Pairing-friendly elliptic curve library" 15 | documentation = "https://docs.rs/pairing/" 16 | homepage = "https://github.com/matterinc/pairing" 17 | repository = "https://github.com/matterinc/pairing" 18 | 19 | [dependencies] 20 | rand = "0.4" 21 | byteorder = "1" 22 | ff = { path = '../ff', features = ["derive"] } 23 | serde = "1.0.80" 24 | serde_derive = "1.0.80" 25 | serde_json = "1.0.33" 26 | hex = "0.3.2" 27 | 28 | [features] 29 | unstable-features = ["expose-arith"] 30 | expose-arith = [] 31 | default = [] 32 | -------------------------------------------------------------------------------- /sapling-crypto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Sean Bowe ", "Alex Vlasov "] 3 | description = "Cryptographic library for Zcash Sapling with more content" 4 | documentation = "https://github.com/matterinc/sapling-crypto" 5 | homepage = "https://github.com/matterinc/sapling-crypto" 6 | license = "MIT/Apache-2.0" 7 | name = "sapling-crypto" 8 | repository = "https://github.com/matterinc/sapling-crypto" 9 | version = "0.0.3" 10 | 11 | [lib] 12 | crate-type = ["lib", "staticlib"] 13 | 14 | [dependencies] 15 | rand = "0.4" 16 | digest = "0.7" 17 | byteorder = "1" 18 | ff = { path = '../ff', features = ["derive"] } 19 | pairing = { path = '../pairing', features = ["expose-arith"] } 20 | bellman = { path = '../bellman'} 21 | serde = "1.0.80" 22 | serde_derive = "1.0.80" 23 | serde_json = "1.0.33" 24 | 25 | [dependencies.blake2-rfc] 26 | git = "https://github.com/gtank/blake2-rfc" 27 | rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" 28 | 29 | [dev-dependencies] 30 | hex-literal = "0.1" 31 | rust-crypto = "0.2" 32 | -------------------------------------------------------------------------------- /bellman/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /pairing/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /sapling-crypto/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /sapling-crypto/src/circuit/mod.rs: -------------------------------------------------------------------------------- 1 | // #[cfg(test)] 2 | pub mod test; 3 | 4 | pub mod boolean; 5 | pub mod multieq; 6 | pub mod uint32; 7 | pub mod blake2s; 8 | pub mod num; 9 | pub mod lookup; 10 | pub mod baby_ecc; 11 | pub mod ecc; 12 | pub mod pedersen_hash; 13 | pub mod baby_pedersen_hash; 14 | pub mod multipack; 15 | pub mod sha256; 16 | pub mod baby_eddsa; 17 | pub mod float_point; 18 | // pub mod shark_mimc; 19 | 20 | pub mod sapling; 21 | pub mod sprout; 22 | 23 | use bellman::{ 24 | SynthesisError 25 | }; 26 | 27 | // TODO: This should probably be removed and we 28 | // should use existing helper methods on `Option` 29 | // for mapping with an error. 30 | /// This basically is just an extension to `Option` 31 | /// which allows for a convenient mapping to an 32 | /// error on `None`. 33 | pub trait Assignment { 34 | fn get(&self) -> Result<&T, SynthesisError>; 35 | } 36 | 37 | impl Assignment for Option { 38 | fn get(&self) -> Result<&T, SynthesisError> { 39 | match *self { 40 | Some(ref v) => Ok(v), 41 | None => Err(SynthesisError::AssignmentMissing) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ff/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Sean Bowe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /pairing/README.md: -------------------------------------------------------------------------------- 1 | # pairing "community edition" 2 | 3 | Originally developed by ZCash, with extensions from us to make it a little more pleasant. 4 | 5 | This is a Rust crate for using pairing-friendly elliptic curves. Currently, only the [BLS12-381](https://z.cash/blog/new-snark-curve.html) and BN256 curves are implemented. 6 | 7 | ## [Documentation](https://docs.rs/pairing/) 8 | 9 | Bring the `pairing` crate into your project just as you normally would. 10 | 11 | ## Security Warnings 12 | 13 | This library does not make any guarantees about constant-time operations, memory access patterns, or resistance to side-channel attacks. 14 | 15 | ## License 16 | 17 | Licensed under either of 18 | 19 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 20 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 21 | 22 | at your option. 23 | 24 | ### Contribution 25 | 26 | Unless you explicitly state otherwise, any contribution intentionally 27 | submitted for inclusion in the work by you, as defined in the Apache-2.0 28 | license, shall be dual licensed as above, without any additional terms or 29 | conditions. 30 | -------------------------------------------------------------------------------- /sapling-crypto/src/baby_group_hash.rs: -------------------------------------------------------------------------------- 1 | use babyjubjub::{ 2 | JubjubEngine, 3 | PrimeOrder, 4 | edwards 5 | }; 6 | 7 | use ff::{ 8 | PrimeField 9 | }; 10 | 11 | use blake2_rfc::blake2s::Blake2s; 12 | use constants; 13 | 14 | /// Produces a random point in the Jubjub curve. 15 | /// The point is guaranteed to be prime order 16 | /// and not the identity. 17 | pub fn group_hash( 18 | tag: &[u8], 19 | personalization: &[u8], 20 | params: &E::Params 21 | ) -> Option> 22 | { 23 | assert_eq!(personalization.len(), 8); 24 | 25 | // Check to see that scalar field is 254 bits 26 | assert!(E::Fr::NUM_BITS == 254); 27 | 28 | let mut h = Blake2s::with_params(32, &[], &[], personalization); 29 | h.update(constants::GH_FIRST_BLOCK); 30 | h.update(tag); 31 | let h = h.finalize().as_ref().to_vec(); 32 | assert!(h.len() == 32); 33 | 34 | match edwards::Point::::read(&h[..], params) { 35 | Ok(p) => { 36 | let p = p.mul_by_cofactor(params); 37 | 38 | if p != edwards::Point::zero() { 39 | Some(p) 40 | } else { 41 | None 42 | } 43 | }, 44 | Err(_) => None 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /sapling-crypto/src/circuit/sprout/commitment.rs: -------------------------------------------------------------------------------- 1 | use pairing::{Engine}; 2 | use bellman::{ConstraintSystem, SynthesisError}; 3 | use circuit::sha256::{ 4 | sha256 5 | }; 6 | use circuit::boolean::{ 7 | Boolean 8 | }; 9 | 10 | pub fn note_comm( 11 | cs: CS, 12 | a_pk: &[Boolean], 13 | value: &[Boolean], 14 | rho: &[Boolean], 15 | r: &[Boolean] 16 | ) -> Result, SynthesisError> 17 | where E: Engine, CS: ConstraintSystem 18 | { 19 | assert_eq!(a_pk.len(), 256); 20 | assert_eq!(value.len(), 64); 21 | assert_eq!(rho.len(), 256); 22 | assert_eq!(r.len(), 256); 23 | 24 | let mut image = vec![]; 25 | image.push(Boolean::constant(true)); 26 | image.push(Boolean::constant(false)); 27 | image.push(Boolean::constant(true)); 28 | image.push(Boolean::constant(true)); 29 | image.push(Boolean::constant(false)); 30 | image.push(Boolean::constant(false)); 31 | image.push(Boolean::constant(false)); 32 | image.push(Boolean::constant(false)); 33 | image.extend(a_pk.iter().cloned()); 34 | image.extend(value.iter().cloned()); 35 | image.extend(rho.iter().cloned()); 36 | image.extend(r.iter().cloned()); 37 | 38 | sha256( 39 | cs, 40 | &image 41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /sapling-crypto/src/circuit/sprout/output.rs: -------------------------------------------------------------------------------- 1 | use pairing::{Engine}; 2 | use bellman::{ConstraintSystem, SynthesisError}; 3 | use circuit::boolean::{Boolean}; 4 | 5 | use super::*; 6 | use super::prfs::*; 7 | use super::commitment::note_comm; 8 | 9 | pub struct OutputNote { 10 | pub cm: Vec 11 | } 12 | 13 | impl OutputNote { 14 | pub fn compute<'a, E, CS>( 15 | mut cs: CS, 16 | a_pk: Option, 17 | value: &NoteValue, 18 | r: Option, 19 | phi: &[Boolean], 20 | h_sig: &[Boolean], 21 | nonce: bool 22 | ) -> Result 23 | where E: Engine, CS: ConstraintSystem, 24 | { 25 | let rho = prf_rho( 26 | cs.namespace(|| "rho"), 27 | phi, 28 | h_sig, 29 | nonce 30 | )?; 31 | 32 | let a_pk = witness_u256( 33 | cs.namespace(|| "a_pk"), 34 | a_pk.as_ref().map(|a_pk| &a_pk.0[..]) 35 | )?; 36 | 37 | let r = witness_u256( 38 | cs.namespace(|| "r"), 39 | r.as_ref().map(|r| &r.0[..]) 40 | )?; 41 | 42 | let cm = note_comm( 43 | cs.namespace(|| "cm computation"), 44 | &a_pk, 45 | &value.bits_le(), 46 | &rho, 47 | &r 48 | )?; 49 | 50 | Ok(OutputNote { 51 | cm: cm 52 | }) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-miximus 2 | 3 | This repo contains a MVP, WASM compatible zkSNARK of barrywhitehat's original [Miximus](https://github.com/barryWhiteHat/miximus). Details of the construction are as follows. 4 | 5 | ## Miximus 6 | Miximus is an anonymous cryptocurrency mixer using zkSNARKs. A full implementation allows users to deposit coins into a smart contract as in Ethereum or blockchain runtime as in Substrate, create a leaf in a merkle tree with some secret data, and then withdraw these coins anonymously by providing a zkSNARK over data in the merkle tree. The proof allows a valid depositor to prove they deposited coins into the merkle tree without enforcing that the withdrawer show which leaf they are proving over. 7 | 8 | ## Double-spend protection 9 | To use Miximus on a blockchain, one must ensure participants cannot double spend/withdraw coins. This is done by using a zkSNARK that proves knowledge of a preimage _P_ for a leaf _L_ in a merkle tree _T_ such that _P_ is the concatenation of a nullifier _N_ and a secret _S_. 10 | 11 | The private inputs of the zkSNARK are: 12 | 1. The secret _S_. 13 | 2. The merkle authentication path _PATH_. 14 | 15 | The public inputs of the zkSNARK are: 16 | 1. The nullifier _N_. 17 | 2. The merkle root _T_. 18 | 19 | The zkSNARK ensures in zero-knowledge that _HASH(N|S)_ is a valid leaf by using it to reconstruct _T_ using an authentication path _PATH_. Since the nullifier is a public input, this can be recorded in a persistent manner to ensure users can't prove knowledge of deposits more than once as each nullifier is only good for a single leaf. A simple boolean check on a blockchain runtime prevents double spending from occurring. -------------------------------------------------------------------------------- /pairing/src/bn256/fr.rs: -------------------------------------------------------------------------------- 1 | use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr}; 2 | 3 | #[derive(PrimeField)] 4 | #[PrimeFieldModulus = "21888242871839275222246405745257275088548364400416034343698204186575808495617"] 5 | #[PrimeFieldGenerator = "7"] 6 | pub struct Fr(FrRepr); 7 | 8 | #[test] 9 | fn test_to_hex() { 10 | assert_eq!(Fr::one().to_hex(), "0000000000000000000000000000000000000000000000000000000000000001"); 11 | } 12 | 13 | #[test] 14 | fn test_fr_from_hex() { 15 | let fr = Fr::from_hex("0000000000000000000000000000000000000000000000000000000000000001").unwrap(); 16 | assert_eq!(fr, Fr::one()); 17 | 18 | let fr = Fr::from_hex("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(); 19 | assert_eq!(fr, Fr::one()); 20 | 21 | let fr = Fr::from_hex("0x01").unwrap(); 22 | assert_eq!(fr, Fr::one()); 23 | 24 | let fr = Fr::from_hex("0x00").unwrap(); 25 | assert_eq!(fr, Fr::zero()); 26 | 27 | let fr = Fr::from_hex("00").unwrap(); 28 | assert_eq!(fr, Fr::zero()); 29 | } 30 | 31 | #[test] 32 | fn test_fr_serialize() { 33 | assert_eq!( 34 | serde_json::to_string(&Fr::one()).unwrap(), 35 | r#""0x0000000000000000000000000000000000000000000000000000000000000001""#); 36 | } 37 | 38 | #[test] 39 | fn test_fr_deserialize() { 40 | let json = r#""0x0000000000000000000000000000000000000000000000000000000000000001""#; 41 | let fr: Fr = serde_json::from_str(json).unwrap(); 42 | assert_eq!(fr, Fr::one()); 43 | } 44 | 45 | #[test] 46 | fn test_roots_of_unity() { 47 | assert_eq!(Fr::S, 28); 48 | } 49 | 50 | #[test] 51 | fn test_default() { 52 | assert_eq!(Fr::default(), Fr::zero()); 53 | } -------------------------------------------------------------------------------- /bellman/src/groth16/verifier.rs: -------------------------------------------------------------------------------- 1 | use pairing::{ 2 | Engine, 3 | CurveProjective, 4 | CurveAffine, 5 | }; 6 | 7 | use ff::{ 8 | PrimeField 9 | }; 10 | 11 | use super::{ 12 | Proof, 13 | VerifyingKey, 14 | PreparedVerifyingKey 15 | }; 16 | 17 | use ::{ 18 | SynthesisError 19 | }; 20 | 21 | pub fn prepare_verifying_key( 22 | vk: &VerifyingKey 23 | ) -> PreparedVerifyingKey 24 | { 25 | let mut gamma = vk.gamma_g2; 26 | gamma.negate(); 27 | let mut delta = vk.delta_g2; 28 | delta.negate(); 29 | 30 | PreparedVerifyingKey { 31 | alpha_g1_beta_g2: E::pairing(vk.alpha_g1, vk.beta_g2), 32 | neg_gamma_g2: gamma.prepare(), 33 | neg_delta_g2: delta.prepare(), 34 | ic: vk.ic.clone() 35 | } 36 | } 37 | 38 | pub fn verify_proof<'a, E: Engine>( 39 | pvk: &'a PreparedVerifyingKey, 40 | proof: &Proof, 41 | public_inputs: &[E::Fr] 42 | ) -> Result 43 | { 44 | if (public_inputs.len() + 1) != pvk.ic.len() { 45 | return Err(SynthesisError::MalformedVerifyingKey); 46 | } 47 | 48 | let mut acc = pvk.ic[0].into_projective(); 49 | 50 | for (i, b) in public_inputs.iter().zip(pvk.ic.iter().skip(1)) { 51 | acc.add_assign(&b.mul(i.into_repr())); 52 | } 53 | 54 | // The original verification equation is: 55 | // A * B = alpha * beta + inputs * gamma + C * delta 56 | // ... however, we rearrange it so that it is: 57 | // A * B - inputs * gamma - C * delta = alpha * beta 58 | // or equivalently: 59 | // A * B + inputs * (-gamma) + C * (-delta) = alpha * beta 60 | // which allows us to do a single final exponentiation. 61 | 62 | Ok(E::final_exponentiation( 63 | &E::miller_loop([ 64 | (&proof.a.prepare(), &proof.b.prepare()), 65 | (&acc.into_affine().prepare(), &pvk.neg_gamma_g2), 66 | (&proof.c.prepare(), &pvk.neg_delta_g2) 67 | ].into_iter()) 68 | ).unwrap() == pvk.alpha_g1_beta_g2) 69 | } 70 | -------------------------------------------------------------------------------- /ff/README.md: -------------------------------------------------------------------------------- 1 | # ff 2 | 3 | `ff` is a finite field library written in pure Rust, with no `unsafe{}` code. 4 | 5 | ## Disclaimers 6 | 7 | * This library does not provide constant-time guarantees. 8 | 9 | ## Usage 10 | 11 | Add the `ff` crate to your `Cargo.toml`: 12 | 13 | ```toml 14 | [dependencies] 15 | ff = "0.4" 16 | ``` 17 | 18 | The `ff` crate contains `Field`, `PrimeField`, `PrimeFieldRepr` and `SqrtField` traits. See the **[documentation](https://docs.rs/ff/0.4.0/ff/)** for more. 19 | 20 | ### #![derive(PrimeField)] 21 | 22 | If you need an implementation of a prime field, this library also provides a procedural macro that will expand into an efficient implementation of a prime field when supplied with the modulus. `PrimeFieldGenerator` must be an element of Fp of p-1 order, that is also quadratic nonresidue. 23 | 24 | First, enable the `derive` crate feature: 25 | 26 | ```toml 27 | [dependencies] 28 | ff = { path = "../ff", features = ["derive"] } 29 | ``` 30 | 31 | And then use the macro like so: 32 | 33 | ```rust 34 | extern crate rand; 35 | #[macro_use] 36 | extern crate ff; 37 | 38 | #[derive(PrimeField)] 39 | #[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"] 40 | #[PrimeFieldGenerator = "7"] 41 | struct Fp(FpRepr); 42 | ``` 43 | 44 | And that's it! `Fp` now implements `Field` and `PrimeField`. `Fp` will also implement `SqrtField` if supported. The library implements `FpRepr` itself and derives `PrimeFieldRepr` for it. 45 | 46 | ## License 47 | 48 | Licensed under either of 49 | 50 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 51 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 52 | 53 | at your option. 54 | 55 | ### Contribution 56 | 57 | Unless you explicitly state otherwise, any contribution intentionally 58 | submitted for inclusion in the work by you, as defined in the Apache-2.0 59 | license, shall be dual licensed as above, without any additional terms or 60 | conditions. 61 | -------------------------------------------------------------------------------- /sapling-crypto/src/constants.rs: -------------------------------------------------------------------------------- 1 | /// First 64 bytes of the BLAKE2s input during group hash. 2 | /// This is chosen to be some random string that we couldn't have anticipated when we designed 3 | /// the algorithm, for rigidity purposes. 4 | /// We deliberately use an ASCII hex string of 32 bytes here. 5 | pub const GH_FIRST_BLOCK: &'static [u8; 64] 6 | = b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0"; 7 | 8 | // BLAKE2s invocation personalizations 9 | /// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | nk) 10 | pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8] 11 | = b"Zcashivk"; 12 | 13 | /// BLAKE2s Personalization for PRF^nf = BLAKE2s(nk | rho) 14 | pub const PRF_NF_PERSONALIZATION: &'static [u8; 8] 15 | = b"Zcash_nf"; 16 | 17 | // Group hash personalizations 18 | /// BLAKE2s Personalization for Pedersen hash generators. 19 | pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8] 20 | = b"Zcash_PH"; 21 | 22 | /// BLAKE2s Personalization for the group hash for key diversification 23 | pub const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8] 24 | = b"Zcash_gd"; 25 | 26 | /// BLAKE2s Personalization for the spending key base point 27 | pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8] 28 | = b"Zcash_G_"; 29 | 30 | /// BLAKE2s Personalization for the proof generation key base point 31 | pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8] 32 | = b"Zcash_H_"; 33 | 34 | /// BLAKE2s Personalization for the value commitment generator for the value 35 | pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &'static [u8; 8] 36 | = b"Zcash_cv"; 37 | 38 | /// BLAKE2s Personalization for the nullifier position generator (for computing rho) 39 | pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8] 40 | = b"Zcash_J_"; 41 | 42 | /// BLAKE2s Personalization hash of (R_x || message) in EdDSA variant with 256 bit hash 43 | pub const MATTER_EDDSA_BLAKE2S_PERSONALIZATION: &'static [u8; 8] 44 | = b"Matter_H"; -------------------------------------------------------------------------------- /sapling-crypto/src/circuit/sprout/prfs.rs: -------------------------------------------------------------------------------- 1 | use pairing::{Engine}; 2 | use bellman::{ConstraintSystem, SynthesisError}; 3 | use circuit::sha256::{ 4 | sha256_block_no_padding 5 | }; 6 | use circuit::boolean::{ 7 | Boolean 8 | }; 9 | 10 | fn prf( 11 | cs: CS, 12 | a: bool, 13 | b: bool, 14 | c: bool, 15 | d: bool, 16 | x: &[Boolean], 17 | y: &[Boolean] 18 | ) -> Result, SynthesisError> 19 | where E: Engine, CS: ConstraintSystem 20 | { 21 | assert_eq!(x.len(), 252); 22 | assert_eq!(y.len(), 256); 23 | 24 | let mut image = vec![]; 25 | image.push(Boolean::constant(a)); 26 | image.push(Boolean::constant(b)); 27 | image.push(Boolean::constant(c)); 28 | image.push(Boolean::constant(d)); 29 | image.extend(x.iter().cloned()); 30 | image.extend(y.iter().cloned()); 31 | 32 | assert_eq!(image.len(), 512); 33 | 34 | sha256_block_no_padding( 35 | cs, 36 | &image 37 | ) 38 | } 39 | 40 | pub fn prf_a_pk( 41 | cs: CS, 42 | a_sk: &[Boolean] 43 | ) -> Result, SynthesisError> 44 | where E: Engine, CS: ConstraintSystem 45 | { 46 | prf(cs, true, true, false, false, a_sk, &(0..256).map(|_| Boolean::constant(false)).collect::>()) 47 | } 48 | 49 | pub fn prf_nf( 50 | cs: CS, 51 | a_sk: &[Boolean], 52 | rho: &[Boolean] 53 | ) -> Result, SynthesisError> 54 | where E: Engine, CS: ConstraintSystem 55 | { 56 | prf(cs, true, true, true, false, a_sk, rho) 57 | } 58 | 59 | pub fn prf_pk( 60 | cs: CS, 61 | a_sk: &[Boolean], 62 | h_sig: &[Boolean], 63 | nonce: bool 64 | ) -> Result, SynthesisError> 65 | where E: Engine, CS: ConstraintSystem 66 | { 67 | prf(cs, false, nonce, false, false, a_sk, h_sig) 68 | } 69 | 70 | pub fn prf_rho( 71 | cs: CS, 72 | phi: &[Boolean], 73 | h_sig: &[Boolean], 74 | nonce: bool 75 | ) -> Result, SynthesisError> 76 | where E: Engine, CS: ConstraintSystem 77 | { 78 | prf(cs, false, nonce, true, false, phi, h_sig) 79 | } 80 | -------------------------------------------------------------------------------- /sapling-crypto/src/group_hash.rs: -------------------------------------------------------------------------------- 1 | use jubjub::{ 2 | JubjubEngine, 3 | PrimeOrder, 4 | edwards 5 | }; 6 | 7 | use ff::{ 8 | PrimeField 9 | }; 10 | 11 | use blake2_rfc::blake2s::Blake2s; 12 | use constants; 13 | 14 | /// Produces a random point in the Jubjub curve. 15 | /// The point is guaranteed to be prime order 16 | /// and not the identity. 17 | pub fn group_hash( 18 | tag: &[u8], 19 | personalization: &[u8], 20 | params: &E::Params 21 | ) -> Option> 22 | { 23 | assert_eq!(personalization.len(), 8); 24 | 25 | // Check to see that scalar field is 255 bits 26 | assert!(E::Fr::NUM_BITS == 255); 27 | 28 | let mut h = Blake2s::with_params(32, &[], &[], personalization); 29 | h.update(constants::GH_FIRST_BLOCK); 30 | h.update(tag); 31 | let h = h.finalize().as_ref().to_vec(); 32 | assert!(h.len() == 32); 33 | 34 | match edwards::Point::::read(&h[..], params) { 35 | Ok(p) => { 36 | let p = p.mul_by_cofactor(params); 37 | 38 | if p != edwards::Point::zero() { 39 | Some(p) 40 | } else { 41 | None 42 | } 43 | }, 44 | Err(_) => None 45 | } 46 | } 47 | 48 | /// Produces a random point in the Alt Baby Jubjub curve. 49 | /// The point is guaranteed to be prime order 50 | /// and not the identity. 51 | pub fn baby_group_hash( 52 | tag: &[u8], 53 | personalization: &[u8], 54 | params: &E::Params 55 | ) -> Option> 56 | { 57 | assert_eq!(personalization.len(), 8); 58 | 59 | // Check to see that scalar field is 255 bits 60 | assert!(E::Fr::NUM_BITS == 254); 61 | 62 | let mut h = Blake2s::with_params(32, &[], &[], personalization); 63 | h.update(constants::GH_FIRST_BLOCK); 64 | h.update(tag); 65 | let h = h.finalize().as_ref().to_vec(); 66 | assert!(h.len() == 32); 67 | 68 | match edwards::Point::::read(&h[..], params) { 69 | Ok(p) => { 70 | let p = p.mul_by_cofactor(params); 71 | 72 | if p != edwards::Point::zero() { 73 | Some(p) 74 | } else { 75 | None 76 | } 77 | }, 78 | Err(_) => None 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /pairing/benches/bn256/fq12.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rand, SeedableRng, XorShiftRng}; 2 | 3 | use ff::Field; 4 | use pairing::bn256::*; 5 | 6 | #[bench] 7 | fn bench_fq12_add_assign(b: &mut ::test::Bencher) { 8 | const SAMPLES: usize = 1000; 9 | 10 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 11 | 12 | let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) 13 | .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) 14 | .collect(); 15 | 16 | let mut count = 0; 17 | b.iter(|| { 18 | let mut tmp = v[count].0; 19 | tmp.add_assign(&v[count].1); 20 | count = (count + 1) % SAMPLES; 21 | tmp 22 | }); 23 | } 24 | 25 | #[bench] 26 | fn bench_fq12_sub_assign(b: &mut ::test::Bencher) { 27 | const SAMPLES: usize = 1000; 28 | 29 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 30 | 31 | let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) 32 | .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) 33 | .collect(); 34 | 35 | let mut count = 0; 36 | b.iter(|| { 37 | let mut tmp = v[count].0; 38 | tmp.sub_assign(&v[count].1); 39 | count = (count + 1) % SAMPLES; 40 | tmp 41 | }); 42 | } 43 | 44 | #[bench] 45 | fn bench_fq12_mul_assign(b: &mut ::test::Bencher) { 46 | const SAMPLES: usize = 1000; 47 | 48 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 49 | 50 | let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) 51 | .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) 52 | .collect(); 53 | 54 | let mut count = 0; 55 | b.iter(|| { 56 | let mut tmp = v[count].0; 57 | tmp.mul_assign(&v[count].1); 58 | count = (count + 1) % SAMPLES; 59 | tmp 60 | }); 61 | } 62 | 63 | #[bench] 64 | fn bench_fq12_squaring(b: &mut ::test::Bencher) { 65 | const SAMPLES: usize = 1000; 66 | 67 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 68 | 69 | let v: Vec = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect(); 70 | 71 | let mut count = 0; 72 | b.iter(|| { 73 | let mut tmp = v[count]; 74 | tmp.square(); 75 | count = (count + 1) % SAMPLES; 76 | tmp 77 | }); 78 | } 79 | 80 | #[bench] 81 | fn bench_fq12_inverse(b: &mut ::test::Bencher) { 82 | const SAMPLES: usize = 1000; 83 | 84 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 85 | 86 | let v: Vec = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect(); 87 | 88 | let mut count = 0; 89 | b.iter(|| { 90 | let tmp = v[count].inverse(); 91 | count = (count + 1) % SAMPLES; 92 | tmp 93 | }); 94 | } 95 | -------------------------------------------------------------------------------- /pairing/benches/bls12_381/fq12.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rand, SeedableRng, XorShiftRng}; 2 | 3 | use ff::Field; 4 | use pairing::bls12_381::*; 5 | 6 | #[bench] 7 | fn bench_fq12_add_assign(b: &mut ::test::Bencher) { 8 | const SAMPLES: usize = 1000; 9 | 10 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 11 | 12 | let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) 13 | .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) 14 | .collect(); 15 | 16 | let mut count = 0; 17 | b.iter(|| { 18 | let mut tmp = v[count].0; 19 | tmp.add_assign(&v[count].1); 20 | count = (count + 1) % SAMPLES; 21 | tmp 22 | }); 23 | } 24 | 25 | #[bench] 26 | fn bench_fq12_sub_assign(b: &mut ::test::Bencher) { 27 | const SAMPLES: usize = 1000; 28 | 29 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 30 | 31 | let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) 32 | .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) 33 | .collect(); 34 | 35 | let mut count = 0; 36 | b.iter(|| { 37 | let mut tmp = v[count].0; 38 | tmp.sub_assign(&v[count].1); 39 | count = (count + 1) % SAMPLES; 40 | tmp 41 | }); 42 | } 43 | 44 | #[bench] 45 | fn bench_fq12_mul_assign(b: &mut ::test::Bencher) { 46 | const SAMPLES: usize = 1000; 47 | 48 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 49 | 50 | let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) 51 | .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) 52 | .collect(); 53 | 54 | let mut count = 0; 55 | b.iter(|| { 56 | let mut tmp = v[count].0; 57 | tmp.mul_assign(&v[count].1); 58 | count = (count + 1) % SAMPLES; 59 | tmp 60 | }); 61 | } 62 | 63 | #[bench] 64 | fn bench_fq12_squaring(b: &mut ::test::Bencher) { 65 | const SAMPLES: usize = 1000; 66 | 67 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 68 | 69 | let v: Vec = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect(); 70 | 71 | let mut count = 0; 72 | b.iter(|| { 73 | let mut tmp = v[count]; 74 | tmp.square(); 75 | count = (count + 1) % SAMPLES; 76 | tmp 77 | }); 78 | } 79 | 80 | #[bench] 81 | fn bench_fq12_inverse(b: &mut ::test::Bencher) { 82 | const SAMPLES: usize = 1000; 83 | 84 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 85 | 86 | let v: Vec = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect(); 87 | 88 | let mut count = 0; 89 | b.iter(|| { 90 | let tmp = v[count].inverse(); 91 | count = (count + 1) % SAMPLES; 92 | tmp 93 | }); 94 | } 95 | -------------------------------------------------------------------------------- /pairing/src/tests/repr.rs: -------------------------------------------------------------------------------- 1 | use ff::PrimeFieldRepr; 2 | use rand::{SeedableRng, XorShiftRng}; 3 | 4 | pub fn random_repr_tests() { 5 | random_encoding_tests::(); 6 | random_shl_tests::(); 7 | random_shr_tests::(); 8 | } 9 | 10 | fn random_encoding_tests() { 11 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 12 | 13 | for _ in 0..1000 { 14 | let r = R::rand(&mut rng); 15 | 16 | // Big endian 17 | { 18 | let mut rdecoded = R::default(); 19 | 20 | let mut v: Vec = vec![]; 21 | r.write_be(&mut v).unwrap(); 22 | rdecoded.read_be(&v[0..]).unwrap(); 23 | 24 | assert_eq!(r, rdecoded); 25 | } 26 | 27 | // Little endian 28 | { 29 | let mut rdecoded = R::default(); 30 | 31 | let mut v: Vec = vec![]; 32 | r.write_le(&mut v).unwrap(); 33 | rdecoded.read_le(&v[0..]).unwrap(); 34 | 35 | assert_eq!(r, rdecoded); 36 | } 37 | 38 | { 39 | let mut rdecoded_le = R::default(); 40 | let mut rdecoded_be_flip = R::default(); 41 | 42 | let mut v: Vec = vec![]; 43 | r.write_le(&mut v).unwrap(); 44 | 45 | // This reads in little-endian, so we are done. 46 | rdecoded_le.read_le(&v[..]).unwrap(); 47 | 48 | // This reads in big-endian, so we perform a swap of the 49 | // bytes beforehand. 50 | let v: Vec = v.into_iter().rev().collect(); 51 | rdecoded_be_flip.read_be(&v[..]).unwrap(); 52 | 53 | assert_eq!(rdecoded_le, rdecoded_be_flip); 54 | } 55 | } 56 | } 57 | 58 | fn random_shl_tests() { 59 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 60 | 61 | for _ in 0..100 { 62 | let r = R::rand(&mut rng); 63 | 64 | for shift in 0..(r.num_bits() + 1) { 65 | let mut r1 = r; 66 | let mut r2 = r; 67 | 68 | for _ in 0..shift { 69 | r1.mul2(); 70 | } 71 | 72 | r2.shl(shift); 73 | 74 | assert_eq!(r1, r2); 75 | } 76 | } 77 | } 78 | 79 | fn random_shr_tests() { 80 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 81 | 82 | for _ in 0..100 { 83 | let r = R::rand(&mut rng); 84 | 85 | for shift in 0..(r.num_bits() + 1) { 86 | let mut r1 = r; 87 | let mut r2 = r; 88 | 89 | for _ in 0..shift { 90 | r1.div2(); 91 | } 92 | 93 | r2.shr(shift); 94 | 95 | assert_eq!(r1, r2); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /sapling-crypto/src/baby_pedersen_hash.rs: -------------------------------------------------------------------------------- 1 | use babyjubjub::*; 2 | use ff::{Field, PrimeField, PrimeFieldRepr}; 3 | 4 | #[derive(Copy, Clone)] 5 | pub enum Personalization { 6 | NoteCommitment, 7 | MerkleTree(usize) 8 | } 9 | 10 | impl Personalization { 11 | pub fn get_bits(&self) -> Vec { 12 | match *self { 13 | Personalization::NoteCommitment => 14 | vec![true, true, true, true, true, true], 15 | Personalization::MerkleTree(num) => { 16 | assert!(num < 62); 17 | 18 | (0..6).map(|i| (num >> i) & 1 == 1).collect() 19 | } 20 | } 21 | } 22 | } 23 | 24 | pub fn pedersen_hash( 25 | personalization: Personalization, 26 | bits: I, 27 | params: &E::Params 28 | ) -> edwards::Point 29 | where I: IntoIterator, 30 | E: JubjubEngine 31 | { 32 | let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter()); 33 | 34 | let mut result = edwards::Point::zero(); 35 | let mut generators = params.pedersen_hash_exp_table().iter(); 36 | 37 | loop { 38 | let mut acc = E::Fs::zero(); 39 | let mut cur = E::Fs::one(); 40 | let mut chunks_remaining = params.pedersen_hash_chunks_per_generator(); 41 | let mut encountered_bits = false; 42 | 43 | // Grab three bits from the input 44 | while let Some(a) = bits.next() { 45 | encountered_bits = true; 46 | 47 | let b = bits.next().unwrap_or(false); 48 | let c = bits.next().unwrap_or(false); 49 | 50 | // Start computing this portion of the scalar 51 | let mut tmp = cur; 52 | if a { 53 | tmp.add_assign(&cur); 54 | } 55 | cur.double(); // 2^1 * cur 56 | if b { 57 | tmp.add_assign(&cur); 58 | } 59 | 60 | // conditionally negate 61 | if c { 62 | tmp.negate(); 63 | } 64 | 65 | acc.add_assign(&tmp); 66 | 67 | chunks_remaining -= 1; 68 | 69 | if chunks_remaining == 0 { 70 | break; 71 | } else { 72 | cur.double(); // 2^2 * cur 73 | cur.double(); // 2^3 * cur 74 | cur.double(); // 2^4 * cur 75 | } 76 | } 77 | 78 | if !encountered_bits { 79 | break; 80 | } 81 | 82 | let mut table: &[Vec>] = &generators.next().expect("we don't have enough generators"); 83 | let window = JubjubBn256::pedersen_hash_exp_window_size(); 84 | let window_mask = (1 << window) - 1; 85 | 86 | let mut acc = acc.into_repr(); 87 | 88 | let mut tmp = edwards::Point::zero(); 89 | 90 | while !acc.is_zero() { 91 | let i = (acc.as_ref()[0] & window_mask) as usize; 92 | 93 | tmp = tmp.add(&table[0][i], params); 94 | 95 | acc.shr(window); 96 | table = &table[1..]; 97 | } 98 | 99 | result = result.add(&tmp, params); 100 | } 101 | 102 | result 103 | } 104 | -------------------------------------------------------------------------------- /pairing/benches/bn256/mod.rs: -------------------------------------------------------------------------------- 1 | mod ec; 2 | mod fq; 3 | mod fq12; 4 | mod fq2; 5 | mod fr; 6 | 7 | use rand::{Rand, SeedableRng, XorShiftRng}; 8 | 9 | use pairing::bn256::*; 10 | use pairing::{CurveAffine, Engine}; 11 | 12 | #[bench] 13 | fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) { 14 | const SAMPLES: usize = 1000; 15 | 16 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 17 | 18 | let v: Vec = (0..SAMPLES).map(|_| G1::rand(&mut rng)).collect(); 19 | 20 | let mut count = 0; 21 | b.iter(|| { 22 | let tmp = G1Affine::from(v[count]).prepare(); 23 | count = (count + 1) % SAMPLES; 24 | tmp 25 | }); 26 | } 27 | 28 | #[bench] 29 | fn bench_pairing_g2_preparation(b: &mut ::test::Bencher) { 30 | const SAMPLES: usize = 1000; 31 | 32 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 33 | 34 | let v: Vec = (0..SAMPLES).map(|_| G2::rand(&mut rng)).collect(); 35 | 36 | let mut count = 0; 37 | b.iter(|| { 38 | let tmp = G2Affine::from(v[count]).prepare(); 39 | count = (count + 1) % SAMPLES; 40 | tmp 41 | }); 42 | } 43 | 44 | #[bench] 45 | fn bench_pairing_miller_loop(b: &mut ::test::Bencher) { 46 | const SAMPLES: usize = 1000; 47 | 48 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 49 | 50 | let v: Vec<(G1Prepared, G2Prepared)> = (0..SAMPLES) 51 | .map(|_| { 52 | ( 53 | G1Affine::from(G1::rand(&mut rng)).prepare(), 54 | G2Affine::from(G2::rand(&mut rng)).prepare(), 55 | ) 56 | }) 57 | .collect(); 58 | 59 | let mut count = 0; 60 | b.iter(|| { 61 | let tmp = Bn256::miller_loop(&[(&v[count].0, &v[count].1)]); 62 | count = (count + 1) % SAMPLES; 63 | tmp 64 | }); 65 | } 66 | 67 | #[bench] 68 | fn bench_pairing_final_exponentiation(b: &mut ::test::Bencher) { 69 | const SAMPLES: usize = 1000; 70 | 71 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 72 | 73 | let v: Vec = (0..SAMPLES) 74 | .map(|_| { 75 | ( 76 | G1Affine::from(G1::rand(&mut rng)).prepare(), 77 | G2Affine::from(G2::rand(&mut rng)).prepare(), 78 | ) 79 | }) 80 | .map(|(ref p, ref q)| Bn256::miller_loop(&[(p, q)])) 81 | .collect(); 82 | 83 | let mut count = 0; 84 | b.iter(|| { 85 | let tmp = Bn256::final_exponentiation(&v[count]); 86 | count = (count + 1) % SAMPLES; 87 | tmp 88 | }); 89 | } 90 | 91 | #[bench] 92 | fn bench_pairing_full(b: &mut ::test::Bencher) { 93 | const SAMPLES: usize = 1000; 94 | 95 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 96 | 97 | let v: Vec<(G1, G2)> = (0..SAMPLES) 98 | .map(|_| (G1::rand(&mut rng), G2::rand(&mut rng))) 99 | .collect(); 100 | 101 | let mut count = 0; 102 | b.iter(|| { 103 | let tmp = Bn256::pairing(v[count].0, v[count].1); 104 | count = (count + 1) % SAMPLES; 105 | tmp 106 | }); 107 | } 108 | -------------------------------------------------------------------------------- /pairing/benches/bls12_381/mod.rs: -------------------------------------------------------------------------------- 1 | mod ec; 2 | mod fq; 3 | mod fq12; 4 | mod fq2; 5 | mod fr; 6 | 7 | use rand::{Rand, SeedableRng, XorShiftRng}; 8 | 9 | use pairing::bls12_381::*; 10 | use pairing::{CurveAffine, Engine}; 11 | 12 | #[bench] 13 | fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) { 14 | const SAMPLES: usize = 1000; 15 | 16 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 17 | 18 | let v: Vec = (0..SAMPLES).map(|_| G1::rand(&mut rng)).collect(); 19 | 20 | let mut count = 0; 21 | b.iter(|| { 22 | let tmp = G1Affine::from(v[count]).prepare(); 23 | count = (count + 1) % SAMPLES; 24 | tmp 25 | }); 26 | } 27 | 28 | #[bench] 29 | fn bench_pairing_g2_preparation(b: &mut ::test::Bencher) { 30 | const SAMPLES: usize = 1000; 31 | 32 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 33 | 34 | let v: Vec = (0..SAMPLES).map(|_| G2::rand(&mut rng)).collect(); 35 | 36 | let mut count = 0; 37 | b.iter(|| { 38 | let tmp = G2Affine::from(v[count]).prepare(); 39 | count = (count + 1) % SAMPLES; 40 | tmp 41 | }); 42 | } 43 | 44 | #[bench] 45 | fn bench_pairing_miller_loop(b: &mut ::test::Bencher) { 46 | const SAMPLES: usize = 1000; 47 | 48 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 49 | 50 | let v: Vec<(G1Prepared, G2Prepared)> = (0..SAMPLES) 51 | .map(|_| { 52 | ( 53 | G1Affine::from(G1::rand(&mut rng)).prepare(), 54 | G2Affine::from(G2::rand(&mut rng)).prepare(), 55 | ) 56 | }) 57 | .collect(); 58 | 59 | let mut count = 0; 60 | b.iter(|| { 61 | let tmp = Bls12::miller_loop(&[(&v[count].0, &v[count].1)]); 62 | count = (count + 1) % SAMPLES; 63 | tmp 64 | }); 65 | } 66 | 67 | #[bench] 68 | fn bench_pairing_final_exponentiation(b: &mut ::test::Bencher) { 69 | const SAMPLES: usize = 1000; 70 | 71 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 72 | 73 | let v: Vec = (0..SAMPLES) 74 | .map(|_| { 75 | ( 76 | G1Affine::from(G1::rand(&mut rng)).prepare(), 77 | G2Affine::from(G2::rand(&mut rng)).prepare(), 78 | ) 79 | }) 80 | .map(|(ref p, ref q)| Bls12::miller_loop(&[(p, q)])) 81 | .collect(); 82 | 83 | let mut count = 0; 84 | b.iter(|| { 85 | let tmp = Bls12::final_exponentiation(&v[count]); 86 | count = (count + 1) % SAMPLES; 87 | tmp 88 | }); 89 | } 90 | 91 | #[bench] 92 | fn bench_pairing_full(b: &mut ::test::Bencher) { 93 | const SAMPLES: usize = 1000; 94 | 95 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 96 | 97 | let v: Vec<(G1, G2)> = (0..SAMPLES) 98 | .map(|_| (G1::rand(&mut rng), G2::rand(&mut rng))) 99 | .collect(); 100 | 101 | let mut count = 0; 102 | b.iter(|| { 103 | let tmp = Bls12::pairing(v[count].0, v[count].1); 104 | count = (count + 1) % SAMPLES; 105 | tmp 106 | }); 107 | } 108 | -------------------------------------------------------------------------------- /pairing/benches/bn256/fq2.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rand, SeedableRng, XorShiftRng}; 2 | 3 | use ff::{Field, SqrtField}; 4 | use pairing::bn256::*; 5 | 6 | #[bench] 7 | fn bench_fq2_add_assign(b: &mut ::test::Bencher) { 8 | const SAMPLES: usize = 1000; 9 | 10 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 11 | 12 | let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) 13 | .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) 14 | .collect(); 15 | 16 | let mut count = 0; 17 | b.iter(|| { 18 | let mut tmp = v[count].0; 19 | tmp.add_assign(&v[count].1); 20 | count = (count + 1) % SAMPLES; 21 | tmp 22 | }); 23 | } 24 | 25 | #[bench] 26 | fn bench_fq2_sub_assign(b: &mut ::test::Bencher) { 27 | const SAMPLES: usize = 1000; 28 | 29 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 30 | 31 | let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) 32 | .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) 33 | .collect(); 34 | 35 | let mut count = 0; 36 | b.iter(|| { 37 | let mut tmp = v[count].0; 38 | tmp.sub_assign(&v[count].1); 39 | count = (count + 1) % SAMPLES; 40 | tmp 41 | }); 42 | } 43 | 44 | #[bench] 45 | fn bench_fq2_mul_assign(b: &mut ::test::Bencher) { 46 | const SAMPLES: usize = 1000; 47 | 48 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 49 | 50 | let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) 51 | .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) 52 | .collect(); 53 | 54 | let mut count = 0; 55 | b.iter(|| { 56 | let mut tmp = v[count].0; 57 | tmp.mul_assign(&v[count].1); 58 | count = (count + 1) % SAMPLES; 59 | tmp 60 | }); 61 | } 62 | 63 | #[bench] 64 | fn bench_fq2_squaring(b: &mut ::test::Bencher) { 65 | const SAMPLES: usize = 1000; 66 | 67 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 68 | 69 | let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); 70 | 71 | let mut count = 0; 72 | b.iter(|| { 73 | let mut tmp = v[count]; 74 | tmp.square(); 75 | count = (count + 1) % SAMPLES; 76 | tmp 77 | }); 78 | } 79 | 80 | #[bench] 81 | fn bench_fq2_inverse(b: &mut ::test::Bencher) { 82 | const SAMPLES: usize = 1000; 83 | 84 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 85 | 86 | let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); 87 | 88 | let mut count = 0; 89 | b.iter(|| { 90 | let tmp = v[count].inverse(); 91 | count = (count + 1) % SAMPLES; 92 | tmp 93 | }); 94 | } 95 | 96 | #[bench] 97 | fn bench_fq2_sqrt(b: &mut ::test::Bencher) { 98 | const SAMPLES: usize = 1000; 99 | 100 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 101 | 102 | let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); 103 | 104 | let mut count = 0; 105 | b.iter(|| { 106 | let tmp = v[count].sqrt(); 107 | count = (count + 1) % SAMPLES; 108 | tmp 109 | }); 110 | } 111 | -------------------------------------------------------------------------------- /pairing/benches/bls12_381/fq2.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rand, SeedableRng, XorShiftRng}; 2 | 3 | use ff::{Field, SqrtField}; 4 | use pairing::bls12_381::*; 5 | 6 | #[bench] 7 | fn bench_fq2_add_assign(b: &mut ::test::Bencher) { 8 | const SAMPLES: usize = 1000; 9 | 10 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 11 | 12 | let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) 13 | .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) 14 | .collect(); 15 | 16 | let mut count = 0; 17 | b.iter(|| { 18 | let mut tmp = v[count].0; 19 | tmp.add_assign(&v[count].1); 20 | count = (count + 1) % SAMPLES; 21 | tmp 22 | }); 23 | } 24 | 25 | #[bench] 26 | fn bench_fq2_sub_assign(b: &mut ::test::Bencher) { 27 | const SAMPLES: usize = 1000; 28 | 29 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 30 | 31 | let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) 32 | .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) 33 | .collect(); 34 | 35 | let mut count = 0; 36 | b.iter(|| { 37 | let mut tmp = v[count].0; 38 | tmp.sub_assign(&v[count].1); 39 | count = (count + 1) % SAMPLES; 40 | tmp 41 | }); 42 | } 43 | 44 | #[bench] 45 | fn bench_fq2_mul_assign(b: &mut ::test::Bencher) { 46 | const SAMPLES: usize = 1000; 47 | 48 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 49 | 50 | let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) 51 | .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) 52 | .collect(); 53 | 54 | let mut count = 0; 55 | b.iter(|| { 56 | let mut tmp = v[count].0; 57 | tmp.mul_assign(&v[count].1); 58 | count = (count + 1) % SAMPLES; 59 | tmp 60 | }); 61 | } 62 | 63 | #[bench] 64 | fn bench_fq2_squaring(b: &mut ::test::Bencher) { 65 | const SAMPLES: usize = 1000; 66 | 67 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 68 | 69 | let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); 70 | 71 | let mut count = 0; 72 | b.iter(|| { 73 | let mut tmp = v[count]; 74 | tmp.square(); 75 | count = (count + 1) % SAMPLES; 76 | tmp 77 | }); 78 | } 79 | 80 | #[bench] 81 | fn bench_fq2_inverse(b: &mut ::test::Bencher) { 82 | const SAMPLES: usize = 1000; 83 | 84 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 85 | 86 | let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); 87 | 88 | let mut count = 0; 89 | b.iter(|| { 90 | let tmp = v[count].inverse(); 91 | count = (count + 1) % SAMPLES; 92 | tmp 93 | }); 94 | } 95 | 96 | #[bench] 97 | fn bench_fq2_sqrt(b: &mut ::test::Bencher) { 98 | const SAMPLES: usize = 1000; 99 | 100 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 101 | 102 | let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); 103 | 104 | let mut count = 0; 105 | b.iter(|| { 106 | let tmp = v[count].sqrt(); 107 | count = (count + 1) % SAMPLES; 108 | tmp 109 | }); 110 | } 111 | -------------------------------------------------------------------------------- /sapling-crypto/examples/bench.rs: -------------------------------------------------------------------------------- 1 | extern crate sapling_crypto; 2 | extern crate bellman; 3 | extern crate rand; 4 | extern crate pairing; 5 | 6 | use std::time::{Duration, Instant}; 7 | use sapling_crypto::jubjub::{ 8 | JubjubBls12, 9 | edwards, 10 | fs, 11 | }; 12 | use sapling_crypto::circuit::sapling::{ 13 | Spend 14 | }; 15 | use sapling_crypto::primitives::{ 16 | Diversifier, 17 | ProofGenerationKey, 18 | ValueCommitment 19 | }; 20 | use bellman::groth16::*; 21 | use rand::{XorShiftRng, SeedableRng, Rng}; 22 | use pairing::bls12_381::{Bls12, Fr}; 23 | 24 | const TREE_DEPTH: usize = 32; 25 | 26 | fn main() { 27 | let jubjub_params = &JubjubBls12::new(); 28 | let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 29 | 30 | println!("Creating sample parameters..."); 31 | let groth_params = generate_random_parameters::( 32 | Spend { 33 | params: jubjub_params, 34 | value_commitment: None, 35 | proof_generation_key: None, 36 | payment_address: None, 37 | commitment_randomness: None, 38 | ar: None, 39 | auth_path: vec![None; TREE_DEPTH], 40 | anchor: None 41 | }, 42 | rng 43 | ).unwrap(); 44 | 45 | const SAMPLES: u32 = 50; 46 | 47 | let mut total_time = Duration::new(0, 0); 48 | for _ in 0..SAMPLES { 49 | let value_commitment = ValueCommitment { 50 | value: 1, 51 | randomness: rng.gen() 52 | }; 53 | 54 | let nsk: fs::Fs = rng.gen(); 55 | let ak = edwards::Point::rand(rng, jubjub_params).mul_by_cofactor(jubjub_params); 56 | 57 | let proof_generation_key = ProofGenerationKey { 58 | ak: ak.clone(), 59 | nsk: nsk.clone() 60 | }; 61 | 62 | let viewing_key = proof_generation_key.into_viewing_key(jubjub_params); 63 | 64 | let payment_address; 65 | 66 | loop { 67 | let diversifier = Diversifier(rng.gen()); 68 | 69 | if let Some(p) = viewing_key.into_payment_address( 70 | diversifier, 71 | jubjub_params 72 | ) 73 | { 74 | payment_address = p; 75 | break; 76 | } 77 | } 78 | 79 | let commitment_randomness: fs::Fs = rng.gen(); 80 | let auth_path = vec![Some((rng.gen(), rng.gen())); TREE_DEPTH]; 81 | let ar: fs::Fs = rng.gen(); 82 | let anchor: Fr = rng.gen(); 83 | 84 | let start = Instant::now(); 85 | let _ = create_random_proof(Spend { 86 | params: jubjub_params, 87 | value_commitment: Some(value_commitment), 88 | proof_generation_key: Some(proof_generation_key), 89 | payment_address: Some(payment_address), 90 | commitment_randomness: Some(commitment_randomness), 91 | ar: Some(ar), 92 | auth_path: auth_path, 93 | anchor: Some(anchor) 94 | }, &groth_params, rng).unwrap(); 95 | total_time += start.elapsed(); 96 | } 97 | let avg = total_time / SAMPLES; 98 | let avg = avg.subsec_nanos() as f64 / 1_000_000_000f64 99 | + (avg.as_secs() as f64); 100 | 101 | println!("Average proving time (in seconds): {}", avg); 102 | } 103 | -------------------------------------------------------------------------------- /sapling-crypto/src/circuit/multipack.rs: -------------------------------------------------------------------------------- 1 | use pairing::{Engine,}; 2 | use ff::{Field, PrimeField}; 3 | use bellman::{ConstraintSystem, SynthesisError}; 4 | use super::boolean::{Boolean}; 5 | use super::num::Num; 6 | use super::Assignment; 7 | 8 | /// Takes a sequence of booleans and exposes them as compact 9 | /// public inputs 10 | pub fn pack_into_inputs( 11 | mut cs: CS, 12 | bits: &[Boolean] 13 | ) -> Result<(), SynthesisError> 14 | where E: Engine, CS: ConstraintSystem 15 | { 16 | for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() 17 | { 18 | let mut num = Num::::zero(); 19 | let mut coeff = E::Fr::one(); 20 | for bit in bits { 21 | num = num.add_bool_with_coeff(CS::one(), bit, coeff); 22 | 23 | coeff.double(); 24 | } 25 | 26 | let input = cs.alloc_input(|| format!("input {}", i), || { 27 | Ok(*num.get_value().get()?) 28 | })?; 29 | 30 | // num * 1 = input 31 | cs.enforce( 32 | || format!("packing constraint {}", i), 33 | |_| num.lc(E::Fr::one()), 34 | |lc| lc + CS::one(), 35 | |lc| lc + input 36 | ); 37 | } 38 | 39 | Ok(()) 40 | } 41 | 42 | pub fn bytes_to_bits(bytes: &[u8]) -> Vec 43 | { 44 | bytes.iter() 45 | .flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1)) 46 | .collect() 47 | } 48 | 49 | pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec 50 | { 51 | bytes.iter() 52 | .flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1)) 53 | .collect() 54 | } 55 | 56 | pub fn compute_multipacking( 57 | bits: &[bool] 58 | ) -> Vec 59 | { 60 | let mut result = vec![]; 61 | 62 | for bits in bits.chunks(E::Fr::CAPACITY as usize) 63 | { 64 | let mut cur = E::Fr::zero(); 65 | let mut coeff = E::Fr::one(); 66 | 67 | for bit in bits { 68 | if *bit { 69 | cur.add_assign(&coeff); 70 | } 71 | 72 | coeff.double(); 73 | } 74 | 75 | result.push(cur); 76 | } 77 | 78 | result 79 | } 80 | 81 | #[test] 82 | fn test_multipacking() { 83 | use rand::{SeedableRng, Rng, XorShiftRng}; 84 | use bellman::{ConstraintSystem}; 85 | use pairing::bls12_381::{Bls12}; 86 | use ::circuit::test::*; 87 | use super::boolean::{AllocatedBit, Boolean}; 88 | 89 | let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 90 | 91 | for num_bits in 0..1500 { 92 | let mut cs = TestConstraintSystem::::new(); 93 | 94 | let bits: Vec = (0..num_bits).map(|_| rng.gen()).collect(); 95 | 96 | let circuit_bits = bits.iter().enumerate() 97 | .map(|(i, &b)| { 98 | Boolean::from( 99 | AllocatedBit::alloc( 100 | cs.namespace(|| format!("bit {}", i)), 101 | Some(b) 102 | ).unwrap() 103 | ) 104 | }) 105 | .collect::>(); 106 | 107 | let expected_inputs = compute_multipacking::(&bits); 108 | 109 | pack_into_inputs(cs.namespace(|| "pack"), &circuit_bits).unwrap(); 110 | 111 | assert!(cs.is_satisfied()); 112 | assert!(cs.verify(&expected_inputs)); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /sapling-crypto/src/circuit/multieq.rs: -------------------------------------------------------------------------------- 1 | use pairing::{ 2 | Engine, 3 | }; 4 | 5 | use ff::{ 6 | Field, 7 | PrimeField 8 | }; 9 | 10 | use bellman::{ 11 | SynthesisError, 12 | ConstraintSystem, 13 | LinearCombination, 14 | Variable 15 | }; 16 | 17 | pub struct MultiEq>{ 18 | cs: CS, 19 | ops: usize, 20 | bits_used: usize, 21 | lhs: LinearCombination, 22 | rhs: LinearCombination, 23 | } 24 | 25 | impl> MultiEq { 26 | pub fn new(cs: CS) -> Self { 27 | MultiEq { 28 | cs: cs, 29 | ops: 0, 30 | bits_used: 0, 31 | lhs: LinearCombination::zero(), 32 | rhs: LinearCombination::zero() 33 | } 34 | } 35 | 36 | fn accumulate(&mut self) 37 | { 38 | let ops = self.ops; 39 | let lhs = self.lhs.clone(); 40 | let rhs = self.rhs.clone(); 41 | self.cs.enforce( 42 | || format!("multieq {}", ops), 43 | |_| lhs, 44 | |lc| lc + CS::one(), 45 | |_| rhs 46 | ); 47 | self.lhs = LinearCombination::zero(); 48 | self.rhs = LinearCombination::zero(); 49 | self.bits_used = 0; 50 | self.ops += 1; 51 | } 52 | 53 | pub fn enforce_equal( 54 | &mut self, 55 | num_bits: usize, 56 | lhs: &LinearCombination, 57 | rhs: &LinearCombination 58 | ) 59 | { 60 | // Check if we will exceed the capacity 61 | if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) { 62 | self.accumulate(); 63 | } 64 | 65 | assert!((E::Fr::CAPACITY as usize) > (self.bits_used + num_bits)); 66 | 67 | let coeff = E::Fr::from_str("2").unwrap().pow(&[self.bits_used as u64]); 68 | self.lhs = self.lhs.clone() + (coeff, lhs); 69 | self.rhs = self.rhs.clone() + (coeff, rhs); 70 | self.bits_used += num_bits; 71 | } 72 | } 73 | 74 | impl> Drop for MultiEq { 75 | fn drop(&mut self) { 76 | if self.bits_used > 0 { 77 | self.accumulate(); 78 | } 79 | } 80 | } 81 | 82 | impl> ConstraintSystem for MultiEq 83 | { 84 | type Root = Self; 85 | 86 | fn one() -> Variable { 87 | CS::one() 88 | } 89 | 90 | fn alloc( 91 | &mut self, 92 | annotation: A, 93 | f: F 94 | ) -> Result 95 | where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into 96 | { 97 | self.cs.alloc(annotation, f) 98 | } 99 | 100 | fn alloc_input( 101 | &mut self, 102 | annotation: A, 103 | f: F 104 | ) -> Result 105 | where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into 106 | { 107 | self.cs.alloc_input(annotation, f) 108 | } 109 | 110 | fn enforce( 111 | &mut self, 112 | annotation: A, 113 | a: LA, 114 | b: LB, 115 | c: LC 116 | ) 117 | where A: FnOnce() -> AR, AR: Into, 118 | LA: FnOnce(LinearCombination) -> LinearCombination, 119 | LB: FnOnce(LinearCombination) -> LinearCombination, 120 | LC: FnOnce(LinearCombination) -> LinearCombination 121 | { 122 | self.cs.enforce(annotation, a, b, c) 123 | } 124 | 125 | fn push_namespace(&mut self, name_fn: N) 126 | where NR: Into, N: FnOnce() -> NR 127 | { 128 | self.cs.get_root().push_namespace(name_fn) 129 | } 130 | 131 | fn pop_namespace(&mut self) 132 | { 133 | self.cs.get_root().pop_namespace() 134 | } 135 | 136 | fn get_root(&mut self) -> &mut Self::Root 137 | { 138 | self 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /pairing/benches/bn256/ec.rs: -------------------------------------------------------------------------------- 1 | mod g1 { 2 | use rand::{Rand, SeedableRng, XorShiftRng}; 3 | 4 | use pairing::bn256::*; 5 | use pairing::CurveProjective; 6 | 7 | #[bench] 8 | fn bench_g1_mul_assign(b: &mut ::test::Bencher) { 9 | const SAMPLES: usize = 1000; 10 | 11 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 12 | 13 | let v: Vec<(G1, Fr)> = (0..SAMPLES) 14 | .map(|_| (G1::rand(&mut rng), Fr::rand(&mut rng))) 15 | .collect(); 16 | 17 | let mut count = 0; 18 | b.iter(|| { 19 | let mut tmp = v[count].0; 20 | tmp.mul_assign(v[count].1); 21 | count = (count + 1) % SAMPLES; 22 | tmp 23 | }); 24 | } 25 | 26 | #[bench] 27 | fn bench_g1_add_assign(b: &mut ::test::Bencher) { 28 | const SAMPLES: usize = 1000; 29 | 30 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 31 | 32 | let v: Vec<(G1, G1)> = (0..SAMPLES) 33 | .map(|_| (G1::rand(&mut rng), G1::rand(&mut rng))) 34 | .collect(); 35 | 36 | let mut count = 0; 37 | b.iter(|| { 38 | let mut tmp = v[count].0; 39 | tmp.add_assign(&v[count].1); 40 | count = (count + 1) % SAMPLES; 41 | tmp 42 | }); 43 | } 44 | 45 | #[bench] 46 | fn bench_g1_add_assign_mixed(b: &mut ::test::Bencher) { 47 | const SAMPLES: usize = 1000; 48 | 49 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 50 | 51 | let v: Vec<(G1, G1Affine)> = (0..SAMPLES) 52 | .map(|_| (G1::rand(&mut rng), G1::rand(&mut rng).into())) 53 | .collect(); 54 | 55 | let mut count = 0; 56 | b.iter(|| { 57 | let mut tmp = v[count].0; 58 | tmp.add_assign_mixed(&v[count].1); 59 | count = (count + 1) % SAMPLES; 60 | tmp 61 | }); 62 | } 63 | } 64 | 65 | mod g2 { 66 | use rand::{Rand, SeedableRng, XorShiftRng}; 67 | 68 | use pairing::bls12_381::*; 69 | use pairing::CurveProjective; 70 | 71 | #[bench] 72 | fn bench_g2_mul_assign(b: &mut ::test::Bencher) { 73 | const SAMPLES: usize = 1000; 74 | 75 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 76 | 77 | let v: Vec<(G2, Fr)> = (0..SAMPLES) 78 | .map(|_| (G2::rand(&mut rng), Fr::rand(&mut rng))) 79 | .collect(); 80 | 81 | let mut count = 0; 82 | b.iter(|| { 83 | let mut tmp = v[count].0; 84 | tmp.mul_assign(v[count].1); 85 | count = (count + 1) % SAMPLES; 86 | tmp 87 | }); 88 | } 89 | 90 | #[bench] 91 | fn bench_g2_add_assign(b: &mut ::test::Bencher) { 92 | const SAMPLES: usize = 1000; 93 | 94 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 95 | 96 | let v: Vec<(G2, G2)> = (0..SAMPLES) 97 | .map(|_| (G2::rand(&mut rng), G2::rand(&mut rng))) 98 | .collect(); 99 | 100 | let mut count = 0; 101 | b.iter(|| { 102 | let mut tmp = v[count].0; 103 | tmp.add_assign(&v[count].1); 104 | count = (count + 1) % SAMPLES; 105 | tmp 106 | }); 107 | } 108 | 109 | #[bench] 110 | fn bench_g2_add_assign_mixed(b: &mut ::test::Bencher) { 111 | const SAMPLES: usize = 1000; 112 | 113 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 114 | 115 | let v: Vec<(G2, G2Affine)> = (0..SAMPLES) 116 | .map(|_| (G2::rand(&mut rng), G2::rand(&mut rng).into())) 117 | .collect(); 118 | 119 | let mut count = 0; 120 | b.iter(|| { 121 | let mut tmp = v[count].0; 122 | tmp.add_assign_mixed(&v[count].1); 123 | count = (count + 1) % SAMPLES; 124 | tmp 125 | }); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /pairing/benches/bls12_381/ec.rs: -------------------------------------------------------------------------------- 1 | mod g1 { 2 | use rand::{Rand, SeedableRng, XorShiftRng}; 3 | 4 | use pairing::bls12_381::*; 5 | use pairing::CurveProjective; 6 | 7 | #[bench] 8 | fn bench_g1_mul_assign(b: &mut ::test::Bencher) { 9 | const SAMPLES: usize = 1000; 10 | 11 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 12 | 13 | let v: Vec<(G1, Fr)> = (0..SAMPLES) 14 | .map(|_| (G1::rand(&mut rng), Fr::rand(&mut rng))) 15 | .collect(); 16 | 17 | let mut count = 0; 18 | b.iter(|| { 19 | let mut tmp = v[count].0; 20 | tmp.mul_assign(v[count].1); 21 | count = (count + 1) % SAMPLES; 22 | tmp 23 | }); 24 | } 25 | 26 | #[bench] 27 | fn bench_g1_add_assign(b: &mut ::test::Bencher) { 28 | const SAMPLES: usize = 1000; 29 | 30 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 31 | 32 | let v: Vec<(G1, G1)> = (0..SAMPLES) 33 | .map(|_| (G1::rand(&mut rng), G1::rand(&mut rng))) 34 | .collect(); 35 | 36 | let mut count = 0; 37 | b.iter(|| { 38 | let mut tmp = v[count].0; 39 | tmp.add_assign(&v[count].1); 40 | count = (count + 1) % SAMPLES; 41 | tmp 42 | }); 43 | } 44 | 45 | #[bench] 46 | fn bench_g1_add_assign_mixed(b: &mut ::test::Bencher) { 47 | const SAMPLES: usize = 1000; 48 | 49 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 50 | 51 | let v: Vec<(G1, G1Affine)> = (0..SAMPLES) 52 | .map(|_| (G1::rand(&mut rng), G1::rand(&mut rng).into())) 53 | .collect(); 54 | 55 | let mut count = 0; 56 | b.iter(|| { 57 | let mut tmp = v[count].0; 58 | tmp.add_assign_mixed(&v[count].1); 59 | count = (count + 1) % SAMPLES; 60 | tmp 61 | }); 62 | } 63 | } 64 | 65 | mod g2 { 66 | use rand::{Rand, SeedableRng, XorShiftRng}; 67 | 68 | use pairing::bls12_381::*; 69 | use pairing::CurveProjective; 70 | 71 | #[bench] 72 | fn bench_g2_mul_assign(b: &mut ::test::Bencher) { 73 | const SAMPLES: usize = 1000; 74 | 75 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 76 | 77 | let v: Vec<(G2, Fr)> = (0..SAMPLES) 78 | .map(|_| (G2::rand(&mut rng), Fr::rand(&mut rng))) 79 | .collect(); 80 | 81 | let mut count = 0; 82 | b.iter(|| { 83 | let mut tmp = v[count].0; 84 | tmp.mul_assign(v[count].1); 85 | count = (count + 1) % SAMPLES; 86 | tmp 87 | }); 88 | } 89 | 90 | #[bench] 91 | fn bench_g2_add_assign(b: &mut ::test::Bencher) { 92 | const SAMPLES: usize = 1000; 93 | 94 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 95 | 96 | let v: Vec<(G2, G2)> = (0..SAMPLES) 97 | .map(|_| (G2::rand(&mut rng), G2::rand(&mut rng))) 98 | .collect(); 99 | 100 | let mut count = 0; 101 | b.iter(|| { 102 | let mut tmp = v[count].0; 103 | tmp.add_assign(&v[count].1); 104 | count = (count + 1) % SAMPLES; 105 | tmp 106 | }); 107 | } 108 | 109 | #[bench] 110 | fn bench_g2_add_assign_mixed(b: &mut ::test::Bencher) { 111 | const SAMPLES: usize = 1000; 112 | 113 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 114 | 115 | let v: Vec<(G2, G2Affine)> = (0..SAMPLES) 116 | .map(|_| (G2::rand(&mut rng), G2::rand(&mut rng).into())) 117 | .collect(); 118 | 119 | let mut count = 0; 120 | b.iter(|| { 121 | let mut tmp = v[count].0; 122 | tmp.add_assign_mixed(&v[count].1); 123 | count = (count + 1) % SAMPLES; 124 | tmp 125 | }); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /pairing/src/tests/engine.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rand, SeedableRng, XorShiftRng}; 2 | 3 | use {CurveAffine, CurveProjective, Engine, Field, PrimeField}; 4 | 5 | pub fn engine_tests() { 6 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 7 | 8 | for _ in 0..10 { 9 | let a = E::G1::rand(&mut rng).into_affine(); 10 | let b = E::G2::rand(&mut rng).into_affine(); 11 | 12 | assert!(a.pairing_with(&b) == b.pairing_with(&a)); 13 | assert!(a.pairing_with(&b) == E::pairing(a, b)); 14 | } 15 | 16 | for _ in 0..1000 { 17 | let z1 = E::G1Affine::zero().prepare(); 18 | let z2 = E::G2Affine::zero().prepare(); 19 | 20 | let a = E::G1::rand(&mut rng).into_affine().prepare(); 21 | let b = E::G2::rand(&mut rng).into_affine().prepare(); 22 | let c = E::G1::rand(&mut rng).into_affine().prepare(); 23 | let d = E::G2::rand(&mut rng).into_affine().prepare(); 24 | 25 | assert_eq!( 26 | E::Fqk::one(), 27 | E::final_exponentiation(&E::miller_loop(&[(&z1, &b)])).unwrap() 28 | ); 29 | 30 | assert_eq!( 31 | E::Fqk::one(), 32 | E::final_exponentiation(&E::miller_loop(&[(&a, &z2)])).unwrap() 33 | ); 34 | 35 | assert_eq!( 36 | E::final_exponentiation(&E::miller_loop(&[(&z1, &b), (&c, &d)])).unwrap(), 37 | E::final_exponentiation(&E::miller_loop(&[(&a, &z2), (&c, &d)])).unwrap() 38 | ); 39 | 40 | assert_eq!( 41 | E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&z1, &d)])).unwrap(), 42 | E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&c, &z2)])).unwrap() 43 | ); 44 | } 45 | 46 | random_bilinearity_tests::(); 47 | random_miller_loop_tests::(); 48 | } 49 | 50 | fn random_miller_loop_tests() { 51 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 52 | 53 | // Exercise the miller loop for a reduced pairing 54 | for _ in 0..1000 { 55 | let a = E::G1::rand(&mut rng); 56 | let b = E::G2::rand(&mut rng); 57 | 58 | let p2 = E::pairing(a, b); 59 | 60 | let a = a.into_affine().prepare(); 61 | let b = b.into_affine().prepare(); 62 | 63 | let p1 = E::final_exponentiation(&E::miller_loop(&[(&a, &b)])).unwrap(); 64 | 65 | assert_eq!(p1, p2); 66 | } 67 | 68 | // Exercise a double miller loop 69 | for _ in 0..1000 { 70 | let a = E::G1::rand(&mut rng); 71 | let b = E::G2::rand(&mut rng); 72 | let c = E::G1::rand(&mut rng); 73 | let d = E::G2::rand(&mut rng); 74 | 75 | let ab = E::pairing(a, b); 76 | let cd = E::pairing(c, d); 77 | 78 | let mut abcd = ab; 79 | abcd.mul_assign(&cd); 80 | 81 | let a = a.into_affine().prepare(); 82 | let b = b.into_affine().prepare(); 83 | let c = c.into_affine().prepare(); 84 | let d = d.into_affine().prepare(); 85 | 86 | let abcd_with_double_loop = 87 | E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&c, &d)])).unwrap(); 88 | 89 | assert_eq!(abcd, abcd_with_double_loop); 90 | } 91 | } 92 | 93 | fn random_bilinearity_tests() { 94 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 95 | 96 | for _ in 0..1000 { 97 | let a = E::G1::rand(&mut rng); 98 | let b = E::G2::rand(&mut rng); 99 | 100 | let c = E::Fr::rand(&mut rng); 101 | let d = E::Fr::rand(&mut rng); 102 | 103 | let mut ac = a; 104 | ac.mul_assign(c); 105 | 106 | let mut ad = a; 107 | ad.mul_assign(d); 108 | 109 | let mut bc = b; 110 | bc.mul_assign(c); 111 | 112 | let mut bd = b; 113 | bd.mul_assign(d); 114 | 115 | let acbd = E::pairing(ac, bd); 116 | let adbc = E::pairing(ad, bc); 117 | 118 | let mut cd = c; 119 | cd.mul_assign(&d); 120 | 121 | let abcd = E::pairing(a, b).pow(cd.into_repr()); 122 | 123 | assert_eq!(acbd, adbc); 124 | assert_eq!(acbd, abcd); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/zk_util.rs: -------------------------------------------------------------------------------- 1 | use rand::{ChaChaRng, SeedableRng}; 2 | use bellman::groth16::{Proof, Parameters, verify_proof, create_random_proof, prepare_verifying_key, generate_random_parameters}; 3 | use num_bigint::BigInt; 4 | use num_traits::Num; 5 | use std::error::Error; 6 | 7 | 8 | use ff::{PrimeField, Field}; 9 | use sapling_crypto::{ 10 | babyjubjub::{ 11 | JubjubBn256, 12 | }, 13 | }; 14 | 15 | use pairing::{bn256::{Bn256, Fr}}; 16 | use MerkleTreeCircuit; 17 | 18 | #[derive(Serialize)] 19 | pub struct KGGenerate { 20 | pub params: String 21 | } 22 | 23 | #[derive(Serialize)] 24 | pub struct KGProof { 25 | pub proof: String, 26 | // pub nullifier: String, 27 | // pub secret: String, 28 | // pub leaf: String, 29 | // pub path: Vec 30 | } 31 | 32 | #[derive(Serialize)] 33 | pub struct KGVerify { 34 | pub result: bool 35 | } 36 | 37 | pub fn generate(seed_slice: &[u32], depth: u32) -> Result> { 38 | let rng = &mut ChaChaRng::from_seed(seed_slice); 39 | let j_params = &JubjubBn256::new(); 40 | let mut proof_elts = vec![]; 41 | 42 | for _ in 0..depth { 43 | proof_elts.push(Some(( 44 | true, 45 | pairing::bn256::Fr::zero(), 46 | ))); 47 | } 48 | let params = generate_random_parameters::( 49 | MerkleTreeCircuit { 50 | params: j_params, 51 | nullifier: None, 52 | secret: None, 53 | proof: proof_elts, 54 | }, 55 | rng, 56 | )?; 57 | 58 | let mut v = vec![]; 59 | 60 | params.write(&mut v)?; 61 | 62 | Ok(KGGenerate { 63 | params: hex::encode(&v[..]) 64 | }) 65 | } 66 | 67 | pub fn prove( 68 | seed_slice: &[u32], 69 | params: &str, 70 | nullifier_hex: &str, 71 | secret_hex: &str, 72 | mut proof_path_hex: &str, 73 | mut proof_path_sides: &str, 74 | ) -> Result> { 75 | let de_params = Parameters::::read(&hex::decode(params)?[..], true)?; 76 | let j_params = &JubjubBn256::new(); 77 | let rng = &mut ChaChaRng::from_seed(seed_slice); 78 | // Nullifier 79 | let nullifier_big = BigInt::from_str_radix(nullifier_hex, 16)?; 80 | let nullifier_raw = &nullifier_big.to_str_radix(10); 81 | let nullifier = Fr::from_str(nullifier_raw).ok_or("couldn't parse Fr")?; 82 | // Secret preimage data 83 | let secret_big = BigInt::from_str_radix(secret_hex, 16)?; 84 | let secret_raw = &secret_big.to_str_radix(10); 85 | let secret = Fr::from_str(secret_raw).ok_or("couldn't parse Fr")?; 86 | // Proof path 87 | let mut proof_p_big: Vec> = vec![]; 88 | let proof_len = proof_path_sides.len(); 89 | for _ in 0..proof_len { 90 | let (neighbor_i, pfh) = proof_path_hex.split_at(64); 91 | let (side_i, pfs) = proof_path_sides.split_at(1); 92 | proof_path_hex = pfh; 93 | proof_path_sides = pfs; 94 | let mut side_bool = false; 95 | if side_i == "1" { side_bool = true } 96 | 97 | let p_big = BigInt::from_str_radix(neighbor_i, 16)?; 98 | let p_raw = &p_big.to_str_radix(10); 99 | let p = Fr::from_str(p_raw).ok_or("couldn't parse Fr")?; 100 | proof_p_big.push(Some(( 101 | side_bool, 102 | p, 103 | ))); 104 | } 105 | 106 | let proof = create_random_proof( 107 | MerkleTreeCircuit { 108 | params: j_params, 109 | nullifier: Some(nullifier), 110 | secret: Some(secret), 111 | proof: proof_p_big, 112 | }, 113 | &de_params, 114 | rng 115 | ).unwrap(); 116 | println!("hello"); 117 | let mut v = vec![]; 118 | proof.write(&mut v)?; 119 | Ok(KGProof { 120 | proof: hex::encode(&v[..]), 121 | }) 122 | } 123 | 124 | pub fn verify(params: &str, proof: &str, nullifier_hex: &str, root_hex: &str) -> Result> { 125 | let de_params = Parameters::read(&hex::decode(params)?[..], true)?; 126 | let pvk = prepare_verifying_key::(&de_params.vk); 127 | // Nullifier 128 | let nullifier_big = BigInt::from_str_radix(nullifier_hex, 16)?; 129 | let nullifier_raw = &nullifier_big.to_str_radix(10); 130 | let nullifier = Fr::from_str(nullifier_raw).ok_or("couldn't parse Fr")?; 131 | // Root hash 132 | let root_big = BigInt::from_str_radix(root_hex, 16)?; 133 | let root_raw = &root_big.to_str_radix(10); 134 | let root = Fr::from_str(root_raw).ok_or("couldn't parse Fr")?; 135 | let result = verify_proof( 136 | &pvk, 137 | &Proof::read(&hex::decode(proof)?[..])?, 138 | &[ 139 | nullifier, 140 | root 141 | ])?; 142 | 143 | Ok(KGVerify{ 144 | result: result 145 | }) 146 | } 147 | -------------------------------------------------------------------------------- /bellman/src/multicore.rs: -------------------------------------------------------------------------------- 1 | //! This is an interface for dealing with the kinds of 2 | //! parallel computations involved in bellman. It's 3 | //! currently just an optional thin wrapper around CpuPool and 4 | //! crossbeam but may be extended in the future to 5 | //! allow for various parallelism strategies. 6 | //! Compile without the "multithread" feature for targets that 7 | //! don't support parallel computation. 8 | 9 | use futures::{Future, IntoFuture, Poll}; 10 | 11 | #[cfg(feature = "multithread")] 12 | use num_cpus; 13 | #[cfg(feature = "multithread")] 14 | use futures_cpupool::{CpuPool, CpuFuture}; 15 | #[cfg(feature = "multithread")] 16 | use crossbeam::{self, Scope}; 17 | 18 | #[cfg(not(feature = "multithread"))] 19 | use futures::future::{result, FutureResult}; 20 | 21 | #[cfg(feature = "multithread")] 22 | #[derive(Clone)] 23 | pub struct Worker { 24 | cpus: usize, 25 | pool: CpuPool 26 | } 27 | 28 | #[cfg(feature = "multithread")] 29 | impl Worker { 30 | // We don't expose this outside the library so that 31 | // all `Worker` instances have the same number of 32 | // CPUs configured. 33 | pub(crate) fn new_with_cpus(cpus: usize) -> Worker { 34 | 35 | Worker { 36 | cpus: cpus, 37 | pool: CpuPool::new(cpus) 38 | } 39 | } 40 | 41 | pub fn new() -> Worker { 42 | Self::new_with_cpus(num_cpus::get()) 43 | } 44 | 45 | pub fn log_num_cpus(&self) -> u32 { 46 | log2_floor(self.cpus) 47 | } 48 | 49 | pub fn compute( 50 | &self, f: F 51 | ) -> WorkerFuture 52 | where F: FnOnce() -> R + Send + 'static, 53 | R: IntoFuture + 'static, 54 | R::Future: Send + 'static, 55 | R::Item: Send + 'static, 56 | R::Error: Send + 'static 57 | { 58 | WorkerFuture { 59 | future: self.pool.spawn_fn(f) 60 | } 61 | } 62 | 63 | pub fn scope<'a, F, R>( 64 | &self, 65 | elements: usize, 66 | f: F 67 | ) -> R 68 | where F: FnOnce(&Scope<'a>, usize) -> R 69 | { 70 | let chunk_size = if elements < self.cpus { 71 | 1 72 | } else { 73 | elements / self.cpus 74 | }; 75 | 76 | crossbeam::scope(|scope| { 77 | f(scope, chunk_size) 78 | }) 79 | } 80 | } 81 | 82 | #[cfg(feature = "multithread")] 83 | pub struct WorkerFuture { 84 | future: CpuFuture 85 | } 86 | 87 | //Dummy worker for single-threaded mode 88 | #[cfg(not(feature = "multithread"))] 89 | #[derive(Clone)] 90 | pub struct Worker {} 91 | 92 | #[cfg(not(feature = "multithread"))] 93 | impl Worker { 94 | 95 | pub fn new() -> Worker { Worker {} } 96 | 97 | pub fn log_num_cpus(&self) -> u32 { 98 | log2_floor(1) 99 | } 100 | 101 | pub fn compute( 102 | &self, f: F 103 | ) -> WorkerFuture 104 | where F: FnOnce() -> R, 105 | R: IntoFuture + 'static, 106 | R::Future: Send + 'static, 107 | R::Item: Send + 'static, 108 | R::Error: Send + 'static 109 | { 110 | let future = f().into_future(); 111 | 112 | WorkerFuture { 113 | future: result(future.wait()) 114 | } 115 | } 116 | 117 | pub fn scope( 118 | &self, 119 | _elements: usize, 120 | f: F 121 | ) -> R 122 | where F: FnOnce(&Scope, usize) -> R 123 | { 124 | let scope = Scope {}; 125 | f(&scope, 1) 126 | } 127 | } 128 | 129 | // 130 | #[cfg(not(feature = "multithread"))] 131 | pub struct Scope { 132 | } 133 | 134 | #[cfg(not(feature = "multithread"))] 135 | impl Scope { 136 | pub fn spawn(&self, f: F) -> T where 137 | F: FnOnce() -> T + Send , T: Send 138 | { 139 | f() 140 | } 141 | 142 | } 143 | 144 | #[cfg(not(feature = "multithread"))] 145 | pub struct WorkerFuture { 146 | future: FutureResult 147 | } 148 | 149 | impl Future for WorkerFuture { 150 | type Item = T; 151 | type Error = E; 152 | 153 | fn poll(&mut self) -> Poll 154 | { 155 | self.future.poll() 156 | } 157 | } 158 | 159 | fn log2_floor(num: usize) -> u32 { 160 | assert!(num > 0); 161 | 162 | let mut pow = 0; 163 | 164 | while (1 << (pow+1)) <= num { 165 | pow += 1; 166 | } 167 | 168 | pow 169 | } 170 | 171 | #[test] 172 | fn test_log2_floor() { 173 | assert_eq!(log2_floor(1), 0); 174 | assert_eq!(log2_floor(2), 1); 175 | assert_eq!(log2_floor(3), 1); 176 | assert_eq!(log2_floor(4), 2); 177 | assert_eq!(log2_floor(5), 2); 178 | assert_eq!(log2_floor(6), 2); 179 | assert_eq!(log2_floor(7), 2); 180 | assert_eq!(log2_floor(8), 3); 181 | } -------------------------------------------------------------------------------- /pairing/src/bls12_381/fq12.rs: -------------------------------------------------------------------------------- 1 | use super::fq::FROBENIUS_COEFF_FQ12_C1; 2 | use super::fq2::Fq2; 3 | use super::fq6::Fq6; 4 | use ff::Field; 5 | use rand::{Rand, Rng}; 6 | 7 | /// An element of Fq12, represented by c0 + c1 * w. 8 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 9 | pub struct Fq12 { 10 | pub c0: Fq6, 11 | pub c1: Fq6, 12 | } 13 | 14 | impl ::std::fmt::Display for Fq12 { 15 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 16 | write!(f, "Fq12({} + {} * w)", self.c0, self.c1) 17 | } 18 | } 19 | 20 | impl Rand for Fq12 { 21 | fn rand(rng: &mut R) -> Self { 22 | Fq12 { 23 | c0: rng.gen(), 24 | c1: rng.gen(), 25 | } 26 | } 27 | } 28 | 29 | impl Fq12 { 30 | pub fn conjugate(&mut self) { 31 | self.c1.negate(); 32 | } 33 | 34 | pub fn mul_by_014(&mut self, c0: &Fq2, c1: &Fq2, c4: &Fq2) { 35 | let mut aa = self.c0; 36 | aa.mul_by_01(c0, c1); 37 | let mut bb = self.c1; 38 | bb.mul_by_1(c4); 39 | let mut o = *c1; 40 | o.add_assign(c4); 41 | self.c1.add_assign(&self.c0); 42 | self.c1.mul_by_01(c0, &o); 43 | self.c1.sub_assign(&aa); 44 | self.c1.sub_assign(&bb); 45 | self.c0 = bb; 46 | self.c0.mul_by_nonresidue(); 47 | self.c0.add_assign(&aa); 48 | } 49 | } 50 | 51 | impl Field for Fq12 { 52 | fn zero() -> Self { 53 | Fq12 { 54 | c0: Fq6::zero(), 55 | c1: Fq6::zero(), 56 | } 57 | } 58 | 59 | fn one() -> Self { 60 | Fq12 { 61 | c0: Fq6::one(), 62 | c1: Fq6::zero(), 63 | } 64 | } 65 | 66 | fn is_zero(&self) -> bool { 67 | self.c0.is_zero() && self.c1.is_zero() 68 | } 69 | 70 | fn double(&mut self) { 71 | self.c0.double(); 72 | self.c1.double(); 73 | } 74 | 75 | fn negate(&mut self) { 76 | self.c0.negate(); 77 | self.c1.negate(); 78 | } 79 | 80 | fn add_assign(&mut self, other: &Self) { 81 | self.c0.add_assign(&other.c0); 82 | self.c1.add_assign(&other.c1); 83 | } 84 | 85 | fn sub_assign(&mut self, other: &Self) { 86 | self.c0.sub_assign(&other.c0); 87 | self.c1.sub_assign(&other.c1); 88 | } 89 | 90 | fn frobenius_map(&mut self, power: usize) { 91 | self.c0.frobenius_map(power); 92 | self.c1.frobenius_map(power); 93 | 94 | self.c1.c0.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); 95 | self.c1.c1.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); 96 | self.c1.c2.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); 97 | } 98 | 99 | fn square(&mut self) { 100 | let mut ab = self.c0; 101 | ab.mul_assign(&self.c1); 102 | let mut c0c1 = self.c0; 103 | c0c1.add_assign(&self.c1); 104 | let mut c0 = self.c1; 105 | c0.mul_by_nonresidue(); 106 | c0.add_assign(&self.c0); 107 | c0.mul_assign(&c0c1); 108 | c0.sub_assign(&ab); 109 | self.c1 = ab; 110 | self.c1.add_assign(&ab); 111 | ab.mul_by_nonresidue(); 112 | c0.sub_assign(&ab); 113 | self.c0 = c0; 114 | } 115 | 116 | fn mul_assign(&mut self, other: &Self) { 117 | let mut aa = self.c0; 118 | aa.mul_assign(&other.c0); 119 | let mut bb = self.c1; 120 | bb.mul_assign(&other.c1); 121 | let mut o = other.c0; 122 | o.add_assign(&other.c1); 123 | self.c1.add_assign(&self.c0); 124 | self.c1.mul_assign(&o); 125 | self.c1.sub_assign(&aa); 126 | self.c1.sub_assign(&bb); 127 | self.c0 = bb; 128 | self.c0.mul_by_nonresidue(); 129 | self.c0.add_assign(&aa); 130 | } 131 | 132 | fn inverse(&self) -> Option { 133 | let mut c0s = self.c0; 134 | c0s.square(); 135 | let mut c1s = self.c1; 136 | c1s.square(); 137 | c1s.mul_by_nonresidue(); 138 | c0s.sub_assign(&c1s); 139 | 140 | c0s.inverse().map(|t| { 141 | let mut tmp = Fq12 { c0: t, c1: t }; 142 | tmp.c0.mul_assign(&self.c0); 143 | tmp.c1.mul_assign(&self.c1); 144 | tmp.c1.negate(); 145 | 146 | tmp 147 | }) 148 | } 149 | } 150 | 151 | #[cfg(test)] 152 | use rand::{SeedableRng, XorShiftRng}; 153 | 154 | #[test] 155 | fn test_fq12_mul_by_014() { 156 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 157 | 158 | for _ in 0..1000 { 159 | let c0 = Fq2::rand(&mut rng); 160 | let c1 = Fq2::rand(&mut rng); 161 | let c5 = Fq2::rand(&mut rng); 162 | let mut a = Fq12::rand(&mut rng); 163 | let mut b = a; 164 | 165 | a.mul_by_014(&c0, &c1, &c5); 166 | b.mul_assign(&Fq12 { 167 | c0: Fq6 { 168 | c0: c0, 169 | c1: c1, 170 | c2: Fq2::zero(), 171 | }, 172 | c1: Fq6 { 173 | c0: Fq2::zero(), 174 | c1: c5, 175 | c2: Fq2::zero(), 176 | }, 177 | }); 178 | 179 | assert_eq!(a, b); 180 | } 181 | } 182 | 183 | #[test] 184 | fn fq12_field_tests() { 185 | use ff::PrimeField; 186 | 187 | ::tests::field::random_field_tests::(); 188 | ::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); 189 | } 190 | -------------------------------------------------------------------------------- /sapling-crypto/src/pedersen_hash.rs: -------------------------------------------------------------------------------- 1 | use jubjub::*; 2 | use ff::{Field, PrimeField, PrimeFieldRepr}; 3 | 4 | #[derive(Copy, Clone)] 5 | pub enum Personalization { 6 | NoteCommitment, 7 | MerkleTree(usize) 8 | } 9 | 10 | impl Personalization { 11 | pub fn get_bits(&self) -> Vec { 12 | match *self { 13 | Personalization::NoteCommitment => 14 | vec![true, true, true, true, true, true], 15 | Personalization::MerkleTree(num) => { 16 | assert!(num < 63); 17 | 18 | (0..6).map(|i| (num >> i) & 1 == 1).collect() 19 | } 20 | } 21 | } 22 | } 23 | 24 | pub fn pedersen_hash( 25 | personalization: Personalization, 26 | bits: I, 27 | params: &E::Params 28 | ) -> edwards::Point 29 | where I: IntoIterator, 30 | E: JubjubEngine 31 | { 32 | let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter()); 33 | 34 | let mut result = edwards::Point::zero(); 35 | let mut generators = params.pedersen_hash_exp_table().iter(); 36 | 37 | loop { 38 | let mut acc = E::Fs::zero(); 39 | let mut cur = E::Fs::one(); 40 | let mut chunks_remaining = params.pedersen_hash_chunks_per_generator(); 41 | let mut encountered_bits = false; 42 | 43 | // Grab three bits from the input 44 | while let Some(a) = bits.next() { 45 | encountered_bits = true; 46 | 47 | let b = bits.next().unwrap_or(false); 48 | let c = bits.next().unwrap_or(false); 49 | 50 | // Start computing this portion of the scalar 51 | let mut tmp = cur; 52 | if a { 53 | tmp.add_assign(&cur); 54 | } 55 | cur.double(); // 2^1 * cur 56 | if b { 57 | tmp.add_assign(&cur); 58 | } 59 | 60 | // conditionally negate 61 | if c { 62 | tmp.negate(); 63 | } 64 | 65 | acc.add_assign(&tmp); 66 | 67 | chunks_remaining -= 1; 68 | 69 | if chunks_remaining == 0 { 70 | break; 71 | } else { 72 | cur.double(); // 2^2 * cur 73 | cur.double(); // 2^3 * cur 74 | cur.double(); // 2^4 * cur 75 | } 76 | } 77 | 78 | if !encountered_bits { 79 | break; 80 | } 81 | 82 | let mut table: &[Vec>] = &generators.next().expect("we don't have enough generators"); 83 | let window = params.pedersen_hash_exp_window_size(); 84 | let window_mask = (1 << window) - 1; 85 | 86 | let mut acc = acc.into_repr(); 87 | 88 | let mut tmp = edwards::Point::zero(); 89 | 90 | while !acc.is_zero() { 91 | let i = (acc.as_ref()[0] & window_mask) as usize; 92 | 93 | tmp = tmp.add(&table[0][i], params); 94 | 95 | acc.shr(window); 96 | table = &table[1..]; 97 | } 98 | 99 | result = result.add(&tmp, params); 100 | } 101 | 102 | result 103 | } 104 | 105 | use alt_babyjubjub::{AltJubjubBn256}; 106 | 107 | pub fn baby_pedersen_hash( 108 | personalization: Personalization, 109 | bits: I, 110 | params: &E::Params 111 | ) -> edwards::Point 112 | where I: IntoIterator, 113 | E: JubjubEngine 114 | { 115 | let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter()); 116 | 117 | let mut result = edwards::Point::zero(); 118 | let mut generators = params.pedersen_hash_exp_table().iter(); 119 | 120 | loop { 121 | let mut acc = E::Fs::zero(); 122 | let mut cur = E::Fs::one(); 123 | let mut chunks_remaining = params.pedersen_hash_chunks_per_generator(); 124 | let mut encountered_bits = false; 125 | 126 | // Grab three bits from the input 127 | while let Some(a) = bits.next() { 128 | encountered_bits = true; 129 | 130 | let b = bits.next().unwrap_or(false); 131 | let c = bits.next().unwrap_or(false); 132 | 133 | // Start computing this portion of the scalar 134 | let mut tmp = cur; 135 | if a { 136 | tmp.add_assign(&cur); 137 | } 138 | cur.double(); // 2^1 * cur 139 | if b { 140 | tmp.add_assign(&cur); 141 | } 142 | 143 | // conditionally negate 144 | if c { 145 | tmp.negate(); 146 | } 147 | 148 | acc.add_assign(&tmp); 149 | 150 | chunks_remaining -= 1; 151 | 152 | if chunks_remaining == 0 { 153 | break; 154 | } else { 155 | cur.double(); // 2^2 * cur 156 | cur.double(); // 2^3 * cur 157 | cur.double(); // 2^4 * cur 158 | } 159 | } 160 | 161 | if !encountered_bits { 162 | break; 163 | } 164 | 165 | let mut table: &[Vec>] = &generators.next().expect("we don't have enough generators"); 166 | let window = params.pedersen_hash_exp_window_size(); 167 | let window_mask = (1 << window) - 1; 168 | 169 | let mut acc = acc.into_repr(); 170 | 171 | let mut tmp = edwards::Point::zero(); 172 | 173 | while !acc.is_zero() { 174 | let i = (acc.as_ref()[0] & window_mask) as usize; 175 | 176 | tmp = tmp.add(&table[0][i], params); 177 | 178 | acc.shr(window); 179 | table = &table[1..]; 180 | } 181 | 182 | result = result.add(&tmp, params); 183 | } 184 | 185 | result 186 | } 187 | -------------------------------------------------------------------------------- /pairing/src/bls12_381/README.md: -------------------------------------------------------------------------------- 1 | # BLS12-381 2 | 3 | This is an implementation of the BLS12-381 pairing-friendly elliptic curve construction. 4 | 5 | ## BLS12 Parameterization 6 | 7 | BLS12 curves are parameterized by a value *x* such that the base field modulus *q* and subgroup *r* can be computed by: 8 | 9 | * q = (x - 1)2 ((x4 - x2 + 1) / 3) + x 10 | * r = (x4 - x2 + 1) 11 | 12 | Given primes *q* and *r* parameterized as above, we can easily construct an elliptic curve over the prime field F*q* which contains a subgroup of order *r* such that *r* | (*q*12 - 1), giving it an embedding degree of 12. Instantiating its sextic twist over an extension field Fq2 gives rise to an efficient bilinear pairing function between elements of the order *r* subgroups of either curves, into an order *r* multiplicative subgroup of Fq12. 13 | 14 | In zk-SNARK schemes, we require Fr with large 2n roots of unity for performing efficient fast-fourier transforms. As such, guaranteeing that large 2n | (r - 1), or equivalently that *x* has a large 2n factor, gives rise to BLS12 curves suitable for zk-SNARKs. 15 | 16 | Due to recent research, it is estimated by many that *q* should be approximately 384 bits to target 128-bit security. Conveniently, *r* is approximately 256 bits when *q* is approximately 384 bits, making BLS12 curves ideal for 128-bit security. It also makes them ideal for many zk-SNARK applications, as the scalar field can be used for keying material such as embedded curve constructions. 17 | 18 | Many curves match our descriptions, but we require some extra properties for efficiency purposes: 19 | 20 | * *q* should be smaller than 2383, and *r* should be smaller than 2255, so that the most significant bit is unset when using 64-bit or 32-bit limbs. This allows for cheap reductions. 21 | * Fq12 is typically constructed using towers of extension fields. As a byproduct of [research](https://eprint.iacr.org/2011/465.pdf) for BLS curves of embedding degree 24, we can identify subfamilies of BLS12 curves (for our purposes, where x mod 72 = {16, 64}) that produce efficient extension field towers and twisting isomorphisms. 22 | * We desire *x* of small Hamming weight, to increase the performance of the pairing function. 23 | 24 | ## BLS12-381 Instantiation 25 | 26 | The BLS12-381 construction is instantiated by `x = -0xd201000000010000`, which produces the largest `q` and smallest Hamming weight of `x` that meets the above requirements. This produces: 27 | 28 | * q = `0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab` (381 bits) 29 | * r = `0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001` (255 bits) 30 | 31 | Our extension field tower is constructed as follows: 32 | 33 | 1. Fq2 is constructed as Fq(u) / (u2 - β) where β = -1. 34 | 2. Fq6 is constructed as Fq2(v) / (v3 - ξ) where ξ = u + 1 35 | 3. Fq12 is constructed as Fq6(w) / (w2 - γ) where γ = v 36 | 37 | Now, we instantiate the elliptic curve E(Fq) : y2 = x3 + 4, and the elliptic curve E'(Fq2) : y2 = x3 + 4(u + 1). 38 | 39 | The group G1 is the *r* order subgroup of E, which has cofactor (x - 1)2 / 3. The group G2 is the *r* order subgroup of E', which has cofactor (x8 - 4x7 + 5x6 - 4x4 + 6x3 - 4x2 - 4x + 13) / 9. 40 | 41 | ### Generators 42 | 43 | The generators of G1 and G2 are computed by finding the lexicographically smallest valid `x`-coordinate, and its lexicographically smallest `y`-coordinate and scaling it by the cofactor such that the result is not the point at infinity. 44 | 45 | #### G1 46 | 47 | ``` 48 | x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507 49 | y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569 50 | ``` 51 | 52 | #### G2 53 | 54 | ``` 55 | x = 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758*u + 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160 56 | y = 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582*u + 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905 57 | ``` 58 | 59 | ### Serialization 60 | 61 | * Fq elements are encoded in big-endian form. They occupy 48 bytes in this form. 62 | * Fq2 elements are encoded in big-endian form, meaning that the Fq element c0 + c1 * u is represented by the Fq element c1 followed by the Fq element c0. This means Fq2 elements occupy 96 bytes in this form. 63 | * The group G1 uses Fq elements for coordinates. The group G2 uses Fq2 elements for coordinates. 64 | * G1 and G2 elements can be encoded in uncompressed form (the x-coordinate followed by the y-coordinate) or in compressed form (just the x-coordinate). G1 elements occupy 96 bytes in uncompressed form, and 48 bytes in compressed form. G2 elements occupy 192 bytes in uncompressed form, and 96 bytes in compressed form. 65 | 66 | The most-significant three bits of a G1 or G2 encoding should be masked away before the coordinate(s) are interpreted. These bits are used to unambiguously represent the underlying element: 67 | 68 | * The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. 69 | * The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. 70 | * The third-most significant bit is set if (and only if) this point is in compressed form _and_ it is not the point at infinity _and_ its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. 71 | 72 | -------------------------------------------------------------------------------- /pairing/src/wnaf.rs: -------------------------------------------------------------------------------- 1 | use super::{CurveProjective, PrimeField, PrimeFieldRepr}; 2 | 3 | /// Replaces the contents of `table` with a w-NAF window table for the given window size. 4 | pub(crate) fn wnaf_table(table: &mut Vec, mut base: G, window: usize) { 5 | table.truncate(0); 6 | table.reserve(1 << (window - 1)); 7 | 8 | let mut dbl = base; 9 | dbl.double(); 10 | 11 | for _ in 0..(1 << (window - 1)) { 12 | table.push(base); 13 | base.add_assign(&dbl); 14 | } 15 | } 16 | 17 | /// Replaces the contents of `wnaf` with the w-NAF representation of a scalar. 18 | pub(crate) fn wnaf_form(wnaf: &mut Vec, mut c: S, window: usize) { 19 | wnaf.truncate(0); 20 | 21 | while !c.is_zero() { 22 | let mut u; 23 | if c.is_odd() { 24 | u = (c.as_ref()[0] % (1 << (window + 1))) as i64; 25 | 26 | if u > (1 << window) { 27 | u -= 1 << (window + 1); 28 | } 29 | 30 | if u > 0 { 31 | c.sub_noborrow(&S::from(u as u64)); 32 | } else { 33 | c.add_nocarry(&S::from((-u) as u64)); 34 | } 35 | } else { 36 | u = 0; 37 | } 38 | 39 | wnaf.push(u); 40 | 41 | c.div2(); 42 | } 43 | } 44 | 45 | /// Performs w-NAF exponentiation with the provided window table and w-NAF form scalar. 46 | /// 47 | /// This function must be provided a `table` and `wnaf` that were constructed with 48 | /// the same window size; otherwise, it may panic or produce invalid results. 49 | pub(crate) fn wnaf_exp(table: &[G], wnaf: &[i64]) -> G { 50 | let mut result = G::zero(); 51 | 52 | let mut found_one = false; 53 | 54 | for n in wnaf.iter().rev() { 55 | if found_one { 56 | result.double(); 57 | } 58 | 59 | if *n != 0 { 60 | found_one = true; 61 | 62 | if *n > 0 { 63 | result.add_assign(&table[(n / 2) as usize]); 64 | } else { 65 | result.sub_assign(&table[((-n) / 2) as usize]); 66 | } 67 | } 68 | } 69 | 70 | result 71 | } 72 | 73 | /// A "w-ary non-adjacent form" exponentiation context. 74 | #[derive(Debug)] 75 | pub struct Wnaf { 76 | base: B, 77 | scalar: S, 78 | window_size: W, 79 | } 80 | 81 | impl Wnaf<(), Vec, Vec> { 82 | /// Construct a new wNAF context without allocating. 83 | pub fn new() -> Self { 84 | Wnaf { 85 | base: vec![], 86 | scalar: vec![], 87 | window_size: (), 88 | } 89 | } 90 | 91 | /// Given a base and a number of scalars, compute a window table and return a `Wnaf` object that 92 | /// can perform exponentiations with `.scalar(..)`. 93 | pub fn base(&mut self, base: G, num_scalars: usize) -> Wnaf> { 94 | // Compute the appropriate window size based on the number of scalars. 95 | let window_size = G::recommended_wnaf_for_num_scalars(num_scalars); 96 | 97 | // Compute a wNAF table for the provided base and window size. 98 | wnaf_table(&mut self.base, base, window_size); 99 | 100 | // Return a Wnaf object that immutably borrows the computed base storage location, 101 | // but mutably borrows the scalar storage location. 102 | Wnaf { 103 | base: &self.base[..], 104 | scalar: &mut self.scalar, 105 | window_size, 106 | } 107 | } 108 | 109 | /// Given a scalar, compute its wNAF representation and return a `Wnaf` object that can perform 110 | /// exponentiations with `.base(..)`. 111 | pub fn scalar( 112 | &mut self, 113 | scalar: <::Scalar as PrimeField>::Repr, 114 | ) -> Wnaf, &[i64]> { 115 | // Compute the appropriate window size for the scalar. 116 | let window_size = G::recommended_wnaf_for_scalar(scalar); 117 | 118 | // Compute the wNAF form of the scalar. 119 | wnaf_form(&mut self.scalar, scalar, window_size); 120 | 121 | // Return a Wnaf object that mutably borrows the base storage location, but 122 | // immutably borrows the computed wNAF form scalar location. 123 | Wnaf { 124 | base: &mut self.base, 125 | scalar: &self.scalar[..], 126 | window_size, 127 | } 128 | } 129 | } 130 | 131 | impl<'a, G: CurveProjective> Wnaf> { 132 | /// Constructs new space for the scalar representation while borrowing 133 | /// the computed window table, for sending the window table across threads. 134 | pub fn shared(&self) -> Wnaf> { 135 | Wnaf { 136 | base: self.base, 137 | scalar: vec![], 138 | window_size: self.window_size, 139 | } 140 | } 141 | } 142 | 143 | impl<'a, G: CurveProjective> Wnaf, &'a [i64]> { 144 | /// Constructs new space for the window table while borrowing 145 | /// the computed scalar representation, for sending the scalar representation 146 | /// across threads. 147 | pub fn shared(&self) -> Wnaf, &'a [i64]> { 148 | Wnaf { 149 | base: vec![], 150 | scalar: self.scalar, 151 | window_size: self.window_size, 152 | } 153 | } 154 | } 155 | 156 | impl> Wnaf { 157 | /// Performs exponentiation given a base. 158 | pub fn base(&mut self, base: G) -> G 159 | where 160 | B: AsMut>, 161 | { 162 | wnaf_table(self.base.as_mut(), base, self.window_size); 163 | wnaf_exp(self.base.as_mut(), self.scalar.as_ref()) 164 | } 165 | } 166 | 167 | impl>> Wnaf { 168 | /// Performs exponentiation given a scalar. 169 | pub fn scalar( 170 | &mut self, 171 | scalar: <::Scalar as PrimeField>::Repr, 172 | ) -> G 173 | where 174 | B: AsRef<[G]>, 175 | { 176 | wnaf_form(self.scalar.as_mut(), scalar, self.window_size); 177 | wnaf_exp(self.base.as_ref(), self.scalar.as_mut()) 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /pairing/src/bn256/fq12.rs: -------------------------------------------------------------------------------- 1 | use super::fq::FROBENIUS_COEFF_FQ12_C1; 2 | use super::fq2::Fq2; 3 | use super::fq6::Fq6; 4 | use ff::Field; 5 | use rand::{Rand, Rng}; 6 | 7 | /// An element of Fq12, represented by c0 + c1 * w. 8 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 9 | pub struct Fq12 { 10 | pub c0: Fq6, 11 | pub c1: Fq6, 12 | } 13 | 14 | impl ::std::fmt::Display for Fq12 { 15 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 16 | write!(f, "Fq12({} + {} * w)", self.c0, self.c1) 17 | } 18 | } 19 | 20 | impl Rand for Fq12 { 21 | fn rand(rng: &mut R) -> Self { 22 | Fq12 { 23 | c0: rng.gen(), 24 | c1: rng.gen(), 25 | } 26 | } 27 | } 28 | 29 | // BN256 and BLS12 implementations should be the same 30 | // Defined over w^2 - v = 0 31 | 32 | impl Fq12 { 33 | pub fn conjugate(&mut self) { 34 | self.c1.negate(); 35 | } 36 | 37 | pub fn mul_by_014(&mut self, c0: &Fq2, c1: &Fq2, c4: &Fq2) { 38 | let mut aa = self.c0; 39 | aa.mul_by_01(c0, c1); 40 | let mut bb = self.c1; 41 | bb.mul_by_1(c4); 42 | let mut o = *c1; 43 | o.add_assign(c4); 44 | self.c1.add_assign(&self.c0); 45 | self.c1.mul_by_01(c0, &o); 46 | self.c1.sub_assign(&aa); 47 | self.c1.sub_assign(&bb); 48 | self.c0 = bb; 49 | self.c0.mul_by_nonresidue(); 50 | self.c0.add_assign(&aa); 51 | } 52 | // TODO make it hand optimized 53 | // // multiply by (c0, c1, c2) + (c3, c4, c5)*w where only c0, c3 and c4 are non-zero 54 | pub fn mul_by_034(&mut self, c0: &Fq2, c3: &Fq2, c4: &Fq2) { 55 | self.mul_assign(&Fq12 { 56 | c0: Fq6 { 57 | c0: *c0, 58 | c1: Fq2::zero(), 59 | c2: Fq2::zero(), 60 | }, 61 | c1: Fq6 { 62 | c0: *c3, 63 | c1: *c4, 64 | c2: Fq2::zero(), 65 | }, 66 | }); 67 | } 68 | } 69 | 70 | impl Field for Fq12 { 71 | fn zero() -> Self { 72 | Fq12 { 73 | c0: Fq6::zero(), 74 | c1: Fq6::zero(), 75 | } 76 | } 77 | 78 | fn one() -> Self { 79 | Fq12 { 80 | c0: Fq6::one(), 81 | c1: Fq6::zero(), 82 | } 83 | } 84 | 85 | fn is_zero(&self) -> bool { 86 | self.c0.is_zero() && self.c1.is_zero() 87 | } 88 | 89 | fn double(&mut self) { 90 | self.c0.double(); 91 | self.c1.double(); 92 | } 93 | 94 | fn negate(&mut self) { 95 | self.c0.negate(); 96 | self.c1.negate(); 97 | } 98 | 99 | fn add_assign(&mut self, other: &Self) { 100 | self.c0.add_assign(&other.c0); 101 | self.c1.add_assign(&other.c1); 102 | } 103 | 104 | fn sub_assign(&mut self, other: &Self) { 105 | self.c0.sub_assign(&other.c0); 106 | self.c1.sub_assign(&other.c1); 107 | } 108 | 109 | fn frobenius_map(&mut self, power: usize) { 110 | self.c0.frobenius_map(power); 111 | self.c1.frobenius_map(power); 112 | 113 | self.c1.c0.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); 114 | self.c1.c1.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); 115 | self.c1.c2.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); 116 | } 117 | 118 | fn square(&mut self) { 119 | let mut ab = self.c0; 120 | ab.mul_assign(&self.c1); 121 | let mut c0c1 = self.c0; 122 | c0c1.add_assign(&self.c1); 123 | let mut c0 = self.c1; 124 | c0.mul_by_nonresidue(); 125 | c0.add_assign(&self.c0); 126 | c0.mul_assign(&c0c1); 127 | c0.sub_assign(&ab); 128 | self.c1 = ab; 129 | self.c1.add_assign(&ab); 130 | ab.mul_by_nonresidue(); 131 | c0.sub_assign(&ab); 132 | self.c0 = c0; 133 | } 134 | 135 | fn mul_assign(&mut self, other: &Self) { 136 | let mut aa = self.c0; 137 | aa.mul_assign(&other.c0); 138 | let mut bb = self.c1; 139 | bb.mul_assign(&other.c1); 140 | let mut o = other.c0; 141 | o.add_assign(&other.c1); 142 | self.c1.add_assign(&self.c0); 143 | self.c1.mul_assign(&o); 144 | self.c1.sub_assign(&aa); 145 | self.c1.sub_assign(&bb); 146 | self.c0 = bb; 147 | self.c0.mul_by_nonresidue(); 148 | self.c0.add_assign(&aa); 149 | } 150 | 151 | fn inverse(&self) -> Option { 152 | let mut c0s = self.c0; 153 | c0s.square(); 154 | let mut c1s = self.c1; 155 | c1s.square(); 156 | c1s.mul_by_nonresidue(); 157 | c0s.sub_assign(&c1s); 158 | 159 | c0s.inverse().map(|t| { 160 | let mut tmp = Fq12 { c0: t, c1: t }; 161 | tmp.c0.mul_assign(&self.c0); 162 | tmp.c1.mul_assign(&self.c1); 163 | tmp.c1.negate(); 164 | 165 | tmp 166 | }) 167 | } 168 | } 169 | 170 | #[cfg(test)] 171 | use rand::{SeedableRng, XorShiftRng}; 172 | 173 | #[test] 174 | fn test_fq12_mul_by_014() { 175 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 176 | 177 | for _ in 0..1000 { 178 | let c0 = Fq2::rand(&mut rng); 179 | let c1 = Fq2::rand(&mut rng); 180 | let c5 = Fq2::rand(&mut rng); 181 | let mut a = Fq12::rand(&mut rng); 182 | let mut b = a; 183 | 184 | a.mul_by_014(&c0, &c1, &c5); 185 | b.mul_assign(&Fq12 { 186 | c0: Fq6 { 187 | c0: c0, 188 | c1: c1, 189 | c2: Fq2::zero(), 190 | }, 191 | c1: Fq6 { 192 | c0: Fq2::zero(), 193 | c1: c5, 194 | c2: Fq2::zero(), 195 | }, 196 | }); 197 | 198 | assert_eq!(a, b); 199 | } 200 | } 201 | 202 | #[test] 203 | fn test_squaring() { 204 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 205 | 206 | for _ in 0..1000 { 207 | let mut a = Fq12::rand(&mut rng); 208 | let mut b = a; 209 | b.mul_assign(&a); 210 | a.square(); 211 | assert_eq!(a, b); 212 | } 213 | } 214 | 215 | #[test] 216 | fn fq12_field_tests() { 217 | use ff::PrimeField; 218 | 219 | ::tests::field::random_field_tests::(); 220 | ::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); 221 | } 222 | -------------------------------------------------------------------------------- /src/blake_merkle_tree.rs: -------------------------------------------------------------------------------- 1 | use blake2_rfc::blake2s::{blake2s}; 2 | /// Binary Tree where leaves hold a stand-alone value. 3 | #[derive(Clone, Debug, PartialEq, Eq)] 4 | pub enum Tree { 5 | Empty { 6 | hash: [u8; 32], 7 | parent: Option>, 8 | }, 9 | Node { 10 | hash: [u8; 32], 11 | left: Box, 12 | right: Box, 13 | parent: Option>, 14 | }, 15 | } 16 | 17 | impl Tree { 18 | /// Returns a hash from the tree. 19 | pub fn hash(&self) -> &[u8; 32] { 20 | match *self { 21 | Tree::Empty { ref hash, .. } => hash, 22 | Tree::Node { ref hash, .. } => hash, 23 | } 24 | } 25 | } 26 | 27 | #[derive(Debug)] 28 | pub struct MerkleTree { 29 | pub root: Tree, 30 | } 31 | 32 | static ZERO_BYTES: [u8; 32] = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; 33 | pub const SUBSTRATE_BLAKE2_PERSONALIZATION: &'static [u8; 8] 34 | = b"TFWTFWTF"; 35 | 36 | pub fn create_leaf_from_preimage(nullifier: [u8; 32], secret: [u8; 32]) -> Tree { 37 | let mut hash: [u8; 32] = ZERO_BYTES; 38 | let mut preimage: Vec = vec![]; 39 | preimage.extend(nullifier.into_iter()); 40 | preimage.extend(secret.into_iter()); 41 | 42 | hash.copy_from_slice(&blake2s(32, SUBSTRATE_BLAKE2_PERSONALIZATION, &preimage[..]).as_bytes()[0..32]); 43 | return Tree::Empty { 44 | hash: hash, 45 | parent: None, 46 | }; 47 | } 48 | 49 | pub fn create_leaf_list(mut nodes: Vec<[u8; 32]>, depth: usize) -> Vec> { 50 | for _ in 0..((2 << (depth - 1)) - nodes.len()) { 51 | nodes.push(ZERO_BYTES.clone()); 52 | } 53 | 54 | let mut tree_nodes: Vec> = vec![]; 55 | for i in 0..nodes.len() { 56 | tree_nodes.push(Box::new(Tree::Empty { 57 | hash: nodes[i], 58 | parent: None, 59 | })); 60 | } 61 | 62 | return tree_nodes; 63 | } 64 | 65 | #[allow(dead_code)] 66 | pub fn build_merkle_tree_with_proof( 67 | nodes: Vec>, 68 | depth: usize, 69 | top_depth: usize, 70 | target_node: [u8; 32], 71 | curr_list: Vec>, 72 | ) -> (MerkleTree, Vec>) { 73 | let ( mut new_nodes, target_node, new_curr_list ) = hash_nodes_rec(nodes, depth, top_depth, target_node, curr_list); 74 | if new_nodes.len() == 1 { 75 | let root = new_nodes.remove(0); 76 | return ( 77 | MerkleTree { root: *root }, 78 | new_curr_list, 79 | ); 80 | } else { 81 | return build_merkle_tree_with_proof( 82 | new_nodes, 83 | depth - 1, 84 | top_depth, 85 | target_node, 86 | new_curr_list, 87 | ); 88 | } 89 | } 90 | 91 | #[allow(dead_code)] 92 | pub fn hash_nodes_rec( 93 | mut nodes: Vec>, 94 | depth: usize, 95 | top_depth: usize, 96 | mut target_node: [u8; 32], 97 | mut curr_list: Vec> 98 | ) -> (Vec>, [u8; 32], Vec>) { 99 | if nodes.len() == 2 { 100 | let left = nodes.remove(0); 101 | let right = nodes.remove(0); 102 | let temp_bool = target_node == *left.hash() || target_node == *right.hash(); 103 | let mut val = vec![]; 104 | if target_node == *left.hash() { 105 | val.push(Some((true, *right.hash()))); 106 | } 107 | 108 | if target_node == *right.hash() { 109 | val.push(Some((false, *left.hash()))); 110 | } 111 | 112 | let cur = hash_leaf_pair(top_depth - depth, *left, *right); 113 | if temp_bool { 114 | target_node = *cur.hash(); 115 | } 116 | if depth == 1 { 117 | curr_list.append(&mut val); 118 | return ( 119 | vec![cur], 120 | target_node, 121 | curr_list, 122 | ); 123 | } else { 124 | return ( 125 | vec![cur], 126 | target_node, 127 | val, 128 | ); 129 | } 130 | } else { 131 | let ( mut left_new_nodes, left_target_node, mut left_new_curr_list ) = hash_nodes_rec( 132 | nodes[..(nodes.len() / 2)].to_vec(), 133 | depth, 134 | top_depth, 135 | target_node, 136 | curr_list.clone(), 137 | ); 138 | let ( mut right_new_nodes, right_target_node, mut right_new_curr_list ) = hash_nodes_rec( 139 | nodes[(nodes.len() / 2)..].to_vec(), 140 | depth, 141 | top_depth, 142 | target_node, 143 | curr_list.clone(), 144 | ); 145 | 146 | if left_target_node == target_node { 147 | target_node = right_target_node; 148 | } else { 149 | target_node = left_target_node; 150 | } 151 | 152 | left_new_nodes.append(&mut right_new_nodes); 153 | curr_list.append(&mut left_new_curr_list); 154 | curr_list.append(&mut right_new_curr_list); 155 | 156 | return ( 157 | left_new_nodes, 158 | target_node, 159 | curr_list, 160 | ); 161 | } 162 | } 163 | 164 | pub fn hash_leaf_pair(_index: usize, lhs: Tree, rhs: Tree) -> Box { 165 | let mut hash: [u8; 32] = ZERO_BYTES; 166 | let mut preimage: Vec = vec![]; 167 | preimage.extend(lhs.hash().into_iter()); 168 | preimage.extend(rhs.hash().into_iter()); 169 | hash.copy_from_slice(&blake2s(32, SUBSTRATE_BLAKE2_PERSONALIZATION, &preimage[..]).as_bytes()[0..32]); 170 | return Box::new(Tree::Node { 171 | hash: hash, 172 | left: Box::new(lhs), 173 | right: Box::new(rhs), 174 | parent: None, 175 | }); 176 | } 177 | 178 | pub fn compute_root_from_proof(leaf: [u8; 32], path: Vec>) -> [u8; 32] { 179 | let mut hash = leaf; 180 | for i in 0..path.len() { 181 | match path[i] { 182 | Some((right_side, pt)) => { 183 | if right_side { 184 | hash = *hash_leaf_pair( 185 | i, 186 | Tree::Empty { hash: hash, parent: None }, 187 | Tree::Empty { hash: pt, parent: None }) 188 | .hash(); 189 | } else { 190 | hash = *hash_leaf_pair( 191 | i, 192 | Tree::Empty { hash: pt, parent: None }, 193 | Tree::Empty { hash: hash, parent: None }) 194 | .hash(); 195 | } 196 | }, 197 | None => {}, 198 | } 199 | } 200 | 201 | return hash; 202 | } 203 | -------------------------------------------------------------------------------- /sapling-crypto/src/circuit/baby_pedersen_hash.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use super::baby_ecc::{ 3 | MontgomeryPoint, 4 | EdwardsPoint 5 | }; 6 | use super::boolean::Boolean; 7 | use ::babyjubjub::*; 8 | use bellman::{ 9 | ConstraintSystem 10 | }; 11 | use super::lookup::*; 12 | pub use baby_pedersen_hash::Personalization; 13 | 14 | impl Personalization { 15 | fn get_constant_bools(&self) -> Vec { 16 | self.get_bits() 17 | .into_iter() 18 | .map(|e| Boolean::constant(e)) 19 | .collect() 20 | } 21 | } 22 | 23 | pub fn pedersen_hash( 24 | mut cs: CS, 25 | personalization: Personalization, 26 | bits: &[Boolean], 27 | params: &E::Params 28 | ) -> Result, SynthesisError> 29 | where CS: ConstraintSystem 30 | { 31 | let personalization = personalization.get_constant_bools(); 32 | assert_eq!(personalization.len(), 6); 33 | 34 | let mut edwards_result = None; 35 | let mut bits = personalization.iter().chain(bits.iter()); 36 | let mut segment_generators = params.pedersen_circuit_generators().iter(); 37 | let boolean_false = Boolean::constant(false); 38 | 39 | let mut segment_i = 0; 40 | loop { 41 | let mut segment_result = None; 42 | let mut segment_windows = &segment_generators.next() 43 | .expect("enough segments")[..]; 44 | 45 | let mut window_i = 0; 46 | while let Some(a) = bits.next() { 47 | let b = bits.next().unwrap_or(&boolean_false); 48 | let c = bits.next().unwrap_or(&boolean_false); 49 | 50 | let tmp = lookup3_xy_with_conditional_negation( 51 | cs.namespace(|| format!("segment {}, window {}", segment_i, window_i)), 52 | &[a.clone(), b.clone(), c.clone()], 53 | &segment_windows[0] 54 | )?; 55 | 56 | let tmp = MontgomeryPoint::interpret_unchecked(tmp.0, tmp.1); 57 | 58 | match segment_result { 59 | None => { 60 | segment_result = Some(tmp); 61 | }, 62 | Some(ref mut segment_result) => { 63 | *segment_result = tmp.add( 64 | cs.namespace(|| format!("addition of segment {}, window {}", segment_i, window_i)), 65 | segment_result, 66 | params 67 | )?; 68 | } 69 | } 70 | 71 | segment_windows = &segment_windows[1..]; 72 | 73 | if segment_windows.len() == 0 { 74 | break; 75 | } 76 | 77 | window_i += 1; 78 | } 79 | 80 | match segment_result { 81 | Some(segment_result) => { 82 | // Convert this segment into twisted Edwards form. 83 | let segment_result = segment_result.into_edwards( 84 | cs.namespace(|| format!("conversion of segment {} into edwards", segment_i)), 85 | params 86 | )?; 87 | 88 | match edwards_result { 89 | Some(ref mut edwards_result) => { 90 | *edwards_result = segment_result.add( 91 | cs.namespace(|| format!("addition of segment {} to accumulator", segment_i)), 92 | edwards_result, 93 | params 94 | )?; 95 | }, 96 | None => { 97 | edwards_result = Some(segment_result); 98 | } 99 | } 100 | }, 101 | None => { 102 | // We didn't process any new bits. 103 | break; 104 | } 105 | } 106 | 107 | segment_i += 1; 108 | } 109 | 110 | Ok(edwards_result.unwrap()) 111 | } 112 | 113 | #[cfg(test)] 114 | mod test { 115 | use rand::{SeedableRng, Rng, XorShiftRng}; 116 | use super::*; 117 | use ::circuit::test::*; 118 | use ::circuit::boolean::{Boolean, AllocatedBit}; 119 | use pairing::bn256::{Bn256, Fr}; 120 | use ff::PrimeField; 121 | 122 | #[test] 123 | fn test_pedersen_hash_constraints() { 124 | let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 125 | let params = &JubjubBn256::new(); 126 | let mut cs = TestConstraintSystem::::new(); 127 | 128 | let input: Vec = (0..(Fr::NUM_BITS * 2)).map(|_| rng.gen()).collect(); 129 | 130 | let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { 131 | Boolean::from( 132 | AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() 133 | ) 134 | }).collect(); 135 | 136 | pedersen_hash( 137 | cs.namespace(|| "pedersen hash"), 138 | Personalization::NoteCommitment, 139 | &input_bools, 140 | params 141 | ).unwrap(); 142 | 143 | assert!(cs.is_satisfied()); 144 | assert_eq!(cs.num_constraints(), 1376); 145 | } 146 | 147 | #[test] 148 | fn test_pedersen_hash() { 149 | let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 150 | let params = &JubjubBn256::new(); 151 | 152 | for length in 0..751 { 153 | for _ in 0..5 { 154 | let mut input: Vec = (0..length).map(|_| rng.gen()).collect(); 155 | 156 | let mut cs = TestConstraintSystem::::new(); 157 | 158 | let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { 159 | Boolean::from( 160 | AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() 161 | ) 162 | }).collect(); 163 | 164 | let res = pedersen_hash( 165 | cs.namespace(|| "pedersen hash"), 166 | Personalization::MerkleTree(1), 167 | &input_bools, 168 | params 169 | ).unwrap(); 170 | 171 | assert!(cs.is_satisfied()); 172 | 173 | let expected = ::baby_pedersen_hash::pedersen_hash::( 174 | Personalization::MerkleTree(1), 175 | input.clone().into_iter(), 176 | params 177 | ).into_xy(); 178 | 179 | assert_eq!(res.get_x().get_value().unwrap(), expected.0); 180 | assert_eq!(res.get_y().get_value().unwrap(), expected.1); 181 | 182 | // Test against the output of a different personalization 183 | let unexpected = ::baby_pedersen_hash::pedersen_hash::( 184 | Personalization::MerkleTree(0), 185 | input.into_iter(), 186 | params 187 | ).into_xy(); 188 | 189 | assert!(res.get_x().get_value().unwrap() != unexpected.0); 190 | assert!(res.get_y().get_value().unwrap() != unexpected.1); 191 | } 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /sapling-crypto/src/circuit/sprout/input.rs: -------------------------------------------------------------------------------- 1 | use pairing::{Engine}; 2 | use bellman::{ConstraintSystem, SynthesisError}; 3 | use circuit::sha256::{ 4 | sha256_block_no_padding 5 | }; 6 | use circuit::boolean::{ 7 | AllocatedBit, 8 | Boolean 9 | }; 10 | 11 | use super::*; 12 | use super::prfs::*; 13 | use super::commitment::note_comm; 14 | 15 | pub struct InputNote { 16 | pub nf: Vec, 17 | pub mac: Vec, 18 | } 19 | 20 | impl InputNote { 21 | pub fn compute( 22 | mut cs: CS, 23 | a_sk: Option, 24 | rho: Option, 25 | r: Option, 26 | value: &NoteValue, 27 | h_sig: &[Boolean], 28 | nonce: bool, 29 | auth_path: [Option<([u8; 32], bool)>; TREE_DEPTH], 30 | rt: &[Boolean] 31 | ) -> Result 32 | where E: Engine, CS: ConstraintSystem 33 | { 34 | let a_sk = witness_u252( 35 | cs.namespace(|| "a_sk"), 36 | a_sk.as_ref().map(|a_sk| &a_sk.0[..]) 37 | )?; 38 | 39 | let rho = witness_u256( 40 | cs.namespace(|| "rho"), 41 | rho.as_ref().map(|rho| &rho.0[..]) 42 | )?; 43 | 44 | let r = witness_u256( 45 | cs.namespace(|| "r"), 46 | r.as_ref().map(|r| &r.0[..]) 47 | )?; 48 | 49 | let a_pk = prf_a_pk( 50 | cs.namespace(|| "a_pk computation"), 51 | &a_sk 52 | )?; 53 | 54 | let nf = prf_nf( 55 | cs.namespace(|| "nf computation"), 56 | &a_sk, 57 | &rho 58 | )?; 59 | 60 | let mac = prf_pk( 61 | cs.namespace(|| "mac computation"), 62 | &a_sk, 63 | h_sig, 64 | nonce 65 | )?; 66 | 67 | let cm = note_comm( 68 | cs.namespace(|| "cm computation"), 69 | &a_pk, 70 | &value.bits_le(), 71 | &rho, 72 | &r 73 | )?; 74 | 75 | // Witness into the merkle tree 76 | let mut cur = cm.clone(); 77 | 78 | for (i, layer) in auth_path.into_iter().enumerate() { 79 | let cs = &mut cs.namespace(|| format!("layer {}", i)); 80 | 81 | let cur_is_right = AllocatedBit::alloc( 82 | cs.namespace(|| "cur is right"), 83 | layer.as_ref().map(|&(_, p)| p) 84 | )?; 85 | 86 | let lhs = cur; 87 | let rhs = witness_u256( 88 | cs.namespace(|| "sibling"), 89 | layer.as_ref().map(|&(ref sibling, _)| &sibling[..]) 90 | )?; 91 | 92 | // Conditionally swap if cur is right 93 | let preimage = conditionally_swap_u256( 94 | cs.namespace(|| "conditional swap"), 95 | &lhs[..], 96 | &rhs[..], 97 | &cur_is_right 98 | )?; 99 | 100 | cur = sha256_block_no_padding( 101 | cs.namespace(|| "hash of this layer"), 102 | &preimage 103 | )?; 104 | } 105 | 106 | // enforce must be true if the value is nonzero 107 | let enforce = AllocatedBit::alloc( 108 | cs.namespace(|| "enforce"), 109 | value.get_value().map(|n| n != 0) 110 | )?; 111 | 112 | // value * (1 - enforce) = 0 113 | // If `value` is zero, `enforce` _can_ be zero. 114 | // If `value` is nonzero, `enforce` _must_ be one. 115 | cs.enforce( 116 | || "enforce validity", 117 | |_| value.lc(), 118 | |lc| lc + CS::one() - enforce.get_variable(), 119 | |lc| lc 120 | ); 121 | 122 | assert_eq!(cur.len(), rt.len()); 123 | 124 | // Check that the anchor (exposed as a public input) 125 | // is equal to the merkle tree root that we calculated 126 | // for this note 127 | for (i, (cur, rt)) in cur.into_iter().zip(rt.iter()).enumerate() { 128 | // (cur - rt) * enforce = 0 129 | // if enforce is zero, cur and rt can be different 130 | // if enforce is one, they must be equal 131 | cs.enforce( 132 | || format!("conditionally enforce correct root for bit {}", i), 133 | |_| cur.lc(CS::one(), E::Fr::one()) - &rt.lc(CS::one(), E::Fr::one()), 134 | |lc| lc + enforce.get_variable(), 135 | |lc| lc 136 | ); 137 | } 138 | 139 | Ok(InputNote { 140 | mac: mac, 141 | nf: nf 142 | }) 143 | } 144 | } 145 | 146 | /// Swaps two 256-bit blobs conditionally, returning the 147 | /// 512-bit concatenation. 148 | pub fn conditionally_swap_u256( 149 | mut cs: CS, 150 | lhs: &[Boolean], 151 | rhs: &[Boolean], 152 | condition: &AllocatedBit 153 | ) -> Result, SynthesisError> 154 | where E: Engine, CS: ConstraintSystem, 155 | { 156 | assert_eq!(lhs.len(), 256); 157 | assert_eq!(rhs.len(), 256); 158 | 159 | let mut new_lhs = vec![]; 160 | let mut new_rhs = vec![]; 161 | 162 | for (i, (lhs, rhs)) in lhs.iter().zip(rhs.iter()).enumerate() { 163 | let cs = &mut cs.namespace(|| format!("bit {}", i)); 164 | 165 | let x = Boolean::from(AllocatedBit::alloc( 166 | cs.namespace(|| "x"), 167 | condition.get_value().and_then(|v| { 168 | if v { 169 | rhs.get_value() 170 | } else { 171 | lhs.get_value() 172 | } 173 | }) 174 | )?); 175 | 176 | // x = (1-condition)lhs + (condition)rhs 177 | // x = lhs - lhs(condition) + rhs(condition) 178 | // x - lhs = condition (rhs - lhs) 179 | // if condition is zero, we don't swap, so 180 | // x - lhs = 0 181 | // x = lhs 182 | // if condition is one, we do swap, so 183 | // x - lhs = rhs - lhs 184 | // x = rhs 185 | cs.enforce( 186 | || "conditional swap for x", 187 | |lc| lc + &rhs.lc(CS::one(), E::Fr::one()) 188 | - &lhs.lc(CS::one(), E::Fr::one()), 189 | |lc| lc + condition.get_variable(), 190 | |lc| lc + &x.lc(CS::one(), E::Fr::one()) 191 | - &lhs.lc(CS::one(), E::Fr::one()) 192 | ); 193 | 194 | let y = Boolean::from(AllocatedBit::alloc( 195 | cs.namespace(|| "y"), 196 | condition.get_value().and_then(|v| { 197 | if v { 198 | lhs.get_value() 199 | } else { 200 | rhs.get_value() 201 | } 202 | }) 203 | )?); 204 | 205 | // y = (1-condition)rhs + (condition)lhs 206 | // y - rhs = condition (lhs - rhs) 207 | cs.enforce( 208 | || "conditional swap for y", 209 | |lc| lc + &lhs.lc(CS::one(), E::Fr::one()) 210 | - &rhs.lc(CS::one(), E::Fr::one()), 211 | |lc| lc + condition.get_variable(), 212 | |lc| lc + &y.lc(CS::one(), E::Fr::one()) 213 | - &rhs.lc(CS::one(), E::Fr::one()) 214 | ); 215 | 216 | new_lhs.push(x); 217 | new_rhs.push(y); 218 | } 219 | 220 | let mut f = new_lhs; 221 | f.extend(new_rhs); 222 | 223 | assert_eq!(f.len(), 512); 224 | 225 | Ok(f) 226 | } 227 | -------------------------------------------------------------------------------- /src/merkle_tree.rs: -------------------------------------------------------------------------------- 1 | use ff::{BitIterator, PrimeField, Field}; 2 | use pairing::{bn256::{Bn256, Fr}}; 3 | use sapling_crypto::{ 4 | babyjubjub::{ 5 | JubjubBn256, 6 | }, 7 | }; 8 | 9 | /// Binary Tree where leaves hold a stand-alone value. 10 | #[derive(Clone, Debug, PartialEq, Eq)] 11 | pub enum Tree { 12 | Empty { 13 | hash: pairing::bn256::Fr, 14 | parent: Option>, 15 | }, 16 | Node { 17 | hash: pairing::bn256::Fr, 18 | left: Box, 19 | right: Box, 20 | parent: Option>, 21 | }, 22 | } 23 | 24 | impl Tree { 25 | /// Returns a hash from the tree. 26 | pub fn hash(&self) -> &pairing::bn256::Fr { 27 | match *self { 28 | Tree::Empty { ref hash, .. } => hash, 29 | Tree::Node { ref hash, .. } => hash, 30 | } 31 | } 32 | } 33 | 34 | #[derive(Debug)] 35 | pub struct MerkleTree { 36 | pub root: Tree, 37 | } 38 | 39 | pub fn create_leaf_from_preimage(nullifier: pairing::bn256::Fr, secret: pairing::bn256::Fr) -> Tree { 40 | let params = &JubjubBn256::new(); 41 | let mut lhs: Vec = BitIterator::new(nullifier.into_repr()).collect(); 42 | let mut rhs: Vec = BitIterator::new(secret.into_repr()).collect(); 43 | lhs.reverse(); 44 | rhs.reverse(); 45 | let hash = sapling_crypto::baby_pedersen_hash::pedersen_hash::( 46 | sapling_crypto::baby_pedersen_hash::Personalization::NoteCommitment, 47 | lhs.into_iter() 48 | .take(Fr::NUM_BITS as usize) 49 | .chain(rhs.into_iter().take(Fr::NUM_BITS as usize)), 50 | params 51 | ).into_xy().0; 52 | return Tree::Empty { 53 | hash: hash, 54 | parent: None, 55 | }; 56 | } 57 | 58 | pub fn create_leaf_list(mut nodes: Vec, depth: usize) -> Vec> { 59 | for _ in 0..((2 << (depth - 1)) - nodes.len()) { 60 | nodes.push(::zero()); 61 | } 62 | 63 | let mut tree_nodes: Vec> = vec![]; 64 | for i in 0..nodes.len() { 65 | tree_nodes.push(Box::new(Tree::Empty { 66 | hash: nodes[i], 67 | parent: None, 68 | })); 69 | } 70 | 71 | return tree_nodes; 72 | } 73 | 74 | #[allow(dead_code)] 75 | pub fn build_merkle_tree_with_proof( 76 | nodes: Vec>, 77 | depth: usize, 78 | top_depth: usize, 79 | target_node: pairing::bn256::Fr, 80 | curr_list: Vec>, 81 | ) -> (MerkleTree, Vec>) { 82 | let ( mut new_nodes, target_node, new_curr_list ) = hash_nodes_rec(nodes, depth, top_depth, target_node, curr_list); 83 | if new_nodes.len() == 1 { 84 | let root = new_nodes.remove(0); 85 | return ( 86 | MerkleTree { root: *root }, 87 | new_curr_list, 88 | ); 89 | } else { 90 | return build_merkle_tree_with_proof( 91 | new_nodes, 92 | depth - 1, 93 | top_depth, 94 | target_node, 95 | new_curr_list, 96 | ); 97 | } 98 | } 99 | 100 | #[allow(dead_code)] 101 | pub fn hash_nodes_rec( 102 | mut nodes: Vec>, 103 | depth: usize, 104 | top_depth: usize, 105 | mut target_node: pairing::bn256::Fr, 106 | mut curr_list: Vec> 107 | ) -> (Vec>, pairing::bn256::Fr, Vec>) { 108 | if nodes.len() == 2 { 109 | let left = nodes.remove(0); 110 | let right = nodes.remove(0); 111 | let temp_bool = target_node == *left.hash() || target_node == *right.hash(); 112 | let mut val = vec![]; 113 | if target_node == *left.hash() { 114 | val.push(Some((true, *right.hash()))); 115 | } 116 | 117 | if target_node == *right.hash() { 118 | val.push(Some((false, *left.hash()))); 119 | } 120 | 121 | let cur = hash_leaf_pair(top_depth - depth, *left, *right); 122 | if temp_bool { 123 | target_node = *cur.hash(); 124 | } 125 | if depth == 1 { 126 | curr_list.append(&mut val); 127 | return ( 128 | vec![cur], 129 | target_node, 130 | curr_list, 131 | ); 132 | } else { 133 | return ( 134 | vec![cur], 135 | target_node, 136 | val, 137 | ); 138 | } 139 | } else { 140 | let ( mut left_new_nodes, left_target_node, mut left_new_curr_list ) = hash_nodes_rec( 141 | nodes[..(nodes.len() / 2)].to_vec(), 142 | depth, 143 | top_depth, 144 | target_node, 145 | curr_list.clone(), 146 | ); 147 | let ( mut right_new_nodes, right_target_node, mut right_new_curr_list ) = hash_nodes_rec( 148 | nodes[(nodes.len() / 2)..].to_vec(), 149 | depth, 150 | top_depth, 151 | target_node, 152 | curr_list.clone(), 153 | ); 154 | 155 | if left_target_node == target_node { 156 | target_node = right_target_node; 157 | } else { 158 | target_node = left_target_node; 159 | } 160 | 161 | left_new_nodes.append(&mut right_new_nodes); 162 | curr_list.append(&mut left_new_curr_list); 163 | curr_list.append(&mut right_new_curr_list); 164 | 165 | return ( 166 | left_new_nodes, 167 | target_node, 168 | curr_list, 169 | ); 170 | } 171 | } 172 | 173 | pub fn hash_leaf_pair(index: usize, lhs: Tree, rhs: Tree) -> Box { 174 | let params = &JubjubBn256::new(); 175 | let mut lhs_bool: Vec = BitIterator::new((lhs).hash().into_repr()).collect(); 176 | let mut rhs_bool: Vec = BitIterator::new((rhs).hash().into_repr()).collect(); 177 | lhs_bool.reverse(); 178 | rhs_bool.reverse(); 179 | let personalization = sapling_crypto::baby_pedersen_hash::Personalization::MerkleTree(index as usize); 180 | let hash = sapling_crypto::baby_pedersen_hash::pedersen_hash::( 181 | personalization, 182 | lhs_bool.clone().into_iter() 183 | .take(Fr::NUM_BITS as usize) 184 | .chain(rhs_bool.clone().into_iter().take(Fr::NUM_BITS as usize)), 185 | params 186 | ).into_xy().0; 187 | return Box::new(Tree::Node { 188 | hash: hash, 189 | left: Box::new(lhs), 190 | right: Box::new(rhs), 191 | parent: None, 192 | }); 193 | } 194 | 195 | pub fn compute_root_from_proof(leaf: pairing::bn256::Fr, path: Vec>) -> pairing::bn256::Fr { 196 | let mut hash = leaf; 197 | for i in 0..path.len() { 198 | match path[i] { 199 | Some((right_side, pt)) => { 200 | if right_side { 201 | hash = *hash_leaf_pair( 202 | i, 203 | Tree::Empty { hash: hash, parent: None }, 204 | Tree::Empty { hash: pt, parent: None }) 205 | .hash(); 206 | } else { 207 | hash = *hash_leaf_pair( 208 | i, 209 | Tree::Empty { hash: pt, parent: None }, 210 | Tree::Empty { hash: hash, parent: None }) 211 | .hash(); 212 | } 213 | }, 214 | None => {}, 215 | } 216 | } 217 | 218 | return hash; 219 | } 220 | -------------------------------------------------------------------------------- /pairing/benches/bn256/fq.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rand, SeedableRng, XorShiftRng}; 2 | 3 | use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; 4 | use pairing::bn256::*; 5 | 6 | #[bench] 7 | fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) { 8 | const SAMPLES: usize = 1000; 9 | 10 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 11 | 12 | let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES) 13 | .map(|_| { 14 | let mut tmp1 = FqRepr::rand(&mut rng); 15 | let mut tmp2 = FqRepr::rand(&mut rng); 16 | // Shave a few bits off to avoid overflow. 17 | for _ in 0..3 { 18 | tmp1.div2(); 19 | tmp2.div2(); 20 | } 21 | (tmp1, tmp2) 22 | }) 23 | .collect(); 24 | 25 | let mut count = 0; 26 | b.iter(|| { 27 | let mut tmp = v[count].0; 28 | tmp.add_nocarry(&v[count].1); 29 | count = (count + 1) % SAMPLES; 30 | tmp 31 | }); 32 | } 33 | 34 | #[bench] 35 | fn bench_fq_repr_sub_noborrow(b: &mut ::test::Bencher) { 36 | const SAMPLES: usize = 1000; 37 | 38 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 39 | 40 | let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES) 41 | .map(|_| { 42 | let tmp1 = FqRepr::rand(&mut rng); 43 | let mut tmp2 = tmp1; 44 | // Ensure tmp2 is smaller than tmp1. 45 | for _ in 0..10 { 46 | tmp2.div2(); 47 | } 48 | (tmp1, tmp2) 49 | }) 50 | .collect(); 51 | 52 | let mut count = 0; 53 | b.iter(|| { 54 | let mut tmp = v[count].0; 55 | tmp.sub_noborrow(&v[count].1); 56 | count = (count + 1) % SAMPLES; 57 | tmp 58 | }); 59 | } 60 | 61 | #[bench] 62 | fn bench_fq_repr_num_bits(b: &mut ::test::Bencher) { 63 | const SAMPLES: usize = 1000; 64 | 65 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 66 | 67 | let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); 68 | 69 | let mut count = 0; 70 | b.iter(|| { 71 | let tmp = v[count].num_bits(); 72 | count = (count + 1) % SAMPLES; 73 | tmp 74 | }); 75 | } 76 | 77 | #[bench] 78 | fn bench_fq_repr_mul2(b: &mut ::test::Bencher) { 79 | const SAMPLES: usize = 1000; 80 | 81 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 82 | 83 | let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); 84 | 85 | let mut count = 0; 86 | b.iter(|| { 87 | let mut tmp = v[count]; 88 | tmp.mul2(); 89 | count = (count + 1) % SAMPLES; 90 | tmp 91 | }); 92 | } 93 | 94 | #[bench] 95 | fn bench_fq_repr_div2(b: &mut ::test::Bencher) { 96 | const SAMPLES: usize = 1000; 97 | 98 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 99 | 100 | let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); 101 | 102 | let mut count = 0; 103 | b.iter(|| { 104 | let mut tmp = v[count]; 105 | tmp.div2(); 106 | count = (count + 1) % SAMPLES; 107 | tmp 108 | }); 109 | } 110 | 111 | #[bench] 112 | fn bench_fq_add_assign(b: &mut ::test::Bencher) { 113 | const SAMPLES: usize = 1000; 114 | 115 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 116 | 117 | let v: Vec<(Fq, Fq)> = (0..SAMPLES) 118 | .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) 119 | .collect(); 120 | 121 | let mut count = 0; 122 | b.iter(|| { 123 | let mut tmp = v[count].0; 124 | tmp.add_assign(&v[count].1); 125 | count = (count + 1) % SAMPLES; 126 | tmp 127 | }); 128 | } 129 | 130 | #[bench] 131 | fn bench_fq_sub_assign(b: &mut ::test::Bencher) { 132 | const SAMPLES: usize = 1000; 133 | 134 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 135 | 136 | let v: Vec<(Fq, Fq)> = (0..SAMPLES) 137 | .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) 138 | .collect(); 139 | 140 | let mut count = 0; 141 | b.iter(|| { 142 | let mut tmp = v[count].0; 143 | tmp.sub_assign(&v[count].1); 144 | count = (count + 1) % SAMPLES; 145 | tmp 146 | }); 147 | } 148 | 149 | #[bench] 150 | fn bench_fq_mul_assign(b: &mut ::test::Bencher) { 151 | const SAMPLES: usize = 1000; 152 | 153 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 154 | 155 | let v: Vec<(Fq, Fq)> = (0..SAMPLES) 156 | .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) 157 | .collect(); 158 | 159 | let mut count = 0; 160 | b.iter(|| { 161 | let mut tmp = v[count].0; 162 | tmp.mul_assign(&v[count].1); 163 | count = (count + 1) % SAMPLES; 164 | tmp 165 | }); 166 | } 167 | 168 | #[bench] 169 | fn bench_fq_square(b: &mut ::test::Bencher) { 170 | const SAMPLES: usize = 1000; 171 | 172 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 173 | 174 | let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); 175 | 176 | let mut count = 0; 177 | b.iter(|| { 178 | let mut tmp = v[count]; 179 | tmp.square(); 180 | count = (count + 1) % SAMPLES; 181 | tmp 182 | }); 183 | } 184 | 185 | #[bench] 186 | fn bench_fq_inverse(b: &mut ::test::Bencher) { 187 | const SAMPLES: usize = 1000; 188 | 189 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 190 | 191 | let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); 192 | 193 | let mut count = 0; 194 | b.iter(|| { 195 | count = (count + 1) % SAMPLES; 196 | v[count].inverse() 197 | }); 198 | } 199 | 200 | #[bench] 201 | fn bench_fq_negate(b: &mut ::test::Bencher) { 202 | const SAMPLES: usize = 1000; 203 | 204 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 205 | 206 | let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); 207 | 208 | let mut count = 0; 209 | b.iter(|| { 210 | let mut tmp = v[count]; 211 | tmp.negate(); 212 | count = (count + 1) % SAMPLES; 213 | tmp 214 | }); 215 | } 216 | 217 | #[bench] 218 | fn bench_fq_sqrt(b: &mut ::test::Bencher) { 219 | const SAMPLES: usize = 1000; 220 | 221 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 222 | 223 | let v: Vec = (0..SAMPLES) 224 | .map(|_| { 225 | let mut tmp = Fq::rand(&mut rng); 226 | tmp.square(); 227 | tmp 228 | }) 229 | .collect(); 230 | 231 | let mut count = 0; 232 | b.iter(|| { 233 | count = (count + 1) % SAMPLES; 234 | v[count].sqrt() 235 | }); 236 | } 237 | 238 | #[bench] 239 | fn bench_fq_into_repr(b: &mut ::test::Bencher) { 240 | const SAMPLES: usize = 1000; 241 | 242 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 243 | 244 | let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); 245 | 246 | let mut count = 0; 247 | b.iter(|| { 248 | count = (count + 1) % SAMPLES; 249 | v[count].into_repr() 250 | }); 251 | } 252 | 253 | #[bench] 254 | fn bench_fq_from_repr(b: &mut ::test::Bencher) { 255 | const SAMPLES: usize = 1000; 256 | 257 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 258 | 259 | let v: Vec = (0..SAMPLES) 260 | .map(|_| Fq::rand(&mut rng).into_repr()) 261 | .collect(); 262 | 263 | let mut count = 0; 264 | b.iter(|| { 265 | count = (count + 1) % SAMPLES; 266 | Fq::from_repr(v[count]) 267 | }); 268 | } 269 | -------------------------------------------------------------------------------- /pairing/benches/bn256/fr.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rand, SeedableRng, XorShiftRng}; 2 | 3 | use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; 4 | use pairing::bn256::*; 5 | 6 | #[bench] 7 | fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) { 8 | const SAMPLES: usize = 1000; 9 | 10 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 11 | 12 | let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES) 13 | .map(|_| { 14 | let mut tmp1 = FrRepr::rand(&mut rng); 15 | let mut tmp2 = FrRepr::rand(&mut rng); 16 | // Shave a few bits off to avoid overflow. 17 | for _ in 0..3 { 18 | tmp1.div2(); 19 | tmp2.div2(); 20 | } 21 | (tmp1, tmp2) 22 | }) 23 | .collect(); 24 | 25 | let mut count = 0; 26 | b.iter(|| { 27 | let mut tmp = v[count].0; 28 | tmp.add_nocarry(&v[count].1); 29 | count = (count + 1) % SAMPLES; 30 | tmp 31 | }); 32 | } 33 | 34 | #[bench] 35 | fn bench_fr_repr_sub_noborrow(b: &mut ::test::Bencher) { 36 | const SAMPLES: usize = 1000; 37 | 38 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 39 | 40 | let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES) 41 | .map(|_| { 42 | let tmp1 = FrRepr::rand(&mut rng); 43 | let mut tmp2 = tmp1; 44 | // Ensure tmp2 is smaller than tmp1. 45 | for _ in 0..10 { 46 | tmp2.div2(); 47 | } 48 | (tmp1, tmp2) 49 | }) 50 | .collect(); 51 | 52 | let mut count = 0; 53 | b.iter(|| { 54 | let mut tmp = v[count].0; 55 | tmp.sub_noborrow(&v[count].1); 56 | count = (count + 1) % SAMPLES; 57 | tmp 58 | }); 59 | } 60 | 61 | #[bench] 62 | fn bench_fr_repr_num_bits(b: &mut ::test::Bencher) { 63 | const SAMPLES: usize = 1000; 64 | 65 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 66 | 67 | let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); 68 | 69 | let mut count = 0; 70 | b.iter(|| { 71 | let tmp = v[count].num_bits(); 72 | count = (count + 1) % SAMPLES; 73 | tmp 74 | }); 75 | } 76 | 77 | #[bench] 78 | fn bench_fr_repr_mul2(b: &mut ::test::Bencher) { 79 | const SAMPLES: usize = 1000; 80 | 81 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 82 | 83 | let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); 84 | 85 | let mut count = 0; 86 | b.iter(|| { 87 | let mut tmp = v[count]; 88 | tmp.mul2(); 89 | count = (count + 1) % SAMPLES; 90 | tmp 91 | }); 92 | } 93 | 94 | #[bench] 95 | fn bench_fr_repr_div2(b: &mut ::test::Bencher) { 96 | const SAMPLES: usize = 1000; 97 | 98 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 99 | 100 | let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); 101 | 102 | let mut count = 0; 103 | b.iter(|| { 104 | let mut tmp = v[count]; 105 | tmp.div2(); 106 | count = (count + 1) % SAMPLES; 107 | tmp 108 | }); 109 | } 110 | 111 | #[bench] 112 | fn bench_fr_add_assign(b: &mut ::test::Bencher) { 113 | const SAMPLES: usize = 1000; 114 | 115 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 116 | 117 | let v: Vec<(Fr, Fr)> = (0..SAMPLES) 118 | .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) 119 | .collect(); 120 | 121 | let mut count = 0; 122 | b.iter(|| { 123 | let mut tmp = v[count].0; 124 | tmp.add_assign(&v[count].1); 125 | count = (count + 1) % SAMPLES; 126 | tmp 127 | }); 128 | } 129 | 130 | #[bench] 131 | fn bench_fr_sub_assign(b: &mut ::test::Bencher) { 132 | const SAMPLES: usize = 1000; 133 | 134 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 135 | 136 | let v: Vec<(Fr, Fr)> = (0..SAMPLES) 137 | .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) 138 | .collect(); 139 | 140 | let mut count = 0; 141 | b.iter(|| { 142 | let mut tmp = v[count].0; 143 | tmp.sub_assign(&v[count].1); 144 | count = (count + 1) % SAMPLES; 145 | tmp 146 | }); 147 | } 148 | 149 | #[bench] 150 | fn bench_fr_mul_assign(b: &mut ::test::Bencher) { 151 | const SAMPLES: usize = 1000; 152 | 153 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 154 | 155 | let v: Vec<(Fr, Fr)> = (0..SAMPLES) 156 | .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) 157 | .collect(); 158 | 159 | let mut count = 0; 160 | b.iter(|| { 161 | let mut tmp = v[count].0; 162 | tmp.mul_assign(&v[count].1); 163 | count = (count + 1) % SAMPLES; 164 | tmp 165 | }); 166 | } 167 | 168 | #[bench] 169 | fn bench_fr_square(b: &mut ::test::Bencher) { 170 | const SAMPLES: usize = 1000; 171 | 172 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 173 | 174 | let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); 175 | 176 | let mut count = 0; 177 | b.iter(|| { 178 | let mut tmp = v[count]; 179 | tmp.square(); 180 | count = (count + 1) % SAMPLES; 181 | tmp 182 | }); 183 | } 184 | 185 | #[bench] 186 | fn bench_fr_inverse(b: &mut ::test::Bencher) { 187 | const SAMPLES: usize = 1000; 188 | 189 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 190 | 191 | let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); 192 | 193 | let mut count = 0; 194 | b.iter(|| { 195 | count = (count + 1) % SAMPLES; 196 | v[count].inverse() 197 | }); 198 | } 199 | 200 | #[bench] 201 | fn bench_fr_negate(b: &mut ::test::Bencher) { 202 | const SAMPLES: usize = 1000; 203 | 204 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 205 | 206 | let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); 207 | 208 | let mut count = 0; 209 | b.iter(|| { 210 | let mut tmp = v[count]; 211 | tmp.negate(); 212 | count = (count + 1) % SAMPLES; 213 | tmp 214 | }); 215 | } 216 | 217 | #[bench] 218 | fn bench_fr_sqrt(b: &mut ::test::Bencher) { 219 | const SAMPLES: usize = 1000; 220 | 221 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 222 | 223 | let v: Vec = (0..SAMPLES) 224 | .map(|_| { 225 | let mut tmp = Fr::rand(&mut rng); 226 | tmp.square(); 227 | tmp 228 | }) 229 | .collect(); 230 | 231 | let mut count = 0; 232 | b.iter(|| { 233 | count = (count + 1) % SAMPLES; 234 | v[count].sqrt() 235 | }); 236 | } 237 | 238 | #[bench] 239 | fn bench_fr_into_repr(b: &mut ::test::Bencher) { 240 | const SAMPLES: usize = 1000; 241 | 242 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 243 | 244 | let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); 245 | 246 | let mut count = 0; 247 | b.iter(|| { 248 | count = (count + 1) % SAMPLES; 249 | v[count].into_repr() 250 | }); 251 | } 252 | 253 | #[bench] 254 | fn bench_fr_from_repr(b: &mut ::test::Bencher) { 255 | const SAMPLES: usize = 1000; 256 | 257 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 258 | 259 | let v: Vec = (0..SAMPLES) 260 | .map(|_| Fr::rand(&mut rng).into_repr()) 261 | .collect(); 262 | 263 | let mut count = 0; 264 | b.iter(|| { 265 | count = (count + 1) % SAMPLES; 266 | Fr::from_repr(v[count]) 267 | }); 268 | } 269 | -------------------------------------------------------------------------------- /pairing/benches/bls12_381/fq.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rand, SeedableRng, XorShiftRng}; 2 | 3 | use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; 4 | use pairing::bls12_381::*; 5 | 6 | #[bench] 7 | fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) { 8 | const SAMPLES: usize = 1000; 9 | 10 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 11 | 12 | let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES) 13 | .map(|_| { 14 | let mut tmp1 = FqRepr::rand(&mut rng); 15 | let mut tmp2 = FqRepr::rand(&mut rng); 16 | // Shave a few bits off to avoid overflow. 17 | for _ in 0..3 { 18 | tmp1.div2(); 19 | tmp2.div2(); 20 | } 21 | (tmp1, tmp2) 22 | }) 23 | .collect(); 24 | 25 | let mut count = 0; 26 | b.iter(|| { 27 | let mut tmp = v[count].0; 28 | tmp.add_nocarry(&v[count].1); 29 | count = (count + 1) % SAMPLES; 30 | tmp 31 | }); 32 | } 33 | 34 | #[bench] 35 | fn bench_fq_repr_sub_noborrow(b: &mut ::test::Bencher) { 36 | const SAMPLES: usize = 1000; 37 | 38 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 39 | 40 | let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES) 41 | .map(|_| { 42 | let tmp1 = FqRepr::rand(&mut rng); 43 | let mut tmp2 = tmp1; 44 | // Ensure tmp2 is smaller than tmp1. 45 | for _ in 0..10 { 46 | tmp2.div2(); 47 | } 48 | (tmp1, tmp2) 49 | }) 50 | .collect(); 51 | 52 | let mut count = 0; 53 | b.iter(|| { 54 | let mut tmp = v[count].0; 55 | tmp.sub_noborrow(&v[count].1); 56 | count = (count + 1) % SAMPLES; 57 | tmp 58 | }); 59 | } 60 | 61 | #[bench] 62 | fn bench_fq_repr_num_bits(b: &mut ::test::Bencher) { 63 | const SAMPLES: usize = 1000; 64 | 65 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 66 | 67 | let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); 68 | 69 | let mut count = 0; 70 | b.iter(|| { 71 | let tmp = v[count].num_bits(); 72 | count = (count + 1) % SAMPLES; 73 | tmp 74 | }); 75 | } 76 | 77 | #[bench] 78 | fn bench_fq_repr_mul2(b: &mut ::test::Bencher) { 79 | const SAMPLES: usize = 1000; 80 | 81 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 82 | 83 | let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); 84 | 85 | let mut count = 0; 86 | b.iter(|| { 87 | let mut tmp = v[count]; 88 | tmp.mul2(); 89 | count = (count + 1) % SAMPLES; 90 | tmp 91 | }); 92 | } 93 | 94 | #[bench] 95 | fn bench_fq_repr_div2(b: &mut ::test::Bencher) { 96 | const SAMPLES: usize = 1000; 97 | 98 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 99 | 100 | let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); 101 | 102 | let mut count = 0; 103 | b.iter(|| { 104 | let mut tmp = v[count]; 105 | tmp.div2(); 106 | count = (count + 1) % SAMPLES; 107 | tmp 108 | }); 109 | } 110 | 111 | #[bench] 112 | fn bench_fq_add_assign(b: &mut ::test::Bencher) { 113 | const SAMPLES: usize = 1000; 114 | 115 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 116 | 117 | let v: Vec<(Fq, Fq)> = (0..SAMPLES) 118 | .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) 119 | .collect(); 120 | 121 | let mut count = 0; 122 | b.iter(|| { 123 | let mut tmp = v[count].0; 124 | tmp.add_assign(&v[count].1); 125 | count = (count + 1) % SAMPLES; 126 | tmp 127 | }); 128 | } 129 | 130 | #[bench] 131 | fn bench_fq_sub_assign(b: &mut ::test::Bencher) { 132 | const SAMPLES: usize = 1000; 133 | 134 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 135 | 136 | let v: Vec<(Fq, Fq)> = (0..SAMPLES) 137 | .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) 138 | .collect(); 139 | 140 | let mut count = 0; 141 | b.iter(|| { 142 | let mut tmp = v[count].0; 143 | tmp.sub_assign(&v[count].1); 144 | count = (count + 1) % SAMPLES; 145 | tmp 146 | }); 147 | } 148 | 149 | #[bench] 150 | fn bench_fq_mul_assign(b: &mut ::test::Bencher) { 151 | const SAMPLES: usize = 1000; 152 | 153 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 154 | 155 | let v: Vec<(Fq, Fq)> = (0..SAMPLES) 156 | .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) 157 | .collect(); 158 | 159 | let mut count = 0; 160 | b.iter(|| { 161 | let mut tmp = v[count].0; 162 | tmp.mul_assign(&v[count].1); 163 | count = (count + 1) % SAMPLES; 164 | tmp 165 | }); 166 | } 167 | 168 | #[bench] 169 | fn bench_fq_square(b: &mut ::test::Bencher) { 170 | const SAMPLES: usize = 1000; 171 | 172 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 173 | 174 | let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); 175 | 176 | let mut count = 0; 177 | b.iter(|| { 178 | let mut tmp = v[count]; 179 | tmp.square(); 180 | count = (count + 1) % SAMPLES; 181 | tmp 182 | }); 183 | } 184 | 185 | #[bench] 186 | fn bench_fq_inverse(b: &mut ::test::Bencher) { 187 | const SAMPLES: usize = 1000; 188 | 189 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 190 | 191 | let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); 192 | 193 | let mut count = 0; 194 | b.iter(|| { 195 | count = (count + 1) % SAMPLES; 196 | v[count].inverse() 197 | }); 198 | } 199 | 200 | #[bench] 201 | fn bench_fq_negate(b: &mut ::test::Bencher) { 202 | const SAMPLES: usize = 1000; 203 | 204 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 205 | 206 | let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); 207 | 208 | let mut count = 0; 209 | b.iter(|| { 210 | let mut tmp = v[count]; 211 | tmp.negate(); 212 | count = (count + 1) % SAMPLES; 213 | tmp 214 | }); 215 | } 216 | 217 | #[bench] 218 | fn bench_fq_sqrt(b: &mut ::test::Bencher) { 219 | const SAMPLES: usize = 1000; 220 | 221 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 222 | 223 | let v: Vec = (0..SAMPLES) 224 | .map(|_| { 225 | let mut tmp = Fq::rand(&mut rng); 226 | tmp.square(); 227 | tmp 228 | }) 229 | .collect(); 230 | 231 | let mut count = 0; 232 | b.iter(|| { 233 | count = (count + 1) % SAMPLES; 234 | v[count].sqrt() 235 | }); 236 | } 237 | 238 | #[bench] 239 | fn bench_fq_into_repr(b: &mut ::test::Bencher) { 240 | const SAMPLES: usize = 1000; 241 | 242 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 243 | 244 | let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); 245 | 246 | let mut count = 0; 247 | b.iter(|| { 248 | count = (count + 1) % SAMPLES; 249 | v[count].into_repr() 250 | }); 251 | } 252 | 253 | #[bench] 254 | fn bench_fq_from_repr(b: &mut ::test::Bencher) { 255 | const SAMPLES: usize = 1000; 256 | 257 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 258 | 259 | let v: Vec = (0..SAMPLES) 260 | .map(|_| Fq::rand(&mut rng).into_repr()) 261 | .collect(); 262 | 263 | let mut count = 0; 264 | b.iter(|| { 265 | count = (count + 1) % SAMPLES; 266 | Fq::from_repr(v[count]) 267 | }); 268 | } 269 | -------------------------------------------------------------------------------- /pairing/benches/bls12_381/fr.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rand, SeedableRng, XorShiftRng}; 2 | 3 | use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; 4 | use pairing::bls12_381::*; 5 | 6 | #[bench] 7 | fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) { 8 | const SAMPLES: usize = 1000; 9 | 10 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 11 | 12 | let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES) 13 | .map(|_| { 14 | let mut tmp1 = FrRepr::rand(&mut rng); 15 | let mut tmp2 = FrRepr::rand(&mut rng); 16 | // Shave a few bits off to avoid overflow. 17 | for _ in 0..3 { 18 | tmp1.div2(); 19 | tmp2.div2(); 20 | } 21 | (tmp1, tmp2) 22 | }) 23 | .collect(); 24 | 25 | let mut count = 0; 26 | b.iter(|| { 27 | let mut tmp = v[count].0; 28 | tmp.add_nocarry(&v[count].1); 29 | count = (count + 1) % SAMPLES; 30 | tmp 31 | }); 32 | } 33 | 34 | #[bench] 35 | fn bench_fr_repr_sub_noborrow(b: &mut ::test::Bencher) { 36 | const SAMPLES: usize = 1000; 37 | 38 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 39 | 40 | let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES) 41 | .map(|_| { 42 | let tmp1 = FrRepr::rand(&mut rng); 43 | let mut tmp2 = tmp1; 44 | // Ensure tmp2 is smaller than tmp1. 45 | for _ in 0..10 { 46 | tmp2.div2(); 47 | } 48 | (tmp1, tmp2) 49 | }) 50 | .collect(); 51 | 52 | let mut count = 0; 53 | b.iter(|| { 54 | let mut tmp = v[count].0; 55 | tmp.sub_noborrow(&v[count].1); 56 | count = (count + 1) % SAMPLES; 57 | tmp 58 | }); 59 | } 60 | 61 | #[bench] 62 | fn bench_fr_repr_num_bits(b: &mut ::test::Bencher) { 63 | const SAMPLES: usize = 1000; 64 | 65 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 66 | 67 | let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); 68 | 69 | let mut count = 0; 70 | b.iter(|| { 71 | let tmp = v[count].num_bits(); 72 | count = (count + 1) % SAMPLES; 73 | tmp 74 | }); 75 | } 76 | 77 | #[bench] 78 | fn bench_fr_repr_mul2(b: &mut ::test::Bencher) { 79 | const SAMPLES: usize = 1000; 80 | 81 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 82 | 83 | let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); 84 | 85 | let mut count = 0; 86 | b.iter(|| { 87 | let mut tmp = v[count]; 88 | tmp.mul2(); 89 | count = (count + 1) % SAMPLES; 90 | tmp 91 | }); 92 | } 93 | 94 | #[bench] 95 | fn bench_fr_repr_div2(b: &mut ::test::Bencher) { 96 | const SAMPLES: usize = 1000; 97 | 98 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 99 | 100 | let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); 101 | 102 | let mut count = 0; 103 | b.iter(|| { 104 | let mut tmp = v[count]; 105 | tmp.div2(); 106 | count = (count + 1) % SAMPLES; 107 | tmp 108 | }); 109 | } 110 | 111 | #[bench] 112 | fn bench_fr_add_assign(b: &mut ::test::Bencher) { 113 | const SAMPLES: usize = 1000; 114 | 115 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 116 | 117 | let v: Vec<(Fr, Fr)> = (0..SAMPLES) 118 | .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) 119 | .collect(); 120 | 121 | let mut count = 0; 122 | b.iter(|| { 123 | let mut tmp = v[count].0; 124 | tmp.add_assign(&v[count].1); 125 | count = (count + 1) % SAMPLES; 126 | tmp 127 | }); 128 | } 129 | 130 | #[bench] 131 | fn bench_fr_sub_assign(b: &mut ::test::Bencher) { 132 | const SAMPLES: usize = 1000; 133 | 134 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 135 | 136 | let v: Vec<(Fr, Fr)> = (0..SAMPLES) 137 | .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) 138 | .collect(); 139 | 140 | let mut count = 0; 141 | b.iter(|| { 142 | let mut tmp = v[count].0; 143 | tmp.sub_assign(&v[count].1); 144 | count = (count + 1) % SAMPLES; 145 | tmp 146 | }); 147 | } 148 | 149 | #[bench] 150 | fn bench_fr_mul_assign(b: &mut ::test::Bencher) { 151 | const SAMPLES: usize = 1000; 152 | 153 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 154 | 155 | let v: Vec<(Fr, Fr)> = (0..SAMPLES) 156 | .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) 157 | .collect(); 158 | 159 | let mut count = 0; 160 | b.iter(|| { 161 | let mut tmp = v[count].0; 162 | tmp.mul_assign(&v[count].1); 163 | count = (count + 1) % SAMPLES; 164 | tmp 165 | }); 166 | } 167 | 168 | #[bench] 169 | fn bench_fr_square(b: &mut ::test::Bencher) { 170 | const SAMPLES: usize = 1000; 171 | 172 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 173 | 174 | let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); 175 | 176 | let mut count = 0; 177 | b.iter(|| { 178 | let mut tmp = v[count]; 179 | tmp.square(); 180 | count = (count + 1) % SAMPLES; 181 | tmp 182 | }); 183 | } 184 | 185 | #[bench] 186 | fn bench_fr_inverse(b: &mut ::test::Bencher) { 187 | const SAMPLES: usize = 1000; 188 | 189 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 190 | 191 | let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); 192 | 193 | let mut count = 0; 194 | b.iter(|| { 195 | count = (count + 1) % SAMPLES; 196 | v[count].inverse() 197 | }); 198 | } 199 | 200 | #[bench] 201 | fn bench_fr_negate(b: &mut ::test::Bencher) { 202 | const SAMPLES: usize = 1000; 203 | 204 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 205 | 206 | let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); 207 | 208 | let mut count = 0; 209 | b.iter(|| { 210 | let mut tmp = v[count]; 211 | tmp.negate(); 212 | count = (count + 1) % SAMPLES; 213 | tmp 214 | }); 215 | } 216 | 217 | #[bench] 218 | fn bench_fr_sqrt(b: &mut ::test::Bencher) { 219 | const SAMPLES: usize = 1000; 220 | 221 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 222 | 223 | let v: Vec = (0..SAMPLES) 224 | .map(|_| { 225 | let mut tmp = Fr::rand(&mut rng); 226 | tmp.square(); 227 | tmp 228 | }) 229 | .collect(); 230 | 231 | let mut count = 0; 232 | b.iter(|| { 233 | count = (count + 1) % SAMPLES; 234 | v[count].sqrt() 235 | }); 236 | } 237 | 238 | #[bench] 239 | fn bench_fr_into_repr(b: &mut ::test::Bencher) { 240 | const SAMPLES: usize = 1000; 241 | 242 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 243 | 244 | let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); 245 | 246 | let mut count = 0; 247 | b.iter(|| { 248 | count = (count + 1) % SAMPLES; 249 | v[count].into_repr() 250 | }); 251 | } 252 | 253 | #[bench] 254 | fn bench_fr_from_repr(b: &mut ::test::Bencher) { 255 | const SAMPLES: usize = 1000; 256 | 257 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 258 | 259 | let v: Vec = (0..SAMPLES) 260 | .map(|_| Fr::rand(&mut rng).into_repr()) 261 | .collect(); 262 | 263 | let mut count = 0; 264 | b.iter(|| { 265 | count = (count + 1) % SAMPLES; 266 | Fr::from_repr(v[count]) 267 | }); 268 | } 269 | -------------------------------------------------------------------------------- /sapling-crypto/src/primitives/mod.rs: -------------------------------------------------------------------------------- 1 | use ff::{ 2 | Field, 3 | PrimeField, 4 | PrimeFieldRepr 5 | }; 6 | 7 | use constants; 8 | 9 | use group_hash::group_hash; 10 | 11 | use pedersen_hash::{ 12 | pedersen_hash, 13 | Personalization 14 | }; 15 | 16 | use byteorder::{ 17 | LittleEndian, 18 | WriteBytesExt 19 | }; 20 | 21 | use jubjub::{ 22 | JubjubEngine, 23 | JubjubParams, 24 | edwards, 25 | PrimeOrder, 26 | FixedGenerators 27 | }; 28 | 29 | use blake2_rfc::blake2s::Blake2s; 30 | 31 | #[derive(Clone)] 32 | pub struct ValueCommitment { 33 | pub value: u64, 34 | pub randomness: E::Fs 35 | } 36 | 37 | impl ValueCommitment { 38 | pub fn cm( 39 | &self, 40 | params: &E::Params 41 | ) -> edwards::Point 42 | { 43 | params.generator(FixedGenerators::ValueCommitmentValue) 44 | .mul(self.value, params) 45 | .add( 46 | ¶ms.generator(FixedGenerators::ValueCommitmentRandomness) 47 | .mul(self.randomness, params), 48 | params 49 | ) 50 | } 51 | } 52 | 53 | #[derive(Clone)] 54 | pub struct ProofGenerationKey { 55 | pub ak: edwards::Point, 56 | pub nsk: E::Fs 57 | } 58 | 59 | impl ProofGenerationKey { 60 | pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey { 61 | ViewingKey { 62 | ak: self.ak.clone(), 63 | nk: params.generator(FixedGenerators::ProofGenerationKey) 64 | .mul(self.nsk, params) 65 | } 66 | } 67 | } 68 | 69 | pub struct ViewingKey { 70 | pub ak: edwards::Point, 71 | pub nk: edwards::Point 72 | } 73 | 74 | impl ViewingKey { 75 | pub fn rk( 76 | &self, 77 | ar: E::Fs, 78 | params: &E::Params 79 | ) -> edwards::Point { 80 | self.ak.add( 81 | ¶ms.generator(FixedGenerators::SpendingKeyGenerator) 82 | .mul(ar, params), 83 | params 84 | ) 85 | } 86 | 87 | pub fn ivk(&self) -> E::Fs { 88 | let mut preimage = [0; 64]; 89 | 90 | self.ak.write(&mut preimage[0..32]).unwrap(); 91 | self.nk.write(&mut preimage[32..64]).unwrap(); 92 | 93 | let mut h = Blake2s::with_params(32, &[], &[], constants::CRH_IVK_PERSONALIZATION); 94 | h.update(&preimage); 95 | let mut h = h.finalize().as_ref().to_vec(); 96 | 97 | // Drop the most significant five bits, so it can be interpreted as a scalar. 98 | h[31] &= 0b0000_0111; 99 | 100 | let mut e = ::Repr::default(); 101 | e.read_le(&h[..]).unwrap(); 102 | 103 | E::Fs::from_repr(e).expect("should be a valid scalar") 104 | } 105 | 106 | pub fn into_payment_address( 107 | &self, 108 | diversifier: Diversifier, 109 | params: &E::Params 110 | ) -> Option> 111 | { 112 | diversifier.g_d(params).map(|g_d| { 113 | let pk_d = g_d.mul(self.ivk(), params); 114 | 115 | PaymentAddress { 116 | pk_d: pk_d, 117 | diversifier: diversifier 118 | } 119 | }) 120 | } 121 | } 122 | 123 | #[derive(Copy, Clone)] 124 | pub struct Diversifier(pub [u8; 11]); 125 | 126 | impl Diversifier { 127 | pub fn g_d( 128 | &self, 129 | params: &E::Params 130 | ) -> Option> 131 | { 132 | group_hash::(&self.0, constants::KEY_DIVERSIFICATION_PERSONALIZATION, params) 133 | } 134 | } 135 | 136 | #[derive(Clone)] 137 | pub struct PaymentAddress { 138 | pub pk_d: edwards::Point, 139 | pub diversifier: Diversifier 140 | } 141 | 142 | impl PaymentAddress { 143 | pub fn g_d( 144 | &self, 145 | params: &E::Params 146 | ) -> Option> 147 | { 148 | self.diversifier.g_d(params) 149 | } 150 | 151 | pub fn create_note( 152 | &self, 153 | value: u64, 154 | randomness: E::Fs, 155 | params: &E::Params 156 | ) -> Option> 157 | { 158 | self.g_d(params).map(|g_d| { 159 | Note { 160 | value: value, 161 | r: randomness, 162 | g_d: g_d, 163 | pk_d: self.pk_d.clone() 164 | } 165 | }) 166 | } 167 | } 168 | 169 | pub struct Note { 170 | /// The value of the note 171 | pub value: u64, 172 | /// The diversified base of the address, GH(d) 173 | pub g_d: edwards::Point, 174 | /// The public key of the address, g_d^ivk 175 | pub pk_d: edwards::Point, 176 | /// The commitment randomness 177 | pub r: E::Fs 178 | } 179 | 180 | impl Note { 181 | pub fn uncommitted() -> E::Fr { 182 | // The smallest u-coordinate that is not on the curve 183 | // is one. 184 | // TODO: This should be relocated to JubjubEngine as 185 | // it's specific to the curve we're using, not all 186 | // twisted edwards curves. 187 | E::Fr::one() 188 | } 189 | 190 | /// Computes the note commitment, returning the full point. 191 | fn cm_full_point(&self, params: &E::Params) -> edwards::Point 192 | { 193 | // Calculate the note contents, as bytes 194 | let mut note_contents = vec![]; 195 | 196 | // Writing the value in little endian 197 | (&mut note_contents).write_u64::(self.value).unwrap(); 198 | 199 | // Write g_d 200 | self.g_d.write(&mut note_contents).unwrap(); 201 | 202 | // Write pk_d 203 | self.pk_d.write(&mut note_contents).unwrap(); 204 | 205 | assert_eq!(note_contents.len(), 32 + 32 + 8); 206 | 207 | // Compute the Pedersen hash of the note contents 208 | let hash_of_contents = pedersen_hash( 209 | Personalization::NoteCommitment, 210 | note_contents.into_iter() 211 | .flat_map(|byte| { 212 | (0..8).map(move |i| ((byte >> i) & 1) == 1) 213 | }), 214 | params 215 | ); 216 | 217 | // Compute final commitment 218 | params.generator(FixedGenerators::NoteCommitmentRandomness) 219 | .mul(self.r, params) 220 | .add(&hash_of_contents, params) 221 | } 222 | 223 | /// Computes the nullifier given the viewing key and 224 | /// note position 225 | pub fn nf( 226 | &self, 227 | viewing_key: &ViewingKey, 228 | position: u64, 229 | params: &E::Params 230 | ) -> Vec 231 | { 232 | // Compute rho = cm + position.G 233 | let rho = self 234 | .cm_full_point(params) 235 | .add( 236 | ¶ms.generator(FixedGenerators::NullifierPosition) 237 | .mul(position, params), 238 | params 239 | ); 240 | 241 | // Compute nf = BLAKE2s(nk | rho) 242 | let mut nf_preimage = [0u8; 64]; 243 | viewing_key.nk.write(&mut nf_preimage[0..32]).unwrap(); 244 | rho.write(&mut nf_preimage[32..64]).unwrap(); 245 | let mut h = Blake2s::with_params(32, &[], &[], constants::PRF_NF_PERSONALIZATION); 246 | h.update(&nf_preimage); 247 | 248 | h.finalize().as_ref().to_vec() 249 | } 250 | 251 | /// Computes the note commitment 252 | pub fn cm(&self, params: &E::Params) -> E::Fr 253 | { 254 | // The commitment is in the prime order subgroup, so mapping the 255 | // commitment to the x-coordinate is an injective encoding. 256 | self.cm_full_point(params).into_xy().0 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /pairing/src/tests/field.rs: -------------------------------------------------------------------------------- 1 | use ff::{Field, LegendreSymbol, PrimeField, SqrtField}; 2 | use rand::{Rng, SeedableRng, XorShiftRng}; 3 | 4 | pub fn random_frobenius_tests>(characteristic: C, maxpower: usize) { 5 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 6 | 7 | for _ in 0..100 { 8 | for i in 0..(maxpower + 1) { 9 | let mut a = F::rand(&mut rng); 10 | let mut b = a; 11 | 12 | for _ in 0..i { 13 | a = a.pow(&characteristic); 14 | } 15 | b.frobenius_map(i); 16 | 17 | assert_eq!(a, b); 18 | } 19 | } 20 | } 21 | 22 | pub fn random_sqrt_tests() { 23 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 24 | 25 | for _ in 0..10000 { 26 | let a = F::rand(&mut rng); 27 | let mut b = a; 28 | b.square(); 29 | assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); 30 | 31 | let b = b.sqrt().unwrap(); 32 | let mut negb = b; 33 | negb.negate(); 34 | 35 | assert!(a == b || a == negb); 36 | } 37 | 38 | let mut c = F::one(); 39 | for _ in 0..10000 { 40 | let mut b = c; 41 | b.square(); 42 | assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); 43 | 44 | b = b.sqrt().unwrap(); 45 | 46 | if b != c { 47 | b.negate(); 48 | } 49 | 50 | assert_eq!(b, c); 51 | 52 | c.add_assign(&F::one()); 53 | } 54 | } 55 | 56 | pub fn random_field_tests() { 57 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 58 | 59 | random_multiplication_tests::(&mut rng); 60 | random_addition_tests::(&mut rng); 61 | random_subtraction_tests::(&mut rng); 62 | random_negation_tests::(&mut rng); 63 | random_doubling_tests::(&mut rng); 64 | random_squaring_tests::(&mut rng); 65 | random_inversion_tests::(&mut rng); 66 | random_expansion_tests::(&mut rng); 67 | 68 | assert!(F::zero().is_zero()); 69 | { 70 | let mut z = F::zero(); 71 | z.negate(); 72 | assert!(z.is_zero()); 73 | } 74 | 75 | assert!(F::zero().inverse().is_none()); 76 | 77 | // Multiplication by zero 78 | { 79 | let mut a = F::rand(&mut rng); 80 | a.mul_assign(&F::zero()); 81 | assert!(a.is_zero()); 82 | } 83 | 84 | // Addition by zero 85 | { 86 | let mut a = F::rand(&mut rng); 87 | let copy = a; 88 | a.add_assign(&F::zero()); 89 | assert_eq!(a, copy); 90 | } 91 | } 92 | 93 | pub fn from_str_tests() { 94 | { 95 | let a = "84395729384759238745923745892374598234705297301958723458712394587103249587213984572934750213947582345792304758273458972349582734958273495872304598234"; 96 | let b = "38495729084572938457298347502349857029384609283450692834058293405982304598230458230495820394850293845098234059823049582309485203948502938452093482039"; 97 | let c = "3248875134290623212325429203829831876024364170316860259933542844758450336418538569901990710701240661702808867062612075657861768196242274635305077449545396068598317421057721935408562373834079015873933065667961469731886739181625866970316226171512545167081793907058686908697431878454091011239990119126"; 98 | 99 | let mut a = F::from_str(a).unwrap(); 100 | let b = F::from_str(b).unwrap(); 101 | let c = F::from_str(c).unwrap(); 102 | 103 | a.mul_assign(&b); 104 | 105 | assert_eq!(a, c); 106 | } 107 | 108 | { 109 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 110 | 111 | for _ in 0..1000 { 112 | let n: u64 = rng.gen(); 113 | 114 | let a = F::from_str(&format!("{}", n)).unwrap(); 115 | let b = F::from_repr(n.into()).unwrap(); 116 | 117 | assert_eq!(a, b); 118 | } 119 | } 120 | 121 | assert!(F::from_str("").is_none()); 122 | assert!(F::from_str("0").unwrap().is_zero()); 123 | assert!(F::from_str("00").is_none()); 124 | assert!(F::from_str("00000000000").is_none()); 125 | } 126 | 127 | fn random_multiplication_tests(rng: &mut R) { 128 | for _ in 0..10000 { 129 | let a = F::rand(rng); 130 | let b = F::rand(rng); 131 | let c = F::rand(rng); 132 | 133 | let mut t0 = a; // (a * b) * c 134 | t0.mul_assign(&b); 135 | t0.mul_assign(&c); 136 | 137 | let mut t1 = a; // (a * c) * b 138 | t1.mul_assign(&c); 139 | t1.mul_assign(&b); 140 | 141 | let mut t2 = b; // (b * c) * a 142 | t2.mul_assign(&c); 143 | t2.mul_assign(&a); 144 | 145 | assert_eq!(t0, t1); 146 | assert_eq!(t1, t2); 147 | } 148 | } 149 | 150 | fn random_addition_tests(rng: &mut R) { 151 | for _ in 0..10000 { 152 | let a = F::rand(rng); 153 | let b = F::rand(rng); 154 | let c = F::rand(rng); 155 | 156 | let mut t0 = a; // (a + b) + c 157 | t0.add_assign(&b); 158 | t0.add_assign(&c); 159 | 160 | let mut t1 = a; // (a + c) + b 161 | t1.add_assign(&c); 162 | t1.add_assign(&b); 163 | 164 | let mut t2 = b; // (b + c) + a 165 | t2.add_assign(&c); 166 | t2.add_assign(&a); 167 | 168 | assert_eq!(t0, t1); 169 | assert_eq!(t1, t2); 170 | } 171 | } 172 | 173 | fn random_subtraction_tests(rng: &mut R) { 174 | for _ in 0..10000 { 175 | let a = F::rand(rng); 176 | let b = F::rand(rng); 177 | 178 | let mut t0 = a; // (a - b) 179 | t0.sub_assign(&b); 180 | 181 | let mut t1 = b; // (b - a) 182 | t1.sub_assign(&a); 183 | 184 | let mut t2 = t0; // (a - b) + (b - a) = 0 185 | t2.add_assign(&t1); 186 | 187 | assert!(t2.is_zero()); 188 | } 189 | } 190 | 191 | fn random_negation_tests(rng: &mut R) { 192 | for _ in 0..10000 { 193 | let a = F::rand(rng); 194 | let mut b = a; 195 | b.negate(); 196 | b.add_assign(&a); 197 | 198 | assert!(b.is_zero()); 199 | } 200 | } 201 | 202 | fn random_doubling_tests(rng: &mut R) { 203 | for _ in 0..10000 { 204 | let mut a = F::rand(rng); 205 | let mut b = a; 206 | a.add_assign(&b); 207 | b.double(); 208 | 209 | assert_eq!(a, b); 210 | } 211 | } 212 | 213 | fn random_squaring_tests(rng: &mut R) { 214 | for _ in 0..10000 { 215 | let mut a = F::rand(rng); 216 | let mut b = a; 217 | a.mul_assign(&b); 218 | b.square(); 219 | 220 | assert_eq!(a, b); 221 | } 222 | } 223 | 224 | fn random_inversion_tests(rng: &mut R) { 225 | assert!(F::zero().inverse().is_none()); 226 | 227 | for _ in 0..10000 { 228 | let mut a = F::rand(rng); 229 | let b = a.inverse().unwrap(); // probablistically nonzero 230 | a.mul_assign(&b); 231 | 232 | assert_eq!(a, F::one()); 233 | } 234 | } 235 | 236 | fn random_expansion_tests(rng: &mut R) { 237 | for _ in 0..10000 { 238 | // Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d) 239 | 240 | let a = F::rand(rng); 241 | let b = F::rand(rng); 242 | let c = F::rand(rng); 243 | let d = F::rand(rng); 244 | 245 | let mut t0 = a; 246 | t0.add_assign(&b); 247 | let mut t1 = c; 248 | t1.add_assign(&d); 249 | t0.mul_assign(&t1); 250 | 251 | let mut t2 = a; 252 | t2.mul_assign(&c); 253 | let mut t3 = b; 254 | t3.mul_assign(&c); 255 | let mut t4 = a; 256 | t4.mul_assign(&d); 257 | let mut t5 = b; 258 | t5.mul_assign(&d); 259 | 260 | t2.add_assign(&t3); 261 | t2.add_assign(&t4); 262 | t2.add_assign(&t5); 263 | 264 | assert_eq!(t0, t2); 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /bellman/tests/mimc.rs: -------------------------------------------------------------------------------- 1 | extern crate bellman; 2 | extern crate pairing; 3 | extern crate rand; 4 | 5 | // For randomness (during paramgen and proof generation) 6 | use rand::{thread_rng, Rng}; 7 | 8 | // For benchmarking 9 | use std::time::{Duration, Instant}; 10 | 11 | // Bring in some tools for using pairing-friendly curves 12 | use pairing::{ 13 | Engine, 14 | Field 15 | }; 16 | 17 | // We're going to use the BLS12-381 pairing-friendly elliptic curve. 18 | use pairing::bls12_381::{ 19 | Bls12 20 | }; 21 | 22 | // We'll use these interfaces to construct our circuit. 23 | use bellman::{ 24 | Circuit, 25 | ConstraintSystem, 26 | SynthesisError 27 | }; 28 | 29 | // We're going to use the Groth16 proving system. 30 | use bellman::groth16::{ 31 | Proof, 32 | generate_random_parameters, 33 | prepare_verifying_key, 34 | create_random_proof, 35 | verify_proof, 36 | }; 37 | 38 | const MIMC_ROUNDS: usize = 322; 39 | 40 | /// This is an implementation of MiMC, specifically a 41 | /// variant named `LongsightF322p3` for BLS12-381. 42 | /// See http://eprint.iacr.org/2016/492 for more 43 | /// information about this construction. 44 | /// 45 | /// ``` 46 | /// function LongsightF322p3(xL ⦂ Fp, xR ⦂ Fp) { 47 | /// for i from 0 up to 321 { 48 | /// xL, xR := xR + (xL + Ci)^3, xL 49 | /// } 50 | /// return xL 51 | /// } 52 | /// ``` 53 | fn mimc( 54 | mut xl: E::Fr, 55 | mut xr: E::Fr, 56 | constants: &[E::Fr] 57 | ) -> E::Fr 58 | { 59 | assert_eq!(constants.len(), MIMC_ROUNDS); 60 | 61 | for i in 0..MIMC_ROUNDS { 62 | let mut tmp1 = xl; 63 | tmp1.add_assign(&constants[i]); 64 | let mut tmp2 = tmp1; 65 | tmp2.square(); 66 | tmp2.mul_assign(&tmp1); 67 | tmp2.add_assign(&xr); 68 | xr = xl; 69 | xl = tmp2; 70 | } 71 | 72 | xl 73 | } 74 | 75 | /// This is our demo circuit for proving knowledge of the 76 | /// preimage of a MiMC hash invocation. 77 | struct MiMCDemo<'a, E: Engine> { 78 | xl: Option, 79 | xr: Option, 80 | constants: &'a [E::Fr] 81 | } 82 | 83 | /// Our demo circuit implements this `Circuit` trait which 84 | /// is used during paramgen and proving in order to 85 | /// synthesize the constraint system. 86 | impl<'a, E: Engine> Circuit for MiMCDemo<'a, E> { 87 | fn synthesize>( 88 | self, 89 | cs: &mut CS 90 | ) -> Result<(), SynthesisError> 91 | { 92 | assert_eq!(self.constants.len(), MIMC_ROUNDS); 93 | 94 | // Allocate the first component of the preimage. 95 | let mut xl_value = self.xl; 96 | let mut xl = cs.alloc(|| "preimage xl", || { 97 | xl_value.ok_or(SynthesisError::AssignmentMissing) 98 | })?; 99 | 100 | // Allocate the second component of the preimage. 101 | let mut xr_value = self.xr; 102 | let mut xr = cs.alloc(|| "preimage xr", || { 103 | xr_value.ok_or(SynthesisError::AssignmentMissing) 104 | })?; 105 | 106 | for i in 0..MIMC_ROUNDS { 107 | // xL, xR := xR + (xL + Ci)^3, xL 108 | let cs = &mut cs.namespace(|| format!("round {}", i)); 109 | 110 | // tmp = (xL + Ci)^2 111 | let mut tmp_value = xl_value.map(|mut e| { 112 | e.add_assign(&self.constants[i]); 113 | e.square(); 114 | e 115 | }); 116 | let mut tmp = cs.alloc(|| "tmp", || { 117 | tmp_value.ok_or(SynthesisError::AssignmentMissing) 118 | })?; 119 | 120 | cs.enforce( 121 | || "tmp = (xL + Ci)^2", 122 | |lc| lc + xl + (self.constants[i], CS::one()), 123 | |lc| lc + xl + (self.constants[i], CS::one()), 124 | |lc| lc + tmp 125 | ); 126 | 127 | // new_xL = xR + (xL + Ci)^3 128 | // new_xL = xR + tmp * (xL + Ci) 129 | // new_xL - xR = tmp * (xL + Ci) 130 | let mut new_xl_value = xl_value.map(|mut e| { 131 | e.add_assign(&self.constants[i]); 132 | e.mul_assign(&tmp_value.unwrap()); 133 | e.add_assign(&xr_value.unwrap()); 134 | e 135 | }); 136 | 137 | let mut new_xl = if i == (MIMC_ROUNDS-1) { 138 | // This is the last round, xL is our image and so 139 | // we allocate a public input. 140 | cs.alloc_input(|| "image", || { 141 | new_xl_value.ok_or(SynthesisError::AssignmentMissing) 142 | })? 143 | } else { 144 | cs.alloc(|| "new_xl", || { 145 | new_xl_value.ok_or(SynthesisError::AssignmentMissing) 146 | })? 147 | }; 148 | 149 | cs.enforce( 150 | || "new_xL = xR + (xL + Ci)^3", 151 | |lc| lc + tmp, 152 | |lc| lc + xl + (self.constants[i], CS::one()), 153 | |lc| lc + new_xl - xr 154 | ); 155 | 156 | // xR = xL 157 | xr = xl; 158 | xr_value = xl_value; 159 | 160 | // xL = new_xL 161 | xl = new_xl; 162 | xl_value = new_xl_value; 163 | } 164 | 165 | Ok(()) 166 | } 167 | } 168 | 169 | #[test] 170 | fn test_mimc() { 171 | // This may not be cryptographically safe, use 172 | // `OsRng` (for example) in production software. 173 | let rng = &mut thread_rng(); 174 | 175 | // Generate the MiMC round constants 176 | let constants = (0..MIMC_ROUNDS).map(|_| rng.gen()).collect::>(); 177 | 178 | println!("Creating parameters..."); 179 | 180 | // Create parameters for our circuit 181 | let params = { 182 | let c = MiMCDemo:: { 183 | xl: None, 184 | xr: None, 185 | constants: &constants 186 | }; 187 | 188 | generate_random_parameters(c, rng).unwrap() 189 | }; 190 | 191 | // Prepare the verification key (for proof verification) 192 | let pvk = prepare_verifying_key(¶ms.vk); 193 | 194 | println!("Creating proofs..."); 195 | 196 | // Let's benchmark stuff! 197 | const SAMPLES: u32 = 50; 198 | let mut total_proving = Duration::new(0, 0); 199 | let mut total_verifying = Duration::new(0, 0); 200 | 201 | // Just a place to put the proof data, so we can 202 | // benchmark deserialization. 203 | let mut proof_vec = vec![]; 204 | 205 | for _ in 0..SAMPLES { 206 | // Generate a random preimage and compute the image 207 | let xl = rng.gen(); 208 | let xr = rng.gen(); 209 | let image = mimc::(xl, xr, &constants); 210 | 211 | proof_vec.truncate(0); 212 | 213 | let start = Instant::now(); 214 | { 215 | // Create an instance of our circuit (with the 216 | // witness) 217 | let c = MiMCDemo { 218 | xl: Some(xl), 219 | xr: Some(xr), 220 | constants: &constants 221 | }; 222 | 223 | // Create a groth16 proof with our parameters. 224 | let proof = create_random_proof(c, ¶ms, rng).unwrap(); 225 | 226 | proof.write(&mut proof_vec).unwrap(); 227 | } 228 | 229 | total_proving += start.elapsed(); 230 | 231 | let start = Instant::now(); 232 | let proof = Proof::read(&proof_vec[..]).unwrap(); 233 | // Check the proof 234 | assert!(verify_proof( 235 | &pvk, 236 | &proof, 237 | &[image] 238 | ).unwrap()); 239 | total_verifying += start.elapsed(); 240 | } 241 | let proving_avg = total_proving / SAMPLES; 242 | let proving_avg = proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 243 | + (proving_avg.as_secs() as f64); 244 | 245 | let verifying_avg = total_verifying / SAMPLES; 246 | let verifying_avg = verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 247 | + (verifying_avg.as_secs() as f64); 248 | 249 | println!("Average proving time: {:?} seconds", proving_avg); 250 | println!("Average verifying time: {:?} seconds", verifying_avg); 251 | } 252 | -------------------------------------------------------------------------------- /bellman/src/multiexp.rs: -------------------------------------------------------------------------------- 1 | use pairing::{ 2 | CurveAffine, 3 | CurveProjective, 4 | }; 5 | use ff::{ 6 | Field, 7 | PrimeField, 8 | PrimeFieldRepr, 9 | ScalarEngine, 10 | }; 11 | use std::sync::Arc; 12 | use std::io; 13 | use bit_vec::{self, BitVec}; 14 | use std::iter; 15 | use futures::{Future}; 16 | use super::multicore::Worker; 17 | 18 | use super::SynthesisError; 19 | 20 | /// An object that builds a source of bases. 21 | pub trait SourceBuilder: Send + Sync + 'static + Clone { 22 | type Source: Source; 23 | 24 | fn new(self) -> Self::Source; 25 | } 26 | 27 | /// A source of bases, like an iterator. 28 | pub trait Source { 29 | /// Parses the element from the source. Fails if the point is at infinity. 30 | fn add_assign_mixed(&mut self, to: &mut ::Projective) -> Result<(), SynthesisError>; 31 | 32 | /// Skips `amt` elements from the source, avoiding deserialization. 33 | fn skip(&mut self, amt: usize) -> Result<(), SynthesisError>; 34 | } 35 | 36 | impl SourceBuilder for (Arc>, usize) { 37 | type Source = (Arc>, usize); 38 | 39 | fn new(self) -> (Arc>, usize) { 40 | (self.0.clone(), self.1) 41 | } 42 | } 43 | 44 | impl Source for (Arc>, usize) { 45 | fn add_assign_mixed(&mut self, to: &mut ::Projective) -> Result<(), SynthesisError> { 46 | if self.0.len() <= self.1 { 47 | return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); 48 | } 49 | 50 | if self.0[self.1].is_zero() { 51 | return Err(SynthesisError::UnexpectedIdentity) 52 | } 53 | 54 | to.add_assign_mixed(&self.0[self.1]); 55 | 56 | self.1 += 1; 57 | 58 | Ok(()) 59 | } 60 | 61 | fn skip(&mut self, amt: usize) -> Result<(), SynthesisError> { 62 | if self.0.len() <= self.1 { 63 | return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); 64 | } 65 | 66 | self.1 += amt; 67 | 68 | Ok(()) 69 | } 70 | } 71 | 72 | pub trait QueryDensity { 73 | /// Returns whether the base exists. 74 | type Iter: Iterator; 75 | 76 | fn iter(self) -> Self::Iter; 77 | fn get_query_size(self) -> Option; 78 | } 79 | 80 | #[derive(Clone)] 81 | pub struct FullDensity; 82 | 83 | impl AsRef for FullDensity { 84 | fn as_ref(&self) -> &FullDensity { 85 | self 86 | } 87 | } 88 | 89 | impl<'a> QueryDensity for &'a FullDensity { 90 | type Iter = iter::Repeat; 91 | 92 | fn iter(self) -> Self::Iter { 93 | iter::repeat(true) 94 | } 95 | 96 | fn get_query_size(self) -> Option { 97 | None 98 | } 99 | } 100 | 101 | pub struct DensityTracker { 102 | bv: BitVec, 103 | total_density: usize 104 | } 105 | 106 | impl<'a> QueryDensity for &'a DensityTracker { 107 | type Iter = bit_vec::Iter<'a>; 108 | 109 | fn iter(self) -> Self::Iter { 110 | self.bv.iter() 111 | } 112 | 113 | fn get_query_size(self) -> Option { 114 | Some(self.bv.len()) 115 | } 116 | } 117 | 118 | impl DensityTracker { 119 | pub fn new() -> DensityTracker { 120 | DensityTracker { 121 | bv: BitVec::new(), 122 | total_density: 0 123 | } 124 | } 125 | 126 | pub fn add_element(&mut self) { 127 | self.bv.push(false); 128 | } 129 | 130 | pub fn inc(&mut self, idx: usize) { 131 | if !self.bv.get(idx).unwrap() { 132 | self.bv.set(idx, true); 133 | self.total_density += 1; 134 | } 135 | } 136 | 137 | pub fn get_total_density(&self) -> usize { 138 | self.total_density 139 | } 140 | } 141 | 142 | fn multiexp_inner( 143 | pool: &Worker, 144 | bases: S, 145 | density_map: D, 146 | exponents: Arc::Fr as PrimeField>::Repr>>, 147 | mut skip: u32, 148 | c: u32, 149 | handle_trivial: bool 150 | ) -> Box::Projective, Error=SynthesisError>> 151 | where for<'a> &'a Q: QueryDensity, 152 | D: Send + Sync + 'static + Clone + AsRef, 153 | G: CurveAffine, 154 | S: SourceBuilder 155 | { 156 | // Perform this region of the multiexp 157 | let this = { 158 | let bases = bases.clone(); 159 | let exponents = exponents.clone(); 160 | let density_map = density_map.clone(); 161 | 162 | pool.compute(move || { 163 | // Accumulate the result 164 | let mut acc = G::Projective::zero(); 165 | 166 | // Build a source for the bases 167 | let mut bases = bases.new(); 168 | 169 | // Create space for the buckets 170 | let mut buckets = vec![::Projective::zero(); (1 << c) - 1]; 171 | 172 | let zero = ::Fr::zero().into_repr(); 173 | let one = ::Fr::one().into_repr(); 174 | 175 | // Sort the bases into buckets 176 | for (&exp, density) in exponents.iter().zip(density_map.as_ref().iter()) { 177 | if density { 178 | if exp == zero { 179 | bases.skip(1)?; 180 | } else if exp == one { 181 | if handle_trivial { 182 | bases.add_assign_mixed(&mut acc)?; 183 | } else { 184 | bases.skip(1)?; 185 | } 186 | } else { 187 | let mut exp = exp; 188 | exp.shr(skip); 189 | let exp = exp.as_ref()[0] % (1 << c); 190 | 191 | if exp != 0 { 192 | bases.add_assign_mixed(&mut buckets[(exp - 1) as usize])?; 193 | } else { 194 | bases.skip(1)?; 195 | } 196 | } 197 | } 198 | } 199 | 200 | // Summation by parts 201 | // e.g. 3a + 2b + 1c = a + 202 | // (a) + b + 203 | // ((a) + b) + c 204 | let mut running_sum = G::Projective::zero(); 205 | for exp in buckets.into_iter().rev() { 206 | running_sum.add_assign(&exp); 207 | acc.add_assign(&running_sum); 208 | } 209 | 210 | Ok(acc) 211 | }) 212 | }; 213 | 214 | skip += c; 215 | 216 | if skip >= ::Fr::NUM_BITS { 217 | // There isn't another region. 218 | Box::new(this) 219 | } else { 220 | // There's another region more significant. Calculate and join it with 221 | // this region recursively. 222 | Box::new( 223 | this.join(multiexp_inner(pool, bases, density_map, exponents, skip, c, false)) 224 | .map(move |(this, mut higher)| { 225 | for _ in 0..c { 226 | higher.double(); 227 | } 228 | 229 | higher.add_assign(&this); 230 | 231 | higher 232 | }) 233 | ) 234 | } 235 | } 236 | 237 | /// Perform multi-exponentiation. The caller is responsible for ensuring the 238 | /// query size is the same as the number of exponents. 239 | pub fn multiexp( 240 | pool: &Worker, 241 | bases: S, 242 | density_map: D, 243 | exponents: Arc::Fr as PrimeField>::Repr>> 244 | ) -> Box::Projective, Error=SynthesisError>> 245 | where for<'a> &'a Q: QueryDensity, 246 | D: Send + Sync + 'static + Clone + AsRef, 247 | G: CurveAffine, 248 | S: SourceBuilder 249 | { 250 | let c = if exponents.len() < 32 { 251 | 3u32 252 | } else { 253 | (f64::from(exponents.len() as u32)).ln().ceil() as u32 254 | }; 255 | 256 | if let Some(query_size) = density_map.as_ref().get_query_size() { 257 | // If the density map has a known query size, it should not be 258 | // inconsistent with the number of exponents. 259 | 260 | assert!(query_size == exponents.len()); 261 | } 262 | 263 | multiexp_inner(pool, bases, density_map, exponents, 0, c, true) 264 | } 265 | 266 | #[test] 267 | fn test_with_bls12() { 268 | fn naive_multiexp( 269 | bases: Arc>, 270 | exponents: Arc::Repr>> 271 | ) -> G::Projective 272 | { 273 | assert_eq!(bases.len(), exponents.len()); 274 | 275 | let mut acc = G::Projective::zero(); 276 | 277 | for (base, exp) in bases.iter().zip(exponents.iter()) { 278 | acc.add_assign(&base.mul(*exp)); 279 | } 280 | 281 | acc 282 | } 283 | 284 | use rand::{self, Rand}; 285 | use pairing::bls12_381::Bls12; 286 | 287 | const SAMPLES: usize = 1 << 14; 288 | 289 | let rng = &mut rand::thread_rng(); 290 | let v = Arc::new((0..SAMPLES).map(|_| ::Fr::rand(rng).into_repr()).collect::>()); 291 | let g = Arc::new((0..SAMPLES).map(|_| ::G1::rand(rng).into_affine()).collect::>()); 292 | 293 | let naive = naive_multiexp(g.clone(), v.clone()); 294 | 295 | let pool = Worker::new(); 296 | 297 | let fast = multiexp( 298 | &pool, 299 | (g, 0), 300 | FullDensity, 301 | v 302 | ).wait().unwrap(); 303 | 304 | assert_eq!(naive, fast); 305 | } 306 | --------------------------------------------------------------------------------