From 26ef9c9842257ee560185739ca550564f86139dc Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 18 Dec 2019 17:53:39 -0600 Subject: [PATCH 1/2] Pass modulus to prime_field_constants_and_sqrt by reference --- ff/ff_derive/src/lib.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index 7b19d9664..dceb50803 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -47,7 +47,7 @@ pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let mut gen = proc_macro2::TokenStream::new(); let (constants_impl, sqrt_impl) = - prime_field_constants_and_sqrt(&ast.ident, &repr_ident, modulus, limbs, generator); + prime_field_constants_and_sqrt(&ast.ident, &repr_ident, &modulus, limbs, generator); gen.extend(constants_impl); gen.extend(prime_field_repr_impl(&repr_ident, limbs)); @@ -383,7 +383,7 @@ fn test_exp() { fn prime_field_constants_and_sqrt( name: &syn::Ident, repr: &syn::Ident, - modulus: BigUint, + modulus: &BigUint, limbs: usize, generator: BigUint, ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) { @@ -396,28 +396,26 @@ fn prime_field_constants_and_sqrt( let repr_shave_bits = (64 * limbs as u32) - biguint_num_bits(modulus.clone()); // Compute R = 2**(64 * limbs) mod m - let r = (BigUint::one() << (limbs * 64)) % &modulus; + let r = (BigUint::one() << (limbs * 64)) % modulus; // modulus - 1 = 2^s * t let mut s: u32 = 0; - let mut t = &modulus - BigUint::from_str("1").unwrap(); + let mut t = modulus - BigUint::from_str("1").unwrap(); while t.is_even() { t = t >> 1; s += 1; } // Compute 2^s root of unity given the generator - let root_of_unity = biguint_to_u64_vec( - (exp(generator.clone(), &t, &modulus) * &r) % &modulus, - limbs, - ); - let generator = biguint_to_u64_vec((generator.clone() * &r) % &modulus, limbs); + let root_of_unity = + biguint_to_u64_vec((exp(generator.clone(), &t, &modulus) * &r) % modulus, limbs); + let generator = biguint_to_u64_vec((generator.clone() * &r) % modulus, limbs); - let sqrt_impl = if (&modulus % BigUint::from_str("4").unwrap()) + let sqrt_impl = if (modulus % BigUint::from_str("4").unwrap()) == BigUint::from_str("3").unwrap() { let mod_plus_1_over_4 = - biguint_to_u64_vec((&modulus + BigUint::from_str("1").unwrap()) >> 2, limbs); + biguint_to_u64_vec((modulus + BigUint::from_str("1").unwrap()) >> 2, limbs); quote! { impl ::ff::SqrtField for #name { @@ -436,7 +434,7 @@ fn prime_field_constants_and_sqrt( } } } - } else if (&modulus % BigUint::from_str("16").unwrap()) == BigUint::from_str("1").unwrap() { + } else if (modulus % BigUint::from_str("16").unwrap()) == BigUint::from_str("1").unwrap() { let t_minus_1_over_2 = biguint_to_u64_vec((&t - BigUint::one()) >> 1, limbs); quote! { @@ -490,10 +488,10 @@ fn prime_field_constants_and_sqrt( }; // Compute R^2 mod m - let r2 = biguint_to_u64_vec((&r * &r) % &modulus, limbs); + let r2 = biguint_to_u64_vec((&r * &r) % modulus, limbs); let r = biguint_to_u64_vec(r, limbs); - let modulus = biguint_to_real_u64_vec(modulus, limbs); + let modulus = biguint_to_real_u64_vec(modulus.clone(), limbs); // Compute -m^-1 mod 2**64 by exponentiating by totient(2**64) - 1 let mut inv = 1u64; From 56999d0f7336347a0b9b7e89738be264401b888e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 19 Dec 2019 08:22:06 -0600 Subject: [PATCH 2/2] Constant-time field inversion in ff_derive using Field::pow_vartime This is around 2.5-3x slower than the non-constant-time inversion. We can regain some of this speed later by dynamically generating addition chains. --- ff/ff_derive/src/lib.rs | 85 +++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 55 deletions(-) diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index dceb50803..59d9e11dc 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -51,7 +51,7 @@ pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream { gen.extend(constants_impl); gen.extend(prime_field_repr_impl(&repr_ident, limbs)); - gen.extend(prime_field_impl(&ast.ident, &repr_ident, limbs)); + gen.extend(prime_field_impl(&ast.ident, &repr_ident, &modulus, limbs)); gen.extend(sqrt_impl); // Return the generated impl @@ -540,6 +540,7 @@ fn prime_field_constants_and_sqrt( fn prime_field_impl( name: &syn::Ident, repr: &syn::Ident, + modulus: &BigUint, limbs: usize, ) -> proc_macro2::TokenStream { // Returns r{n} as an ident. @@ -742,8 +743,35 @@ fn prime_field_impl( gen } + /// Generates an implementation of multiplicative inversion within the target prime + /// field. + fn inv_impl( + a: proc_macro2::TokenStream, + name: &syn::Ident, + modulus: &BigUint, + limbs: usize, + ) -> proc_macro2::TokenStream { + let mod_minus_2 = biguint_to_u64_vec(modulus - BigUint::from(2u64), limbs); + + // TODO: Improve on this by computing an addition chain for mod_minus_two + quote! { + use ::subtle::ConstantTimeEq; + + // By Euler's theorem, if `a` is coprime to `p` (i.e. `gcd(a, p) = 1`), then: + // a^-1 ≡ a^(phi(p) - 1) mod p + // + // `ff_derive` requires that `p` is prime; in this case, `phi(p) = p - 1`, and + // thus: + // a^-1 ≡ a^(p - 2) mod p + let inv = #a.pow_vartime(#mod_minus_2); + + ::subtle::CtOption::new(inv, !#a.ct_eq(&#name::zero())) + } + } + let squaring_impl = sqr_impl(quote! {self}, limbs); let multiply_impl = mul_impl(quote! {self}, quote! {other}, limbs); + let invert_impl = inv_impl(quote! {self}, name, modulus, limbs); let montgomery_impl = mont_impl(limbs); // (self.0).0[0].ct_eq(&(other.0).0[0]) & (self.0).0[1].ct_eq(&(other.0).0[1]) & ... @@ -1056,61 +1084,8 @@ fn prime_field_impl( ret } - /// WARNING: THIS IS NOT ACTUALLY CONSTANT TIME YET! - /// TODO: Make this constant-time. fn invert(&self) -> ::subtle::CtOption { - if self.is_zero() { - ::subtle::CtOption::new(#name::zero(), ::subtle::Choice::from(0)) - } else { - // Guajardo Kumar Paar Pelzl - // Efficient Software-Implementation of Finite Fields with Applications to Cryptography - // Algorithm 16 (BEA for Inversion in Fp) - - let one = #repr::from(1); - - let mut u = self.0; - let mut v = MODULUS; - let mut b = #name(R2); // Avoids unnecessary reduction step. - let mut c = Self::zero(); - - while u != one && v != one { - while u.is_even() { - u.div2(); - - if b.0.is_even() { - b.0.div2(); - } else { - b.0.add_nocarry(&MODULUS); - b.0.div2(); - } - } - - while v.is_even() { - v.div2(); - - if c.0.is_even() { - c.0.div2(); - } else { - c.0.add_nocarry(&MODULUS); - c.0.div2(); - } - } - - if v < u { - u.sub_noborrow(&v); - b.sub_assign(&c); - } else { - v.sub_noborrow(&u); - c.sub_assign(&b); - } - } - - if u == one { - ::subtle::CtOption::new(b, ::subtle::Choice::from(1)) - } else { - ::subtle::CtOption::new(c, ::subtle::Choice::from(1)) - } - } + #invert_impl } #[inline(always)]