From 13a822f994e1d9c13218c79a3a2ba8fb4cc5cf68 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Mon, 26 Jun 2017 11:47:35 -0600 Subject: [PATCH] Add auto-derivation of prime fields, and modify the traits a little bit. --- ff_derive/src/lib.rs | 637 +++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 26 +- 2 files changed, 635 insertions(+), 28 deletions(-) diff --git a/ff_derive/src/lib.rs b/ff_derive/src/lib.rs index 740cda2..02234d4 100644 --- a/ff_derive/src/lib.rs +++ b/ff_derive/src/lib.rs @@ -1,20 +1,22 @@ +#![recursion_limit="1024"] + extern crate proc_macro; -//extern crate syn; -//#[macro_use] +extern crate syn; +#[macro_use] extern crate quote; -//extern crate num_bigint; -//extern crate num_traits; +extern crate num_bigint; +extern crate num_traits; -//use num_traits::{Zero, One, ToPrimitive}; -//use num_bigint::BigUint; +use num_traits::{Zero, One, ToPrimitive}; +use num_bigint::BigUint; +use std::str::FromStr; #[proc_macro_derive(PrimeField, attributes(PrimeFieldModulus))] pub fn prime_field( - _: proc_macro::TokenStream + input: proc_macro::TokenStream ) -> proc_macro::TokenStream { - /* // Construct a string representation of the type definition let s = input.to_string(); @@ -32,7 +34,6 @@ pub fn prime_field( // The arithmetic in this library only works if the modulus*2 is smaller than the backing // representation. Compute the number of limbs we need. - let mut limbs = 1; { let mod2 = (&modulus) << 1; // modulus * 2 @@ -42,20 +43,18 @@ pub fn prime_field( cur = cur << 64; } } - */ - let gen = quote::Tokens::new(); + let mut gen = quote::Tokens::new(); - //gen.append(prime_field_repr_impl(&repr_ident, limbs)); - //gen.append(prime_field_constants(&repr_ident, modulus, limbs)); - //gen.append(prime_field_impl(&ast.ident, &repr_ident)); + gen.append(prime_field_repr_impl(&repr_ident, limbs)); + gen.append(prime_field_constants_and_sqrt(&ast.ident, &repr_ident, modulus, limbs)); + gen.append(prime_field_impl(&ast.ident, &repr_ident, limbs)); //gen.append(prime_field_arith_impl(&ast.ident, &repr_ident, limbs)); // Return the generated impl gen.parse().unwrap() } -/* fn fetch_wrapped_ident( body: &syn::Body ) -> Option @@ -108,4 +107,610 @@ fn fetch_attr( None } -*/ + +fn prime_field_repr_impl( + repr: &syn::Ident, + limbs: usize +) -> quote::Tokens +{ + quote! { + #[derive(Copy, Clone, PartialEq, Eq, Default)] + pub struct #repr(pub [u64; #limbs]); + + impl ::rand::Rand for #repr { + fn rand(rng: &mut R) -> Self { + #repr(rng.gen()) + } + } + + impl ::std::fmt::Debug for #repr + { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + try!(write!(f, "0x")); + for i in self.0.iter().rev() { + try!(write!(f, "{:016x}", *i)); + } + + Ok(()) + } + } + + impl AsRef<[u64]> for #repr { + fn as_ref(&self) -> &[u64] { + &self.0 + } + } + + impl From for #repr { + #[inline(always)] + fn from(val: u64) -> #repr { + use std::default::Default; + + let mut repr = Self::default(); + repr.0[0] = val; + repr + } + } + + impl Ord for #repr { + fn cmp(&self, other: &#repr) -> ::std::cmp::Ordering { + for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) { + if a < b { + return ::std::cmp::Ordering::Less + } else if a > b { + return ::std::cmp::Ordering::Greater + } + } + + ::std::cmp::Ordering::Equal + } + } + + impl PartialOrd for #repr { + fn partial_cmp(&self, other: &#repr) -> Option<::std::cmp::Ordering> { + Some(self.cmp(other)) + } + } + + impl ::ff::PrimeFieldRepr for #repr { + #[inline(always)] + fn is_odd(&self) -> bool { + self.0[0] & 1 == 1 + } + + #[inline(always)] + fn is_even(&self) -> bool { + !self.is_odd() + } + + #[inline(always)] + fn is_zero(&self) -> bool { + self.0.iter().all(|&e| e == 0) + } + + #[inline(always)] + fn div2(&mut self) { + let mut t = 0; + for i in self.0.iter_mut().rev() { + let t2 = *i << 63; + *i >>= 1; + *i |= t; + t = t2; + } + } + + #[inline(always)] + fn mul2(&mut self) { + let mut last = 0; + for i in self.0.iter_mut() { + let tmp = *i >> 63; + *i <<= 1; + *i |= last; + last = tmp; + } + } + + #[inline(always)] + fn num_bits(&self) -> u32 { + let mut ret = (#limbs as u32) * 64; + for i in self.0.iter().rev() { + let leading = i.leading_zeros(); + ret -= leading; + if leading != 64 { + break; + } + } + + ret + } + + #[inline(always)] + fn add_nocarry(&mut self, other: &#repr) -> bool { + let mut carry = 0; + + for (a, b) in self.0.iter_mut().zip(other.0.iter()) { + *a = ::ff::adc(*a, *b, &mut carry); + } + + carry != 0 + } + + #[inline(always)] + fn sub_noborrow(&mut self, other: &#repr) -> bool { + let mut borrow = 0; + + for (a, b) in self.0.iter_mut().zip(other.0.iter()) { + *a = ::ff::sbb(*a, *b, &mut borrow); + } + + borrow != 0 + } + } + } +} + +fn biguint_to_u64_vec( + mut v: BigUint +) -> Vec +{ + let m = BigUint::one() << 64; + let mut ret = vec![]; + + while v > BigUint::zero() { + ret.push((&v % &m).to_u64().unwrap()); + v = v >> 64; + } + + ret +} + +fn biguint_num_bits( + mut v: BigUint +) -> u32 +{ + let mut bits = 0; + + while v != BigUint::zero() { + v = v >> 1; + bits += 1; + } + + bits +} + +fn prime_field_constants_and_sqrt( + name: &syn::Ident, + repr: &syn::Ident, + modulus: BigUint, + limbs: usize +) -> quote::Tokens +{ + let modulus_num_bits = 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 + let r = (BigUint::one() << (limbs * 64)) % &modulus; + + let sqrt_impl = + if (&modulus % BigUint::from_str("4").unwrap()) == BigUint::from_str("3").unwrap() { + let mod_minus_3_over_4 = biguint_to_u64_vec((&modulus - BigUint::from_str("3").unwrap()) >> 2); + + // Compute -R as (m - r) + let rneg = biguint_to_u64_vec(&modulus - &r); + + quote!{ + impl ::ff::SqrtField for #name { + fn sqrt(&self) -> Option { + // Shank's algorithm for q mod 4 = 3 + // https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2) + + let mut a1 = self.pow(#mod_minus_3_over_4); + + let mut a0 = a1; + a0.square(); + a0.mul_assign(self); + + if a0.0 == #repr(#rneg) { + None + } else { + a1.mul_assign(self); + Some(a1) + } + } + } + } + } else { + quote!{} + }; + + // Compute R^2 mod m + let r2 = biguint_to_u64_vec((&r * &r) % &modulus); + + let r = biguint_to_u64_vec(r); + let modulus = biguint_to_u64_vec(modulus); + + // Compute -m^-1 mod 2**64 by exponentiating by totient(2**64) - 1 + let mut inv = 1u64; + for _ in 0..63 { + inv = inv.wrapping_mul(inv); + inv = inv.wrapping_mul(modulus[0]); + } + inv = inv.wrapping_neg(); + + quote! { + /// This is the modulus m of the prime field + const MODULUS: #repr = #repr(#modulus); + + /// The number of bits needed to represent the modulus. + const MODULUS_BITS: u32 = #modulus_num_bits; + + /// The number of bits that must be shaved from the beginning of + /// the representation when randomly sampling. + const REPR_SHAVE_BITS: u32 = #repr_shave_bits; + + /// 2^{limbs*64} mod m + const R: #repr = #repr(#r); + + /// 2^{limbs*64*2} mod m + const R2: #repr = #repr(#r2); + + /// -(m^{-1} mod m) mod m + const INV: u64 = #inv; + + #sqrt_impl + } +} + +fn prime_field_impl( + name: &syn::Ident, + repr: &syn::Ident, + limbs: usize +) -> quote::Tokens +{ + fn get_temp(n: usize) -> syn::Ident { + syn::Ident::from(format!("r{}", n)) + } + + let mut mont_paramlist = quote::Tokens::new(); + mont_paramlist.append_separated( + (0..(limbs*2)).map(|i| (i, get_temp(i))) + .map(|(i, x)| { + if i != 0 { + quote!{mut #x: u64} + } else { + quote!{#x: u64} + } + }), + "," + ); // r0: u64, mut r1: u64, mut r2: u64, ... + + let mut mont_impl = quote::Tokens::new(); + for i in 0..limbs { + { + let temp = get_temp(i); + mont_impl.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); + 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 mul_impl(a: quote::Tokens, b: quote::Tokens, limbs: usize) -> quote::Tokens + { + let mut gen = quote::Tokens::new(); + + for i in 0..limbs { + gen.append(quote!{ + let mut carry = 0; + }); + + for j in 0..limbs { + let temp = get_temp(i + j); + + if i == 0 { + gen.append(quote!{ + let #temp = ::ff::mac_with_carry(0, (#a.0).0[#i], (#b.0).0[#j], &mut carry); + }); + } else { + gen.append(quote!{ + let #temp = ::ff::mac_with_carry(#temp, (#a.0).0[#i], (#b.0).0[#j], &mut carry); + }); + } + } + + let temp = get_temp(i + limbs); + + gen.append(quote!{ + let #temp = carry; + }); + } + + let mut mont_calling = quote::Tokens::new(); + mont_calling.append_separated((0..(limbs*2)).map(|i| get_temp(i)), ","); + + gen.append(quote!{ + self.mont_reduce(#mont_calling); + }); + + gen + } + + let squaring_impl = mul_impl(quote!{self}, quote!{self}, limbs); + let multiply_impl = mul_impl(quote!{self}, quote!{other}, limbs); + + let mut into_repr_params = quote::Tokens::new(); + into_repr_params.append_separated( + (0..limbs).map(|i| quote!{ (self.0).0[#i] }) + .chain((0..limbs).map(|_| quote!{0})), + "," + ); + + quote!{ + impl Copy for #name { } + + impl Clone for #name { + fn clone(&self) -> #name { + *self + } + } + + impl PartialEq for #name { + fn eq(&self, other: &#name) -> bool { + self.0 == other.0 + } + } + + impl Eq for #name { } + + impl ::std::fmt::Debug for #name + { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{}({:?})", stringify!(#name), self.into_repr()) + } + } + + impl Rand for #name { + /// Computes a uniformly random element using rejection sampling. + fn rand(rng: &mut R) -> Self { + loop { + let mut tmp = #name(#repr::rand(rng)); + for _ in 0..REPR_SHAVE_BITS { + tmp.0.div2(); + } + if tmp.is_valid() { + return tmp + } + } + } + } + + impl ::ff::PrimeField for #name { + type Repr = #repr; + + fn from_repr(r: #repr) -> Result<#name, ()> { + let mut r = #name(r); + if r.is_valid() { + r.mul_assign(&#name(R2)); + + Ok(r) + } else { + Err(()) + } + } + + fn into_repr(&self) -> #repr { + let mut r = *self; + r.mont_reduce( + #into_repr_params + ); + + r.0 + } + + fn char() -> #repr { + MODULUS + } + + fn num_bits() -> u32 { + MODULUS_BITS + } + + fn capacity() -> u32 { + Self::num_bits() - 1 + } + } + + impl ::ff::Field for #name { + #[inline] + fn zero() -> Self { + #name(#repr::from(0)) + } + + #[inline] + fn one() -> Self { + #name(R) + } + + #[inline] + fn is_zero(&self) -> bool { + self.0.is_zero() + } + + #[inline] + fn add_assign(&mut self, other: &#name) { + // This cannot exceed the backing capacity. + self.0.add_nocarry(&other.0); + + // However, it may need to be reduced. + self.reduce(); + } + + #[inline] + fn double(&mut self) { + // This cannot exceed the backing capacity. + self.0.mul2(); + + // However, it may need to be reduced. + self.reduce(); + } + + #[inline] + fn sub_assign(&mut self, other: &#name) { + // If `other` is larger than `self`, we'll need to add the modulus to self first. + if other.0 > self.0 { + self.0.add_nocarry(&MODULUS); + } + + self.0.sub_noborrow(&other.0); + } + + #[inline] + fn negate(&mut self) { + if !self.is_zero() { + let mut tmp = MODULUS; + tmp.sub_noborrow(&self.0); + self.0 = tmp; + } + } + + fn inverse(&self) -> Option { + if self.is_zero() { + None + } 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 { + Some(b) + } else { + Some(c) + } + } + } + + #[inline(always)] + fn frobenius_map(&mut self, _: usize) { + // This has no effect in a prime field. + } + + #[inline] + fn mul_assign(&mut self, other: &#name) + { + #multiply_impl + } + + #[inline] + fn square(&mut self) + { + #squaring_impl + } + } + + impl #name { + /// Determines if the element is really in the field. This is only used + /// internally. + #[inline(always)] + fn is_valid(&self) -> bool { + self.0 < MODULUS + } + + /// Subtracts the modulus from this element if this element is not in the + /// field. Only used interally. + #[inline(always)] + fn reduce(&mut self) { + if !self.is_valid() { + self.0.sub_noborrow(&MODULUS); + } + } + + #[inline(always)] + fn mont_reduce( + &mut self, + #mont_paramlist + ) + { + // The Montgomery reduction here is based on Algorithm 14.32 in + // Handbook of Applied Cryptography + // . + + #mont_impl + + self.reduce(); + } + } + } +} diff --git a/src/lib.rs b/src/lib.rs index bd76b93..c29117f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,12 @@ #![feature(i128_type)] +#![allow(unused_imports)] extern crate rand; -//#[macro_use] -//extern crate ff_derive; +#[macro_use] +extern crate ff_derive; -//pub use ff_derive::*; +pub use ff_derive::*; use std::fmt; @@ -50,7 +51,8 @@ pub trait Field: Sized + /// Computes the multiplicative inverse of this element, if nonzero. fn inverse(&self) -> Option; - /// Exponentiates this element by a power of the modulus. + /// Exponentiates this element by a power of the base prime modulus via + /// the Frobenius automorphism. fn frobenius_map(&mut self, power: usize); /// Exponentiates this element by a number represented with `u64` limbs, @@ -94,14 +96,14 @@ pub trait PrimeFieldRepr: Sized + AsRef<[u64]> + From { - /// Subtract another reprensetation from this one. Underflow is ignored. - fn sub_noborrow(&mut self, other: &Self); + /// Subtract another reprensetation from this one, returning the borrow bit. + fn sub_noborrow(&mut self, other: &Self) -> bool; - /// Add another representation to this one. Overflow is ignored. - fn add_nocarry(&mut self, other: &Self); + /// Add another representation to this one, returning the carry bit. + fn add_nocarry(&mut self, other: &Self) -> bool; /// Compute the number of bits needed to encode this number. - fn num_bits(&self) -> usize; + fn num_bits(&self) -> u32; /// Returns true iff this number is zero. fn is_zero(&self) -> bool; @@ -122,7 +124,7 @@ pub trait PrimeFieldRepr: Sized + } /// This represents an element of a prime field. -pub trait PrimeField: SqrtField +pub trait PrimeField: Field { /// The prime field can be converted back and forth into this biginteger /// representation. @@ -140,11 +142,11 @@ pub trait PrimeField: SqrtField /// Returns how many bits are needed to represent an element of this /// field. - fn num_bits() -> usize; + fn num_bits() -> u32; /// Returns how many bits of information can be reliably stored in the /// field element. - fn capacity() -> usize; + fn capacity() -> u32; } pub struct BitIterator {