├── .gitignore ├── .gitlab-ci.yml ├── .travis.yml ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── bellman-verifier ├── Cargo.toml └── src │ ├── dummy_engine.rs │ ├── lib.rs │ └── verifier.rs ├── bellman ├── .gitignore ├── COPYRIGHT ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── src │ ├── domain.rs │ ├── groth16 │ │ ├── generator.rs │ │ ├── mod.rs │ │ ├── prover.rs │ │ ├── tests │ │ │ ├── dummy_engine.rs │ │ │ └── mod.rs │ │ └── verifier.rs │ ├── lib.rs │ ├── multicore.rs │ └── multiexp.rs └── tests │ └── mimc.rs ├── jubjub ├── Cargo.toml └── src │ ├── constants.rs │ ├── group_hash.rs │ ├── jubjub │ ├── edwards.rs │ ├── fs.rs │ ├── mod.rs │ ├── montgomery.rs │ └── tests.rs │ ├── lib.rs │ ├── redjubjub.rs │ └── util.rs ├── pairing ├── .gitignore ├── COPYRIGHT ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ ├── bls12_381 │ │ ├── ec.rs │ │ ├── fq.rs │ │ ├── fq12.rs │ │ ├── fq2.rs │ │ ├── fr.rs │ │ └── mod.rs │ └── pairing_benches.rs └── src │ ├── bls12_381 │ ├── README.md │ ├── ec.rs │ ├── fq.rs │ ├── fq12.rs │ ├── fq2.rs │ ├── fq6.rs │ ├── fr.rs │ ├── mod.rs │ └── tests │ │ ├── g1_compressed_valid_test_vectors.dat │ │ ├── g1_uncompressed_invalid_test_vectors.dat │ │ ├── g1_uncompressed_valid_test_vectors.dat │ │ ├── g2_compressed_valid_test_vectors.dat │ │ ├── g2_uncompressed_valid_test_vectors.dat │ │ └── mod.rs │ ├── lib.rs │ ├── tests │ ├── curve.rs │ ├── engine.rs │ ├── field.rs │ ├── mod.rs │ └── repr.rs │ ├── utils.rs │ └── wnaf.rs ├── sapling-crypto ├── .gitignore ├── COPYRIGHT ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ └── pedersen_hash.rs ├── examples │ └── bench.rs └── src │ ├── circuit │ ├── blake2s.rs │ ├── boolean.rs │ ├── ecc.rs │ ├── lookup.rs │ ├── mod.rs │ ├── multieq.rs │ ├── multipack.rs │ ├── num.rs │ ├── pedersen_hash.rs │ ├── sapling │ │ └── mod.rs │ ├── sha256.rs │ ├── sprout │ │ ├── commitment.rs │ │ ├── input.rs │ │ ├── mod.rs │ │ ├── output.rs │ │ ├── prfs.rs │ │ └── test_vectors.dat │ ├── test │ │ └── mod.rs │ └── uint32.rs │ ├── constants.rs │ ├── group_hash.rs │ ├── jubjub │ ├── edwards.rs │ ├── fs.rs │ ├── mod.rs │ ├── montgomery.rs │ └── tests.rs │ ├── lib.rs │ ├── pedersen_hash.rs │ ├── primitives │ └── mod.rs │ ├── redjubjub.rs │ └── util.rs └── zcash_primitives ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src ├── lib.rs ├── serialize.rs └── transaction ├── components.rs ├── mod.rs ├── sighash.rs └── tests.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | 2 | # /************************************************************************ 3 | # File: .gitlab-ci.yml 4 | # Author: mdr0id 5 | # Date: 9/10/2018 6 | # Description: Used to setup runners/jobs for librustzcash 7 | # Usage: Commit source and the pipeline will trigger the according jobs. 8 | # For now the build and test are done in the same jobs. 9 | # 10 | # Known bugs/missing features: 11 | # 12 | # ************************************************************************/ 13 | 14 | stages: 15 | - build 16 | - test 17 | - deploy 18 | 19 | rust-latest: 20 | stage: build 21 | image: rust:latest 22 | script: 23 | - cargo --verbose --version 24 | - time cargo build --verbose 25 | 26 | rust-nightly: 27 | stage: build 28 | image: rustlang/rust:nightly 29 | script: 30 | - cargo --verbose --version 31 | - cargo build --verbose 32 | allow_failure: true 33 | 34 | librustzcash-test-latest: 35 | stage: test 36 | image: rust:latest 37 | script: 38 | - cargo --verbose --version 39 | - time cargo test --release --verbose 40 | 41 | librustzcash-test-rust-nightly: 42 | stage: test 43 | image: rustlang/rust:nightly 44 | script: 45 | - cargo --verbose --version 46 | - cargo test --release --verbose 47 | allow_failure: true 48 | 49 | #used to manually deploy a given release 50 | librustzcash-rust-rc: 51 | stage: deploy 52 | image: rust:latest 53 | script: 54 | - cargo --verbose --version 55 | - time cargo build --release --verbose 56 | when: manual 57 | 58 | #used to manually deploy a given release 59 | librustzcash-rust-nightly-rc: 60 | stage: deploy 61 | image: rustlang/rust:nightly 62 | script: 63 | - cargo --verbose --version 64 | - cargo build --release --verbose 65 | allow_failure: true 66 | when: manual 67 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - 1.31.0 4 | 5 | cache: cargo 6 | 7 | script: 8 | - cargo test --verbose --release --all 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "bellman", 4 | "pairing", 5 | "sapling-crypto", 6 | "zcash_primitives", 7 | "bellman-verifier", 8 | "jubjub", 9 | ] 10 | 11 | [profile.release] 12 | lto = true 13 | panic = 'abort' 14 | codegen-units = 1 15 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Zcash Company 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zk-proofs for substrate 2 | 3 | This library supports for using zk-SNARKs on [substrate](https://github.com/paritytech/substrate) and is implemented as an extension of [librustzcash](https://github.com/zcash/librustzcash). 4 | 5 | Primary purpose of this library is to be used with [zero-chain](https://github.com/LayerXcom/zero-chain). However, it is designed to be as flexible as possible and might be suited well for any other projects to use zk-SNARKs on Substrate. 6 | 7 | In order to use the bellman-based zk-SNARKS on Substrate, following features are added to this library. 8 | - `no_std` compatible 9 | - some attributes (like `Encode`, `Decode`, etc...)for binary serialization and deserialization. (These codec is implemented as a [parity-codec](https://github.com/paritytech/parity-codec).) 10 | - `Rng` fixes to be compatible with wasm. 11 | 12 | 13 | ## Security Warnings 14 | 15 | These libraries are currently under development and have not been fully-reviewed. 16 | 17 | ## License 18 | 19 | All code in this workspace is licensed under either of 20 | 21 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 22 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 23 | 24 | at your option. 25 | 26 | ### Contribution 27 | 28 | Unless you explicitly state otherwise, any contribution intentionally 29 | submitted for inclusion in the work by you, as defined in the Apache-2.0 30 | license, shall be dual licensed as above, without any additional terms or 31 | conditions. 32 | -------------------------------------------------------------------------------- /bellman-verifier/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bellman-verifier" 3 | version = "0.1.0" 4 | authors = ["osuke "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | rand = { version = "0.4", default-features = false } 9 | parity-codec-derive = { version = "3.0", default-features = false } 10 | parity-codec = { version = "3.0", default-features = false} 11 | serde = { version = "1.0", optional = true, default-features = false } 12 | serde_derive = { version = "1.0", optional = true } 13 | rstd = { package = "sr-std", git = "https://github.com/paritytech/substrate", default-features = false } 14 | pairing = { path = "../pairing", default-features = false } 15 | 16 | [features] 17 | default = ["std"] 18 | std = [ 19 | "rand/std", 20 | "parity-codec/std", 21 | "parity-codec-derive/std", 22 | "serde/std", 23 | "serde_derive", 24 | "rstd/std", 25 | ] 26 | -------------------------------------------------------------------------------- /bellman-verifier/src/verifier.rs: -------------------------------------------------------------------------------- 1 | use pairing::{ 2 | Engine, 3 | CurveProjective, 4 | CurveAffine, 5 | PrimeField 6 | }; 7 | 8 | use super::{ 9 | Proof, 10 | VerifyingKey, 11 | PreparedVerifyingKey, 12 | SynthesisError 13 | }; 14 | 15 | 16 | pub fn prepare_verifying_key( 17 | vk: &VerifyingKey 18 | ) -> PreparedVerifyingKey 19 | { 20 | let mut gamma = vk.gamma_g2; 21 | gamma.negate(); 22 | let mut delta = vk.delta_g2; 23 | delta.negate(); 24 | 25 | PreparedVerifyingKey { 26 | alpha_g1_beta_g2: E::pairing(vk.alpha_g1, vk.beta_g2), 27 | neg_gamma_g2: gamma.prepare(), 28 | neg_delta_g2: delta.prepare(), 29 | ic: vk.ic.clone() 30 | } 31 | } 32 | 33 | pub fn verify_proof<'a, E: Engine>( 34 | pvk: &'a PreparedVerifyingKey, 35 | proof: &Proof, 36 | public_inputs: &[E::Fr] 37 | ) -> Result 38 | { 39 | if (public_inputs.len() + 1) != pvk.ic.len() { 40 | return Err(SynthesisError::MalformedVerifyingKey); 41 | } 42 | 43 | let mut acc = pvk.ic[0].into_projective(); 44 | 45 | for (i, b) in public_inputs.iter().zip(pvk.ic.iter().skip(1)) { 46 | acc.add_assign(&b.mul(i.into_repr())); 47 | } 48 | 49 | // The original verification equation is: 50 | // A * B = alpha * beta + inputs * gamma + C * delta 51 | // ... however, we rearrange it so that it is: 52 | // A * B - inputs * gamma - C * delta = alpha * beta 53 | // or equivalently: 54 | // A * B + inputs * (-gamma) + C * (-delta) = alpha * beta 55 | // which allows us to do a single final exponentiation. 56 | 57 | Ok(E::final_exponentiation( 58 | &E::miller_loop([ 59 | (&proof.a.prepare(), &proof.b.prepare()), 60 | (&acc.into_affine().prepare(), &pvk.neg_gamma_g2), 61 | (&proof.c.prepare(), &pvk.neg_delta_g2) 62 | ].into_iter()) 63 | ).unwrap() == pvk.alpha_g1_beta_g2) 64 | } 65 | 66 | #[cfg(test)] 67 | mod tests { 68 | use super::*; 69 | use super::super::dummy_engine::{Fr, DummyEngine}; 70 | use rstd::num::Wrapping; 71 | 72 | #[test] 73 | fn test_verify() { 74 | let pvk = PreparedVerifyingKey:: { 75 | alpha_g1_beta_g2: Fr(Wrapping(18634)), 76 | neg_gamma_g2: Fr(Wrapping(11181)), 77 | neg_delta_g2: Fr(Wrapping(59032)), 78 | ic: vec![Fr(Wrapping(14034)), Fr(Wrapping(58774))], 79 | }; 80 | 81 | let proof = Proof { 82 | a: Fr(Wrapping(3269)), 83 | b: Fr(Wrapping(471)), 84 | c: Fr(Wrapping(8383)), 85 | }; 86 | 87 | let pub_inp = [Fr(Wrapping(1)); 1]; 88 | 89 | assert!(verify_proof(&pvk, &proof, &pub_inp).unwrap()); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /bellman/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /bellman/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = [ 3 | "Sean Bowe ", 4 | "Osuke Sudo ", 5 | ] 6 | description = "zk-SNARK library" 7 | license = "MIT/Apache-2.0" 8 | name = "bellman" 9 | version = "0.1.0" 10 | 11 | [dependencies] 12 | rand = { version = "0.4", default-features = false } 13 | bit-vec = { git = "https://github.com/osuketh/bit-vec", default-features = false } 14 | futures = { version = "0.1", default-features = false } 15 | byteorder = { version = "1", default-features = false } 16 | parity-codec-derive = { version = "3.0", default-features = false } 17 | parity-codec = { version = "3.0", default-features = false } 18 | serde = { version = "1.0", optional = true, default-features = false } 19 | serde_derive = { version = "1.0", optional = true } 20 | sr-std = { git = "https://github.com/paritytech/substrate", default-features = false } 21 | sr-io = { git = "https://github.com/paritytech/substrate", default-features = false } 22 | pairing = { path = "../pairing" } 23 | futures-cpupool = { version = "0.1", optional = true } 24 | num_cpus = { version = "1", optional = true } 25 | crossbeam = { version = "0.3", optional = true } 26 | 27 | [features] 28 | default = ["std"] 29 | std = [ 30 | "rand/std", 31 | "bit-vec/std", 32 | "futures/use_std", 33 | "byteorder/std", 34 | "parity-codec/std", 35 | "parity-codec-derive/std", 36 | "serde/std", 37 | "serde_derive", 38 | "sr-std/std", 39 | "sr-io/std" 40 | ] 41 | multithread = [ 42 | "futures-cpupool", 43 | "num_cpus", 44 | "crossbeam", 45 | ] 46 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /bellman/src/groth16/verifier.rs: -------------------------------------------------------------------------------- 1 | use pairing::{ 2 | Engine, 3 | CurveProjective, 4 | CurveAffine, 5 | PrimeField 6 | }; 7 | 8 | use super::{ 9 | Proof, 10 | VerifyingKey, 11 | PreparedVerifyingKey 12 | }; 13 | 14 | use ::{ 15 | SynthesisError 16 | }; 17 | 18 | pub fn prepare_verifying_key( 19 | vk: &VerifyingKey 20 | ) -> PreparedVerifyingKey 21 | { 22 | let mut gamma = vk.gamma_g2; 23 | gamma.negate(); 24 | let mut delta = vk.delta_g2; 25 | delta.negate(); 26 | 27 | PreparedVerifyingKey { 28 | alpha_g1_beta_g2: E::pairing(vk.alpha_g1, vk.beta_g2), 29 | neg_gamma_g2: gamma.prepare(), 30 | neg_delta_g2: delta.prepare(), 31 | ic: vk.ic.clone() 32 | } 33 | } 34 | 35 | pub fn verify_proof<'a, E: Engine>( 36 | pvk: &'a PreparedVerifyingKey, 37 | proof: &Proof, 38 | public_inputs: &[E::Fr] 39 | ) -> Result 40 | { 41 | if (public_inputs.len() + 1) != pvk.ic.len() { 42 | return Err(SynthesisError::MalformedVerifyingKey); 43 | } 44 | 45 | let mut acc = pvk.ic[0].into_projective(); 46 | 47 | for (i, b) in public_inputs.iter().zip(pvk.ic.iter().skip(1)) { 48 | acc.add_assign(&b.mul(i.into_repr())); 49 | } 50 | 51 | // The original verification equation is: 52 | // A * B = alpha * beta + inputs * gamma + C * delta 53 | // ... however, we rearrange it so that it is: 54 | // A * B - inputs * gamma - C * delta = alpha * beta 55 | // or equivalently: 56 | // A * B + inputs * (-gamma) + C * (-delta) = alpha * beta 57 | // which allows us to do a single final exponentiation. 58 | 59 | Ok(E::final_exponentiation( 60 | &E::miller_loop([ 61 | (&proof.a.prepare(), &proof.b.prepare()), 62 | (&acc.into_affine().prepare(), &pvk.neg_gamma_g2), 63 | (&proof.c.prepare(), &pvk.neg_delta_g2) 64 | ].into_iter()) 65 | ).unwrap() == pvk.alpha_g1_beta_g2) 66 | } 67 | -------------------------------------------------------------------------------- /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 a thin wrapper around CpuPool and 4 | //! crossbeam but may be extended in the future to 5 | //! allow for various parallelism strategies. 6 | 7 | use futures::{Future, IntoFuture, Poll}; 8 | #[cfg(feature = "multithread")] 9 | use num_cpus; 10 | #[cfg(feature = "multithread")] 11 | use futures_cpupool::{CpuPool, CpuFuture}; 12 | #[cfg(feature = "multithread")] 13 | use crossbeam::{self, Scope}; 14 | #[cfg(not(feature = "multithread"))] 15 | use futures::future::{result, FutureResult}; 16 | 17 | #[cfg(feature = "multithread")] 18 | #[derive(Clone)] 19 | pub struct Worker { 20 | cpus: usize, 21 | pool: CpuPool 22 | } 23 | 24 | #[cfg(feature = "multithread")] 25 | impl Worker { 26 | // We don't expose this outside the library so that 27 | // all `Worker` instances have the same number of 28 | // CPUs configured. 29 | pub(crate) fn new_with_cpus(cpus: usize) -> Worker { 30 | Worker { 31 | cpus: cpus, 32 | pool: CpuPool::new(cpus) 33 | } 34 | } 35 | 36 | pub fn new() -> Worker { 37 | Self::new_with_cpus(num_cpus::get()) 38 | } 39 | 40 | pub fn log_num_cpus(&self) -> u32 { 41 | log2_floor(self.cpus) 42 | } 43 | 44 | pub fn compute( 45 | &self, f: F 46 | ) -> WorkerFuture 47 | where F: FnOnce() -> R + Send + 'static, 48 | R: IntoFuture + 'static, 49 | R::Future: Send + 'static, 50 | R::Item: Send + 'static, 51 | R::Error: Send + 'static 52 | { 53 | WorkerFuture { 54 | future: self.pool.spawn_fn(f) 55 | } 56 | } 57 | 58 | pub fn scope<'a, F, R>( 59 | &self, 60 | elements: usize, 61 | f: F 62 | ) -> R 63 | where F: FnOnce(&Scope<'a>, usize) -> R 64 | { 65 | let chunk_size = if elements < self.cpus { 66 | 1 67 | } else { 68 | elements / self.cpus 69 | }; 70 | 71 | crossbeam::scope(|scope| { 72 | f(scope, chunk_size) 73 | }) 74 | } 75 | } 76 | 77 | #[cfg(feature = "multithread")] 78 | pub struct WorkerFuture { 79 | future: CpuFuture 80 | } 81 | 82 | #[cfg(not(feature = "multithread"))] 83 | #[derive(Clone)] 84 | pub struct Worker {} 85 | 86 | #[cfg(not(feature = "multithread"))] 87 | impl Worker { 88 | 89 | pub fn new() -> Worker { Worker {} } 90 | 91 | pub fn log_num_cpus(&self) -> u32 { 92 | log2_floor(1) 93 | } 94 | 95 | pub fn compute( 96 | &self, f: F 97 | ) -> WorkerFuture 98 | where F: FnOnce() -> R, 99 | R: IntoFuture + 'static, 100 | R::Future: Send + 'static, 101 | R::Item: Send + 'static, 102 | R::Error: Send + 'static 103 | { 104 | let future = f().into_future(); 105 | 106 | WorkerFuture { 107 | future: result(future.wait()) 108 | } 109 | } 110 | 111 | pub fn scope( 112 | &self, 113 | _elements: usize, 114 | f: F 115 | ) -> R 116 | where F: FnOnce(&Scope, usize) -> R 117 | { 118 | 119 | let scope = Scope {}; 120 | f(&scope, 1) 121 | 122 | } 123 | } 124 | 125 | #[cfg(not(feature = "multithread"))] 126 | pub struct Scope { 127 | } 128 | 129 | #[cfg(not(feature = "multithread"))] 130 | impl Scope { 131 | pub fn spawn(&self, f: F) -> T where 132 | F: FnOnce() -> T + Send , T: Send 133 | { 134 | f() 135 | } 136 | 137 | } 138 | 139 | #[cfg(not(feature = "multithread"))] 140 | pub struct WorkerFuture { 141 | future: FutureResult 142 | } 143 | 144 | 145 | impl Future for WorkerFuture { 146 | type Item = T; 147 | type Error = E; 148 | 149 | fn poll(&mut self) -> Poll 150 | { 151 | self.future.poll() 152 | } 153 | } 154 | 155 | fn log2_floor(num: usize) -> u32 { 156 | assert!(num > 0); 157 | 158 | let mut pow = 0; 159 | 160 | while (1 << (pow+1)) <= num { 161 | pow += 1; 162 | } 163 | 164 | pow 165 | } 166 | 167 | #[test] 168 | fn test_log2_floor() { 169 | assert_eq!(log2_floor(1), 0); 170 | assert_eq!(log2_floor(2), 1); 171 | assert_eq!(log2_floor(3), 1); 172 | assert_eq!(log2_floor(4), 2); 173 | assert_eq!(log2_floor(5), 2); 174 | assert_eq!(log2_floor(6), 2); 175 | assert_eq!(log2_floor(7), 2); 176 | assert_eq!(log2_floor(8), 3); 177 | } 178 | -------------------------------------------------------------------------------- /bellman/src/multiexp.rs: -------------------------------------------------------------------------------- 1 | use pairing::{ 2 | CurveAffine, 3 | CurveProjective, 4 | Engine, 5 | PrimeField, 6 | Field, 7 | PrimeFieldRepr 8 | }; 9 | use rstd::prelude::*; 10 | #[cfg(feature = "std")] 11 | use std::sync::Arc; 12 | #[cfg(not(feature = "std"))] 13 | use alloc::sync::Arc; 14 | #[cfg(feature = "std")] 15 | use std::io; 16 | use bit_vec::{self, BitVec}; 17 | use rstd::iter; 18 | use futures::{Future}; 19 | use super::multicore::Worker; 20 | 21 | use super::SynthesisError; 22 | 23 | /// An object that builds a source of bases. 24 | pub trait SourceBuilder: Send + Sync + 'static + Clone { 25 | type Source: Source; 26 | 27 | fn new(self) -> Self::Source; 28 | } 29 | 30 | /// A source of bases, like an iterator. 31 | pub trait Source { 32 | /// Parses the element from the source. Fails if the point is at infinity. 33 | fn add_assign_mixed(&mut self, to: &mut ::Projective) -> Result<(), SynthesisError>; 34 | 35 | /// Skips `amt` elements from the source, avoiding deserialization. 36 | fn skip(&mut self, amt: usize) -> Result<(), SynthesisError>; 37 | } 38 | 39 | impl SourceBuilder for (Arc>, usize) { 40 | type Source = (Arc>, usize); 41 | 42 | fn new(self) -> (Arc>, usize) { 43 | (self.0.clone(), self.1) 44 | } 45 | } 46 | 47 | impl Source for (Arc>, usize) { 48 | fn add_assign_mixed(&mut self, to: &mut ::Projective) -> Result<(), SynthesisError> { 49 | if self.0.len() <= self.1 { 50 | #[cfg(feature = "std")] 51 | return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); 52 | #[cfg(not(feature = "std"))] 53 | return Err(SynthesisError::IoError); 54 | } 55 | 56 | if self.0[self.1].is_zero() { 57 | return Err(SynthesisError::UnexpectedIdentity) 58 | } 59 | 60 | to.add_assign_mixed(&self.0[self.1]); 61 | 62 | self.1 += 1; 63 | 64 | Ok(()) 65 | } 66 | 67 | fn skip(&mut self, amt: usize) -> Result<(), SynthesisError> { 68 | if self.0.len() <= self.1 { 69 | #[cfg(feature = "std")] 70 | return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); 71 | #[cfg(not(feature = "std"))] 72 | return Err(SynthesisError::IoError); 73 | } 74 | 75 | self.1 += amt; 76 | 77 | Ok(()) 78 | } 79 | } 80 | 81 | pub trait QueryDensity { 82 | /// Returns whether the base exists. 83 | type Iter: Iterator; 84 | 85 | fn iter(self) -> Self::Iter; 86 | fn get_query_size(self) -> Option; 87 | } 88 | 89 | #[derive(Clone)] 90 | pub struct FullDensity; 91 | 92 | impl AsRef for FullDensity { 93 | fn as_ref(&self) -> &FullDensity { 94 | self 95 | } 96 | } 97 | 98 | impl<'a> QueryDensity for &'a FullDensity { 99 | type Iter = iter::Repeat; 100 | 101 | fn iter(self) -> Self::Iter { 102 | iter::repeat(true) 103 | } 104 | 105 | fn get_query_size(self) -> Option { 106 | None 107 | } 108 | } 109 | 110 | pub struct DensityTracker { 111 | bv: BitVec, 112 | total_density: usize 113 | } 114 | 115 | impl<'a> QueryDensity for &'a DensityTracker { 116 | type Iter = bit_vec::Iter<'a>; 117 | 118 | fn iter(self) -> Self::Iter { 119 | self.bv.iter() 120 | } 121 | 122 | fn get_query_size(self) -> Option { 123 | Some(self.bv.len()) 124 | } 125 | } 126 | 127 | impl DensityTracker { 128 | pub fn new() -> DensityTracker { 129 | DensityTracker { 130 | bv: BitVec::new(), 131 | total_density: 0 132 | } 133 | } 134 | 135 | pub fn add_element(&mut self) { 136 | self.bv.push(false); 137 | } 138 | 139 | pub fn inc(&mut self, idx: usize) { 140 | if !self.bv.get(idx).unwrap() { 141 | self.bv.set(idx, true); 142 | self.total_density += 1; 143 | } 144 | } 145 | 146 | pub fn get_total_density(&self) -> usize { 147 | self.total_density 148 | } 149 | } 150 | 151 | fn multiexp_inner( 152 | pool: &Worker, 153 | bases: S, 154 | density_map: D, 155 | exponents: Arc::Fr as PrimeField>::Repr>>, 156 | mut skip: u32, 157 | c: u32, 158 | handle_trivial: bool 159 | ) -> Box::Projective, Error=SynthesisError>> 160 | where for<'a> &'a Q: QueryDensity, 161 | D: Send + Sync + 'static + Clone + AsRef, 162 | G: CurveAffine, 163 | S: SourceBuilder 164 | { 165 | // Perform this region of the multiexp 166 | let this = { 167 | let bases = bases.clone(); 168 | let exponents = exponents.clone(); 169 | let density_map = density_map.clone(); 170 | 171 | pool.compute(move || { 172 | // Accumulate the result 173 | let mut acc = G::Projective::zero(); 174 | 175 | // Build a source for the bases 176 | let mut bases = bases.new(); 177 | 178 | // Create space for the buckets 179 | let mut buckets = vec![::Projective::zero(); (1 << c) - 1]; 180 | 181 | let zero = ::Fr::zero().into_repr(); 182 | let one = ::Fr::one().into_repr(); 183 | 184 | // Sort the bases into buckets 185 | for (&exp, density) in exponents.iter().zip(density_map.as_ref().iter()) { 186 | if density { 187 | if exp == zero { 188 | bases.skip(1)?; 189 | } else if exp == one { 190 | if handle_trivial { 191 | bases.add_assign_mixed(&mut acc)?; 192 | } else { 193 | bases.skip(1)?; 194 | } 195 | } else { 196 | let mut exp = exp; 197 | exp.shr(skip); 198 | let exp = exp.as_ref()[0] % (1 << c); 199 | 200 | if exp != 0 { 201 | bases.add_assign_mixed(&mut buckets[(exp - 1) as usize])?; 202 | } else { 203 | bases.skip(1)?; 204 | } 205 | } 206 | } 207 | } 208 | 209 | // Summation by parts 210 | // e.g. 3a + 2b + 1c = a + 211 | // (a) + b + 212 | // ((a) + b) + c 213 | let mut running_sum = G::Projective::zero(); 214 | for exp in buckets.into_iter().rev() { 215 | running_sum.add_assign(&exp); 216 | acc.add_assign(&running_sum); 217 | } 218 | 219 | Ok(acc) 220 | }) 221 | }; 222 | 223 | skip += c; 224 | 225 | if skip >= ::Fr::NUM_BITS { 226 | // There isn't another region. 227 | Box::new(this) 228 | } else { 229 | // There's another region more significant. Calculate and join it with 230 | // this region recursively. 231 | Box::new( 232 | this.join(multiexp_inner(pool, bases, density_map, exponents, skip, c, false)) 233 | .map(move |(this, mut higher)| { 234 | for _ in 0..c { 235 | higher.double(); 236 | } 237 | 238 | higher.add_assign(&this); 239 | 240 | higher 241 | }) 242 | ) 243 | } 244 | } 245 | 246 | /// Perform multi-exponentiation. The caller is responsible for ensuring the 247 | /// query size is the same as the number of exponents. 248 | pub fn multiexp( 249 | pool: &Worker, 250 | bases: S, 251 | density_map: D, 252 | exponents: Arc::Fr as PrimeField>::Repr>> 253 | ) -> Box::Projective, Error=SynthesisError>> 254 | where for<'a> &'a Q: QueryDensity, 255 | D: Send + Sync + 'static + Clone + AsRef, 256 | G: CurveAffine, 257 | S: SourceBuilder 258 | { 259 | let c = if exponents.len() < 32 { 260 | 3u32 261 | } else { 262 | (f64::from(exponents.len() as u32)).ln().ceil() as u32 263 | }; 264 | 265 | if let Some(query_size) = density_map.as_ref().get_query_size() { 266 | // If the density map has a known query size, it should not be 267 | // inconsistent with the number of exponents. 268 | 269 | assert!(query_size == exponents.len()); 270 | } 271 | 272 | multiexp_inner(pool, bases, density_map, exponents, 0, c, true) 273 | } 274 | 275 | #[test] 276 | fn test_with_bls12() { 277 | fn naive_multiexp( 278 | bases: Arc>, 279 | exponents: Arc::Repr>> 280 | ) -> G::Projective 281 | { 282 | assert_eq!(bases.len(), exponents.len()); 283 | 284 | let mut acc = G::Projective::zero(); 285 | 286 | for (base, exp) in bases.iter().zip(exponents.iter()) { 287 | acc.add_assign(&base.mul(*exp)); 288 | } 289 | 290 | acc 291 | } 292 | 293 | use rand::{self, Rand}; 294 | use pairing::bls12_381::Bls12; 295 | 296 | const SAMPLES: usize = 1 << 14; 297 | 298 | let rng = &mut rand::thread_rng(); 299 | let v = Arc::new((0..SAMPLES).map(|_| ::Fr::rand(rng).into_repr()).collect::>()); 300 | let g = Arc::new((0..SAMPLES).map(|_| ::G1::rand(rng).into_affine()).collect::>()); 301 | 302 | let naive = naive_multiexp(g.clone(), v.clone()); 303 | 304 | let pool = Worker::new(); 305 | 306 | let fast = multiexp( 307 | &pool, 308 | (g, 0), 309 | FullDensity, 310 | v 311 | ).wait().unwrap(); 312 | 313 | assert_eq!(naive, fast); 314 | } 315 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /jubjub/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jubjub" 3 | version = "0.1.0" 4 | authors = ["osuke "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | rstd = { package = "sr-std", git = "https://github.com/paritytech/substrate", default-features = false } 9 | pairing = { path = "../pairing", default-features = false } 10 | byteorder = { version = "1", default-features = false } 11 | rand = { version = "0.4", default-features = false } 12 | parity-codec-derive = { version = "3.0", default-features = false } 13 | parity-codec = { version = "3.0", default-features = false} 14 | hex-literal = { version = "0.1", optional = true } 15 | 16 | [dependencies.blake2-rfc] 17 | git = "https://github.com/gtank/blake2-rfc" 18 | rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" 19 | default-features = false 20 | 21 | [features] 22 | default = ["std"] 23 | std = [ 24 | "rstd/std", 25 | "pairing/std", 26 | "byteorder/std", 27 | "rand/std", 28 | "parity-codec/std", 29 | "parity-codec-derive/std", 30 | "hex-literal", 31 | ] 32 | -------------------------------------------------------------------------------- /jubjub/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 | -------------------------------------------------------------------------------- /jubjub/src/group_hash.rs: -------------------------------------------------------------------------------- 1 | use crate::jubjub::{ 2 | JubjubEngine, 3 | PrimeOrder, 4 | edwards 5 | }; 6 | 7 | use pairing::{ 8 | PrimeField 9 | }; 10 | 11 | use blake2_rfc::blake2s::Blake2s; 12 | use crate::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 | -------------------------------------------------------------------------------- /jubjub/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate parity_codec_derive; 3 | 4 | #[cfg(test)] 5 | #[macro_use] 6 | extern crate hex_literal; 7 | 8 | pub mod jubjub; 9 | pub mod group_hash; 10 | pub mod constants; 11 | pub mod redjubjub; 12 | pub mod util; 13 | -------------------------------------------------------------------------------- /jubjub/src/util.rs: -------------------------------------------------------------------------------- 1 | use blake2_rfc::blake2b::Blake2b; 2 | 3 | use crate::jubjub::{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/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /pairing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pairing" 3 | 4 | # Remember to change version string in README.md. 5 | version = "0.14.2" 6 | authors = [ 7 | "Sean Bowe ", 8 | "Osuke Sudo ", 9 | ] 10 | license = "MIT/Apache-2.0" 11 | description = "Pairing-friendly elliptic curve library" 12 | 13 | 14 | [dependencies] 15 | rand = { version = "0.4", default-features = false } 16 | byteorder = { version = "1", default-features = false } 17 | parity-codec-derive = { version = "3.0", default-features = false } 18 | parity-codec = { version = "3.0", default-features = false } 19 | serde = { version = "1.0", optional = true, default-features = false } 20 | serde_derive = { version = "1.0", optional = true } 21 | sr-std = { git = "https://github.com/paritytech/substrate", default-features = false } 22 | 23 | [features] 24 | unstable-features = ["expose-arith"] 25 | expose-arith = [] 26 | u128-support = [] 27 | default = ["std"] 28 | std = [ 29 | "rand/std", 30 | "byteorder/std", 31 | "parity-codec/std", 32 | "parity-codec-derive/std", 33 | "serde/std", 34 | "serde_derive", 35 | "sr-std/std", 36 | ] 37 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /pairing/README.md: -------------------------------------------------------------------------------- 1 | # pairing [![Crates.io](https://img.shields.io/crates/v/pairing.svg)](https://crates.io/crates/pairing) # 2 | 3 | This is a Rust crate for using pairing-friendly elliptic curves. Currently, only the [BLS12-381](https://z.cash/blog/new-snark-curve.html) construction is implemented. 4 | 5 | ## [Documentation](https://docs.rs/pairing/) 6 | 7 | Bring the `pairing` crate into your project just as you normally would. 8 | 9 | If you're using a supported platform and the nightly Rust compiler, you can enable the `u128-support` feature for faster arithmetic. 10 | 11 | ```toml 12 | [dependencies.pairing] 13 | version = "0.14" 14 | features = ["u128-support"] 15 | ``` 16 | 17 | ## Security Warnings 18 | 19 | This library does not make any guarantees about constant-time operations, memory access patterns, or resistance to side-channel attacks. 20 | 21 | ## License 22 | 23 | Licensed under either of 24 | 25 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 26 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 27 | 28 | at your option. 29 | 30 | ### Contribution 31 | 32 | Unless you explicitly state otherwise, any contribution intentionally 33 | submitted for inclusion in the work by you, as defined in the Apache-2.0 34 | license, shall be dual licensed as above, without any additional terms or 35 | conditions. 36 | -------------------------------------------------------------------------------- /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/benches/bls12_381/fq.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rand, SeedableRng, XorShiftRng}; 2 | 3 | use pairing::bls12_381::*; 4 | use pairing::{Field, PrimeField, PrimeFieldRepr, SqrtField}; 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/fq12.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rand, SeedableRng, XorShiftRng}; 2 | 3 | use pairing::bls12_381::*; 4 | use pairing::Field; 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/fq2.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rand, SeedableRng, XorShiftRng}; 2 | 3 | use pairing::bls12_381::*; 4 | use pairing::{Field, SqrtField}; 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/fr.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rand, SeedableRng, XorShiftRng}; 2 | 3 | use pairing::bls12_381::*; 4 | use pairing::{Field, PrimeField, PrimeFieldRepr, SqrtField}; 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/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/pairing_benches.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate pairing; 4 | extern crate rand; 5 | extern crate test; 6 | 7 | mod bls12_381; 8 | -------------------------------------------------------------------------------- /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/bls12_381/fq12.rs: -------------------------------------------------------------------------------- 1 | use super::fq::FROBENIUS_COEFF_FQ12_C1; 2 | use super::fq2::Fq2; 3 | use super::fq6::Fq6; 4 | use rand::{Rand, Rng}; 5 | use Field; 6 | use core::fmt; 7 | 8 | /// An element of Fq12, represented by c0 + c1 * w. 9 | #[derive(Copy, Clone, Debug, Eq, PartialEq, Encode, Decode, Default)] 10 | pub struct Fq12 { 11 | pub c0: Fq6, 12 | pub c1: Fq6, 13 | } 14 | 15 | impl fmt::Display for Fq12 { 16 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 17 | write!(f, "Fq12({} + {} * w)", self.c0, self.c1) 18 | } 19 | } 20 | 21 | impl Rand for Fq12 { 22 | fn rand(rng: &mut R) -> Self { 23 | Fq12 { 24 | c0: rng.gen(), 25 | c1: rng.gen(), 26 | } 27 | } 28 | } 29 | 30 | impl Fq12 { 31 | pub fn conjugate(&mut self) { 32 | self.c1.negate(); 33 | } 34 | 35 | pub fn mul_by_014(&mut self, c0: &Fq2, c1: &Fq2, c4: &Fq2) { 36 | let mut aa = self.c0; 37 | aa.mul_by_01(c0, c1); 38 | let mut bb = self.c1; 39 | bb.mul_by_1(c4); 40 | let mut o = *c1; 41 | o.add_assign(c4); 42 | self.c1.add_assign(&self.c0); 43 | self.c1.mul_by_01(c0, &o); 44 | self.c1.sub_assign(&aa); 45 | self.c1.sub_assign(&bb); 46 | self.c0 = bb; 47 | self.c0.mul_by_nonresidue(); 48 | self.c0.add_assign(&aa); 49 | } 50 | } 51 | 52 | impl Field for Fq12 { 53 | fn zero() -> Self { 54 | Fq12 { 55 | c0: Fq6::zero(), 56 | c1: Fq6::zero(), 57 | } 58 | } 59 | 60 | fn one() -> Self { 61 | Fq12 { 62 | c0: Fq6::one(), 63 | c1: Fq6::zero(), 64 | } 65 | } 66 | 67 | fn is_zero(&self) -> bool { 68 | self.c0.is_zero() && self.c1.is_zero() 69 | } 70 | 71 | fn double(&mut self) { 72 | self.c0.double(); 73 | self.c1.double(); 74 | } 75 | 76 | fn negate(&mut self) { 77 | self.c0.negate(); 78 | self.c1.negate(); 79 | } 80 | 81 | fn add_assign(&mut self, other: &Self) { 82 | self.c0.add_assign(&other.c0); 83 | self.c1.add_assign(&other.c1); 84 | } 85 | 86 | fn sub_assign(&mut self, other: &Self) { 87 | self.c0.sub_assign(&other.c0); 88 | self.c1.sub_assign(&other.c1); 89 | } 90 | 91 | fn frobenius_map(&mut self, power: usize) { 92 | self.c0.frobenius_map(power); 93 | self.c1.frobenius_map(power); 94 | 95 | self.c1.c0.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); 96 | self.c1.c1.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); 97 | self.c1.c2.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); 98 | } 99 | 100 | fn square(&mut self) { 101 | let mut ab = self.c0; 102 | ab.mul_assign(&self.c1); 103 | let mut c0c1 = self.c0; 104 | c0c1.add_assign(&self.c1); 105 | let mut c0 = self.c1; 106 | c0.mul_by_nonresidue(); 107 | c0.add_assign(&self.c0); 108 | c0.mul_assign(&c0c1); 109 | c0.sub_assign(&ab); 110 | self.c1 = ab; 111 | self.c1.add_assign(&ab); 112 | ab.mul_by_nonresidue(); 113 | c0.sub_assign(&ab); 114 | self.c0 = c0; 115 | } 116 | 117 | fn mul_assign(&mut self, other: &Self) { 118 | let mut aa = self.c0; 119 | aa.mul_assign(&other.c0); 120 | let mut bb = self.c1; 121 | bb.mul_assign(&other.c1); 122 | let mut o = other.c0; 123 | o.add_assign(&other.c1); 124 | self.c1.add_assign(&self.c0); 125 | self.c1.mul_assign(&o); 126 | self.c1.sub_assign(&aa); 127 | self.c1.sub_assign(&bb); 128 | self.c0 = bb; 129 | self.c0.mul_by_nonresidue(); 130 | self.c0.add_assign(&aa); 131 | } 132 | 133 | fn inverse(&self) -> Option { 134 | let mut c0s = self.c0; 135 | c0s.square(); 136 | let mut c1s = self.c1; 137 | c1s.square(); 138 | c1s.mul_by_nonresidue(); 139 | c0s.sub_assign(&c1s); 140 | 141 | c0s.inverse().map(|t| { 142 | let mut tmp = Fq12 { c0: t, c1: t }; 143 | tmp.c0.mul_assign(&self.c0); 144 | tmp.c1.mul_assign(&self.c1); 145 | tmp.c1.negate(); 146 | 147 | tmp 148 | }) 149 | } 150 | } 151 | 152 | #[cfg(test)] 153 | use rand::{SeedableRng, XorShiftRng}; 154 | 155 | #[test] 156 | fn test_fq12_mul_by_014() { 157 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 158 | 159 | for _ in 0..1000 { 160 | let c0 = Fq2::rand(&mut rng); 161 | let c1 = Fq2::rand(&mut rng); 162 | let c5 = Fq2::rand(&mut rng); 163 | let mut a = Fq12::rand(&mut rng); 164 | let mut b = a; 165 | 166 | a.mul_by_014(&c0, &c1, &c5); 167 | b.mul_assign(&Fq12 { 168 | c0: Fq6 { 169 | c0: c0, 170 | c1: c1, 171 | c2: Fq2::zero(), 172 | }, 173 | c1: Fq6 { 174 | c0: Fq2::zero(), 175 | c1: c5, 176 | c2: Fq2::zero(), 177 | }, 178 | }); 179 | 180 | assert_eq!(a, b); 181 | } 182 | } 183 | 184 | #[test] 185 | fn fq12_field_tests() { 186 | use PrimeField; 187 | 188 | ::tests::field::random_field_tests::(); 189 | ::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); 190 | } 191 | -------------------------------------------------------------------------------- /pairing/src/bls12_381/fq6.rs: -------------------------------------------------------------------------------- 1 | use super::fq::{FROBENIUS_COEFF_FQ6_C1, FROBENIUS_COEFF_FQ6_C2}; 2 | use super::fq2::Fq2; 3 | use rand::{Rand, Rng}; 4 | use Field; 5 | use core::fmt; 6 | 7 | /// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2). 8 | #[derive(Copy, Clone, Debug, Eq, PartialEq, Encode, Decode, Default)] 9 | pub struct Fq6 { 10 | pub c0: Fq2, 11 | pub c1: Fq2, 12 | pub c2: Fq2, 13 | } 14 | 15 | impl fmt::Display for Fq6 { 16 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 17 | write!(f, "Fq6({} + {} * v, {} * v^2)", self.c0, self.c1, self.c2) 18 | } 19 | } 20 | 21 | impl Rand for Fq6 { 22 | fn rand(rng: &mut R) -> Self { 23 | Fq6 { 24 | c0: rng.gen(), 25 | c1: rng.gen(), 26 | c2: rng.gen(), 27 | } 28 | } 29 | } 30 | 31 | impl Fq6 { 32 | /// Multiply by quadratic nonresidue v. 33 | pub fn mul_by_nonresidue(&mut self) { 34 | use rstd::mem::swap; 35 | swap(&mut self.c0, &mut self.c1); 36 | swap(&mut self.c0, &mut self.c2); 37 | 38 | self.c0.mul_by_nonresidue(); 39 | } 40 | 41 | pub fn mul_by_1(&mut self, c1: &Fq2) { 42 | let mut b_b = self.c1; 43 | b_b.mul_assign(c1); 44 | 45 | let mut t1 = *c1; 46 | { 47 | let mut tmp = self.c1; 48 | tmp.add_assign(&self.c2); 49 | 50 | t1.mul_assign(&tmp); 51 | t1.sub_assign(&b_b); 52 | t1.mul_by_nonresidue(); 53 | } 54 | 55 | let mut t2 = *c1; 56 | { 57 | let mut tmp = self.c0; 58 | tmp.add_assign(&self.c1); 59 | 60 | t2.mul_assign(&tmp); 61 | t2.sub_assign(&b_b); 62 | } 63 | 64 | self.c0 = t1; 65 | self.c1 = t2; 66 | self.c2 = b_b; 67 | } 68 | 69 | pub fn mul_by_01(&mut self, c0: &Fq2, c1: &Fq2) { 70 | let mut a_a = self.c0; 71 | let mut b_b = self.c1; 72 | a_a.mul_assign(c0); 73 | b_b.mul_assign(c1); 74 | 75 | let mut t1 = *c1; 76 | { 77 | let mut tmp = self.c1; 78 | tmp.add_assign(&self.c2); 79 | 80 | t1.mul_assign(&tmp); 81 | t1.sub_assign(&b_b); 82 | t1.mul_by_nonresidue(); 83 | t1.add_assign(&a_a); 84 | } 85 | 86 | let mut t3 = *c0; 87 | { 88 | let mut tmp = self.c0; 89 | tmp.add_assign(&self.c2); 90 | 91 | t3.mul_assign(&tmp); 92 | t3.sub_assign(&a_a); 93 | t3.add_assign(&b_b); 94 | } 95 | 96 | let mut t2 = *c0; 97 | t2.add_assign(c1); 98 | { 99 | let mut tmp = self.c0; 100 | tmp.add_assign(&self.c1); 101 | 102 | t2.mul_assign(&tmp); 103 | t2.sub_assign(&a_a); 104 | t2.sub_assign(&b_b); 105 | } 106 | 107 | self.c0 = t1; 108 | self.c1 = t2; 109 | self.c2 = t3; 110 | } 111 | } 112 | 113 | impl Field for Fq6 { 114 | fn zero() -> Self { 115 | Fq6 { 116 | c0: Fq2::zero(), 117 | c1: Fq2::zero(), 118 | c2: Fq2::zero(), 119 | } 120 | } 121 | 122 | fn one() -> Self { 123 | Fq6 { 124 | c0: Fq2::one(), 125 | c1: Fq2::zero(), 126 | c2: Fq2::zero(), 127 | } 128 | } 129 | 130 | fn is_zero(&self) -> bool { 131 | self.c0.is_zero() && self.c1.is_zero() && self.c2.is_zero() 132 | } 133 | 134 | fn double(&mut self) { 135 | self.c0.double(); 136 | self.c1.double(); 137 | self.c2.double(); 138 | } 139 | 140 | fn negate(&mut self) { 141 | self.c0.negate(); 142 | self.c1.negate(); 143 | self.c2.negate(); 144 | } 145 | 146 | fn add_assign(&mut self, other: &Self) { 147 | self.c0.add_assign(&other.c0); 148 | self.c1.add_assign(&other.c1); 149 | self.c2.add_assign(&other.c2); 150 | } 151 | 152 | fn sub_assign(&mut self, other: &Self) { 153 | self.c0.sub_assign(&other.c0); 154 | self.c1.sub_assign(&other.c1); 155 | self.c2.sub_assign(&other.c2); 156 | } 157 | 158 | fn frobenius_map(&mut self, power: usize) { 159 | self.c0.frobenius_map(power); 160 | self.c1.frobenius_map(power); 161 | self.c2.frobenius_map(power); 162 | 163 | self.c1.mul_assign(&FROBENIUS_COEFF_FQ6_C1[power % 6]); 164 | self.c2.mul_assign(&FROBENIUS_COEFF_FQ6_C2[power % 6]); 165 | } 166 | 167 | fn square(&mut self) { 168 | let mut s0 = self.c0; 169 | s0.square(); 170 | let mut ab = self.c0; 171 | ab.mul_assign(&self.c1); 172 | let mut s1 = ab; 173 | s1.double(); 174 | let mut s2 = self.c0; 175 | s2.sub_assign(&self.c1); 176 | s2.add_assign(&self.c2); 177 | s2.square(); 178 | let mut bc = self.c1; 179 | bc.mul_assign(&self.c2); 180 | let mut s3 = bc; 181 | s3.double(); 182 | let mut s4 = self.c2; 183 | s4.square(); 184 | 185 | self.c0 = s3; 186 | self.c0.mul_by_nonresidue(); 187 | self.c0.add_assign(&s0); 188 | 189 | self.c1 = s4; 190 | self.c1.mul_by_nonresidue(); 191 | self.c1.add_assign(&s1); 192 | 193 | self.c2 = s1; 194 | self.c2.add_assign(&s2); 195 | self.c2.add_assign(&s3); 196 | self.c2.sub_assign(&s0); 197 | self.c2.sub_assign(&s4); 198 | } 199 | 200 | fn mul_assign(&mut self, other: &Self) { 201 | let mut a_a = self.c0; 202 | let mut b_b = self.c1; 203 | let mut c_c = self.c2; 204 | a_a.mul_assign(&other.c0); 205 | b_b.mul_assign(&other.c1); 206 | c_c.mul_assign(&other.c2); 207 | 208 | let mut t1 = other.c1; 209 | t1.add_assign(&other.c2); 210 | { 211 | let mut tmp = self.c1; 212 | tmp.add_assign(&self.c2); 213 | 214 | t1.mul_assign(&tmp); 215 | t1.sub_assign(&b_b); 216 | t1.sub_assign(&c_c); 217 | t1.mul_by_nonresidue(); 218 | t1.add_assign(&a_a); 219 | } 220 | 221 | let mut t3 = other.c0; 222 | t3.add_assign(&other.c2); 223 | { 224 | let mut tmp = self.c0; 225 | tmp.add_assign(&self.c2); 226 | 227 | t3.mul_assign(&tmp); 228 | t3.sub_assign(&a_a); 229 | t3.add_assign(&b_b); 230 | t3.sub_assign(&c_c); 231 | } 232 | 233 | let mut t2 = other.c0; 234 | t2.add_assign(&other.c1); 235 | { 236 | let mut tmp = self.c0; 237 | tmp.add_assign(&self.c1); 238 | 239 | t2.mul_assign(&tmp); 240 | t2.sub_assign(&a_a); 241 | t2.sub_assign(&b_b); 242 | c_c.mul_by_nonresidue(); 243 | t2.add_assign(&c_c); 244 | } 245 | 246 | self.c0 = t1; 247 | self.c1 = t2; 248 | self.c2 = t3; 249 | } 250 | 251 | fn inverse(&self) -> Option { 252 | let mut c0 = self.c2; 253 | c0.mul_by_nonresidue(); 254 | c0.mul_assign(&self.c1); 255 | c0.negate(); 256 | { 257 | let mut c0s = self.c0; 258 | c0s.square(); 259 | c0.add_assign(&c0s); 260 | } 261 | let mut c1 = self.c2; 262 | c1.square(); 263 | c1.mul_by_nonresidue(); 264 | { 265 | let mut c01 = self.c0; 266 | c01.mul_assign(&self.c1); 267 | c1.sub_assign(&c01); 268 | } 269 | let mut c2 = self.c1; 270 | c2.square(); 271 | { 272 | let mut c02 = self.c0; 273 | c02.mul_assign(&self.c2); 274 | c2.sub_assign(&c02); 275 | } 276 | 277 | let mut tmp1 = self.c2; 278 | tmp1.mul_assign(&c1); 279 | let mut tmp2 = self.c1; 280 | tmp2.mul_assign(&c2); 281 | tmp1.add_assign(&tmp2); 282 | tmp1.mul_by_nonresidue(); 283 | tmp2 = self.c0; 284 | tmp2.mul_assign(&c0); 285 | tmp1.add_assign(&tmp2); 286 | 287 | match tmp1.inverse() { 288 | Some(t) => { 289 | let mut tmp = Fq6 { 290 | c0: t, 291 | c1: t, 292 | c2: t, 293 | }; 294 | tmp.c0.mul_assign(&c0); 295 | tmp.c1.mul_assign(&c1); 296 | tmp.c2.mul_assign(&c2); 297 | 298 | Some(tmp) 299 | } 300 | None => None, 301 | } 302 | } 303 | } 304 | 305 | #[cfg(test)] 306 | use rand::{SeedableRng, XorShiftRng}; 307 | 308 | #[test] 309 | fn test_fq6_mul_nonresidue() { 310 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 311 | 312 | let nqr = Fq6 { 313 | c0: Fq2::zero(), 314 | c1: Fq2::one(), 315 | c2: Fq2::zero(), 316 | }; 317 | 318 | for _ in 0..1000 { 319 | let mut a = Fq6::rand(&mut rng); 320 | let mut b = a; 321 | a.mul_by_nonresidue(); 322 | b.mul_assign(&nqr); 323 | 324 | assert_eq!(a, b); 325 | } 326 | } 327 | 328 | #[test] 329 | fn test_fq6_mul_by_1() { 330 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 331 | 332 | for _ in 0..1000 { 333 | let c1 = Fq2::rand(&mut rng); 334 | let mut a = Fq6::rand(&mut rng); 335 | let mut b = a; 336 | 337 | a.mul_by_1(&c1); 338 | b.mul_assign(&Fq6 { 339 | c0: Fq2::zero(), 340 | c1: c1, 341 | c2: Fq2::zero(), 342 | }); 343 | 344 | assert_eq!(a, b); 345 | } 346 | } 347 | 348 | #[test] 349 | fn test_fq6_mul_by_01() { 350 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 351 | 352 | for _ in 0..1000 { 353 | let c0 = Fq2::rand(&mut rng); 354 | let c1 = Fq2::rand(&mut rng); 355 | let mut a = Fq6::rand(&mut rng); 356 | let mut b = a; 357 | 358 | a.mul_by_01(&c0, &c1); 359 | b.mul_assign(&Fq6 { 360 | c0: c0, 361 | c1: c1, 362 | c2: Fq2::zero(), 363 | }); 364 | 365 | assert_eq!(a, b); 366 | } 367 | } 368 | 369 | #[test] 370 | fn fq6_field_tests() { 371 | use PrimeField; 372 | 373 | ::tests::field::random_field_tests::(); 374 | ::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); 375 | } 376 | -------------------------------------------------------------------------------- /pairing/src/bls12_381/mod.rs: -------------------------------------------------------------------------------- 1 | mod ec; 2 | mod fq; 3 | mod fq12; 4 | mod fq2; 5 | mod fq6; 6 | mod fr; 7 | 8 | #[cfg(test)] 9 | mod tests; 10 | 11 | pub use self::ec::{ 12 | G1, G1Affine, G1Compressed, G1Prepared, G1Uncompressed, G2, G2Affine, G2Compressed, G2Prepared, 13 | G2Uncompressed, 14 | }; 15 | pub use self::fq::{Fq, FqRepr}; 16 | pub use self::fq12::Fq12; 17 | pub use self::fq2::Fq2; 18 | pub use self::fq6::Fq6; 19 | pub use self::fr::{Fr, FrRepr}; 20 | 21 | use super::{BitIterator, CurveAffine, Engine, Field}; 22 | 23 | // The BLS parameter x for BLS12-381 is -0xd201000000010000 24 | const BLS_X: u64 = 0xd201000000010000; 25 | const BLS_X_IS_NEGATIVE: bool = true; 26 | 27 | #[derive(Clone, Encode, Decode, Default, PartialEq, Eq, Debug)] 28 | pub struct Bls12; 29 | 30 | impl Engine for Bls12 { 31 | type Fr = Fr; 32 | type G1 = G1; 33 | type G1Affine = G1Affine; 34 | type G2 = G2; 35 | type G2Affine = G2Affine; 36 | type Fq = Fq; 37 | type Fqe = Fq2; 38 | type Fqk = Fq12; 39 | 40 | fn miller_loop<'a, I>(i: I) -> Self::Fqk 41 | where 42 | I: IntoIterator< 43 | Item = &'a ( 44 | &'a ::Prepared, 45 | &'a ::Prepared, 46 | ), 47 | >, 48 | { 49 | let mut pairs = vec![]; 50 | for &(p, q) in i { 51 | if !p.is_zero() && !q.is_zero() { 52 | pairs.push((p, q.coeffs.iter())); 53 | } 54 | } 55 | 56 | // Twisting isomorphism from E to E' 57 | fn ell(f: &mut Fq12, coeffs: &(Fq2, Fq2, Fq2), p: &G1Affine) { 58 | let mut c0 = coeffs.0; 59 | let mut c1 = coeffs.1; 60 | 61 | c0.c0.mul_assign(&p.y); 62 | c0.c1.mul_assign(&p.y); 63 | 64 | c1.c0.mul_assign(&p.x); 65 | c1.c1.mul_assign(&p.x); 66 | 67 | // Sparse multiplication in Fq12 68 | f.mul_by_014(&coeffs.2, &c1, &c0); 69 | } 70 | 71 | let mut f = Fq12::one(); 72 | 73 | let mut found_one = false; 74 | for i in BitIterator::new(&[BLS_X >> 1]) { 75 | if !found_one { 76 | found_one = i; 77 | continue; 78 | } 79 | 80 | for &mut (p, ref mut coeffs) in &mut pairs { 81 | ell(&mut f, coeffs.next().unwrap(), &p.0); 82 | } 83 | 84 | if i { 85 | for &mut (p, ref mut coeffs) in &mut pairs { 86 | ell(&mut f, coeffs.next().unwrap(), &p.0); 87 | } 88 | } 89 | 90 | f.square(); 91 | } 92 | 93 | for &mut (p, ref mut coeffs) in &mut pairs { 94 | ell(&mut f, coeffs.next().unwrap(), &p.0); 95 | } 96 | 97 | if BLS_X_IS_NEGATIVE { 98 | f.conjugate(); 99 | } 100 | 101 | f 102 | } 103 | 104 | fn final_exponentiation(r: &Fq12) -> Option { 105 | let mut f1 = *r; 106 | f1.conjugate(); 107 | 108 | match r.inverse() { 109 | Some(mut f2) => { 110 | let mut r = f1; 111 | r.mul_assign(&f2); 112 | f2 = r; 113 | r.frobenius_map(2); 114 | r.mul_assign(&f2); 115 | 116 | fn exp_by_x(f: &mut Fq12, x: u64) { 117 | *f = f.pow(&[x]); 118 | if BLS_X_IS_NEGATIVE { 119 | f.conjugate(); 120 | } 121 | } 122 | 123 | let mut x = BLS_X; 124 | let mut y0 = r; 125 | y0.square(); 126 | let mut y1 = y0; 127 | exp_by_x(&mut y1, x); 128 | x >>= 1; 129 | let mut y2 = y1; 130 | exp_by_x(&mut y2, x); 131 | x <<= 1; 132 | let mut y3 = r; 133 | y3.conjugate(); 134 | y1.mul_assign(&y3); 135 | y1.conjugate(); 136 | y1.mul_assign(&y2); 137 | y2 = y1; 138 | exp_by_x(&mut y2, x); 139 | y3 = y2; 140 | exp_by_x(&mut y3, x); 141 | y1.conjugate(); 142 | y3.mul_assign(&y1); 143 | y1.conjugate(); 144 | y1.frobenius_map(3); 145 | y2.frobenius_map(2); 146 | y1.mul_assign(&y2); 147 | y2 = y3; 148 | exp_by_x(&mut y2, x); 149 | y2.mul_assign(&y0); 150 | y2.mul_assign(&r); 151 | y1.mul_assign(&y2); 152 | y2 = y3; 153 | y2.frobenius_map(1); 154 | y1.mul_assign(&y2); 155 | 156 | Some(y1) 157 | } 158 | None => None, 159 | } 160 | } 161 | } 162 | 163 | impl G2Prepared { 164 | pub fn is_zero(&self) -> bool { 165 | self.infinity 166 | } 167 | 168 | pub fn from_affine(q: G2Affine) -> Self { 169 | if q.is_zero() { 170 | return G2Prepared { 171 | coeffs: vec![], 172 | infinity: true, 173 | }; 174 | } 175 | 176 | fn doubling_step(r: &mut G2) -> (Fq2, Fq2, Fq2) { 177 | // Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf 178 | let mut tmp0 = r.x; 179 | tmp0.square(); 180 | 181 | let mut tmp1 = r.y; 182 | tmp1.square(); 183 | 184 | let mut tmp2 = tmp1; 185 | tmp2.square(); 186 | 187 | let mut tmp3 = tmp1; 188 | tmp3.add_assign(&r.x); 189 | tmp3.square(); 190 | tmp3.sub_assign(&tmp0); 191 | tmp3.sub_assign(&tmp2); 192 | tmp3.double(); 193 | 194 | let mut tmp4 = tmp0; 195 | tmp4.double(); 196 | tmp4.add_assign(&tmp0); 197 | 198 | let mut tmp6 = r.x; 199 | tmp6.add_assign(&tmp4); 200 | 201 | let mut tmp5 = tmp4; 202 | tmp5.square(); 203 | 204 | let mut zsquared = r.z; 205 | zsquared.square(); 206 | 207 | r.x = tmp5; 208 | r.x.sub_assign(&tmp3); 209 | r.x.sub_assign(&tmp3); 210 | 211 | r.z.add_assign(&r.y); 212 | r.z.square(); 213 | r.z.sub_assign(&tmp1); 214 | r.z.sub_assign(&zsquared); 215 | 216 | r.y = tmp3; 217 | r.y.sub_assign(&r.x); 218 | r.y.mul_assign(&tmp4); 219 | 220 | tmp2.double(); 221 | tmp2.double(); 222 | tmp2.double(); 223 | 224 | r.y.sub_assign(&tmp2); 225 | 226 | tmp3 = tmp4; 227 | tmp3.mul_assign(&zsquared); 228 | tmp3.double(); 229 | tmp3.negate(); 230 | 231 | tmp6.square(); 232 | tmp6.sub_assign(&tmp0); 233 | tmp6.sub_assign(&tmp5); 234 | 235 | tmp1.double(); 236 | tmp1.double(); 237 | 238 | tmp6.sub_assign(&tmp1); 239 | 240 | tmp0 = r.z; 241 | tmp0.mul_assign(&zsquared); 242 | tmp0.double(); 243 | 244 | (tmp0, tmp3, tmp6) 245 | } 246 | 247 | fn addition_step(r: &mut G2, q: &G2Affine) -> (Fq2, Fq2, Fq2) { 248 | // Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf 249 | let mut zsquared = r.z; 250 | zsquared.square(); 251 | 252 | let mut ysquared = q.y; 253 | ysquared.square(); 254 | 255 | let mut t0 = zsquared; 256 | t0.mul_assign(&q.x); 257 | 258 | let mut t1 = q.y; 259 | t1.add_assign(&r.z); 260 | t1.square(); 261 | t1.sub_assign(&ysquared); 262 | t1.sub_assign(&zsquared); 263 | t1.mul_assign(&zsquared); 264 | 265 | let mut t2 = t0; 266 | t2.sub_assign(&r.x); 267 | 268 | let mut t3 = t2; 269 | t3.square(); 270 | 271 | let mut t4 = t3; 272 | t4.double(); 273 | t4.double(); 274 | 275 | let mut t5 = t4; 276 | t5.mul_assign(&t2); 277 | 278 | let mut t6 = t1; 279 | t6.sub_assign(&r.y); 280 | t6.sub_assign(&r.y); 281 | 282 | let mut t9 = t6; 283 | t9.mul_assign(&q.x); 284 | 285 | let mut t7 = t4; 286 | t7.mul_assign(&r.x); 287 | 288 | r.x = t6; 289 | r.x.square(); 290 | r.x.sub_assign(&t5); 291 | r.x.sub_assign(&t7); 292 | r.x.sub_assign(&t7); 293 | 294 | r.z.add_assign(&t2); 295 | r.z.square(); 296 | r.z.sub_assign(&zsquared); 297 | r.z.sub_assign(&t3); 298 | 299 | let mut t10 = q.y; 300 | t10.add_assign(&r.z); 301 | 302 | let mut t8 = t7; 303 | t8.sub_assign(&r.x); 304 | t8.mul_assign(&t6); 305 | 306 | t0 = r.y; 307 | t0.mul_assign(&t5); 308 | t0.double(); 309 | 310 | r.y = t8; 311 | r.y.sub_assign(&t0); 312 | 313 | t10.square(); 314 | t10.sub_assign(&ysquared); 315 | 316 | let mut ztsquared = r.z; 317 | ztsquared.square(); 318 | 319 | t10.sub_assign(&ztsquared); 320 | 321 | t9.double(); 322 | t9.sub_assign(&t10); 323 | 324 | t10 = r.z; 325 | t10.double(); 326 | 327 | t6.negate(); 328 | 329 | t1 = t6; 330 | t1.double(); 331 | 332 | (t10, t1, t9) 333 | } 334 | 335 | let mut coeffs = vec![]; 336 | let mut r: G2 = q.into(); 337 | 338 | let mut found_one = false; 339 | for i in BitIterator::new([BLS_X >> 1]) { 340 | if !found_one { 341 | found_one = i; 342 | continue; 343 | } 344 | 345 | coeffs.push(doubling_step(&mut r)); 346 | 347 | if i { 348 | coeffs.push(addition_step(&mut r, &q)); 349 | } 350 | } 351 | 352 | coeffs.push(doubling_step(&mut r)); 353 | 354 | G2Prepared { 355 | coeffs, 356 | infinity: false, 357 | } 358 | } 359 | } 360 | 361 | #[test] 362 | fn bls12_engine_tests() { 363 | ::tests::engine::engine_tests::(); 364 | } 365 | -------------------------------------------------------------------------------- /pairing/src/bls12_381/tests/g1_compressed_valid_test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LayerXcom/bellman-substrate/51f00533b7736835c2c06f5028d9a51c7715bfb2/pairing/src/bls12_381/tests/g1_compressed_valid_test_vectors.dat -------------------------------------------------------------------------------- /pairing/src/bls12_381/tests/g1_uncompressed_invalid_test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LayerXcom/bellman-substrate/51f00533b7736835c2c06f5028d9a51c7715bfb2/pairing/src/bls12_381/tests/g1_uncompressed_invalid_test_vectors.dat -------------------------------------------------------------------------------- /pairing/src/bls12_381/tests/g1_uncompressed_valid_test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LayerXcom/bellman-substrate/51f00533b7736835c2c06f5028d9a51c7715bfb2/pairing/src/bls12_381/tests/g1_uncompressed_valid_test_vectors.dat -------------------------------------------------------------------------------- /pairing/src/bls12_381/tests/g2_compressed_valid_test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LayerXcom/bellman-substrate/51f00533b7736835c2c06f5028d9a51c7715bfb2/pairing/src/bls12_381/tests/g2_compressed_valid_test_vectors.dat -------------------------------------------------------------------------------- /pairing/src/bls12_381/tests/g2_uncompressed_valid_test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LayerXcom/bellman-substrate/51f00533b7736835c2c06f5028d9a51c7715bfb2/pairing/src/bls12_381/tests/g2_uncompressed_valid_test_vectors.dat -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /pairing/src/tests/field.rs: -------------------------------------------------------------------------------- 1 | use rand::{Rng, SeedableRng, XorShiftRng}; 2 | use {Field, LegendreSymbol, PrimeField, SqrtField}; 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 | -------------------------------------------------------------------------------- /pairing/src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod curve; 2 | pub mod engine; 3 | pub mod field; 4 | pub mod repr; 5 | -------------------------------------------------------------------------------- /pairing/src/tests/repr.rs: -------------------------------------------------------------------------------- 1 | use rand::{SeedableRng, XorShiftRng}; 2 | use PrimeFieldRepr; 3 | use rstd::prelude::*; 4 | 5 | pub fn random_repr_tests() { 6 | random_encoding_tests::(); 7 | random_shl_tests::(); 8 | random_shr_tests::(); 9 | } 10 | 11 | fn random_encoding_tests() { 12 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 13 | 14 | for _ in 0..1000 { 15 | let r = R::rand(&mut rng); 16 | 17 | // Big endian 18 | { 19 | let mut rdecoded = R::default(); 20 | 21 | let mut v: Vec = vec![]; 22 | r.write_be(&mut v).unwrap(); 23 | rdecoded.read_be(&v[0..]).unwrap(); 24 | 25 | assert_eq!(r, rdecoded); 26 | } 27 | 28 | // Little endian 29 | { 30 | let mut rdecoded = R::default(); 31 | 32 | let mut v: Vec = vec![]; 33 | r.write_le(&mut v).unwrap(); 34 | rdecoded.read_le(&mut v[0..]).unwrap(); 35 | 36 | assert_eq!(r, rdecoded); 37 | } 38 | 39 | { 40 | let mut rdecoded_le = R::default(); 41 | let mut rdecoded_be_flip = R::default(); 42 | 43 | let mut v: Vec = vec![]; 44 | r.write_le(&mut v).unwrap(); 45 | 46 | // This reads in little-endian, so we are done. 47 | rdecoded_le.read_le(&mut v[..]).unwrap(); 48 | 49 | // This reads in big-endian, so we perform a swap of the 50 | // bytes beforehand. 51 | let v: Vec = v.into_iter().rev().collect(); 52 | rdecoded_be_flip.read_be(&v[..]).unwrap(); 53 | 54 | assert_eq!(rdecoded_le, rdecoded_be_flip); 55 | } 56 | } 57 | } 58 | 59 | fn random_shl_tests() { 60 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 61 | 62 | for _ in 0..100 { 63 | let r = R::rand(&mut rng); 64 | 65 | for shift in 0..(r.num_bits() + 1) { 66 | let mut r1 = r; 67 | let mut r2 = r; 68 | 69 | for _ in 0..shift { 70 | r1.mul2(); 71 | } 72 | 73 | r2.shl(shift); 74 | 75 | assert_eq!(r1, r2); 76 | } 77 | } 78 | } 79 | 80 | fn random_shr_tests() { 81 | let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 82 | 83 | for _ in 0..100 { 84 | let r = R::rand(&mut rng); 85 | 86 | for shift in 0..(r.num_bits() + 1) { 87 | let mut r1 = r; 88 | let mut r2 = r; 89 | 90 | for _ in 0..shift { 91 | r1.div2(); 92 | } 93 | 94 | r2.shr(shift); 95 | 96 | assert_eq!(r1, r2); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /pairing/src/utils.rs: -------------------------------------------------------------------------------- 1 | use IoError; 2 | 3 | use rstd::prelude::*; 4 | use rstd::cmp; 5 | use rstd::ptr::copy_nonoverlapping; 6 | 7 | macro_rules! write_num_bytes { 8 | ($ty:ty, $size:expr, $n:expr, $dst:expr, $which:ident) => ({ 9 | assert!($size <= $dst.len()); 10 | unsafe { 11 | // N.B. https://github.com/rust-lang/rust/issues/22776 12 | let bytes = *(&$n.$which() as *const _ as *const [u8; $size]); 13 | copy_nonoverlapping((&bytes).as_ptr(), $dst.as_mut_ptr(), $size); 14 | } 15 | }); 16 | } 17 | 18 | macro_rules! read_num_bytes { 19 | ($ty:ty, $size:expr, $src:expr, $which:ident) => ({ 20 | assert!($size == ::core::mem::size_of::<$ty>()); 21 | assert!($size <= $src.len()); 22 | let mut data: $ty = 0; 23 | unsafe { 24 | copy_nonoverlapping( 25 | $src.as_ptr(), 26 | &mut data as *mut $ty as *mut u8, 27 | $size); 28 | } 29 | data.$which() 30 | }); 31 | } 32 | 33 | pub trait Write { 34 | fn write(&mut self, buf: &[u8]) -> Result; 35 | fn write_all(&mut self, mut buf: &[u8]) -> Result<(), IoError> { 36 | while !buf.is_empty() { 37 | match self.write(buf) { 38 | Ok(0) => return Err(IoError::WriteZero), 39 | Ok(n) => buf = &buf[n..], 40 | // Err(ref e) if e.kind() == ErrorKind::Interrupted => {} 41 | Err(e) => return Err(e), 42 | } 43 | } 44 | Ok(()) 45 | } 46 | fn write_u32(&mut self, n: u32) -> Result<(), IoError>; 47 | fn write_u64(&mut self, n: u64) -> Result<(), IoError>; 48 | } 49 | 50 | impl Write for Vec { 51 | #[inline] 52 | fn write(&mut self, buf: &[u8]) -> Result { 53 | self.extend_from_slice(buf); 54 | Ok(buf.len()) 55 | } 56 | 57 | #[inline] 58 | fn write_all(&mut self, buf: &[u8]) -> Result<(), IoError> { 59 | self.extend_from_slice(buf); 60 | Ok(()) 61 | } 62 | 63 | #[inline] 64 | fn write_u32(&mut self, n: u32) -> Result<(), IoError> { 65 | let mut buf = [0; 4]; 66 | write_u32_be(&mut buf, n); 67 | self.write_all(&buf) 68 | } 69 | 70 | #[inline] 71 | fn write_u64(&mut self, n: u64) -> Result<(), IoError> { 72 | let mut buf = [0; 8]; 73 | write_u64_be(&mut buf, n); 74 | self.write_all(&buf) 75 | } 76 | } 77 | 78 | #[inline] 79 | fn write_u32_be(buf: &mut [u8], n: u32) { 80 | write_num_bytes!(u32, 4, n, buf, to_be); 81 | } 82 | 83 | #[inline] 84 | fn write_u64_be(buf: &mut [u8], n: u64) { 85 | write_num_bytes!(u64, 8, n, buf, to_be); 86 | } 87 | 88 | #[inline] 89 | fn read_u32_be(buf: &[u8]) -> u32 { 90 | read_num_bytes!(u32, 4, buf, to_be) 91 | } 92 | 93 | #[inline] 94 | fn read_u64_be(buf: &[u8]) -> u64 { 95 | read_num_bytes!(u64, 8, buf, to_be) 96 | } 97 | 98 | pub trait Read { 99 | fn read(&mut self, buf: &mut [u8]) -> Result; 100 | fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), IoError> { 101 | while !buf.is_empty() { 102 | match self.read(buf) { 103 | Ok(0) => break, 104 | Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; } 105 | // Err(ref e) if e.kind() == ErrorKind::Interrupted => {} 106 | Err(e) => return Err(e), 107 | } 108 | } 109 | if !buf.is_empty() { 110 | Err(IoError::Error) 111 | } else { 112 | Ok(()) 113 | } 114 | } 115 | fn read_u32(&mut self) -> Result; 116 | fn read_u64(&mut self) -> Result; 117 | } 118 | 119 | impl<'a> Read for &'a [u8] { 120 | #[inline] 121 | fn read(&mut self, buf: &mut [u8]) -> Result { 122 | let amt = cmp::min(buf.len(), self.len()); 123 | let (a, b) = self.split_at(amt); 124 | 125 | // First check if the amount of bytes we want to read is small: 126 | // `copy_from_slice` will generally expand to a call to `memcpy`, and 127 | // for a single byte the overhead is significant. 128 | if amt == 1 { 129 | buf[0] = a[0]; 130 | } else { 131 | buf[..amt].copy_from_slice(a); 132 | } 133 | 134 | *self = b; 135 | Ok(amt) 136 | } 137 | 138 | #[inline] 139 | fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), IoError> { 140 | if buf.len() > self.len() { 141 | // return Err(Error::new(ErrorKind::UnexpectedEof, 142 | // "failed to fill whole buffer")); 143 | return Err(IoError::Error); 144 | } 145 | let (a, b) = self.split_at(buf.len()); 146 | 147 | // First check if the amount of bytes we want to read is small: 148 | // `copy_from_slice` will generally expand to a call to `memcpy`, and 149 | // for a single byte the overhead is significant. 150 | if buf.len() == 1 { 151 | buf[0] = a[0]; 152 | } else { 153 | buf.copy_from_slice(a); 154 | } 155 | 156 | *self = b; 157 | Ok(()) 158 | } 159 | 160 | #[inline] 161 | fn read_u64(&mut self) -> Result { 162 | let mut buf = [0; 8]; 163 | try!(self.read_exact(&mut buf)); 164 | Ok(read_u64_be(&buf)) 165 | } 166 | 167 | #[inline] 168 | fn read_u32(&mut self) -> Result { 169 | let mut buf = [0; 4]; 170 | try!(self.read_exact(&mut buf)); 171 | Ok(read_u32_be(&buf)) 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /pairing/src/wnaf.rs: -------------------------------------------------------------------------------- 1 | use super::{CurveProjective, PrimeField, PrimeFieldRepr}; 2 | use rstd::prelude::*; 3 | 4 | /// Replaces the contents of `table` with a w-NAF window table for the given window size. 5 | pub(crate) fn wnaf_table(table: &mut Vec, mut base: G, window: usize) { 6 | table.truncate(0); 7 | table.reserve(1 << (window - 1)); 8 | 9 | let mut dbl = base; 10 | dbl.double(); 11 | 12 | for _ in 0..(1 << (window - 1)) { 13 | table.push(base); 14 | base.add_assign(&dbl); 15 | } 16 | } 17 | 18 | /// Replaces the contents of `wnaf` with the w-NAF representation of a scalar. 19 | pub(crate) fn wnaf_form(wnaf: &mut Vec, mut c: S, window: usize) { 20 | wnaf.truncate(0); 21 | 22 | while !c.is_zero() { 23 | let mut u; 24 | if c.is_odd() { 25 | u = (c.as_ref()[0] % (1 << (window + 1))) as i64; 26 | 27 | if u > (1 << window) { 28 | u -= 1 << (window + 1); 29 | } 30 | 31 | if u > 0 { 32 | c.sub_noborrow(&S::from(u as u64)); 33 | } else { 34 | c.add_nocarry(&S::from((-u) as u64)); 35 | } 36 | } else { 37 | u = 0; 38 | } 39 | 40 | wnaf.push(u); 41 | 42 | c.div2(); 43 | } 44 | } 45 | 46 | /// Performs w-NAF exponentiation with the provided window table and w-NAF form scalar. 47 | /// 48 | /// This function must be provided a `table` and `wnaf` that were constructed with 49 | /// the same window size; otherwise, it may panic or produce invalid results. 50 | pub(crate) fn wnaf_exp(table: &[G], wnaf: &[i64]) -> G { 51 | let mut result = G::zero(); 52 | 53 | let mut found_one = false; 54 | 55 | for n in wnaf.iter().rev() { 56 | if found_one { 57 | result.double(); 58 | } 59 | 60 | if *n != 0 { 61 | found_one = true; 62 | 63 | if *n > 0 { 64 | result.add_assign(&table[(n / 2) as usize]); 65 | } else { 66 | result.sub_assign(&table[((-n) / 2) as usize]); 67 | } 68 | } 69 | } 70 | 71 | result 72 | } 73 | 74 | /// A "w-ary non-adjacent form" exponentiation context. 75 | #[derive(Debug)] 76 | pub struct Wnaf { 77 | base: B, 78 | scalar: S, 79 | window_size: W, 80 | } 81 | 82 | impl Wnaf<(), Vec, Vec> { 83 | /// Construct a new wNAF context without allocating. 84 | pub fn new() -> Self { 85 | Wnaf { 86 | base: vec![], 87 | scalar: vec![], 88 | window_size: (), 89 | } 90 | } 91 | 92 | /// Given a base and a number of scalars, compute a window table and return a `Wnaf` object that 93 | /// can perform exponentiations with `.scalar(..)`. 94 | pub fn base(&mut self, base: G, num_scalars: usize) -> Wnaf> { 95 | // Compute the appropriate window size based on the number of scalars. 96 | let window_size = G::recommended_wnaf_for_num_scalars(num_scalars); 97 | 98 | // Compute a wNAF table for the provided base and window size. 99 | wnaf_table(&mut self.base, base, window_size); 100 | 101 | // Return a Wnaf object that immutably borrows the computed base storage location, 102 | // but mutably borrows the scalar storage location. 103 | Wnaf { 104 | base: &self.base[..], 105 | scalar: &mut self.scalar, 106 | window_size, 107 | } 108 | } 109 | 110 | /// Given a scalar, compute its wNAF representation and return a `Wnaf` object that can perform 111 | /// exponentiations with `.base(..)`. 112 | pub fn scalar( 113 | &mut self, 114 | scalar: <::Scalar as PrimeField>::Repr, 115 | ) -> Wnaf, &[i64]> { 116 | // Compute the appropriate window size for the scalar. 117 | let window_size = G::recommended_wnaf_for_scalar(scalar); 118 | 119 | // Compute the wNAF form of the scalar. 120 | wnaf_form(&mut self.scalar, scalar, window_size); 121 | 122 | // Return a Wnaf object that mutably borrows the base storage location, but 123 | // immutably borrows the computed wNAF form scalar location. 124 | Wnaf { 125 | base: &mut self.base, 126 | scalar: &self.scalar[..], 127 | window_size, 128 | } 129 | } 130 | } 131 | 132 | impl<'a, G: CurveProjective> Wnaf> { 133 | /// Constructs new space for the scalar representation while borrowing 134 | /// the computed window table, for sending the window table across threads. 135 | pub fn shared(&self) -> Wnaf> { 136 | Wnaf { 137 | base: self.base, 138 | scalar: vec![], 139 | window_size: self.window_size, 140 | } 141 | } 142 | } 143 | 144 | impl<'a, G: CurveProjective> Wnaf, &'a [i64]> { 145 | /// Constructs new space for the window table while borrowing 146 | /// the computed scalar representation, for sending the scalar representation 147 | /// across threads. 148 | pub fn shared(&self) -> Wnaf, &'a [i64]> { 149 | Wnaf { 150 | base: vec![], 151 | scalar: self.scalar, 152 | window_size: self.window_size, 153 | } 154 | } 155 | } 156 | 157 | impl> Wnaf { 158 | /// Performs exponentiation given a base. 159 | pub fn base(&mut self, base: G) -> G 160 | where 161 | B: AsMut>, 162 | { 163 | wnaf_table(self.base.as_mut(), base, self.window_size); 164 | wnaf_exp(self.base.as_mut(), self.scalar.as_ref()) 165 | } 166 | } 167 | 168 | impl>> Wnaf { 169 | /// Performs exponentiation given a scalar. 170 | pub fn scalar( 171 | &mut self, 172 | scalar: <::Scalar as PrimeField>::Repr, 173 | ) -> G 174 | where 175 | B: AsRef<[G]>, 176 | { 177 | wnaf_form(self.scalar.as_mut(), scalar, self.window_size); 178 | wnaf_exp(self.base.as_ref(), self.scalar.as_mut()) 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /sapling-crypto/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /sapling-crypto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = [ 3 | "Sean Bowe ", 4 | "Osuke Sudo ", 5 | ] 6 | description = "Cryptographic library for Zcash Sapling" 7 | license = "MIT/Apache-2.0" 8 | name = "sapling-crypto" 9 | version = "0.0.1" 10 | 11 | [dependencies.pairing] 12 | path = "../pairing" 13 | features = ["expose-arith"] 14 | 15 | [dependencies] 16 | bellman = { path = "../bellman" } 17 | rand = { version = "0.4", default-features = false } 18 | digest = { version = "0.7", default-features = false } 19 | byteorder = { version = "1", default-features = false } 20 | parity-codec-derive = { version = "3.0", default-features = false } 21 | parity-codec = { version = "3.0", default-features = false } 22 | serde = { version = "1.0", optional = true } 23 | serde_derive = { version = "1.0", optional = true } 24 | sr-std = { git = "https://github.com/paritytech/substrate", default-features = false } 25 | sr-io = { git = "https://github.com/paritytech/substrate", default-features = false } 26 | 27 | [dependencies.blake2-rfc] 28 | git = "https://github.com/gtank/blake2-rfc" 29 | rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" 30 | default-features = false 31 | 32 | [dev-dependencies] 33 | hex-literal = "0.1" 34 | rust-crypto = "0.2" 35 | 36 | [features] 37 | default = ["std"] 38 | u128-support = ["pairing/u128-support"] 39 | std = [ 40 | "pairing/u128-support", 41 | "rand/std", 42 | "digest/std", 43 | "byteorder/std", 44 | "parity-codec/std", 45 | "parity-codec-derive/std", 46 | "sr-std/std", 47 | "sr-io/std", 48 | "blake2-rfc/std", 49 | ] -------------------------------------------------------------------------------- /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/README.md: -------------------------------------------------------------------------------- 1 | # sapling-crypto 2 | 3 | This repository contains a (work-in-progress) implementation of Zcash's "Sapling" cryptography. 4 | 5 | ## Security Warnings 6 | 7 | This library is currently 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 | -------------------------------------------------------------------------------- /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/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/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 ecc; 11 | pub mod pedersen_hash; 12 | pub mod multipack; 13 | pub mod sha256; 14 | 15 | pub mod sapling; 16 | pub mod sprout; 17 | 18 | use bellman::{ 19 | SynthesisError 20 | }; 21 | 22 | // TODO: This should probably be removed and we 23 | // should use existing helper methods on `Option` 24 | // for mapping with an error. 25 | /// This basically is just an extension to `Option` 26 | /// which allows for a convenient mapping to an 27 | /// error on `None`. 28 | trait Assignment { 29 | fn get(&self) -> Result<&T, SynthesisError>; 30 | } 31 | 32 | impl Assignment for Option { 33 | fn get(&self) -> Result<&T, SynthesisError> { 34 | match *self { 35 | Some(ref v) => Ok(v), 36 | None => Err(SynthesisError::AssignmentMissing) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /sapling-crypto/src/circuit/multieq.rs: -------------------------------------------------------------------------------- 1 | use pairing::{ 2 | Engine, 3 | Field, 4 | PrimeField 5 | }; 6 | 7 | use bellman::{ 8 | SynthesisError, 9 | ConstraintSystem, 10 | LinearCombination, 11 | Variable 12 | }; 13 | use rstd::prelude::*; 14 | #[cfg(not(feature = "std"))] 15 | use alloc::string::String; 16 | #[cfg(feature = "std")] 17 | use std::string::String; 18 | 19 | pub struct MultiEq>{ 20 | cs: CS, 21 | ops: usize, 22 | bits_used: usize, 23 | lhs: LinearCombination, 24 | rhs: LinearCombination, 25 | } 26 | 27 | impl> MultiEq { 28 | pub fn new(cs: CS) -> Self { 29 | MultiEq { 30 | cs: cs, 31 | ops: 0, 32 | bits_used: 0, 33 | lhs: LinearCombination::zero(), 34 | rhs: LinearCombination::zero() 35 | } 36 | } 37 | 38 | fn accumulate(&mut self) 39 | { 40 | let ops = self.ops; 41 | let lhs = self.lhs.clone(); 42 | let rhs = self.rhs.clone(); 43 | self.cs.enforce( 44 | || format!("multieq {}", ops), 45 | |_| lhs, 46 | |lc| lc + CS::one(), 47 | |_| rhs 48 | ); 49 | self.lhs = LinearCombination::zero(); 50 | self.rhs = LinearCombination::zero(); 51 | self.bits_used = 0; 52 | self.ops += 1; 53 | } 54 | 55 | pub fn enforce_equal( 56 | &mut self, 57 | num_bits: usize, 58 | lhs: &LinearCombination, 59 | rhs: &LinearCombination 60 | ) 61 | { 62 | // Check if we will exceed the capacity 63 | if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) { 64 | self.accumulate(); 65 | } 66 | 67 | assert!((E::Fr::CAPACITY as usize) > (self.bits_used + num_bits)); 68 | 69 | let coeff = E::Fr::from_str("2").unwrap().pow(&[self.bits_used as u64]); 70 | self.lhs = self.lhs.clone() + (coeff, lhs); 71 | self.rhs = self.rhs.clone() + (coeff, rhs); 72 | self.bits_used += num_bits; 73 | } 74 | } 75 | 76 | impl> Drop for MultiEq { 77 | fn drop(&mut self) { 78 | if self.bits_used > 0 { 79 | self.accumulate(); 80 | } 81 | } 82 | } 83 | 84 | impl> ConstraintSystem for MultiEq 85 | { 86 | type Root = Self; 87 | 88 | fn one() -> Variable { 89 | CS::one() 90 | } 91 | 92 | fn alloc( 93 | &mut self, 94 | annotation: A, 95 | f: F 96 | ) -> Result 97 | where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into 98 | { 99 | self.cs.alloc(annotation, f) 100 | } 101 | 102 | fn alloc_input( 103 | &mut self, 104 | annotation: A, 105 | f: F 106 | ) -> Result 107 | where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into 108 | { 109 | self.cs.alloc_input(annotation, f) 110 | } 111 | 112 | fn enforce( 113 | &mut self, 114 | annotation: A, 115 | a: LA, 116 | b: LB, 117 | c: LC 118 | ) 119 | where A: FnOnce() -> AR, AR: Into, 120 | LA: FnOnce(LinearCombination) -> LinearCombination, 121 | LB: FnOnce(LinearCombination) -> LinearCombination, 122 | LC: FnOnce(LinearCombination) -> LinearCombination 123 | { 124 | self.cs.enforce(annotation, a, b, c) 125 | } 126 | 127 | fn push_namespace(&mut self, name_fn: N) 128 | where NR: Into, N: FnOnce() -> NR 129 | { 130 | self.cs.get_root().push_namespace(name_fn) 131 | } 132 | 133 | fn pop_namespace(&mut self) 134 | { 135 | self.cs.get_root().pop_namespace() 136 | } 137 | 138 | fn get_root(&mut self) -> &mut Self::Root 139 | { 140 | self 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /sapling-crypto/src/circuit/multipack.rs: -------------------------------------------------------------------------------- 1 | use pairing::{Engine, Field, PrimeField}; 2 | use bellman::{ConstraintSystem, SynthesisError}; 3 | use super::boolean::{Boolean}; 4 | use super::num::Num; 5 | use super::Assignment; 6 | use rstd::prelude::*; 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/pedersen_hash.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use super::ecc::{ 3 | MontgomeryPoint, 4 | EdwardsPoint 5 | }; 6 | use super::boolean::Boolean; 7 | use ::jubjub::*; 8 | use bellman::{ 9 | ConstraintSystem 10 | }; 11 | use super::lookup::*; 12 | pub use pedersen_hash::Personalization; 13 | use rstd::prelude::*; 14 | 15 | impl Personalization { 16 | fn get_constant_bools(&self) -> Vec { 17 | self.get_bits() 18 | .into_iter() 19 | .map(|e| Boolean::constant(e)) 20 | .collect() 21 | } 22 | } 23 | 24 | pub fn pedersen_hash( 25 | mut cs: CS, 26 | personalization: Personalization, 27 | bits: &[Boolean], 28 | params: &E::Params 29 | ) -> Result, SynthesisError> 30 | where CS: ConstraintSystem 31 | { 32 | let personalization = personalization.get_constant_bools(); 33 | assert_eq!(personalization.len(), 6); 34 | 35 | let mut edwards_result = None; 36 | let mut bits = personalization.iter().chain(bits.iter()); 37 | let mut segment_generators = params.pedersen_circuit_generators().iter(); 38 | let boolean_false = Boolean::constant(false); 39 | 40 | let mut segment_i = 0; 41 | loop { 42 | let mut segment_result = None; 43 | let mut segment_windows = &segment_generators.next() 44 | .expect("enough segments")[..]; 45 | 46 | let mut window_i = 0; 47 | while let Some(a) = bits.next() { 48 | let b = bits.next().unwrap_or(&boolean_false); 49 | let c = bits.next().unwrap_or(&boolean_false); 50 | 51 | let tmp = lookup3_xy_with_conditional_negation( 52 | cs.namespace(|| format!("segment {}, window {}", segment_i, window_i)), 53 | &[a.clone(), b.clone(), c.clone()], 54 | &segment_windows[0] 55 | )?; 56 | 57 | let tmp = MontgomeryPoint::interpret_unchecked(tmp.0, tmp.1); 58 | 59 | match segment_result { 60 | None => { 61 | segment_result = Some(tmp); 62 | }, 63 | Some(ref mut segment_result) => { 64 | *segment_result = tmp.add( 65 | cs.namespace(|| format!("addition of segment {}, window {}", segment_i, window_i)), 66 | segment_result, 67 | params 68 | )?; 69 | } 70 | } 71 | 72 | segment_windows = &segment_windows[1..]; 73 | 74 | if segment_windows.len() == 0 { 75 | break; 76 | } 77 | 78 | window_i += 1; 79 | } 80 | 81 | match segment_result { 82 | Some(segment_result) => { 83 | // Convert this segment into twisted Edwards form. 84 | let segment_result = segment_result.into_edwards( 85 | cs.namespace(|| format!("conversion of segment {} into edwards", segment_i)), 86 | params 87 | )?; 88 | 89 | match edwards_result { 90 | Some(ref mut edwards_result) => { 91 | *edwards_result = segment_result.add( 92 | cs.namespace(|| format!("addition of segment {} to accumulator", segment_i)), 93 | edwards_result, 94 | params 95 | )?; 96 | }, 97 | None => { 98 | edwards_result = Some(segment_result); 99 | } 100 | } 101 | }, 102 | None => { 103 | // We didn't process any new bits. 104 | break; 105 | } 106 | } 107 | 108 | segment_i += 1; 109 | } 110 | 111 | Ok(edwards_result.unwrap()) 112 | } 113 | 114 | #[cfg(test)] 115 | mod test { 116 | use rand::{SeedableRng, Rng, XorShiftRng}; 117 | use super::*; 118 | use ::circuit::test::*; 119 | use ::circuit::boolean::{Boolean, AllocatedBit}; 120 | use pairing::bls12_381::{Bls12, Fr}; 121 | use pairing::PrimeField; 122 | 123 | #[test] 124 | fn test_pedersen_hash_constraints() { 125 | let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 126 | let params = &JubjubBls12::new(); 127 | let mut cs = TestConstraintSystem::::new(); 128 | 129 | let input: Vec = (0..(Fr::NUM_BITS * 2)).map(|_| rng.gen()).collect(); 130 | 131 | let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { 132 | Boolean::from( 133 | AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() 134 | ) 135 | }).collect(); 136 | 137 | pedersen_hash( 138 | cs.namespace(|| "pedersen hash"), 139 | Personalization::NoteCommitment, 140 | &input_bools, 141 | params 142 | ).unwrap(); 143 | 144 | assert!(cs.is_satisfied()); 145 | assert_eq!(cs.num_constraints(), 1377); 146 | } 147 | 148 | #[test] 149 | fn test_pedersen_hash() { 150 | let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 151 | let params = &JubjubBls12::new(); 152 | 153 | for length in 0..751 { 154 | for _ in 0..5 { 155 | let mut input: Vec = (0..length).map(|_| rng.gen()).collect(); 156 | 157 | let mut cs = TestConstraintSystem::::new(); 158 | 159 | let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { 160 | Boolean::from( 161 | AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() 162 | ) 163 | }).collect(); 164 | 165 | let res = pedersen_hash( 166 | cs.namespace(|| "pedersen hash"), 167 | Personalization::MerkleTree(1), 168 | &input_bools, 169 | params 170 | ).unwrap(); 171 | 172 | assert!(cs.is_satisfied()); 173 | 174 | let expected = ::pedersen_hash::pedersen_hash::( 175 | Personalization::MerkleTree(1), 176 | input.clone().into_iter(), 177 | params 178 | ).into_xy(); 179 | 180 | assert_eq!(res.get_x().get_value().unwrap(), expected.0); 181 | assert_eq!(res.get_y().get_value().unwrap(), expected.1); 182 | 183 | // Test against the output of a different personalization 184 | let unexpected = ::pedersen_hash::pedersen_hash::( 185 | Personalization::MerkleTree(0), 186 | input.into_iter(), 187 | params 188 | ).into_xy(); 189 | 190 | assert!(res.get_x().get_value().unwrap() != unexpected.0); 191 | assert!(res.get_y().get_value().unwrap() != unexpected.1); 192 | } 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /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 | use rstd::prelude::*; 10 | 11 | pub fn note_comm( 12 | cs: CS, 13 | a_pk: &[Boolean], 14 | value: &[Boolean], 15 | rho: &[Boolean], 16 | r: &[Boolean] 17 | ) -> Result, SynthesisError> 18 | where E: Engine, CS: ConstraintSystem 19 | { 20 | assert_eq!(a_pk.len(), 256); 21 | assert_eq!(value.len(), 64); 22 | assert_eq!(rho.len(), 256); 23 | assert_eq!(r.len(), 256); 24 | 25 | let mut image = vec![]; 26 | image.push(Boolean::constant(true)); 27 | image.push(Boolean::constant(false)); 28 | image.push(Boolean::constant(true)); 29 | image.push(Boolean::constant(true)); 30 | image.push(Boolean::constant(false)); 31 | image.push(Boolean::constant(false)); 32 | image.push(Boolean::constant(false)); 33 | image.push(Boolean::constant(false)); 34 | image.extend(a_pk.iter().cloned()); 35 | image.extend(value.iter().cloned()); 36 | image.extend(rho.iter().cloned()); 37 | image.extend(r.iter().cloned()); 38 | 39 | sha256( 40 | cs, 41 | &image 42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | use rstd::prelude::*; 10 | 11 | fn prf( 12 | cs: CS, 13 | a: bool, 14 | b: bool, 15 | c: bool, 16 | d: bool, 17 | x: &[Boolean], 18 | y: &[Boolean] 19 | ) -> Result, SynthesisError> 20 | where E: Engine, CS: ConstraintSystem 21 | { 22 | assert_eq!(x.len(), 252); 23 | assert_eq!(y.len(), 256); 24 | 25 | let mut image = vec![]; 26 | image.push(Boolean::constant(a)); 27 | image.push(Boolean::constant(b)); 28 | image.push(Boolean::constant(c)); 29 | image.push(Boolean::constant(d)); 30 | image.extend(x.iter().cloned()); 31 | image.extend(y.iter().cloned()); 32 | 33 | assert_eq!(image.len(), 512); 34 | 35 | sha256_block_no_padding( 36 | cs, 37 | &image 38 | ) 39 | } 40 | 41 | pub fn prf_a_pk( 42 | cs: CS, 43 | a_sk: &[Boolean] 44 | ) -> Result, SynthesisError> 45 | where E: Engine, CS: ConstraintSystem 46 | { 47 | prf(cs, true, true, false, false, a_sk, &(0..256).map(|_| Boolean::constant(false)).collect::>()) 48 | } 49 | 50 | pub fn prf_nf( 51 | cs: CS, 52 | a_sk: &[Boolean], 53 | rho: &[Boolean] 54 | ) -> Result, SynthesisError> 55 | where E: Engine, CS: ConstraintSystem 56 | { 57 | prf(cs, true, true, true, false, a_sk, rho) 58 | } 59 | 60 | pub fn prf_pk( 61 | cs: CS, 62 | a_sk: &[Boolean], 63 | h_sig: &[Boolean], 64 | nonce: bool 65 | ) -> Result, SynthesisError> 66 | where E: Engine, CS: ConstraintSystem 67 | { 68 | prf(cs, false, nonce, false, false, a_sk, h_sig) 69 | } 70 | 71 | pub fn prf_rho( 72 | cs: CS, 73 | phi: &[Boolean], 74 | h_sig: &[Boolean], 75 | nonce: bool 76 | ) -> Result, SynthesisError> 77 | where E: Engine, CS: ConstraintSystem 78 | { 79 | prf(cs, false, nonce, true, false, phi, h_sig) 80 | } 81 | -------------------------------------------------------------------------------- /sapling-crypto/src/circuit/sprout/test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LayerXcom/bellman-substrate/51f00533b7736835c2c06f5028d9a51c7715bfb2/sapling-crypto/src/circuit/sprout/test_vectors.dat -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /sapling-crypto/src/group_hash.rs: -------------------------------------------------------------------------------- 1 | use jubjub::{ 2 | JubjubEngine, 3 | PrimeOrder, 4 | edwards 5 | }; 6 | 7 | use pairing::{ 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 | -------------------------------------------------------------------------------- /sapling-crypto/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | #![cfg_attr(not(feature = "std"), feature(alloc))] 3 | 4 | extern crate pairing; 5 | extern crate bellman; 6 | extern crate blake2_rfc; 7 | extern crate digest; 8 | extern crate rand; 9 | extern crate byteorder; 10 | 11 | #[cfg(test)] 12 | #[macro_use] 13 | extern crate hex_literal; 14 | 15 | #[cfg(test)] 16 | extern crate crypto; 17 | 18 | #[macro_use] 19 | extern crate parity_codec_derive; 20 | extern crate parity_codec as codec; 21 | // #[cfg(feature = "std")] 22 | // extern crate serde; 23 | // #[cfg(feature = "std")] 24 | // #[macro_use] 25 | // extern crate serde_derive; 26 | #[macro_use] 27 | #[cfg(not(feature = "std"))] 28 | extern crate core; 29 | extern crate sr_std as rstd; 30 | extern crate sr_io as runtime_io; 31 | 32 | pub mod jubjub; 33 | pub mod group_hash; 34 | pub mod circuit; 35 | pub mod pedersen_hash; 36 | pub mod primitives; 37 | pub mod constants; 38 | pub mod redjubjub; 39 | pub mod util; 40 | -------------------------------------------------------------------------------- /sapling-crypto/src/pedersen_hash.rs: -------------------------------------------------------------------------------- 1 | use jubjub::*; 2 | use pairing::*; 3 | use rstd::prelude::*; 4 | 5 | #[derive(Copy, Clone)] 6 | pub enum Personalization { 7 | NoteCommitment, 8 | MerkleTree(usize) 9 | } 10 | 11 | impl Personalization { 12 | pub fn get_bits(&self) -> Vec { 13 | match *self { 14 | Personalization::NoteCommitment => 15 | vec![true, true, true, true, true, true], 16 | Personalization::MerkleTree(num) => { 17 | assert!(num < 63); 18 | 19 | (0..6).map(|i| (num >> i) & 1 == 1).collect() 20 | } 21 | } 22 | } 23 | } 24 | 25 | pub fn pedersen_hash( 26 | personalization: Personalization, 27 | bits: I, 28 | params: &E::Params 29 | ) -> edwards::Point 30 | where I: IntoIterator, 31 | E: JubjubEngine 32 | { 33 | let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter()); 34 | 35 | let mut result = edwards::Point::zero(); 36 | let mut generators = params.pedersen_hash_exp_table().iter(); 37 | 38 | loop { 39 | let mut acc = E::Fs::zero(); 40 | let mut cur = E::Fs::one(); 41 | let mut chunks_remaining = params.pedersen_hash_chunks_per_generator(); 42 | let mut encountered_bits = false; 43 | 44 | // Grab three bits from the input 45 | while let Some(a) = bits.next() { 46 | encountered_bits = true; 47 | 48 | let b = bits.next().unwrap_or(false); 49 | let c = bits.next().unwrap_or(false); 50 | 51 | // Start computing this portion of the scalar 52 | let mut tmp = cur; 53 | if a { 54 | tmp.add_assign(&cur); 55 | } 56 | cur.double(); // 2^1 * cur 57 | if b { 58 | tmp.add_assign(&cur); 59 | } 60 | 61 | // conditionally negate 62 | if c { 63 | tmp.negate(); 64 | } 65 | 66 | acc.add_assign(&tmp); 67 | 68 | chunks_remaining -= 1; 69 | 70 | if chunks_remaining == 0 { 71 | break; 72 | } else { 73 | cur.double(); // 2^2 * cur 74 | cur.double(); // 2^3 * cur 75 | cur.double(); // 2^4 * cur 76 | } 77 | } 78 | 79 | if !encountered_bits { 80 | break; 81 | } 82 | 83 | let mut table: &[Vec>] = &generators.next().expect("we don't have enough generators"); 84 | let window = JubjubBls12::pedersen_hash_exp_window_size(); 85 | let window_mask = (1 << window) - 1; 86 | 87 | let mut acc = acc.into_repr(); 88 | 89 | let mut tmp = edwards::Point::zero(); 90 | 91 | while !acc.is_zero() { 92 | let i = (acc.as_ref()[0] & window_mask) as usize; 93 | 94 | tmp = tmp.add(&table[0][i], params); 95 | 96 | acc.shr(window); 97 | table = &table[1..]; 98 | } 99 | 100 | result = result.add(&tmp, params); 101 | } 102 | 103 | result 104 | } 105 | -------------------------------------------------------------------------------- /sapling-crypto/src/primitives/mod.rs: -------------------------------------------------------------------------------- 1 | use pairing::{ 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 | use rstd::prelude::*; 31 | 32 | #[derive(Clone)] 33 | pub struct ValueCommitment { 34 | pub value: u64, 35 | pub randomness: E::Fs 36 | } 37 | 38 | impl ValueCommitment { 39 | pub fn cm( 40 | &self, 41 | params: &E::Params 42 | ) -> edwards::Point 43 | { 44 | params.generator(FixedGenerators::ValueCommitmentValue) 45 | .mul(self.value, params) 46 | .add( 47 | ¶ms.generator(FixedGenerators::ValueCommitmentRandomness) 48 | .mul(self.randomness, params), 49 | params 50 | ) 51 | } 52 | } 53 | 54 | #[derive(Clone)] 55 | pub struct ProofGenerationKey { 56 | pub ak: edwards::Point, 57 | pub nsk: E::Fs 58 | } 59 | 60 | impl ProofGenerationKey { 61 | pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey { 62 | ViewingKey { 63 | ak: self.ak.clone(), 64 | nk: params.generator(FixedGenerators::ProofGenerationKey) 65 | .mul(self.nsk, params) 66 | } 67 | } 68 | } 69 | 70 | pub struct ViewingKey { 71 | pub ak: edwards::Point, 72 | pub nk: edwards::Point 73 | } 74 | 75 | impl ViewingKey { 76 | pub fn rk( 77 | &self, 78 | ar: E::Fs, 79 | params: &E::Params 80 | ) -> edwards::Point { 81 | self.ak.add( 82 | ¶ms.generator(FixedGenerators::SpendingKeyGenerator) 83 | .mul(ar, params), 84 | params 85 | ) 86 | } 87 | 88 | pub fn ivk(&self) -> E::Fs { 89 | let mut preimage = [0; 64]; 90 | 91 | self.ak.write(&mut preimage[0..32]).unwrap(); 92 | self.nk.write(&mut preimage[32..64]).unwrap(); 93 | 94 | let mut h = Blake2s::with_params(32, &[], &[], constants::CRH_IVK_PERSONALIZATION); 95 | h.update(&preimage); 96 | let mut h = h.finalize().as_ref().to_vec(); 97 | 98 | // Drop the most significant five bits, so it can be interpreted as a scalar. 99 | h[31] &= 0b0000_0111; 100 | 101 | let mut e = ::Repr::default(); 102 | e.read_le(&h[..]).unwrap(); 103 | 104 | E::Fs::from_repr(e).expect("should be a valid scalar") 105 | } 106 | 107 | pub fn into_payment_address( 108 | &self, 109 | diversifier: Diversifier, 110 | params: &E::Params 111 | ) -> Option> 112 | { 113 | diversifier.g_d(params).map(|g_d| { 114 | let pk_d = g_d.mul(self.ivk(), params); 115 | 116 | PaymentAddress { 117 | pk_d: pk_d, 118 | diversifier: diversifier 119 | } 120 | }) 121 | } 122 | } 123 | 124 | #[derive(Copy, Clone)] 125 | pub struct Diversifier(pub [u8; 11]); 126 | 127 | impl Diversifier { 128 | pub fn g_d( 129 | &self, 130 | params: &E::Params 131 | ) -> Option> 132 | { 133 | group_hash::(&self.0, constants::KEY_DIVERSIFICATION_PERSONALIZATION, params) 134 | } 135 | } 136 | 137 | #[derive(Clone)] 138 | pub struct PaymentAddress { 139 | pub pk_d: edwards::Point, 140 | pub diversifier: Diversifier 141 | } 142 | 143 | impl PaymentAddress { 144 | pub fn g_d( 145 | &self, 146 | params: &E::Params 147 | ) -> Option> 148 | { 149 | self.diversifier.g_d(params) 150 | } 151 | 152 | pub fn create_note( 153 | &self, 154 | value: u64, 155 | randomness: E::Fs, 156 | params: &E::Params 157 | ) -> Option> 158 | { 159 | self.g_d(params).map(|g_d| { 160 | Note { 161 | value: value, 162 | r: randomness, 163 | g_d: g_d, 164 | pk_d: self.pk_d.clone() 165 | } 166 | }) 167 | } 168 | } 169 | 170 | pub struct Note { 171 | /// The value of the note 172 | pub value: u64, 173 | /// The diversified base of the address, GH(d) 174 | pub g_d: edwards::Point, 175 | /// The public key of the address, g_d^ivk 176 | pub pk_d: edwards::Point, 177 | /// The commitment randomness 178 | pub r: E::Fs 179 | } 180 | 181 | impl Note { 182 | pub fn uncommitted() -> E::Fr { 183 | // The smallest u-coordinate that is not on the curve 184 | // is one. 185 | // TODO: This should be relocated to JubjubEngine as 186 | // it's specific to the curve we're using, not all 187 | // twisted edwards curves. 188 | E::Fr::one() 189 | } 190 | 191 | /// Computes the note commitment, returning the full point. 192 | fn cm_full_point(&self, params: &E::Params) -> edwards::Point 193 | { 194 | // Calculate the note contents, as bytes 195 | let mut note_contents = vec![]; 196 | 197 | // Writing the value in little endian 198 | (&mut note_contents).write_u64::(self.value).unwrap(); 199 | 200 | // Write g_d 201 | self.g_d.write(&mut note_contents).unwrap(); 202 | 203 | // Write pk_d 204 | self.pk_d.write(&mut note_contents).unwrap(); 205 | 206 | assert_eq!(note_contents.len(), 32 + 32 + 8); 207 | 208 | // Compute the Pedersen hash of the note contents 209 | let hash_of_contents = pedersen_hash( 210 | Personalization::NoteCommitment, 211 | note_contents.into_iter() 212 | .flat_map(|byte| { 213 | (0..8).map(move |i| ((byte >> i) & 1) == 1) 214 | }), 215 | params 216 | ); 217 | 218 | // Compute final commitment 219 | params.generator(FixedGenerators::NoteCommitmentRandomness) 220 | .mul(self.r, params) 221 | .add(&hash_of_contents, params) 222 | } 223 | 224 | /// Computes the nullifier given the viewing key and 225 | /// note position 226 | pub fn nf( 227 | &self, 228 | viewing_key: &ViewingKey, 229 | position: u64, 230 | params: &E::Params 231 | ) -> Vec 232 | { 233 | // Compute rho = cm + position.G 234 | let rho = self 235 | .cm_full_point(params) 236 | .add( 237 | ¶ms.generator(FixedGenerators::NullifierPosition) 238 | .mul(position, params), 239 | params 240 | ); 241 | 242 | // Compute nf = BLAKE2s(nk | rho) 243 | let mut nf_preimage = [0u8; 64]; 244 | viewing_key.nk.write(&mut nf_preimage[0..32]).unwrap(); 245 | rho.write(&mut nf_preimage[32..64]).unwrap(); 246 | let mut h = Blake2s::with_params(32, &[], &[], constants::PRF_NF_PERSONALIZATION); 247 | h.update(&nf_preimage); 248 | 249 | h.finalize().as_ref().to_vec() 250 | } 251 | 252 | /// Computes the note commitment 253 | pub fn cm(&self, params: &E::Params) -> E::Fr 254 | { 255 | // The commitment is in the prime order subgroup, so mapping the 256 | // commitment to the x-coordinate is an injective encoding. 257 | self.cm_full_point(params).into_xy().0 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /sapling-crypto/src/util.rs: -------------------------------------------------------------------------------- 1 | use blake2_rfc::blake2b::Blake2b; 2 | 3 | use jubjub::{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 | -------------------------------------------------------------------------------- /zcash_primitives/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zcash_primitives" 3 | version = "0.0.0" 4 | authors = [ 5 | "Jack Grigg ", 6 | ] 7 | 8 | [dependencies] 9 | byteorder = "1" 10 | lazy_static = "1" 11 | pairing = { path = "../pairing" } 12 | rand = "0.4" 13 | sapling-crypto = { path = "../sapling-crypto" } 14 | 15 | [dependencies.blake2-rfc] 16 | git = "https://github.com/gtank/blake2-rfc" 17 | rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" 18 | -------------------------------------------------------------------------------- /zcash_primitives/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Zcash Company 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 | -------------------------------------------------------------------------------- /zcash_primitives/README.md: -------------------------------------------------------------------------------- 1 | # zcash_primitives 2 | 3 | This library contains Rust implementations of the Zcash primitives. 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 | 21 | -------------------------------------------------------------------------------- /zcash_primitives/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate lazy_static; 3 | 4 | extern crate blake2_rfc; 5 | extern crate byteorder; 6 | extern crate pairing; 7 | extern crate rand; 8 | extern crate sapling_crypto; 9 | 10 | use sapling_crypto::jubjub::JubjubBls12; 11 | 12 | mod serialize; 13 | pub mod transaction; 14 | 15 | lazy_static! { 16 | static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; 17 | } 18 | -------------------------------------------------------------------------------- /zcash_primitives/src/serialize.rs: -------------------------------------------------------------------------------- 1 | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; 2 | use std::io::{self, Read, Write}; 3 | 4 | const MAX_SIZE: usize = 0x02000000; 5 | 6 | struct CompactSize; 7 | 8 | impl CompactSize { 9 | fn read(mut reader: R) -> io::Result { 10 | let flag = reader.read_u8()?; 11 | match if flag < 253 { 12 | Ok(flag as usize) 13 | } else if flag == 253 { 14 | match reader.read_u16::()? { 15 | n if n < 253 => Err(io::Error::new( 16 | io::ErrorKind::InvalidInput, 17 | "non-canonical CompactSize", 18 | )), 19 | n => Ok(n as usize), 20 | } 21 | } else if flag == 254 { 22 | match reader.read_u32::()? { 23 | n if n < 0x10000 => Err(io::Error::new( 24 | io::ErrorKind::InvalidInput, 25 | "non-canonical CompactSize", 26 | )), 27 | n => Ok(n as usize), 28 | } 29 | } else { 30 | match reader.read_u64::()? { 31 | n if n < 0x100000000 => Err(io::Error::new( 32 | io::ErrorKind::InvalidInput, 33 | "non-canonical CompactSize", 34 | )), 35 | n => Ok(n as usize), 36 | } 37 | }? { 38 | s if s > MAX_SIZE => Err(io::Error::new( 39 | io::ErrorKind::InvalidInput, 40 | "CompactSize too large", 41 | )), 42 | s => Ok(s), 43 | } 44 | } 45 | 46 | fn write(mut writer: W, size: usize) -> io::Result<()> { 47 | match size { 48 | s if s < 253 => writer.write_u8(s as u8), 49 | s if s <= 0xFFFF => { 50 | writer.write_u8(253)?; 51 | writer.write_u16::(s as u16) 52 | } 53 | s if s <= 0xFFFFFFFF => { 54 | writer.write_u8(254)?; 55 | writer.write_u32::(s as u32) 56 | } 57 | s => { 58 | writer.write_u8(255)?; 59 | writer.write_u64::(s as u64) 60 | } 61 | } 62 | } 63 | } 64 | 65 | pub struct Vector; 66 | 67 | impl Vector { 68 | pub fn read(mut reader: R, func: F) -> io::Result> 69 | where 70 | F: Fn(&mut R) -> io::Result, 71 | { 72 | let count = CompactSize::read(&mut reader)?; 73 | (0..count).into_iter().map(|_| func(&mut reader)).collect() 74 | } 75 | 76 | pub fn write(mut writer: W, vec: &[E], func: F) -> io::Result<()> 77 | where 78 | F: Fn(&mut W, &E) -> io::Result<()>, 79 | { 80 | CompactSize::write(&mut writer, vec.len())?; 81 | vec.iter().map(|e| func(&mut writer, e)).collect() 82 | } 83 | } 84 | 85 | #[cfg(test)] 86 | mod tests { 87 | use super::*; 88 | 89 | #[test] 90 | fn compact_size() { 91 | macro_rules! eval { 92 | ($value:expr, $expected:expr) => { 93 | let mut data = vec![]; 94 | CompactSize::write(&mut data, $value).unwrap(); 95 | assert_eq!(&data[..], &$expected[..]); 96 | match CompactSize::read(&data[..]) { 97 | Ok(n) => assert_eq!(n, $value), 98 | Err(e) => panic!("Unexpected error: {:?}", e), 99 | } 100 | }; 101 | } 102 | 103 | eval!(0, [0]); 104 | eval!(1, [1]); 105 | eval!(252, [252]); 106 | eval!(253, [253, 253, 0]); 107 | eval!(254, [253, 254, 0]); 108 | eval!(255, [253, 255, 0]); 109 | eval!(256, [253, 0, 1]); 110 | eval!(256, [253, 0, 1]); 111 | eval!(65535, [253, 255, 255]); 112 | eval!(65536, [254, 0, 0, 1, 0]); 113 | eval!(65537, [254, 1, 0, 1, 0]); 114 | 115 | eval!(33554432, [254, 0, 0, 0, 2]); 116 | 117 | { 118 | let value = 33554433; 119 | let encoded = &[254, 1, 0, 0, 2][..]; 120 | let mut data = vec![]; 121 | CompactSize::write(&mut data, value).unwrap(); 122 | assert_eq!(&data[..], encoded); 123 | assert!(CompactSize::read(encoded).is_err()); 124 | } 125 | } 126 | 127 | #[test] 128 | fn vector() { 129 | macro_rules! eval { 130 | ($value:expr, $expected:expr) => { 131 | let mut data = vec![]; 132 | Vector::write(&mut data, &$value, |w, e| w.write_u8(*e)).unwrap(); 133 | assert_eq!(&data[..], &$expected[..]); 134 | match Vector::read(&data[..], |r| r.read_u8()) { 135 | Ok(v) => assert_eq!(v, $value), 136 | Err(e) => panic!("Unexpected error: {:?}", e), 137 | } 138 | }; 139 | } 140 | 141 | eval!(vec![], [0]); 142 | eval!(vec![0], [1, 0]); 143 | eval!(vec![1], [1, 1]); 144 | eval!(vec![5; 8], [8, 5, 5, 5, 5, 5, 5, 5, 5]); 145 | 146 | { 147 | // expected = [253, 4, 1, 7, 7, 7, ...] 148 | let mut expected = vec![7; 263]; 149 | expected[0] = 253; 150 | expected[1] = 4; 151 | expected[2] = 1; 152 | 153 | eval!(vec![7; 260], expected); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /zcash_primitives/src/transaction/mod.rs: -------------------------------------------------------------------------------- 1 | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; 2 | use sapling_crypto::redjubjub::Signature; 3 | use std::io::{self, Read, Write}; 4 | use std::ops::Deref; 5 | 6 | use serialize::Vector; 7 | 8 | pub mod components; 9 | mod sighash; 10 | 11 | #[cfg(test)] 12 | mod tests; 13 | 14 | pub use self::sighash::{signature_hash, signature_hash_data, SIGHASH_ALL}; 15 | 16 | use self::components::{Amount, JSDescription, OutputDescription, SpendDescription, TxIn, TxOut}; 17 | 18 | const OVERWINTER_VERSION_GROUP_ID: u32 = 0x03C48270; 19 | const OVERWINTER_TX_VERSION: u32 = 3; 20 | const SAPLING_VERSION_GROUP_ID: u32 = 0x892F2085; 21 | const SAPLING_TX_VERSION: u32 = 4; 22 | 23 | /// A Zcash transaction. 24 | pub struct Transaction(TransactionData); 25 | 26 | impl Deref for Transaction { 27 | type Target = TransactionData; 28 | 29 | fn deref(&self) -> &TransactionData { 30 | &self.0 31 | } 32 | } 33 | 34 | pub struct TransactionData { 35 | pub overwintered: bool, 36 | pub version: u32, 37 | pub version_group_id: u32, 38 | pub vin: Vec, 39 | pub vout: Vec, 40 | pub lock_time: u32, 41 | pub expiry_height: u32, 42 | pub value_balance: Amount, 43 | pub shielded_spends: Vec, 44 | pub shielded_outputs: Vec, 45 | pub joinsplits: Vec, 46 | pub joinsplit_pubkey: Option<[u8; 32]>, 47 | pub joinsplit_sig: Option<[u8; 64]>, 48 | pub binding_sig: Option, 49 | } 50 | 51 | impl TransactionData { 52 | pub fn new() -> Self { 53 | TransactionData { 54 | overwintered: true, 55 | version: SAPLING_TX_VERSION, 56 | version_group_id: SAPLING_VERSION_GROUP_ID, 57 | vin: vec![], 58 | vout: vec![], 59 | lock_time: 0, 60 | expiry_height: 0, 61 | value_balance: Amount(0), 62 | shielded_spends: vec![], 63 | shielded_outputs: vec![], 64 | joinsplits: vec![], 65 | joinsplit_pubkey: None, 66 | joinsplit_sig: None, 67 | binding_sig: None, 68 | } 69 | } 70 | 71 | fn header(&self) -> u32 { 72 | let mut header = self.version; 73 | if self.overwintered { 74 | header |= 1 << 31; 75 | } 76 | header 77 | } 78 | 79 | pub fn freeze(self) -> Transaction { 80 | Transaction(self) 81 | } 82 | } 83 | 84 | impl Transaction { 85 | pub fn read(mut reader: R) -> io::Result { 86 | let header = reader.read_u32::()?; 87 | let overwintered = (header >> 31) == 1; 88 | let version = header & 0x7FFFFFFF; 89 | 90 | let version_group_id = match overwintered { 91 | true => reader.read_u32::()?, 92 | false => 0, 93 | }; 94 | 95 | let is_overwinter_v3 = overwintered 96 | && version_group_id == OVERWINTER_VERSION_GROUP_ID 97 | && version == OVERWINTER_TX_VERSION; 98 | let is_sapling_v4 = overwintered 99 | && version_group_id == SAPLING_VERSION_GROUP_ID 100 | && version == SAPLING_TX_VERSION; 101 | if overwintered && !(is_overwinter_v3 || is_sapling_v4) { 102 | return Err(io::Error::new( 103 | io::ErrorKind::InvalidInput, 104 | "Unknown transaction format", 105 | )); 106 | } 107 | 108 | let vin = Vector::read(&mut reader, TxIn::read)?; 109 | let vout = Vector::read(&mut reader, TxOut::read)?; 110 | let lock_time = reader.read_u32::()?; 111 | let expiry_height = match is_overwinter_v3 || is_sapling_v4 { 112 | true => reader.read_u32::()?, 113 | false => 0, 114 | }; 115 | 116 | let (value_balance, shielded_spends, shielded_outputs) = if is_sapling_v4 { 117 | let vb = Amount::read_i64(&mut reader, true)?; 118 | let ss = Vector::read(&mut reader, SpendDescription::read)?; 119 | let so = Vector::read(&mut reader, OutputDescription::read)?; 120 | (vb, ss, so) 121 | } else { 122 | (Amount(0), vec![], vec![]) 123 | }; 124 | 125 | let (joinsplits, joinsplit_pubkey, joinsplit_sig) = if version >= 2 { 126 | let jss = Vector::read(&mut reader, |r| { 127 | JSDescription::read(r, overwintered && version >= SAPLING_TX_VERSION) 128 | })?; 129 | let (pubkey, sig) = if !jss.is_empty() { 130 | let mut joinsplit_pubkey = [0; 32]; 131 | let mut joinsplit_sig = [0; 64]; 132 | reader.read_exact(&mut joinsplit_pubkey)?; 133 | reader.read_exact(&mut joinsplit_sig)?; 134 | (Some(joinsplit_pubkey), Some(joinsplit_sig)) 135 | } else { 136 | (None, None) 137 | }; 138 | (jss, pubkey, sig) 139 | } else { 140 | (vec![], None, None) 141 | }; 142 | 143 | let binding_sig = 144 | match is_sapling_v4 && !(shielded_spends.is_empty() && shielded_outputs.is_empty()) { 145 | true => Some(Signature::read(&mut reader)?), 146 | false => None, 147 | }; 148 | 149 | Ok(Transaction(TransactionData { 150 | overwintered, 151 | version, 152 | version_group_id, 153 | vin, 154 | vout, 155 | lock_time, 156 | expiry_height, 157 | value_balance, 158 | shielded_spends, 159 | shielded_outputs, 160 | joinsplits, 161 | joinsplit_pubkey, 162 | joinsplit_sig, 163 | binding_sig, 164 | })) 165 | } 166 | 167 | pub fn write(&self, mut writer: W) -> io::Result<()> { 168 | writer.write_u32::(self.header())?; 169 | if self.overwintered { 170 | writer.write_u32::(self.version_group_id)?; 171 | } 172 | 173 | let is_overwinter_v3 = self.overwintered 174 | && self.version_group_id == OVERWINTER_VERSION_GROUP_ID 175 | && self.version == OVERWINTER_TX_VERSION; 176 | let is_sapling_v4 = self.overwintered 177 | && self.version_group_id == SAPLING_VERSION_GROUP_ID 178 | && self.version == SAPLING_TX_VERSION; 179 | if self.overwintered && !(is_overwinter_v3 || is_sapling_v4) { 180 | return Err(io::Error::new( 181 | io::ErrorKind::InvalidInput, 182 | "Unknown transaction format", 183 | )); 184 | } 185 | 186 | Vector::write(&mut writer, &self.vin, |w, e| e.write(w))?; 187 | Vector::write(&mut writer, &self.vout, |w, e| e.write(w))?; 188 | writer.write_u32::(self.lock_time)?; 189 | if is_overwinter_v3 || is_sapling_v4 { 190 | writer.write_u32::(self.expiry_height)?; 191 | } 192 | 193 | if is_sapling_v4 { 194 | writer.write_i64::(self.value_balance.0)?; 195 | Vector::write(&mut writer, &self.shielded_spends, |w, e| e.write(w))?; 196 | Vector::write(&mut writer, &self.shielded_outputs, |w, e| e.write(w))?; 197 | } 198 | 199 | if self.version >= 2 { 200 | Vector::write(&mut writer, &self.joinsplits, |w, e| e.write(w))?; 201 | if !self.joinsplits.is_empty() { 202 | match self.joinsplit_pubkey { 203 | Some(pubkey) => writer.write_all(&pubkey)?, 204 | None => { 205 | return Err(io::Error::new( 206 | io::ErrorKind::InvalidInput, 207 | "Missing JoinSplit pubkey", 208 | )) 209 | } 210 | } 211 | match self.joinsplit_sig { 212 | Some(sig) => writer.write_all(&sig)?, 213 | None => { 214 | return Err(io::Error::new( 215 | io::ErrorKind::InvalidInput, 216 | "Missing JoinSplit signature", 217 | )) 218 | } 219 | } 220 | } 221 | } 222 | 223 | if self.version < 2 || self.joinsplits.is_empty() { 224 | if self.joinsplit_pubkey.is_some() { 225 | return Err(io::Error::new( 226 | io::ErrorKind::InvalidInput, 227 | "JoinSplit pubkey should not be present", 228 | )); 229 | } 230 | if self.joinsplit_sig.is_some() { 231 | return Err(io::Error::new( 232 | io::ErrorKind::InvalidInput, 233 | "JoinSplit signature should not be present", 234 | )); 235 | } 236 | } 237 | 238 | if is_sapling_v4 && !(self.shielded_spends.is_empty() && self.shielded_outputs.is_empty()) { 239 | match self.binding_sig { 240 | Some(sig) => sig.write(&mut writer)?, 241 | None => { 242 | return Err(io::Error::new( 243 | io::ErrorKind::InvalidInput, 244 | "Missing binding signature", 245 | )) 246 | } 247 | } 248 | } else if self.binding_sig.is_some() { 249 | return Err(io::Error::new( 250 | io::ErrorKind::InvalidInput, 251 | "Binding signature should not be present", 252 | )); 253 | } 254 | 255 | Ok(()) 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /zcash_primitives/src/transaction/sighash.rs: -------------------------------------------------------------------------------- 1 | use blake2_rfc::blake2b::Blake2b; 2 | use byteorder::{LittleEndian, WriteBytesExt}; 3 | use pairing::{PrimeField, PrimeFieldRepr}; 4 | 5 | use super::{ 6 | components::{Amount, Script, TxOut}, 7 | Transaction, TransactionData, OVERWINTER_VERSION_GROUP_ID, SAPLING_TX_VERSION, 8 | SAPLING_VERSION_GROUP_ID, 9 | }; 10 | 11 | const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &'static [u8; 12] = b"ZcashSigHash"; 12 | const ZCASH_PREVOUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashPrevoutHash"; 13 | const ZCASH_SEQUENCE_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSequencHash"; 14 | const ZCASH_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashOutputsHash"; 15 | const ZCASH_JOINSPLITS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashJSplitsHash"; 16 | const ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSSpendsHash"; 17 | const ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSOutputHash"; 18 | 19 | pub const SIGHASH_ALL: u32 = 1; 20 | const SIGHASH_NONE: u32 = 2; 21 | const SIGHASH_SINGLE: u32 = 3; 22 | const SIGHASH_MASK: u32 = 0x1f; 23 | const SIGHASH_ANYONECANPAY: u32 = 0x80; 24 | 25 | macro_rules! update_u32 { 26 | ($h:expr, $value:expr, $tmp:expr) => { 27 | (&mut $tmp[..4]).write_u32::($value).unwrap(); 28 | $h.update(&$tmp[..4]); 29 | }; 30 | } 31 | 32 | macro_rules! update_i64 { 33 | ($h:expr, $value:expr, $tmp:expr) => { 34 | (&mut $tmp[..8]).write_i64::($value).unwrap(); 35 | $h.update(&$tmp[..8]); 36 | }; 37 | } 38 | 39 | macro_rules! update_hash { 40 | ($h:expr, $cond:expr, $value:expr) => { 41 | if $cond { 42 | $h.update(&$value); 43 | } else { 44 | $h.update(&[0; 32]); 45 | } 46 | }; 47 | } 48 | 49 | #[derive(PartialEq)] 50 | enum SigHashVersion { 51 | Sprout, 52 | Overwinter, 53 | Sapling, 54 | } 55 | 56 | impl SigHashVersion { 57 | fn from_tx(tx: &TransactionData) -> Self { 58 | if tx.overwintered { 59 | match tx.version_group_id { 60 | OVERWINTER_VERSION_GROUP_ID => SigHashVersion::Overwinter, 61 | SAPLING_VERSION_GROUP_ID => SigHashVersion::Sapling, 62 | _ => unimplemented!(), 63 | } 64 | } else { 65 | SigHashVersion::Sprout 66 | } 67 | } 68 | } 69 | 70 | fn prevout_hash(tx: &TransactionData) -> Vec { 71 | let mut data = Vec::with_capacity(tx.vin.len() * 36); 72 | for t_in in &tx.vin { 73 | t_in.prevout.write(&mut data).unwrap(); 74 | } 75 | let mut h = Blake2b::with_params(32, &[], &[], ZCASH_PREVOUTS_HASH_PERSONALIZATION); 76 | h.update(&data); 77 | h.finalize().as_ref().to_vec() 78 | } 79 | 80 | fn sequence_hash(tx: &TransactionData) -> Vec { 81 | let mut data = Vec::with_capacity(tx.vin.len() * 4); 82 | for t_in in &tx.vin { 83 | (&mut data) 84 | .write_u32::(t_in.sequence) 85 | .unwrap(); 86 | } 87 | let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SEQUENCE_HASH_PERSONALIZATION); 88 | h.update(&data); 89 | h.finalize().as_ref().to_vec() 90 | } 91 | 92 | fn outputs_hash(tx: &TransactionData) -> Vec { 93 | let mut data = Vec::with_capacity(tx.vout.len() * (4 + 1)); 94 | for t_out in &tx.vout { 95 | t_out.write(&mut data).unwrap(); 96 | } 97 | let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION); 98 | h.update(&data); 99 | h.finalize().as_ref().to_vec() 100 | } 101 | 102 | fn single_output_hash(tx_out: &TxOut) -> Vec { 103 | let mut data = vec![]; 104 | tx_out.write(&mut data).unwrap(); 105 | let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION); 106 | h.update(&data); 107 | h.finalize().as_ref().to_vec() 108 | } 109 | 110 | fn joinsplits_hash(tx: &TransactionData) -> Vec { 111 | let mut data = Vec::with_capacity( 112 | tx.joinsplits.len() 113 | * if tx.version < SAPLING_TX_VERSION { 114 | 1802 // JSDescription with PHGR13 proof 115 | } else { 116 | 1698 // JSDescription with Groth16 proof 117 | }, 118 | ); 119 | for js in &tx.joinsplits { 120 | js.write(&mut data).unwrap(); 121 | } 122 | data.extend_from_slice(&tx.joinsplit_pubkey.unwrap()); 123 | let mut h = Blake2b::with_params(32, &[], &[], ZCASH_JOINSPLITS_HASH_PERSONALIZATION); 124 | h.update(&data); 125 | h.finalize().as_ref().to_vec() 126 | } 127 | 128 | fn shielded_spends_hash(tx: &TransactionData) -> Vec { 129 | let mut data = Vec::with_capacity(tx.shielded_spends.len() * 384); 130 | for s_spend in &tx.shielded_spends { 131 | s_spend.cv.write(&mut data).unwrap(); 132 | s_spend.anchor.into_repr().write_le(&mut data).unwrap(); 133 | data.extend_from_slice(&s_spend.nullifier); 134 | s_spend.rk.write(&mut data).unwrap(); 135 | data.extend_from_slice(&s_spend.zkproof); 136 | } 137 | let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION); 138 | h.update(&data); 139 | h.finalize().as_ref().to_vec() 140 | } 141 | 142 | fn shielded_outputs_hash(tx: &TransactionData) -> Vec { 143 | let mut data = Vec::with_capacity(tx.shielded_outputs.len() * 948); 144 | for s_out in &tx.shielded_outputs { 145 | s_out.write(&mut data).unwrap(); 146 | } 147 | let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION); 148 | h.update(&data); 149 | h.finalize().as_ref().to_vec() 150 | } 151 | 152 | pub fn signature_hash_data( 153 | tx: &TransactionData, 154 | consensus_branch_id: u32, 155 | hash_type: u32, 156 | transparent_input: Option<(usize, Script, Amount)>, 157 | ) -> Vec { 158 | let sigversion = SigHashVersion::from_tx(tx); 159 | match sigversion { 160 | SigHashVersion::Overwinter | SigHashVersion::Sapling => { 161 | let hash_outputs = if (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE 162 | && (hash_type & SIGHASH_MASK) != SIGHASH_NONE 163 | { 164 | outputs_hash(tx) 165 | } else if (hash_type & SIGHASH_MASK) == SIGHASH_SINGLE 166 | && transparent_input.is_some() 167 | && transparent_input.as_ref().unwrap().0 < tx.vout.len() 168 | { 169 | single_output_hash(&tx.vout[transparent_input.as_ref().unwrap().0]) 170 | } else { 171 | vec![0; 32] 172 | }; 173 | 174 | let mut personal = [0; 16]; 175 | (&mut personal[..12]).copy_from_slice(ZCASH_SIGHASH_PERSONALIZATION_PREFIX); 176 | (&mut personal[12..]) 177 | .write_u32::(consensus_branch_id) 178 | .unwrap(); 179 | 180 | let mut h = Blake2b::with_params(32, &[], &[], &personal); 181 | let mut tmp = [0; 8]; 182 | 183 | update_u32!(h, tx.header(), tmp); 184 | update_u32!(h, tx.version_group_id, tmp); 185 | update_hash!(h, hash_type & SIGHASH_ANYONECANPAY == 0, prevout_hash(tx)); 186 | update_hash!( 187 | h, 188 | hash_type & SIGHASH_ANYONECANPAY == 0 189 | && (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE 190 | && (hash_type & SIGHASH_MASK) != SIGHASH_NONE, 191 | sequence_hash(tx) 192 | ); 193 | h.update(&hash_outputs); 194 | update_hash!(h, !tx.joinsplits.is_empty(), joinsplits_hash(tx)); 195 | if sigversion == SigHashVersion::Sapling { 196 | update_hash!(h, !tx.shielded_spends.is_empty(), shielded_spends_hash(tx)); 197 | update_hash!( 198 | h, 199 | !tx.shielded_outputs.is_empty(), 200 | shielded_outputs_hash(tx) 201 | ); 202 | } 203 | update_u32!(h, tx.lock_time, tmp); 204 | update_u32!(h, tx.expiry_height, tmp); 205 | if sigversion == SigHashVersion::Sapling { 206 | update_i64!(h, tx.value_balance.0, tmp); 207 | } 208 | update_u32!(h, hash_type, tmp); 209 | 210 | if let Some((n, script_code, amount)) = transparent_input { 211 | let mut data = vec![]; 212 | tx.vin[n].prevout.write(&mut data).unwrap(); 213 | script_code.write(&mut data).unwrap(); 214 | (&mut data).write_i64::(amount.0).unwrap(); 215 | (&mut data) 216 | .write_u32::(tx.vin[n].sequence) 217 | .unwrap(); 218 | h.update(&data); 219 | } 220 | 221 | h.finalize().as_ref().to_vec() 222 | } 223 | SigHashVersion::Sprout => unimplemented!(), 224 | } 225 | } 226 | 227 | pub fn signature_hash( 228 | tx: &Transaction, 229 | consensus_branch_id: u32, 230 | hash_type: u32, 231 | transparent_input: Option<(usize, Script, Amount)>, 232 | ) -> Vec { 233 | signature_hash_data(tx, consensus_branch_id, hash_type, transparent_input) 234 | } 235 | --------------------------------------------------------------------------------