Comments and slight refactoring.

This commit is contained in:
Sean Bowe 2017-06-27 09:40:58 -06:00
parent 02f503c74d
commit bbc7b44f88

View File

@ -45,7 +45,7 @@ pub fn prime_field(
let mut limbs = 1; let mut limbs = 1;
{ {
let mod2 = (&modulus) << 1; // modulus * 2 let mod2 = (&modulus) << 1; // modulus * 2
let mut cur = BigUint::one() << 64; let mut cur = BigUint::one() << 64; // always 64-bit limbs for now
while cur < mod2 { while cur < mod2 {
limbs += 1; limbs += 1;
cur = cur << 64; cur = cur << 64;
@ -62,6 +62,7 @@ pub fn prime_field(
gen.parse().unwrap() gen.parse().unwrap()
} }
/// Fetches the ident being wrapped by the type we're deriving.
fn fetch_wrapped_ident( fn fetch_wrapped_ident(
body: &syn::Body body: &syn::Body
) -> Option<syn::Ident> ) -> Option<syn::Ident>
@ -115,6 +116,7 @@ fn fetch_attr(
None None
} }
// Implement PrimeFieldRepr for the wrapped ident `repr` with `limbs` limbs.
fn prime_field_repr_impl( fn prime_field_repr_impl(
repr: &syn::Ident, repr: &syn::Ident,
limbs: usize limbs: usize
@ -125,6 +127,7 @@ fn prime_field_repr_impl(
pub struct #repr(pub [u64; #limbs]); pub struct #repr(pub [u64; #limbs]);
impl ::rand::Rand for #repr { impl ::rand::Rand for #repr {
#[inline(always)]
fn rand<R: ::rand::Rng>(rng: &mut R) -> Self { fn rand<R: ::rand::Rng>(rng: &mut R) -> Self {
#repr(rng.gen()) #repr(rng.gen())
} }
@ -143,6 +146,7 @@ fn prime_field_repr_impl(
} }
impl AsRef<[u64]> for #repr { impl AsRef<[u64]> for #repr {
#[inline(always)]
fn as_ref(&self) -> &[u64] { fn as_ref(&self) -> &[u64] {
&self.0 &self.0
} }
@ -160,6 +164,7 @@ fn prime_field_repr_impl(
} }
impl Ord for #repr { impl Ord for #repr {
#[inline(always)]
fn cmp(&self, other: &#repr) -> ::std::cmp::Ordering { fn cmp(&self, other: &#repr) -> ::std::cmp::Ordering {
for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) { for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
if a < b { if a < b {
@ -174,6 +179,7 @@ fn prime_field_repr_impl(
} }
impl PartialOrd for #repr { impl PartialOrd for #repr {
#[inline(always)]
fn partial_cmp(&self, other: &#repr) -> Option<::std::cmp::Ordering> { fn partial_cmp(&self, other: &#repr) -> Option<::std::cmp::Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
} }
@ -256,6 +262,7 @@ fn prime_field_repr_impl(
} }
} }
/// Convert BigUint into a vector of 64-bit limbs.
fn biguint_to_u64_vec( fn biguint_to_u64_vec(
mut v: BigUint, mut v: BigUint,
limbs: usize limbs: usize
@ -273,6 +280,8 @@ fn biguint_to_u64_vec(
ret.push(0); ret.push(0);
} }
assert!(ret.len() == limbs);
ret ret
} }
@ -290,6 +299,7 @@ fn biguint_num_bits(
bits bits
} }
/// BigUint modular exponentiation by square-and-multiply.
fn exp( fn exp(
base: BigUint, base: BigUint,
exp: &BigUint, exp: &BigUint,
@ -332,6 +342,11 @@ fn prime_field_constants_and_sqrt(
) -> quote::Tokens ) -> quote::Tokens
{ {
let modulus_num_bits = biguint_num_bits(modulus.clone()); let modulus_num_bits = biguint_num_bits(modulus.clone());
// The number of bits we should "shave" from a randomly sampled reputation, i.e.,
// if our modulus is 381 bits and our representation is 384 bits, we should shave
// 3 bits from the beginning of a randomly sampled 384 bit representation to
// reduce the cost of rejection sampling.
let repr_shave_bits = (64 * limbs as u32) - biguint_num_bits(modulus.clone()); let repr_shave_bits = (64 * limbs as u32) - biguint_num_bits(modulus.clone());
// Compute R = 2**(64 * limbs) mod m // Compute R = 2**(64 * limbs) mod m
@ -345,7 +360,7 @@ fn prime_field_constants_and_sqrt(
s += 1; s += 1;
} }
// Compute root of unity given the generator // 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 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 generator = biguint_to_u64_vec((generator.clone() * &r) % &modulus, limbs);
@ -480,16 +495,20 @@ fn prime_field_constants_and_sqrt(
} }
} }
/// Implement PrimeField for the derived type.
fn prime_field_impl( fn prime_field_impl(
name: &syn::Ident, name: &syn::Ident,
repr: &syn::Ident, repr: &syn::Ident,
limbs: usize limbs: usize
) -> quote::Tokens ) -> quote::Tokens
{ {
// Returns r{n} as an ident.
fn get_temp(n: usize) -> syn::Ident { fn get_temp(n: usize) -> syn::Ident {
syn::Ident::from(format!("r{}", n)) syn::Ident::from(format!("r{}", n))
} }
// The parameter list for the mont_reduce() internal method.
// r0: u64, mut r1: u64, mut r2: u64, ...
let mut mont_paramlist = quote::Tokens::new(); let mut mont_paramlist = quote::Tokens::new();
mont_paramlist.append_separated( mont_paramlist.append_separated(
(0..(limbs*2)).map(|i| (i, get_temp(i))) (0..(limbs*2)).map(|i| (i, get_temp(i)))
@ -501,51 +520,58 @@ fn prime_field_impl(
} }
}), }),
"," ","
); // r0: u64, mut r1: u64, mut r2: u64, ... );
let mut mont_impl = quote::Tokens::new(); // Implement montgomery reduction for some number of limbs
for i in 0..limbs { fn mont_impl(limbs: usize) -> quote::Tokens
{ {
let temp = get_temp(i); let mut gen = quote::Tokens::new();
mont_impl.append(quote!{
let k = #temp.wrapping_mul(INV); for i in 0..limbs {
let mut carry = 0; {
::ff::mac_with_carry(#temp, k, MODULUS.0[0], &mut carry); let temp = get_temp(i);
gen.append(quote!{
let k = #temp.wrapping_mul(INV);
let mut carry = 0;
::ff::mac_with_carry(#temp, k, MODULUS.0[0], &mut carry);
});
}
for j in 1..limbs {
let temp = get_temp(i + j);
gen.append(quote!{
#temp = ::ff::mac_with_carry(#temp, k, MODULUS.0[#j], &mut carry);
});
}
let temp = get_temp(i + limbs);
if i == 0 {
gen.append(quote!{
#temp = ::ff::adc(#temp, 0, &mut carry);
});
} else {
gen.append(quote!{
#temp = ::ff::adc(#temp, carry2, &mut carry);
});
}
if i != (limbs - 1) {
gen.append(quote!{
let carry2 = carry;
});
}
}
for i in 0..limbs {
let temp = get_temp(limbs + i);
gen.append(quote!{
(self.0).0[#i] = #temp;
}); });
} }
for j in 1..limbs { gen
let temp = get_temp(i + j);
mont_impl.append(quote!{
#temp = ::ff::mac_with_carry(#temp, k, MODULUS.0[#j], &mut carry);
});
}
let temp = get_temp(i + limbs);
if i == 0 {
mont_impl.append(quote!{
#temp = ::ff::adc(#temp, 0, &mut carry);
});
} else {
mont_impl.append(quote!{
#temp = ::ff::adc(#temp, carry2, &mut carry);
});
}
if i != (limbs - 1) {
mont_impl.append(quote!{
let carry2 = carry;
});
}
}
for i in 0..limbs {
let temp = get_temp(limbs + i);
mont_impl.append(quote!{
(self.0).0[#i] = #temp;
});
} }
fn sqr_impl(a: quote::Tokens, limbs: usize) -> quote::Tokens fn sqr_impl(a: quote::Tokens, limbs: usize) -> quote::Tokens
@ -673,7 +699,9 @@ 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 montgomery_impl = mont_impl(limbs);
// (self.0).0[0], (self.0).0[1], ..., 0, 0, 0, 0, ...
let mut into_repr_params = quote::Tokens::new(); let mut into_repr_params = quote::Tokens::new();
into_repr_params.append_separated( into_repr_params.append_separated(
(0..limbs).map(|i| quote!{ (self.0).0[#i] }) (0..limbs).map(|i| quote!{ (self.0).0[#i] })
@ -921,7 +949,7 @@ fn prime_field_impl(
// Handbook of Applied Cryptography // Handbook of Applied Cryptography
// <http://cacr.uwaterloo.ca/hac/about/chap14.pdf>. // <http://cacr.uwaterloo.ca/hac/about/chap14.pdf>.
#mont_impl #montgomery_impl
self.reduce(); self.reduce();
} }