mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-01-30 15:32:14 +00:00
Merge pull request #194 from str4d/ct-invert
Constant-time field inversion in ff_derive using pow_vartime
This commit is contained in:
commit
b5523f610e
@ -47,11 +47,11 @@ 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));
|
||||
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
|
||||
@ -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;
|
||||
@ -542,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.
|
||||
@ -744,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]) & ...
|
||||
@ -1058,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<Self> {
|
||||
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)]
|
||||
|
Loading…
Reference in New Issue
Block a user