Generate addition chains inside Field::invert and SqrtField::sqrt

This commit is contained in:
Jack Grigg 2019-12-19 22:10:29 -06:00
parent 232fb4b7a3
commit 2942e9a7e6
1 changed files with 19 additions and 10 deletions

View File

@ -409,8 +409,11 @@ fn prime_field_constants_and_sqrt(
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() == BigUint::from_str("3").unwrap()
{ {
let mod_plus_1_over_4 = // Addition chain for (r + 1) // 4
biguint_to_u64_vec((modulus + BigUint::from_str("1").unwrap()) >> 2, limbs); let mod_plus_1_over_4 = pow_fixed::generate(
&quote! {self},
(modulus + BigUint::from_str("1").unwrap()) >> 2,
);
quote! { quote! {
impl ::ff::SqrtField for #name { impl ::ff::SqrtField for #name {
@ -420,7 +423,9 @@ fn prime_field_constants_and_sqrt(
// Because r = 3 (mod 4) // Because r = 3 (mod 4)
// sqrt can be done with only one exponentiation, // sqrt can be done with only one exponentiation,
// via the computation of self^((r + 1) // 4) (mod r) // via the computation of self^((r + 1) // 4) (mod r)
let sqrt = self.pow_vartime(#mod_plus_1_over_4); let sqrt = {
#mod_plus_1_over_4
};
::subtle::CtOption::new( ::subtle::CtOption::new(
sqrt, sqrt,
@ -430,7 +435,8 @@ 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); // Addition chain for (t - 1) // 2
let t_minus_1_over_2 = pow_fixed::generate(&quote! {self}, (&t - BigUint::one()) >> 1);
quote! { quote! {
impl ::ff::SqrtField for #name { impl ::ff::SqrtField for #name {
@ -440,7 +446,9 @@ fn prime_field_constants_and_sqrt(
use ::subtle::{ConditionallySelectable, ConstantTimeEq}; use ::subtle::{ConditionallySelectable, ConstantTimeEq};
// w = self^((t - 1) // 2) // w = self^((t - 1) // 2)
let w = self.pow_vartime(#t_minus_1_over_2); let w = {
#t_minus_1_over_2
};
let mut v = S; let mut v = S;
let mut x = *self * &w; let mut x = *self * &w;
@ -744,11 +752,10 @@ fn prime_field_impl(
a: proc_macro2::TokenStream, a: proc_macro2::TokenStream,
name: &syn::Ident, name: &syn::Ident,
modulus: &BigUint, modulus: &BigUint,
limbs: usize,
) -> proc_macro2::TokenStream { ) -> proc_macro2::TokenStream {
let mod_minus_2 = biguint_to_u64_vec(modulus - BigUint::from(2u64), limbs); // Addition chain for p - 2
let mod_minus_2 = pow_fixed::generate(&a, modulus - BigUint::from(2u64));
// TODO: Improve on this by computing an addition chain for mod_minus_two
quote! { quote! {
use ::subtle::ConstantTimeEq; use ::subtle::ConstantTimeEq;
@ -758,7 +765,9 @@ fn prime_field_impl(
// `ff_derive` requires that `p` is prime; in this case, `phi(p) = p - 1`, and // `ff_derive` requires that `p` is prime; in this case, `phi(p) = p - 1`, and
// thus: // thus:
// a^-1 ≡ a^(p - 2) mod p // a^-1 ≡ a^(p - 2) mod p
let inv = #a.pow_vartime(#mod_minus_2); let inv = {
#mod_minus_2
};
::subtle::CtOption::new(inv, !#a.ct_eq(&#name::zero())) ::subtle::CtOption::new(inv, !#a.ct_eq(&#name::zero()))
} }
@ -766,7 +775,7 @@ fn prime_field_impl(
let squaring_impl = sqr_impl(quote! {self}, limbs); let squaring_impl = sqr_impl(quote! {self}, limbs);
let multiply_impl = mul_impl(quote! {self}, quote! {other}, limbs); let multiply_impl = mul_impl(quote! {self}, quote! {other}, limbs);
let invert_impl = inv_impl(quote! {self}, name, modulus, limbs); let invert_impl = inv_impl(quote! {self}, name, modulus);
let montgomery_impl = mont_impl(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]) & ... // (self.0).0[0].ct_eq(&(other.0).0[0]) & (self.0).0[1].ct_eq(&(other.0).0[1]) & ...