diff --git a/Cargo.lock b/Cargo.lock index 4b9f5fa..b0dd6de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,6 +80,7 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -395,6 +396,7 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff_derive 0.4.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -617,6 +619,7 @@ dependencies = [ "group 0.2.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1020,6 +1023,7 @@ dependencies = [ "ripemd160 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "secp256k1 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/bellman/Cargo.toml b/bellman/Cargo.toml index 4f125b4..e6996b0 100644 --- a/bellman/Cargo.toml +++ b/bellman/Cargo.toml @@ -22,6 +22,7 @@ crossbeam = { version = "0.7", optional = true } pairing = { version = "0.15.0", path = "../pairing", optional = true } rand_core = "0.5" byteorder = "1" +subtle = "2.2.1" [dev-dependencies] hex-literal = "0.2" diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 0e722f2..5d6422f 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -10,6 +10,7 @@ use std::cmp::Ordering; use std::fmt; use std::num::Wrapping; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use subtle::{Choice, ConditionallySelectable}; const MODULUS_R: Wrapping = Wrapping(64513); @@ -22,6 +23,16 @@ impl fmt::Display for Fr { } } +impl ConditionallySelectable for Fr { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Fr(Wrapping(u32::conditional_select( + &(a.0).0, + &(b.0).0, + choice, + ))) + } +} + impl Neg for Fr { type Output = Self; diff --git a/ff/Cargo.toml b/ff/Cargo.toml index 9ac1f1e..907fcb2 100644 --- a/ff/Cargo.toml +++ b/ff/Cargo.toml @@ -14,6 +14,7 @@ edition = "2018" byteorder = "1" ff_derive = { version = "0.4.0", path = "ff_derive", optional = true } rand_core = "0.5" +subtle = "2.2.1" [features] default = [] diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index 73b560b..09d5e12 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -833,6 +833,16 @@ fn prime_field_impl( } } + impl ::subtle::ConditionallySelectable for #name { + fn conditional_select(a: &#name, b: &#name, choice: ::subtle::Choice) -> #name { + let mut res = [0u64; #limbs]; + for i in 0..#limbs { + res[i] = u64::conditional_select(&(a.0).0[i], &(b.0).0[i], choice); + } + #name(#repr(res)) + } + } + impl ::std::ops::Neg for #name { type Output = #name; diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 10975a3..e59e627 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -12,6 +12,7 @@ use std::error::Error; use std::fmt; use std::io::{self, Read, Write}; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use subtle::ConditionallySelectable; /// This trait represents an element of a field. pub trait Field: @@ -24,6 +25,7 @@ pub trait Field: + fmt::Debug + fmt::Display + 'static + + ConditionallySelectable + Add + Sub + Mul diff --git a/pairing/Cargo.toml b/pairing/Cargo.toml index 1c59855..32fc1be 100644 --- a/pairing/Cargo.toml +++ b/pairing/Cargo.toml @@ -21,6 +21,7 @@ byteorder = "1" ff = { version = "0.5.0", path = "../ff", features = ["derive"] } group = { version = "0.2.0", path = "../group" } rand_core = "0.5" +subtle = "2.2.1" [dev-dependencies] rand_xorshift = "0.2" diff --git a/pairing/src/bls12_381/fq12.rs b/pairing/src/bls12_381/fq12.rs index 77670e4..66608fa 100644 --- a/pairing/src/bls12_381/fq12.rs +++ b/pairing/src/bls12_381/fq12.rs @@ -4,6 +4,7 @@ use super::fq6::Fq6; use ff::Field; use rand_core::RngCore; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use subtle::{Choice, ConditionallySelectable}; /// An element of Fq12, represented by c0 + c1 * w. #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -40,6 +41,15 @@ impl Fq12 { } } +impl ConditionallySelectable for Fq12 { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Fq12 { + c0: Fq6::conditional_select(&a.c0, &b.c0, choice), + c1: Fq6::conditional_select(&a.c1, &b.c1, choice), + } + } +} + impl Neg for Fq12 { type Output = Self; diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs index f271913..823c635 100644 --- a/pairing/src/bls12_381/fq2.rs +++ b/pairing/src/bls12_381/fq2.rs @@ -3,6 +3,7 @@ use ff::{Field, SqrtField}; use rand_core::RngCore; use std::cmp::Ordering; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use subtle::{Choice, ConditionallySelectable}; /// An element of Fq2, represented by c0 + c1 * u. #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -54,6 +55,15 @@ impl Fq2 { } } +impl ConditionallySelectable for Fq2 { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Fq2 { + c0: Fq::conditional_select(&a.c0, &b.c0, choice), + c1: Fq::conditional_select(&a.c1, &b.c1, choice), + } + } +} + impl Neg for Fq2 { type Output = Self; diff --git a/pairing/src/bls12_381/fq6.rs b/pairing/src/bls12_381/fq6.rs index f8cb619..a64d25b 100644 --- a/pairing/src/bls12_381/fq6.rs +++ b/pairing/src/bls12_381/fq6.rs @@ -3,6 +3,7 @@ use super::fq2::Fq2; use ff::Field; use rand_core::RngCore; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use subtle::{Choice, ConditionallySelectable}; /// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2). #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -100,6 +101,16 @@ impl Fq6 { } } +impl ConditionallySelectable for Fq6 { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Fq6 { + c0: Fq2::conditional_select(&a.c0, &b.c0, choice), + c1: Fq2::conditional_select(&a.c1, &b.c1, choice), + c2: Fq2::conditional_select(&a.c2, &b.c2, choice), + } + } +} + impl Neg for Fq6 { type Output = Self; diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 4766c7a..8ebbbb2 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -28,6 +28,7 @@ rand_core = "0.5.1" ripemd160 = { version = "0.8", optional = true } secp256k1 = { version = "=0.15.0", optional = true } sha2 = "0.8" +subtle = "2.2.1" [dev-dependencies] hex-literal = "0.2" diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index da9bb3e..b1f1d3f 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -6,6 +6,7 @@ use ff::{ }; use rand_core::RngCore; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use subtle::{Choice, ConditionallySelectable}; use super::ToUniform; @@ -269,6 +270,17 @@ impl From for FsRepr { } } +impl ConditionallySelectable for Fs { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Fs(FsRepr([ + u64::conditional_select(&(a.0).0[0], &(b.0).0[0], choice), + u64::conditional_select(&(a.0).0[1], &(b.0).0[1], choice), + u64::conditional_select(&(a.0).0[2], &(b.0).0[2], choice), + u64::conditional_select(&(a.0).0[3], &(b.0).0[3], choice), + ])) + } +} + impl Neg for Fs { type Output = Self;