diff --git a/bellman/src/domain.rs b/bellman/src/domain.rs index 6e8a6a7b1..455a4c0f5 100644 --- a/bellman/src/domain.rs +++ b/bellman/src/domain.rs @@ -73,11 +73,11 @@ impl> EvaluationDomain { coeffs, exp, omega, - omegainv: omega.inverse().unwrap(), - geninv: E::Fr::multiplicative_generator().inverse().unwrap(), + omegainv: omega.invert().unwrap(), + geninv: E::Fr::multiplicative_generator().invert().unwrap(), minv: E::Fr::from_str(&format!("{}", m)) .unwrap() - .inverse() + .invert() .unwrap(), }) } @@ -141,10 +141,7 @@ impl> EvaluationDomain { /// evaluation domain, so we must perform division over /// a coset. pub fn divide_by_z_on_coset(&mut self, worker: &Worker) { - let i = self - .z(&E::Fr::multiplicative_generator()) - .inverse() - .unwrap(); + let i = self.z(&E::Fr::multiplicative_generator()).invert().unwrap(); worker.scope(self.coeffs.len(), |scope, chunk| { for v in self.coeffs.chunks_mut(chunk) { diff --git a/bellman/src/gadgets/num.rs b/bellman/src/gadgets/num.rs index 65bee2518..e460d201c 100644 --- a/bellman/src/gadgets/num.rs +++ b/bellman/src/gadgets/num.rs @@ -288,7 +288,7 @@ impl AllocatedNum { if tmp.is_zero() { Err(SynthesisError::DivisionByZero) } else { - Ok(tmp.inverse().unwrap()) + Ok(tmp.invert().unwrap()) } }, )?; diff --git a/bellman/src/groth16/generator.rs b/bellman/src/groth16/generator.rs index 11844d703..32c9d0765 100644 --- a/bellman/src/groth16/generator.rs +++ b/bellman/src/groth16/generator.rs @@ -215,8 +215,22 @@ where assembly.num_inputs + assembly.num_aux }); - let gamma_inverse = gamma.inverse().ok_or(SynthesisError::UnexpectedIdentity)?; - let delta_inverse = delta.inverse().ok_or(SynthesisError::UnexpectedIdentity)?; + let gamma_inverse = { + let inverse = gamma.invert(); + if bool::from(inverse.is_some()) { + Ok(inverse.unwrap()) + } else { + Err(SynthesisError::UnexpectedIdentity) + } + }?; + let delta_inverse = { + let inverse = delta.invert(); + if bool::from(inverse.is_some()) { + Ok(inverse.unwrap()) + } else { + Err(SynthesisError::UnexpectedIdentity) + } + }?; let worker = Worker::new(); diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 5d6422f57..87c22d623 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -10,13 +10,19 @@ 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}; +use subtle::{Choice, ConditionallySelectable, CtOption}; const MODULUS_R: Wrapping = Wrapping(64513); #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Fr(Wrapping); +impl Default for Fr { + fn default() -> Self { + ::zero() + } +} + impl fmt::Display for Fr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{}", (self.0).0) @@ -159,11 +165,11 @@ impl Field for Fr { Fr((self.0 << 1) % MODULUS_R) } - fn inverse(&self) -> Option { + fn invert(&self) -> CtOption { if ::is_zero(self) { - None + CtOption::new(::zero(), Choice::from(0)) } else { - Some(self.pow(&[(MODULUS_R.0 as u64) - 2])) + CtOption::new(self.pow(&[(MODULUS_R.0 as u64) - 2]), Choice::from(1)) } } @@ -382,8 +388,8 @@ impl Engine for DummyEngine { } /// Perform final exponentiation of the result of a miller loop. - fn final_exponentiation(this: &Self::Fqk) -> Option { - Some(*this) + fn final_exponentiation(this: &Self::Fqk) -> CtOption { + CtOption::new(*this, Choice::from(1)) } } diff --git a/bellman/src/groth16/tests/mod.rs b/bellman/src/groth16/tests/mod.rs index aaefb5f71..f3349a421 100644 --- a/bellman/src/groth16/tests/mod.rs +++ b/bellman/src/groth16/tests/mod.rs @@ -156,8 +156,8 @@ fn test_xordemo() { // We expect our H query to be 7 elements of the form... // {tau^i t(tau) / delta} - let delta_inverse = delta.inverse().unwrap(); - let gamma_inverse = gamma.inverse().unwrap(); + let delta_inverse = delta.invert().unwrap(); + let gamma_inverse = gamma.invert().unwrap(); { let mut coeff = delta_inverse; coeff.mul_assign(&t_at_tau); diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index 09d5e12e2..6a1ecec1e 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -791,6 +791,12 @@ fn prime_field_impl( } } + impl ::std::default::Default for #name { + fn default() -> #name { + #name::zero() + } + } + impl ::std::cmp::PartialEq for #name { fn eq(&self, other: &#name) -> bool { self.0 == other.0 @@ -1062,9 +1068,11 @@ fn prime_field_impl( ret } - fn inverse(&self) -> Option { + /// WARNING: THIS IS NOT ACTUALLY CONSTANT TIME YET! + /// TODO: Make this constant-time. + fn invert(&self) -> ::subtle::CtOption { if self.is_zero() { - None + ::subtle::CtOption::new(#name::zero(), ::subtle::Choice::from(0)) } else { // Guajardo Kumar Paar Pelzl // Efficient Software-Implementation of Finite Fields with Applications to Cryptography @@ -1110,9 +1118,9 @@ fn prime_field_impl( } if u == one { - Some(b) + ::subtle::CtOption::new(b, ::subtle::Choice::from(1)) } else { - Some(c) + ::subtle::CtOption::new(c, ::subtle::Choice::from(1)) } } } diff --git a/ff/src/lib.rs b/ff/src/lib.rs index e59e62727..675d0b30e 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -12,7 +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; +use subtle::{ConditionallySelectable, CtOption}; /// This trait represents an element of a field. pub trait Field: @@ -20,6 +20,7 @@ pub trait Field: + Eq + Copy + Clone + + Default + Send + Sync + fmt::Debug @@ -60,8 +61,9 @@ pub trait Field: #[must_use] fn double(&self) -> Self; - /// Computes the multiplicative inverse of this element, if nonzero. - fn inverse(&self) -> Option; + /// Computes the multiplicative inverse of this element, + /// failing if the element is zero. + fn invert(&self) -> CtOption; /// Exponentiates this element by a power of the base prime modulus via /// the Frobenius automorphism. diff --git a/pairing/benches/bls12_381/fq.rs b/pairing/benches/bls12_381/fq.rs index bd4ed15d5..5ef576802 100644 --- a/pairing/benches/bls12_381/fq.rs +++ b/pairing/benches/bls12_381/fq.rs @@ -217,7 +217,7 @@ fn bench_fq_square(b: &mut ::test::Bencher) { } #[bench] -fn bench_fq_inverse(b: &mut ::test::Bencher) { +fn bench_fq_invert(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; let mut rng = XorShiftRng::from_seed([ @@ -230,7 +230,7 @@ fn bench_fq_inverse(b: &mut ::test::Bencher) { let mut count = 0; b.iter(|| { count = (count + 1) % SAMPLES; - v[count].inverse() + v[count].invert() }); } diff --git a/pairing/benches/bls12_381/fq12.rs b/pairing/benches/bls12_381/fq12.rs index b79bf5c68..eedd9f8de 100644 --- a/pairing/benches/bls12_381/fq12.rs +++ b/pairing/benches/bls12_381/fq12.rs @@ -91,7 +91,7 @@ fn bench_fq12_squaring(b: &mut ::test::Bencher) { } #[bench] -fn bench_fq12_inverse(b: &mut ::test::Bencher) { +fn bench_fq12_invert(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; let mut rng = XorShiftRng::from_seed([ @@ -103,7 +103,7 @@ fn bench_fq12_inverse(b: &mut ::test::Bencher) { let mut count = 0; b.iter(|| { - let tmp = v[count].inverse(); + let tmp = v[count].invert(); count = (count + 1) % SAMPLES; tmp }); diff --git a/pairing/benches/bls12_381/fq2.rs b/pairing/benches/bls12_381/fq2.rs index ace017187..d3a2b4d51 100644 --- a/pairing/benches/bls12_381/fq2.rs +++ b/pairing/benches/bls12_381/fq2.rs @@ -91,7 +91,7 @@ fn bench_fq2_squaring(b: &mut ::test::Bencher) { } #[bench] -fn bench_fq2_inverse(b: &mut ::test::Bencher) { +fn bench_fq2_invert(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; let mut rng = XorShiftRng::from_seed([ @@ -103,7 +103,7 @@ fn bench_fq2_inverse(b: &mut ::test::Bencher) { let mut count = 0; b.iter(|| { - let tmp = v[count].inverse(); + let tmp = v[count].invert(); count = (count + 1) % SAMPLES; tmp }); diff --git a/pairing/benches/bls12_381/fr.rs b/pairing/benches/bls12_381/fr.rs index e4d07d286..4e3d4c2e2 100644 --- a/pairing/benches/bls12_381/fr.rs +++ b/pairing/benches/bls12_381/fr.rs @@ -217,7 +217,7 @@ fn bench_fr_square(b: &mut ::test::Bencher) { } #[bench] -fn bench_fr_inverse(b: &mut ::test::Bencher) { +fn bench_fr_invert(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; let mut rng = XorShiftRng::from_seed([ @@ -230,7 +230,7 @@ fn bench_fr_inverse(b: &mut ::test::Bencher) { let mut count = 0; b.iter(|| { count = (count + 1) % SAMPLES; - v[count].inverse() + v[count].invert() }); } diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index abf6873b8..e80fe1754 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -251,7 +251,7 @@ macro_rules! curve_impl { } // Invert `tmp`. - tmp = tmp.inverse().unwrap(); // Guaranteed to be nonzero. + tmp = tmp.invert().unwrap(); // Guaranteed to be nonzero. // Second pass: iterate backwards to compute inverses for (g, s) in v @@ -571,7 +571,7 @@ macro_rules! curve_impl { } } else { // Z is nonzero, so it must have an inverse in a field. - let zinv = p.z.inverse().unwrap(); + let zinv = p.z.invert().unwrap(); let mut zinv_powered = zinv.square(); // X/Z^2 diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs index 28326f403..bc4a7b3f7 100644 --- a/pairing/src/bls12_381/fq.rs +++ b/pairing/src/bls12_381/fq.rs @@ -1965,8 +1965,8 @@ fn test_fq_squaring() { } #[test] -fn test_fq_inverse() { - assert!(Fq::zero().inverse().is_none()); +fn test_fq_invert() { + assert!(bool::from(Fq::zero().invert().is_none())); let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -1978,7 +1978,7 @@ fn test_fq_inverse() { for _ in 0..1000 { // Ensure that a * a^-1 = 1 let mut a = Fq::random(&mut rng); - let ainv = a.inverse().unwrap(); + let ainv = a.invert().unwrap(); a.mul_assign(&ainv); assert_eq!(a, one); } diff --git a/pairing/src/bls12_381/fq12.rs b/pairing/src/bls12_381/fq12.rs index 66608fa87..7e2751b97 100644 --- a/pairing/src/bls12_381/fq12.rs +++ b/pairing/src/bls12_381/fq12.rs @@ -4,10 +4,10 @@ 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}; +use subtle::{Choice, ConditionallySelectable, CtOption}; /// An element of Fq12, represented by c0 + c1 * w. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] pub struct Fq12 { pub c0: Fq6, pub c1: Fq6, @@ -226,13 +226,13 @@ impl Field for Fq12 { Fq12 { c0, c1 } } - fn inverse(&self) -> Option { + fn invert(&self) -> CtOption { let mut c0s = self.c0.square(); let mut c1s = self.c1.square(); c1s.mul_by_nonresidue(); c0s.sub_assign(&c1s); - c0s.inverse().map(|t| Fq12 { + c0s.invert().map(|t| Fq12 { c0: t.mul(&self.c0), c1: t.mul(&self.c1).neg(), }) diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs index 823c635fe..de0939aad 100644 --- a/pairing/src/bls12_381/fq2.rs +++ b/pairing/src/bls12_381/fq2.rs @@ -3,10 +3,10 @@ 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}; +use subtle::{Choice, ConditionallySelectable, CtOption}; /// An element of Fq2, represented by c0 + c1 * u. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] pub struct Fq2 { pub c0: Fq, pub c1: Fq, @@ -228,11 +228,11 @@ impl Field for Fq2 { } } - fn inverse(&self) -> Option { + fn invert(&self) -> CtOption { let t1 = self.c1.square(); let mut t0 = self.c0.square(); t0.add_assign(&t1); - t0.inverse().map(|t| Fq2 { + t0.invert().map(|t| Fq2 { c0: self.c0.mul(&t), c1: self.c1.mul(&t).neg(), }) @@ -497,11 +497,11 @@ fn test_fq2_mul() { } #[test] -fn test_fq2_inverse() { +fn test_fq2_invert() { use super::fq::FqRepr; use ff::PrimeField; - assert!(Fq2::zero().inverse().is_none()); + assert!(bool::from(Fq2::zero().invert().is_none())); let a = Fq2 { c0: Fq::from_repr(FqRepr([ @@ -523,7 +523,7 @@ fn test_fq2_inverse() { ])) .unwrap(), }; - let a = a.inverse().unwrap(); + let a = a.invert().unwrap(); assert_eq!( a, Fq2 { diff --git a/pairing/src/bls12_381/fq6.rs b/pairing/src/bls12_381/fq6.rs index a64d25b1e..1b3be7f06 100644 --- a/pairing/src/bls12_381/fq6.rs +++ b/pairing/src/bls12_381/fq6.rs @@ -3,10 +3,10 @@ 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}; +use subtle::{Choice, ConditionallySelectable, CtOption}; /// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2). -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] pub struct Fq6 { pub c0: Fq2, pub c1: Fq2, @@ -345,7 +345,7 @@ impl Field for Fq6 { Fq6 { c0, c1, c2 } } - fn inverse(&self) -> Option { + fn invert(&self) -> CtOption { let mut c0 = self.c2; c0.mul_by_nonresidue(); c0.mul_assign(&self.c1); @@ -378,21 +378,18 @@ impl Field for Fq6 { tmp2.mul_assign(&c0); tmp1.add_assign(&tmp2); - match tmp1.inverse() { - Some(t) => { - let mut tmp = Fq6 { - c0: t, - c1: t, - c2: t, - }; - tmp.c0.mul_assign(&c0); - tmp.c1.mul_assign(&c1); - tmp.c2.mul_assign(&c2); + tmp1.invert().map(|t| { + let mut tmp = Fq6 { + c0: t, + c1: t, + c2: t, + }; + tmp.c0.mul_assign(&c0); + tmp.c1.mul_assign(&c1); + tmp.c2.mul_assign(&c2); - Some(tmp) - } - None => None, - } + tmp + }) } } diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs index 777aa8721..226c1aab1 100644 --- a/pairing/src/bls12_381/fr.rs +++ b/pairing/src/bls12_381/fr.rs @@ -724,8 +724,8 @@ fn test_fr_squaring() { } #[test] -fn test_fr_inverse() { - assert!(Fr::zero().inverse().is_none()); +fn test_fr_invert() { + assert!(bool::from(Fr::zero().invert().is_none())); let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -737,7 +737,7 @@ fn test_fr_inverse() { for _ in 0..1000 { // Ensure that a * a^-1 = 1 let mut a = Fr::random(&mut rng); - let ainv = a.inverse().unwrap(); + let ainv = a.invert().unwrap(); a.mul_assign(&ainv); assert_eq!(a, one); } diff --git a/pairing/src/bls12_381/mod.rs b/pairing/src/bls12_381/mod.rs index 5843e94eb..ad66cbde5 100644 --- a/pairing/src/bls12_381/mod.rs +++ b/pairing/src/bls12_381/mod.rs @@ -26,6 +26,7 @@ use super::{Engine, PairingCurveAffine}; use ff::{BitIterator, Field, ScalarEngine}; use group::CurveAffine; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; +use subtle::CtOption; // The BLS parameter x for BLS12-381 is -0xd201000000010000 const BLS_X: u64 = 0xd201000000010000; @@ -111,61 +112,58 @@ impl Engine for Bls12 { f } - fn final_exponentiation(r: &Fq12) -> Option { + fn final_exponentiation(r: &Fq12) -> CtOption { let mut f1 = *r; f1.conjugate(); - match r.inverse() { - Some(mut f2) => { - let mut r = f1; - r.mul_assign(&f2); - f2 = r; - r.frobenius_map(2); - r.mul_assign(&f2); + r.invert().map(|mut f2| { + let mut r = f1; + r.mul_assign(&f2); + f2 = r; + r.frobenius_map(2); + r.mul_assign(&f2); - fn exp_by_x(f: &mut Fq12, x: u64) { - *f = f.pow(&[x]); - if BLS_X_IS_NEGATIVE { - f.conjugate(); - } + fn exp_by_x(f: &mut Fq12, x: u64) { + *f = f.pow(&[x]); + if BLS_X_IS_NEGATIVE { + f.conjugate(); } - - let mut x = BLS_X; - let y0 = r.square(); - let mut y1 = y0; - exp_by_x(&mut y1, x); - x >>= 1; - let mut y2 = y1; - exp_by_x(&mut y2, x); - x <<= 1; - let mut y3 = r; - y3.conjugate(); - y1.mul_assign(&y3); - y1.conjugate(); - y1.mul_assign(&y2); - y2 = y1; - exp_by_x(&mut y2, x); - y3 = y2; - exp_by_x(&mut y3, x); - y1.conjugate(); - y3.mul_assign(&y1); - y1.conjugate(); - y1.frobenius_map(3); - y2.frobenius_map(2); - y1.mul_assign(&y2); - y2 = y3; - exp_by_x(&mut y2, x); - y2.mul_assign(&y0); - y2.mul_assign(&r); - y1.mul_assign(&y2); - y2 = y3; - y2.frobenius_map(1); - y1.mul_assign(&y2); - - Some(y1) } - None => None, - } + + let mut x = BLS_X; + let y0 = r.square(); + let mut y1 = y0; + exp_by_x(&mut y1, x); + x >>= 1; + let mut y2 = y1; + exp_by_x(&mut y2, x); + x <<= 1; + let mut y3 = r; + y3.conjugate(); + y1.mul_assign(&y3); + y1.conjugate(); + y1.mul_assign(&y2); + y2 = y1; + exp_by_x(&mut y2, x); + y3 = y2; + exp_by_x(&mut y3, x); + y1.conjugate(); + y3.mul_assign(&y1); + y1.conjugate(); + y1.frobenius_map(3); + y2.frobenius_map(2); + y1.mul_assign(&y2); + y2 = y3; + exp_by_x(&mut y2, x); + y2.mul_assign(&y0); + y2.mul_assign(&r); + y1.mul_assign(&y2); + y2 = y3; + y2.frobenius_map(1); + y1.mul_assign(&y2); + + y1 + }) } } diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index 9afb42797..bd060a12f 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -22,6 +22,7 @@ pub mod bls12_381; use ff::{Field, PrimeField, ScalarEngine, SqrtField}; use group::{CurveAffine, CurveProjective}; +use subtle::CtOption; /// An "engine" is a collection of types (fields, elliptic curve groups, etc.) /// with well-defined relationships. In particular, the G1/G2 curve groups are @@ -75,7 +76,7 @@ pub trait Engine: ScalarEngine { >; /// Perform final exponentiation of the result of a miller loop. - fn final_exponentiation(_: &Self::Fqk) -> Option; + fn final_exponentiation(_: &Self::Fqk) -> CtOption; /// Performs a complete pairing operation `(p, q)`. fn pairing(p: G1, q: G2) -> Self::Fqk diff --git a/pairing/src/tests/field.rs b/pairing/src/tests/field.rs index eaba476d7..03741229a 100644 --- a/pairing/src/tests/field.rs +++ b/pairing/src/tests/field.rs @@ -78,7 +78,7 @@ pub fn random_field_tests() { assert!(z.is_zero()); } - assert!(F::zero().inverse().is_none()); + assert!(bool::from(F::zero().invert().is_none())); // Multiplication by zero { @@ -222,11 +222,11 @@ fn random_squaring_tests(rng: &mut R) { } fn random_inversion_tests(rng: &mut R) { - assert!(F::zero().inverse().is_none()); + assert!(bool::from(F::zero().invert().is_none())); for _ in 0..10000 { let mut a = F::random(rng); - let b = a.inverse().unwrap(); // probablistically nonzero + let b = a.invert().unwrap(); // probablistically nonzero a.mul_assign(&b); assert_eq!(a, F::one()); diff --git a/zcash_primitives/src/jubjub/edwards.rs b/zcash_primitives/src/jubjub/edwards.rs index 4ae24422d..94f1ceba0 100644 --- a/zcash_primitives/src/jubjub/edwards.rs +++ b/zcash_primitives/src/jubjub/edwards.rs @@ -1,5 +1,6 @@ use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; +use subtle::{Choice, CtOption}; use super::{montgomery, JubjubEngine, JubjubParams, PrimeOrder, Unknown}; @@ -90,10 +91,14 @@ impl Point { y_repr.as_mut()[3] &= 0x7fffffffffffffff; match E::Fr::from_repr(y_repr) { - Ok(y) => match Self::get_for_y(y, x_sign, params) { - Some(p) => Ok(p), - None => Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve")), - }, + Ok(y) => { + let p = Self::get_for_y(y, x_sign, params); + if bool::from(p.is_some()) { + Ok(p.unwrap()) + } else { + Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve")) + } + } Err(_) => Err(io::Error::new( io::ErrorKind::InvalidInput, "y is not in field", @@ -101,7 +106,7 @@ impl Point { } } - pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> Option { + pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> CtOption { // Given a y on the curve, x^2 = (y^2 - 1) / (dy^2 + 1) // This is defined for all valid y-coordinates, // as dy^2 + 1 = 0 has no solution in Fr. @@ -117,33 +122,30 @@ impl Point { // tmp1 = y^2 - 1 tmp1.sub_assign(&E::Fr::one()); - match tmp2.inverse() { - Some(tmp2) => { - // tmp1 = (y^2 - 1) / (dy^2 + 1) - tmp1.mul_assign(&tmp2); + tmp2.invert().and_then(|tmp2| { + // tmp1 = (y^2 - 1) / (dy^2 + 1) + tmp1.mul_assign(&tmp2); - match tmp1.sqrt() { - Some(mut x) => { - if x.into_repr().is_odd() != sign { - x = x.neg(); - } - - let mut t = x; - t.mul_assign(&y); - - Some(Point { - x, - y, - t, - z: E::Fr::one(), - _marker: PhantomData, - }) - } - None => None, + match tmp1.sqrt().map(|mut x| { + if x.into_repr().is_odd() != sign { + x = x.neg(); } + + let mut t = x; + t.mul_assign(&y); + + Point { + x, + y, + t, + z: E::Fr::one(), + _marker: PhantomData, + } + }) { + Some(p) => CtOption::new(p, Choice::from(1)), + None => CtOption::new(Point::zero(), Choice::from(0)), } - None => None, - } + }) } /// This guarantees the point is in the prime order subgroup @@ -159,8 +161,9 @@ impl Point { let y = E::Fr::random(rng); let sign = rng.next_u32() % 2 != 0; - if let Some(p) = Self::get_for_y(y, sign, params) { - return p; + let p = Self::get_for_y(y, sign, params); + if bool::from(p.is_some()) { + return p.unwrap(); } } } @@ -305,7 +308,7 @@ impl Point { /// Convert to affine coordinates pub fn to_xy(&self) -> (E::Fr, E::Fr) { - let zinv = self.z.inverse().unwrap(); + let zinv = self.z.invert().unwrap(); let mut x = self.x; x.mul_assign(&zinv); diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index b1f1d3fca..d2b61cb71 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -6,7 +6,7 @@ use ff::{ }; use rand_core::RngCore; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -use subtle::{Choice, ConditionallySelectable}; +use subtle::{Choice, ConditionallySelectable, CtOption}; use super::ToUniform; @@ -258,6 +258,12 @@ impl PrimeFieldRepr for FsRepr { #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Fs(FsRepr); +impl Default for Fs { + fn default() -> Self { + Fs::zero() + } +} + impl ::std::fmt::Display for Fs { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "Fs({})", self.into_repr()) @@ -526,9 +532,11 @@ impl Field for Fs { ret } - fn inverse(&self) -> Option { + /// WARNING: THIS IS NOT ACTUALLY CONSTANT TIME YET! + /// THIS WILL BE REPLACED BY THE jubjub CRATE, WHICH IS CONSTANT TIME! + fn invert(&self) -> CtOption { if self.is_zero() { - None + CtOption::new(Self::zero(), Choice::from(0)) } else { // Guajardo Kumar Paar Pelzl // Efficient Software-Implementation of Finite Fields with Applications to Cryptography @@ -574,9 +582,9 @@ impl Field for Fs { } if u == one { - Some(b) + CtOption::new(b, Choice::from(1)) } else { - Some(c) + CtOption::new(c, Choice::from(1)) } } } @@ -1454,8 +1462,8 @@ fn test_fr_squaring() { } #[test] -fn test_fs_inverse() { - assert!(Fs::zero().inverse().is_none()); +fn test_fs_invert() { + assert!(bool::from(Fs::zero().invert().is_none())); let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -1467,7 +1475,7 @@ fn test_fs_inverse() { for _ in 0..1000 { // Ensure that a * a^-1 = 1 let mut a = Fs::random(&mut rng); - let ainv = a.inverse().unwrap(); + let ainv = a.invert().unwrap(); a.mul_assign(&ainv); assert_eq!(a, one); } diff --git a/zcash_primitives/src/jubjub/montgomery.rs b/zcash_primitives/src/jubjub/montgomery.rs index a708d028d..b9ca82e10 100644 --- a/zcash_primitives/src/jubjub/montgomery.rs +++ b/zcash_primitives/src/jubjub/montgomery.rs @@ -139,11 +139,11 @@ impl Point { { let mut tmp = E::Fr::one(); tmp.sub_assign(&y); - u.mul_assign(&tmp.inverse().unwrap()) + u.mul_assign(&tmp.invert().unwrap()) } let mut v = u; - v.mul_assign(&x.inverse().unwrap()); + v.mul_assign(&x.invert().unwrap()); // Scale it into the correct curve constants v.mul_assign(params.scale()); @@ -226,7 +226,8 @@ impl Point { } { let tmp = self.y.double(); - delta.mul_assign(&tmp.inverse().expect("y is nonzero so this must be nonzero")); + // y is nonzero so this must be nonzero + delta.mul_assign(&tmp.invert().unwrap()); } let mut x3 = delta.square(); @@ -272,10 +273,8 @@ impl Point { { let mut tmp = other.x; tmp.sub_assign(&self.x); - delta.mul_assign( - &tmp.inverse() - .expect("self.x != other.x, so this must be nonzero"), - ); + // self.x != other.x, so this must be nonzero + delta.mul_assign(&tmp.invert().unwrap()); } let mut x3 = delta.square(); diff --git a/zcash_primitives/src/jubjub/tests.rs b/zcash_primitives/src/jubjub/tests.rs index f0bb46443..511a5eb67 100644 --- a/zcash_primitives/src/jubjub/tests.rs +++ b/zcash_primitives/src/jubjub/tests.rs @@ -234,7 +234,9 @@ fn test_get_for(params: &E::Params) { let y = E::Fr::random(rng); let sign = rng.next_u32() % 2 == 1; - if let Some(mut p) = edwards::Point::::get_for_y(y, sign, params) { + let p = edwards::Point::::get_for_y(y, sign, params); + if bool::from(p.is_some()) { + let mut p = p.unwrap(); assert!(p.to_xy().0.into_repr().is_odd() == sign); p = p.negate(); assert!(edwards::Point::::get_for_y(y, !sign, params).unwrap() == p); @@ -328,7 +330,7 @@ fn test_jubjub_params(params: &E::Params) { let mut tmp = *params.edwards_d(); // 1 / d is nonsquare - assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue); + assert!(tmp.invert().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue); // tmp = -d tmp = tmp.neg(); @@ -337,7 +339,7 @@ fn test_jubjub_params(params: &E::Params) { assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue); // 1 / -d is nonsquare - assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue); + assert!(tmp.invert().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue); } { @@ -358,7 +360,7 @@ fn test_jubjub_params(params: &E::Params) { // Check the validity of the scaling factor let mut tmp = a; tmp.sub_assign(¶ms.edwards_d()); - tmp = tmp.inverse().unwrap(); + tmp = tmp.invert().unwrap(); tmp.mul_assign(&E::Fr::from_str("4").unwrap()); tmp = tmp.sqrt().unwrap(); assert_eq!(&tmp, params.scale()); diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs index 29c14a44a..82e676174 100644 --- a/zcash_proofs/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -344,13 +344,11 @@ impl EdwardsPoint { let mut t1 = E::Fr::one(); t1.add_assign(c.get_value().get()?); - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - } - None => Err(SynthesisError::DivisionByZero), + let res = t1.invert().map(|t1| t0 * &t1); + if bool::from(res.is_some()) { + Ok(res.unwrap()) + } else { + Err(SynthesisError::DivisionByZero) } })?; @@ -371,13 +369,11 @@ impl EdwardsPoint { let mut t1 = E::Fr::one(); t1.sub_assign(c.get_value().get()?); - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - } - None => Err(SynthesisError::DivisionByZero), + let res = t1.invert().map(|t1| t0 * &t1); + if bool::from(res.is_some()) { + Ok(res.unwrap()) + } else { + Err(SynthesisError::DivisionByZero) } })?; @@ -451,13 +447,11 @@ impl EdwardsPoint { let mut t1 = E::Fr::one(); t1.add_assign(c.get_value().get()?); - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - } - None => Err(SynthesisError::DivisionByZero), + let ret = t1.invert().map(|t1| t0 * &t1); + if bool::from(ret.is_some()) { + Ok(ret.unwrap()) + } else { + Err(SynthesisError::DivisionByZero) } })?; @@ -478,13 +472,11 @@ impl EdwardsPoint { let mut t1 = E::Fr::one(); t1.sub_assign(c.get_value().get()?); - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - } - None => Err(SynthesisError::DivisionByZero), + let ret = t1.invert().map(|t1| t0 * &t1); + if bool::from(ret.is_some()) { + Ok(ret.unwrap()) + } else { + Err(SynthesisError::DivisionByZero) } })?; @@ -521,13 +513,11 @@ impl MontgomeryPoint { let mut t0 = *self.x.get_value().get()?; t0.mul_assign(params.scale()); - match self.y.get_value().get()?.inverse() { - Some(invy) => { - t0.mul_assign(&invy); - - Ok(t0) - } - None => Err(SynthesisError::DivisionByZero), + let ret = self.y.get_value().get()?.invert().map(|invy| t0 * &invy); + if bool::from(ret.is_some()) { + Ok(ret.unwrap()) + } else { + Err(SynthesisError::DivisionByZero) } })?; @@ -545,13 +535,11 @@ impl MontgomeryPoint { t0.sub_assign(&E::Fr::one()); t1.add_assign(&E::Fr::one()); - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - } - None => Err(SynthesisError::DivisionByZero), + let ret = t1.invert().map(|t1| t0 * &t1); + if bool::from(ret.is_some()) { + Ok(ret.unwrap()) + } else { + Err(SynthesisError::DivisionByZero) } })?; @@ -593,12 +581,11 @@ impl MontgomeryPoint { let mut d = *other.x.get_value().get()?; d.sub_assign(self.x.get_value().get()?); - match d.inverse() { - Some(d) => { - n.mul_assign(&d); - Ok(n) - } - None => Err(SynthesisError::DivisionByZero), + let ret = d.invert().map(|d| n * &d); + if bool::from(ret.is_some()) { + Ok(ret.unwrap()) + } else { + Err(SynthesisError::DivisionByZero) } })?;